Compare commits

..

2 Commits

Author SHA1 Message Date
a8637a6982 Remove purdytest, update Minitest class name 2023-10-26 16:14:46 +02:00
2cd13729e5 Add ENV vars to config file, switch to ERB template
Also change S3 endpoint config to not require a trailing slash.
2023-10-26 16:14:35 +02:00
11 changed files with 51 additions and 104 deletions

View File

@@ -1,9 +0,0 @@
kind: pipeline
name: default
steps:
- name: test
image: ruby
commands:
- bundle install --jobs=3 --retry=3
- rake test

View File

@@ -1,33 +0,0 @@
name: Tests
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.7', '3.0', '3.1']
redis-version: [6, 7]
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Start Redis
uses: supercharge/redis-github-action@1.4.0
with:
redis-version: ${{ matrix.redis-version }}
- name: Configure
run: cp config.yml.erb.example config.yml.erb
- name: Run tests
run: bundle exec rake test

View File

@@ -28,6 +28,6 @@ jobs:
with:
redis-version: ${{ matrix.redis-version }}
- name: Configure
run: cp config.yml.erb.example config.yml.erb
run: cp config.yml.erb.example config.yml
- name: Run tests
run: bundle exec rake test

View File

@@ -1,13 +0,0 @@
FROM ruby:3.1.4
WORKDIR /liquorcabinet
ENV RACK_ENV=production
COPY Gemfile Gemfile.lock /liquorcabinet/
RUN bundle install
COPY . /liquorcabinet
COPY ./config.yml.erb.example /liquorcabinet/config.yml.erb
EXPOSE 4567
CMD ["bundle", "exec", "rainbows", "--listen", "0.0.0.0:4567"]

View File

@@ -3,9 +3,8 @@ source "https://rubygems.org"
gem "sinatra", "~> 2.2.0"
gem "sinatra-contrib", "~> 2.2.0"
gem "activesupport", "~> 6.1.0"
gem "redis", "~> 4.6.0"
gem "rest-client", "~> 2.1.0"
gem "aws-sigv4", "~> 1.0.0"
gem "redis", "~> 4.6.0"
# Remove require when we can update to 3.0, which sets the new storage
# format to columnar by default. Increases performance
gem "mime-types"

View File

@@ -9,7 +9,6 @@ GEM
zeitwerk (~> 2.3)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
aws-sigv4 (1.0.3)
base64 (0.1.1)
concurrent-ruby (1.2.2)
crack (0.4.5)
@@ -94,7 +93,6 @@ PLATFORMS
DEPENDENCIES
activesupport (~> 6.1.0)
aws-sigv4 (~> 1.0.0)
m
mime-types
minitest

View File

