Initial commit
This commit is contained in:
commit
0d15277178
|
@ -0,0 +1 @@
|
|||
config.yml
|
|
@ -0,0 +1,9 @@
|
|||
source "http://rubygems.org"
|
||||
|
||||
gem "sinatra"
|
||||
gem "sinatra-contrib"
|
||||
gem "riak-client"
|
||||
|
||||
group :test do
|
||||
gem 'purdytest', :require => false
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
backports (2.3.0)
|
||||
beefcake (0.3.7)
|
||||
builder (3.0.0)
|
||||
eventmachine (0.12.10)
|
||||
i18n (0.6.0)
|
||||
minitest (2.10.0)
|
||||
multi_json (1.0.4)
|
||||
purdytest (1.0.0)
|
||||
minitest (~> 2.2)
|
||||
rack (1.3.5)
|
||||
rack-protection (1.1.4)
|
||||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
riak-client (1.0.0)
|
||||
beefcake (~> 0.3.7)
|
||||
builder (>= 2.1.2)
|
||||
i18n (>= 0.4.0)
|
||||
multi_json (~> 1.0.0)
|
||||
sinatra (1.3.1)
|
||||
rack (>= 1.3.4, ~> 1.3)
|
||||
rack-protection (>= 1.1.2, ~> 1.1)
|
||||
tilt (>= 1.3.3, ~> 1.3)
|
||||
sinatra-contrib (1.3.1)
|
||||
backports (>= 2.0)
|
||||
eventmachine
|
||||
rack-protection
|
||||
rack-test
|
||||
sinatra (~> 1.3.0)
|
||||
tilt (~> 1.3)
|
||||
tilt (1.3.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
purdytest
|
||||
riak-client
|
||||
sinatra
|
||||
sinatra-contrib
|
|
@ -0,0 +1,13 @@
|
|||
# Liquor Cabinet
|
||||
|
||||
Liquor Cabinet is where Frank stores all his stuff. It's a
|
||||
remoteStorage-compatible storage provider API, based on Sinatra and currently
|
||||
using Riak as backend. You can use it on its own, or e.g. mount it from a Rails
|
||||
application.
|
||||
|
||||
It's merely implementing the storage API, not including the Webfinger and Oauth
|
||||
parts of remoteStorage. You have to set the authorization keys/values in the
|
||||
database yourself.
|
||||
|
||||
If you have any questions about this thing, drop by #unhosted on Freenode, and
|
||||
we'll happily answer them.
|
|
@ -0,0 +1,5 @@
|
|||
require 'rake/testtask'
|
||||
|
||||
Rake::TestTask.new do |t|
|
||||
t.pattern = 'spec/**/*_spec.rb'
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
require 'rubygems'
|
||||
require 'bundler'
|
||||
|
||||
Bundler.require
|
||||
|
||||
require './liquor_cabinet'
|
||||
run LiquorCabinet
|
|
@ -0,0 +1,11 @@
|
|||
development:
|
||||
riak:
|
||||
host: localhost
|
||||
http_port: 8098
|
||||
|
||||
test:
|
||||
riak:
|
||||
host: localhost
|
||||
http_port: 8098
|
||||
|
||||
production:
|
|
@ -0,0 +1,43 @@
|
|||
require "riak"
|
||||
|
||||
module RemoteStorage
|
||||
module Riak
|
||||
|
||||
def authorize_request(user, category, token)
|
||||
return true if category == "public" && env["REQUEST_METHOD"] == "GET"
|
||||
|
||||
client = ::Riak::Client.new(settings.riak_config)
|
||||
categories = client.bucket("authorizations").get("#{user}:#{token}").data
|
||||
|
||||
halt 403 unless categories.include?(category)
|
||||
rescue ::Riak::HTTPFailedRequest
|
||||
halt 403
|
||||
end
|
||||
|
||||
def get_data(user, category, key)
|
||||
client = ::Riak::Client.new(settings.riak_config)
|
||||
client.bucket("user_data").get("#{user}:#{category}:#{key}").data
|
||||
rescue ::Riak::HTTPFailedRequest
|
||||
halt 404
|
||||
end
|
||||
|
||||
def put_data(user, category, key, data)
|
||||
client = ::Riak::Client.new(settings.riak_config)
|
||||
object = client.bucket("user_data").new("#{user}:#{category}:#{key}")
|
||||
object.content_type = "text/plain"
|
||||
object.data = data
|
||||
object.store
|
||||
rescue ::Riak::HTTPFailedRequest
|
||||
halt 422
|
||||
end
|
||||
|
||||
def delete_data(user, category, key)
|
||||
client = ::Riak::Client.new(settings.riak_config)
|
||||
riak_response = client.bucket("user_data").delete("#{user}:#{category}:#{key}")
|
||||
halt riak_response[:code]
|
||||
rescue ::Riak::HTTPFailedRequest
|
||||
halt 404
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib/', __FILE__)
|
||||
$:.unshift lib unless $:.include?(lib)
|
||||
|
||||
require 'bundler/version'
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "liquor-cabinet"
|
||||
s.version = "0.0.1"
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["Sebastian Kippe"]
|
||||
s.email = ["sebastian@5apps.com"]
|
||||
s.homepage = ""
|
||||
s.summary = ""
|
||||
s.description = ""
|
||||
|
||||
s.required_rubygems_version = ">= 1.3.6"
|
||||
|
||||
s.add_dependency('sinatra')
|
||||
s.add_dependency('sinatra-contrib')
|
||||
s.add_dependency('riak-client')
|
||||
|
||||
s.files = Dir.glob("{bin,lib}/**/*") + Dir['*.rb']
|
||||
# s.executables = ['config.ru']
|
||||
s.require_paths << '.'
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
$LOAD_PATH << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
|
||||
|
||||
require "json"
|
||||
require "sinatra/base"
|
||||
require "sinatra/reloader"
|
||||
require "remote_storage/riak"
|
||||
|
||||
class LiquorCabinet < Sinatra::Base
|
||||
|
||||
include RemoteStorage::Riak
|
||||
|
||||
configure :development do
|
||||
register Sinatra::Reloader
|
||||
enable :logging
|
||||
end
|
||||
|
||||
configure :development, :test, :production do
|
||||
config = File.read(File.expand_path('config.yml', File.dirname(__FILE__)))
|
||||
riak_config = YAML.load(config)[ENV['RACK_ENV']]['riak'].symbolize_keys
|
||||
set :riak_config, riak_config
|
||||
end
|
||||
|
||||
before "/:user/:category/:key" do
|
||||
@user, @category, @key = params[:user], params[:category], params[:key]
|
||||
token = env["HTTP_AUTHORIZATION"] ? env["HTTP_AUTHORIZATION"].split(" ")[1] : ""
|
||||
|
||||
authorize_request(@user, @category, token)
|
||||
end
|
||||
|
||||
get "/ohai" do
|
||||
"Ohai."
|
||||
end
|
||||
|
||||
get "/headers" do
|
||||
env["HTTP_AUTHORIZATION"]
|
||||
end
|
||||
|
||||
get "/:user/:category/:key" do
|
||||
get_data(@user, @category, @key)
|
||||
end
|
||||
|
||||
put "/:user/:category/:key" do
|
||||
data = request.body.read
|
||||
put_data(@user, @category, @key, data)
|
||||
end
|
||||
|
||||
delete "/:user/:category/:key" do
|
||||
delete_data(@user, @category, @key)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,137 @@
|
|||
ENV["RACK_ENV"] = "test"
|
||||
require_relative "spec_helper"
|
||||
|
||||
describe "App" do
|
||||
include Rack::Test::Methods
|
||||
include RemoteStorage::Riak
|
||||
|
||||
def app
|
||||
LiquorCabinet
|
||||
end
|
||||
|
||||
def storage_client
|
||||
::Riak::Client.new(settings.riak_config)
|
||||
end
|
||||
|
||||
it "should say hello" do
|
||||
get "/ohai"
|
||||
assert last_response.ok?
|
||||
last_response.body.must_include "Ohai."
|
||||
end
|
||||
|
||||
it "should return 404 on non-existing routes" do
|
||||
get "/myunclesam"
|
||||
last_response.status.must_equal 404
|
||||
end
|
||||
|
||||
describe "GET public data" do
|
||||
before do
|
||||
object = storage_client.bucket("user_data").new("jimmy:public:foo")
|
||||
object.content_type = "text/plain"
|
||||
object.data = "some text data"
|
||||
object.store
|
||||
end
|
||||
|
||||
after do
|
||||
storage_client.bucket("user_data").delete("jimmy:public:foo")
|
||||
end
|
||||
|
||||
it "returns the value on all get requests" do
|
||||
get "/jimmy/public/foo"
|
||||
|
||||
last_response.status.must_equal 200
|
||||
last_response.body.must_equal "some text data"
|
||||
end
|
||||
end
|
||||
|
||||
describe "private data" do
|
||||
before do
|
||||
object = storage_client.bucket("user_data").new("jimmy:documents:foo")
|
||||
object.content_type = "text/plain"
|
||||
object.data = "some private text data"
|
||||
object.store
|
||||
|
||||
auth = storage_client.bucket("authorizations").new("jimmy:123")
|
||||
auth.data = ["documents", "public"]
|
||||
auth.store
|
||||
end
|
||||
|
||||
after do
|
||||
storage_client.bucket("user_data").delete("jimmy:documents:foo")
|
||||
storage_client.bucket("authorizations").delete("jimmy:123")
|
||||
end
|
||||
|
||||
describe "GET" do
|
||||
it "returns the value" do
|
||||
header "Authorization", "Bearer 123"
|
||||
get "/jimmy/documents/foo"
|
||||
|
||||
last_response.status.must_equal 200
|
||||
last_response.body.must_equal "some private text data"
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET nonexisting key" do
|
||||
it "returns a 404" do
|
||||
header "Authorization", "Bearer 123"
|
||||
get "/jimmy/documents/somestupidkey"
|
||||
|
||||
last_response.status.must_equal 404
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT" do
|
||||
it "saves the value" do
|
||||
header "Authorization", "Bearer 123"
|
||||
put "/jimmy/documents/bar", "another text"
|
||||
|
||||
last_response.status.must_equal 200
|
||||
storage_client.bucket("user_data").get("jimmy:documents:bar").data.must_equal "another text"
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE" do
|
||||
it "removes the key" do
|
||||
header "Authorization", "Bearer 123"
|
||||
delete "/jimmy/documents/foo"
|
||||
|
||||
last_response.status.must_equal 204
|
||||
lambda {storage_client.bucket("user_data").get("jimmy:documents:foo")}.must_raise Riak::HTTPFailedRequest
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "unauthorized access" do
|
||||
before do
|
||||
auth = storage_client.bucket("authorizations").new("jimmy:123")
|
||||
auth.data = ["documents", "public"]
|
||||
auth.store
|
||||
|
||||
header "Authorization", "Bearer 321"
|
||||
end
|
||||
|
||||
describe "GET" do
|
||||
it "returns a 403" do
|
||||
get "/jimmy/documents/foo"
|
||||
|
||||
last_response.status.must_equal 403
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT" do
|
||||
it "returns a 403" do
|
||||
put "/jimmy/documents/foo", "some text"
|
||||
|
||||
last_response.status.must_equal 403
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE" do
|
||||
it "returns a 403" do
|
||||
delete "/jimmy/documents/foo"
|
||||
|
||||
last_response.status.must_equal 403
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler.require
|
||||
|
||||
require_relative '../liquor_cabinet'
|
||||
require 'minitest/autorun'
|
||||
require 'rack/test'
|
||||
require 'purdytest'
|
||||
require 'riak'
|
||||
|
||||
set :environment, :test
|
||||
|
||||
config = File.read(File.expand_path('../config.yml', File.dirname(__FILE__)))
|
||||
riak_config = YAML.load(config)[ENV['RACK_ENV']]['riak'].symbolize_keys
|
||||
set :riak_config, riak_config
|
Loading…
Reference in New Issue