@@ -12,9 +12,10 @@ protocol, but does not include the Webfinger and OAuth parts. It is meant to be
added to existing systems and user accounts, so you will have to add your own
OAuth dialog for remoteStorage authorizations and persist the tokens in Redis.
If you have any questions about this program, please [post to the RS
If you have any questions about this program, drop by #remotestorage on
Freenode, or [post to the RS
forums](https://community.remotestorage.io/c/server-development), and we'll
gladly answer them.
happily answer them.
## Contributing
@@ -22,5 +23,5 @@ We love pull requests. If you want to submit a patch:
* Fork the project.
* Make your feature addition or bug fix.
* Write specs for it. This is important so nobody breaks it in a future version.
* Write specs for it. This is important so nobody breaks it in a future version unintentionally.
* Push to your fork and send a pull request.

View File

@@ -2,11 +2,10 @@ development: &defaults
maintenance: false
redis:
host: <%= ENV["REDIS_HOST"] || "localhost" %>
port: <%= ENV["REDIS_PORT"] || 6379 %>
db: <%= ENV["REDIS_DB"] || 1 %>
port: <%= ENV["REDIS_PORT"] || "6379" %>
s3: &s3_defaults
endpoint: <%= ENV["S3_ENDPOINT"] || "http://127.0.0.1:9000" %>
region: <%= ENV["S3_REGION"] || "us-east-1" %>
region: <%= ENV["S3_REGION"] %>
access_key_id: <%= ENV["S3_ACCESS_KEY"] || "minioadmin" %>
secret_key_id: <%= ENV["S3_SECRET_KEY"] || "minioadmin" %>
bucket: <%= ENV["S3_BUCKET"] || "rs-development" %>

View File

@@ -10,26 +10,18 @@ module RemoteStorage
private
def s3_signer
signer ||= Aws::Sigv4::Signer.new(
service: 's3',
region: settings.s3["region"],
access_key_id: settings.s3["access_key_id"].to_s,
secret_access_key: settings.s3["secret_key_id"].to_s
)
end
# S3 already wraps the ETag with quotes
# S3 already wraps the ETag around quotes
def format_etag(etag)
etag
end
def do_put_request(url, data, content_type)
deal_with_unauthorized_requests do
headers = { "Content-Type" => content_type }
auth_headers = auth_headers_for("PUT", url, headers, data)
res = RestClient.put(url, data, headers.merge(auth_headers))
md5 = Digest::MD5.base64digest(data)
authorization_headers = authorization_headers_for(
"PUT", url, md5, content_type
).merge({ "Content-Type" => content_type, "Content-Md5" => md5 })
res = RestClient.put(url, data, authorization_headers)
return [
res.headers[:etag].delete('"'),
@@ -40,24 +32,24 @@ module RemoteStorage
def do_get_request(url, &block)
deal_with_unauthorized_requests do
headers = {}
headers = { }
headers["Range"] = server.env["HTTP_RANGE"] if server.env["HTTP_RANGE"]
auth_headers = auth_headers_for("GET", url, headers)
RestClient.get(url, headers.merge(auth_headers), &block)
authorization_headers = authorization_headers_for("GET", url)
RestClient.get(url, authorization_headers.merge(headers), &block)
end
end
def do_head_request(url, &block)
deal_with_unauthorized_requests do
auth_headers = auth_headers_for("HEAD", url)
RestClient.head(url, auth_headers, &block)
authorization_headers = authorization_headers_for("HEAD", url)
RestClient.head(url, authorization_headers, &block)
end
end
def do_delete_request(url)
deal_with_unauthorized_requests do
auth_headers = auth_headers_for("DELETE", url)
RestClient.delete(url, auth_headers)
authorization_headers = authorization_headers_for("DELETE", url)
RestClient.delete(url, authorization_headers)
end
end
@@ -75,17 +67,40 @@ module RemoteStorage
return found
end
def auth_headers_for(http_method, url, headers = {}, data = nil)
signature = s3_signer.sign_request(
http_method: http_method, url: url, headers: headers, body: data
)
signature.headers
# This is using the S3 authorizations, not the newer AW V4 Signatures
# (https://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)
def authorization_headers_for(http_verb, url, md5 = nil, content_type = nil)
url = File.join("/", url.gsub(base_url, ""))
date = Time.now.httpdate
signed_data = generate_s3_signature(http_verb, md5, content_type, date, url)
{
"Authorization" => "AWS #{credentials[:access_key_id]}:#{signed_data}",
"Date" => date
}
end
def credentials
@credentials ||= { access_key_id: settings.s3["access_key_id"], secret_key_id: settings.s3["secret_key_id"] }
end
def digest(secret, string_to_sign)
Base64.encode64(hmac(secret, string_to_sign)).strip
end
def hmac(key, value)
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), key, value)
end
def uri_escape(s)
CGI.escape(s).gsub('%5B', '[').gsub('%5D', ']')
end
def generate_s3_signature(http_verb, md5, content_type, date, url)
string_to_sign = [http_verb, md5, content_type, date, url].join "\n"
signature = digest(credentials[:secret_key_id], string_to_sign)
uri_escape(signature)
end
def base_url
@base_url ||= settings.s3["endpoint"]
end
@@ -94,4 +109,5 @@ module RemoteStorage
"#{base_url}/#{settings.s3["bucket"]}/#{user}"
end
end
end

View File

@@ -64,7 +64,7 @@ class LiquorCabinet < Sinatra::Base
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, PUT, DELETE',
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, Origin, If-Match, If-None-Match, Range',
'Access-Control-Expose-Headers' => 'ETag, Content-Length, Content-Range, Content-Type',
'Access-Control-Expose-Headers' => 'ETag, Content-Length, Content-Range',
'Accept-Ranges' => 'bytes'
headers['Access-Control-Allow-Origin'] = env["HTTP_ORIGIN"] if env["HTTP_ORIGIN"]
headers['Cache-Control'] = 'no-cache'

View File

@@ -1,11 +0,0 @@
#!/bin/bash
RACK_ENV=development \
REDIS_HOST=localhost \
REDIS_PORT=6379 \
REDIS_DB=1 \
S3_ENDPOINT='http://localhost:9000' \
S3_ACCESS_KEY='dev-key' \
S3_SECRET_KEY='123456789' \
S3_BUCKET=remotestorage \
bundle exec rackup -p 4567