cloudkit 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +7 -0
- data/README +29 -1
- data/cloudkit.gemspec +5 -3
- data/doc/curl.html +5 -9
- data/doc/index.html +5 -0
- data/doc/main.css +1 -1
- data/examples/3.ru +1 -1
- data/examples/4.ru +1 -1
- data/examples/5.ru +1 -1
- data/examples/6.ru +2 -2
- data/lib/cloudkit.rb +1 -0
- data/lib/cloudkit/oauth_filter.rb +5 -4
- data/lib/cloudkit/openid_filter.rb +19 -9
- data/lib/cloudkit/openid_store.rb +5 -3
- data/lib/cloudkit/rack/builder.rb +1 -1
- data/lib/cloudkit/rack/lint.rb +12 -0
- data/lib/cloudkit/store/response_helpers.rb +3 -1
- data/test/helper.rb +3 -0
- data/test/service_test.rb +11 -1
- metadata +14 -3
data/CHANGES
CHANGED
@@ -1,2 +1,9 @@
|
|
1
|
+
0.9.1
|
2
|
+
- Fixed Rack::Lint/rackup errors related to Content-Type headers
|
3
|
+
- Patched Rack to support StringIO#string in Rack::Lint::InputWrapper
|
4
|
+
- Fixed server_url encoding in OpenIDStore
|
5
|
+
- Added sqlite3-ruby dependency in gemspec
|
6
|
+
- Updated documentation
|
7
|
+
|
1
8
|
0.9.0
|
2
9
|
- First public gem release
|
data/README
CHANGED
@@ -6,6 +6,10 @@ More specifically, CloudKit provides RESTful JSON storage with optional OpenID a
|
|
6
6
|
|
7
7
|
CloudKit is Rack middleware and as such can be used on its own or alongside other Rack-based applications or middleware components like Rails, Merb or Sinatra.
|
8
8
|
|
9
|
+
===Install
|
10
|
+
|
11
|
+
gem install cloudkit
|
12
|
+
|
9
13
|
===Examples
|
10
14
|
|
11
15
|
In a rackup file called config.ru:
|
@@ -29,10 +33,34 @@ An explicit version of example 2, minus the default developer landing page:
|
|
29
33
|
use CloudKit::OAuthFilter
|
30
34
|
use CloudKit::OpenIDFilter
|
31
35
|
use CloudKit::Service, :collections => [:notes, :todos]
|
32
|
-
run lambda {|env| [200, {}, ['HELLO']]}
|
36
|
+
run lambda {|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
|
37
|
+
|
38
|
+
The same as above, using MySQL:
|
39
|
+
|
40
|
+
require 'cloudkit'
|
41
|
+
use Rack::Config { |env|
|
42
|
+
env['cloudkit.storage.uri'] = 'mysql://user:pass@localhost/cloudkit_example'
|
43
|
+
}
|
44
|
+
use Rack::Pool::Session
|
45
|
+
use CloudKit::OAuthFilter
|
46
|
+
use CloudKit::OpenIDFilter
|
47
|
+
use CloudKit::Service, :collections => [:notes, :todos]
|
48
|
+
run lambda {|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
|
33
49
|
|
34
50
|
See the examples directory for more.
|
35
51
|
|
52
|
+
===Online
|
53
|
+
|
54
|
+
Main Site: http://getcloudkit.com
|
55
|
+
|
56
|
+
Blog: http://blog.joncrosby.me
|
57
|
+
|
58
|
+
Google Group: http://groups.google.com/group/cloudkit
|
59
|
+
|
60
|
+
Source: http://github.com/jcrosby/cloudkit
|
61
|
+
|
62
|
+
===License
|
63
|
+
|
36
64
|
Copyright (c) 2008 Jon Crosby http://joncrosby.me
|
37
65
|
|
38
66
|
Permission is hereby granted, free of charge, to any person obtaining
|
data/cloudkit.gemspec
CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
s.name = "cloudkit"
|
5
|
-
s.version = "0.9.
|
6
|
-
s.date = "2008-12-
|
5
|
+
s.version = "0.9.1"
|
6
|
+
s.date = "2008-12-31"
|
7
7
|
s.summary = "An Open Web JSON Appliance."
|
8
8
|
s.description = "An Open Web JSON Appliance."
|
9
9
|
s.authors = ["Jon Crosby"]
|
@@ -11,11 +11,11 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.homepage = "http://getcloudkit.com"
|
12
12
|
s.files = %w[
|
13
13
|
CHANGES
|
14
|
-
cloudkit.gemspec
|
15
14
|
COPYING
|
16
15
|
README
|
17
16
|
Rakefile
|
18
17
|
TODO
|
18
|
+
cloudkit.gemspec
|
19
19
|
doc/curl.html
|
20
20
|
doc/images/example-code.gif
|
21
21
|
doc/images/json-title.gif
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
lib/cloudkit/openid_filter.rb
|
39
39
|
lib/cloudkit/openid_store.rb
|
40
40
|
lib/cloudkit/rack/builder.rb
|
41
|
+
lib/cloudkit/rack/lint.rb
|
41
42
|
lib/cloudkit/rack/router.rb
|
42
43
|
lib/cloudkit/request.rb
|
43
44
|
lib/cloudkit/service.rb
|
@@ -79,4 +80,5 @@ Gem::Specification.new do |s|
|
|
79
80
|
s.add_dependency 'oauth', '>= 0.2.7'
|
80
81
|
s.add_dependency 'ruby-openid', '= 2.1.2'
|
81
82
|
s.add_dependency 'json', '= 1.1.3'
|
83
|
+
s.add_dependency 'sqlite3-ruby', '= 1.2.4'
|
82
84
|
end
|
data/doc/curl.html
CHANGED
@@ -74,6 +74,7 @@ See what we can do with these note resources:
|
|
74
74
|
$ curl -i -XOPTIONS http://localhost:3000/notes<br/>
|
75
75
|
HTTP/1.1 200 OK<br/>
|
76
76
|
Content-Length: 0<br/>
|
77
|
+
Content-Type: application/json<br/>
|
77
78
|
Allow: GET, HEAD, POST, OPTIONS<br/>
|
78
79
|
Connection: keep-alive<br/>
|
79
80
|
</div>
|
@@ -94,10 +95,6 @@ List the currently available notes:
|
|
94
95
|
</div>
|
95
96
|
</p>
|
96
97
|
|
97
|
-
<p>
|
98
|
-
The Link header will be explained momentarily.
|
99
|
-
</p>
|
100
|
-
|
101
98
|
<p>
|
102
99
|
Create a note using <a href="http://tools.ietf.org/html/rfc2616#section-9.5">POST</a>:
|
103
100
|
<div class="code">
|
@@ -179,9 +176,7 @@ Along with the usual metadata, individual resources also provide discovery
|
|
179
176
|
information via
|
180
177
|
<a href="http://www.mnot.net/drafts/draft-nottingham-http-link-header-03.txt">Link Headers</a>
|
181
178
|
as shown above. These links allow user agents to find related resources such as
|
182
|
-
the complete history of a document
|
183
|
-
<a href="http://tools.ietf.org/html/rfc2616#section-14.19">ETags</a>.
|
184
|
-
The utility of these items will be demonstrated momentarily.
|
179
|
+
the complete history of a document.
|
185
180
|
</p>
|
186
181
|
|
187
182
|
<p>
|
@@ -218,8 +213,9 @@ Succeed in updating by being specific:
|
|
218
213
|
</p>
|
219
214
|
|
220
215
|
<p>
|
221
|
-
(Note: Your ETag
|
222
|
-
|
216
|
+
(Note: Your <a href="http://tools.ietf.org/html/rfc2616#section-14.19">ETag</a>
|
217
|
+
will likely be different so substitute the one that curl provided when you
|
218
|
+
created your own "abc" resource.)
|
223
219
|
</p>
|
224
220
|
|
225
221
|
<p>
|
data/doc/index.html
CHANGED
@@ -22,6 +22,11 @@
|
|
22
22
|
<div class="subtitle">An Open Web JSON Appliance</div>
|
23
23
|
</div>
|
24
24
|
</div>
|
25
|
+
<div class="meta">
|
26
|
+
<p class="wrapper">
|
27
|
+
Version 0.9.1 released. Install with <em>gem install cloudkit</em>.
|
28
|
+
</p>
|
29
|
+
</div>
|
25
30
|
<div class="wrapper intro-row">
|
26
31
|
<div class="column-one">
|
27
32
|
<div class="block-header">
|
data/doc/main.css
CHANGED
data/examples/3.ru
CHANGED
data/examples/4.ru
CHANGED
data/examples/5.ru
CHANGED
data/examples/6.ru
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
$:.unshift File.expand_path(File.dirname(__FILE__)) + '/../lib'
|
2
2
|
require 'cloudkit'
|
3
3
|
use Rack::Config do |env|
|
4
|
-
env['cloudkit.storage.uri'] = 'mysql://
|
4
|
+
env['cloudkit.storage.uri'] = 'mysql://user:pass@localhost/cloudkit_example'
|
5
5
|
end
|
6
6
|
use Rack::Session::Pool
|
7
7
|
use CloudKit::OAuthFilter
|
8
8
|
use CloudKit::OpenIDFilter
|
9
9
|
use CloudKit::Service, :collections => [:notes]
|
10
|
-
run lambda{|env| [200, {}, ['HELLO']]}
|
10
|
+
run lambda{|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
|
data/lib/cloudkit.rb
CHANGED
@@ -27,6 +27,7 @@ require 'cloudkit/oauth_store'
|
|
27
27
|
require 'cloudkit/openid_filter'
|
28
28
|
require 'cloudkit/openid_store'
|
29
29
|
require 'cloudkit/rack/builder'
|
30
|
+
require 'cloudkit/rack/lint'
|
30
31
|
require 'cloudkit/rack/router'
|
31
32
|
require 'cloudkit/request'
|
32
33
|
require 'cloudkit/service'
|
@@ -99,7 +99,7 @@ module CloudKit
|
|
99
99
|
@@store.put(
|
100
100
|
"/cloudkit_oauth_request_tokens/#{token_id}",
|
101
101
|
:json => request_token)
|
102
|
-
[201, {}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
|
102
|
+
[201, {'Content-Type' => 'text/html'}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
|
103
103
|
end
|
104
104
|
|
105
105
|
def request_authorization(request)
|
@@ -186,7 +186,7 @@ module CloudKit
|
|
186
186
|
@@store.delete(
|
187
187
|
"/cloudkit_oauth_request_tokens/#{request[:oauth_token]}",
|
188
188
|
:etag => request_token_response.etag)
|
189
|
-
[201, {}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
|
189
|
+
[201, {'Content-Type' => 'text/html'}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
|
190
190
|
end
|
191
191
|
|
192
192
|
def inject_user_or_challenge(request)
|
@@ -232,7 +232,8 @@ module CloudKit
|
|
232
232
|
def challenge_headers(request)
|
233
233
|
{
|
234
234
|
'WWW-Authenticate' => "OAuth realm=\"http://#{request.env['HTTP_HOST']}\"",
|
235
|
-
'Link' => discovery_link(request)
|
235
|
+
'Link' => discovery_link(request),
|
236
|
+
'Content-Type' => 'application/json'
|
236
237
|
}
|
237
238
|
end
|
238
239
|
|
@@ -242,7 +243,7 @@ module CloudKit
|
|
242
243
|
|
243
244
|
def login_redirect(request)
|
244
245
|
request.session['return_to'] = request.url if request.session
|
245
|
-
[302, {'Location' => request.login_url}, []]
|
246
|
+
[302, {'Location' => request.login_url, 'Content-Type' => 'text/html'}, []]
|
246
247
|
end
|
247
248
|
|
248
249
|
def load_user_from_session(request)
|
@@ -11,7 +11,7 @@ module CloudKit
|
|
11
11
|
class OpenIDFilter
|
12
12
|
include Util
|
13
13
|
|
14
|
-
@@lock
|
14
|
+
@@lock = Mutex.new
|
15
15
|
@@store = nil
|
16
16
|
|
17
17
|
def initialize(app, options={})
|
@@ -21,7 +21,7 @@ module CloudKit
|
|
21
21
|
def call(env)
|
22
22
|
@@lock.synchronize do
|
23
23
|
@@store = OpenIDStore.new(env[storage_uri_key])
|
24
|
-
@users
|
24
|
+
@users = UserStore.new(env[storage_uri_key])
|
25
25
|
@@store.get_association('x') rescue nil # refresh sqlite3
|
26
26
|
end unless @@store
|
27
27
|
|
@@ -39,7 +39,11 @@ module CloudKit
|
|
39
39
|
else
|
40
40
|
if request.env[challenge_key]
|
41
41
|
store_location(request)
|
42
|
-
erb(
|
42
|
+
erb(
|
43
|
+
request,
|
44
|
+
:openid_login,
|
45
|
+
request.env[challenge_key].merge('Content-Type' => 'text/html'),
|
46
|
+
401)
|
43
47
|
elsif !request.via.include?(oauth_filter_key)
|
44
48
|
store_location(request)
|
45
49
|
login_redirect(request)
|
@@ -61,7 +65,10 @@ module CloudKit
|
|
61
65
|
|
62
66
|
request.env[auth_key] = nil
|
63
67
|
request.flash['info'] = 'You have been logged out.'
|
64
|
-
response = Rack::Response.new(
|
68
|
+
response = Rack::Response.new(
|
69
|
+
[],
|
70
|
+
302,
|
71
|
+
{'Location' => request.login_url, 'Content-Type' => 'text/html'})
|
65
72
|
response.delete_cookie('remember_me')
|
66
73
|
response.finish
|
67
74
|
end
|
@@ -72,14 +79,14 @@ module CloudKit
|
|
72
79
|
|
73
80
|
def begin_openid_login(request)
|
74
81
|
begin
|
75
|
-
response = openid_consumer(request).begin
|
82
|
+
response = openid_consumer(request).begin(request[:openid_url])
|
76
83
|
rescue => e
|
77
84
|
request.flash[:error] = e
|
78
85
|
return login_redirect(request)
|
79
86
|
end
|
80
87
|
|
81
88
|
redirect_url = response.redirect_url(base_url(request), full_url(request))
|
82
|
-
[302, {'Location' => redirect_url}, []]
|
89
|
+
[302, {'Location' => redirect_url, 'Content-Type' => 'text/html'}, []]
|
83
90
|
end
|
84
91
|
|
85
92
|
def complete_openid_login(request)
|
@@ -116,10 +123,13 @@ module CloudKit
|
|
116
123
|
user['remember_me_token'] = Base64.encode64(
|
117
124
|
OpenSSL::Random.random_bytes(32)).gsub(/\W/,'')
|
118
125
|
url = request.session.delete('return_to')
|
119
|
-
response = Rack::Response.new(
|
126
|
+
response = Rack::Response.new(
|
127
|
+
[],
|
128
|
+
302,
|
129
|
+
{'Location' => (url || '/'), 'Content-Type' => 'text/html'})
|
120
130
|
response.set_cookie(
|
121
131
|
'remember_me', {
|
122
|
-
:value
|
132
|
+
:value => user['remember_me_token'],
|
123
133
|
:expires => Time.at(user['remember_me_expiration']).utc})
|
124
134
|
json = JSON.generate(user)
|
125
135
|
@users.put(user_uri, :etag => user_result.etag, :json => json)
|
@@ -132,7 +142,7 @@ module CloudKit
|
|
132
142
|
end
|
133
143
|
|
134
144
|
def login_redirect(request)
|
135
|
-
[302, {'Location' => request.login_url}, []]
|
145
|
+
[302, {'Location' => request.login_url, 'Content-Type' => 'text/html'}, []]
|
136
146
|
end
|
137
147
|
|
138
148
|
def base_url(request)
|
@@ -72,9 +72,11 @@ module CloudKit
|
|
72
72
|
def use_nonce(server_url, timestamp, salt) #:nodoc:
|
73
73
|
return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
|
74
74
|
|
75
|
-
fragment = URI.escape(
|
76
|
-
|
77
|
-
|
75
|
+
fragment = URI.escape(
|
76
|
+
[server_url, timestamp, salt].join('-'),
|
77
|
+
Regexp.union(URI::REGEXP::UNSAFE, '/', ':'))
|
78
|
+
uri = "/cloudkit_openid_nonces/#{fragment}"
|
79
|
+
result = @@store.put(uri, :json => '{}')
|
78
80
|
return (result.status == 201)
|
79
81
|
end
|
80
82
|
|
@@ -39,7 +39,9 @@ module CloudKit::ResponseHelpers
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def allow(methods)
|
42
|
-
CloudKit::Response.new(
|
42
|
+
CloudKit::Response.new(
|
43
|
+
200,
|
44
|
+
{'Allow' => methods.join(', '), 'Content-Type' => 'application/json'})
|
43
45
|
end
|
44
46
|
|
45
47
|
def response(status, content='', etag=nil, last_modified=nil, options={})
|
data/test/helper.rb
CHANGED
@@ -21,6 +21,7 @@ end
|
|
21
21
|
|
22
22
|
def plain_service
|
23
23
|
Rack::Builder.new do
|
24
|
+
use Rack::Lint
|
24
25
|
use Rack::Config do |env|
|
25
26
|
env['cloudkit.storage.uri'] = 'sqlite://service.db'
|
26
27
|
end
|
@@ -31,6 +32,7 @@ end
|
|
31
32
|
|
32
33
|
def authed_service
|
33
34
|
Rack::Builder.new do
|
35
|
+
use Rack::Lint
|
34
36
|
use Rack::Config do |env|
|
35
37
|
env['cloudkit.storage.uri'] = 'sqlite://service.db'
|
36
38
|
r = CloudKit::Request.new(env)
|
@@ -43,6 +45,7 @@ end
|
|
43
45
|
|
44
46
|
def openid_app
|
45
47
|
Rack::Builder.new do
|
48
|
+
use Rack::Lint
|
46
49
|
use Rack::Session::Pool
|
47
50
|
use CloudKit::OpenIDFilter
|
48
51
|
run echo_env(auth_key)
|
data/test/service_test.rb
CHANGED
@@ -14,7 +14,17 @@ class ServiceTest < Test::Unit::TestCase
|
|
14
14
|
should "return a 501 for unimplemented methods" do
|
15
15
|
response = @request.request('TRACE', '/items')
|
16
16
|
assert_equal 501, response.status
|
17
|
-
|
17
|
+
|
18
|
+
# disable Rack::Lint so that an invalid HTTP method
|
19
|
+
# can be tested
|
20
|
+
app = Rack::Builder.new {
|
21
|
+
use Rack::Config do |env|
|
22
|
+
env['cloudkit.storage.uri'] = 'sqlite://service.db'
|
23
|
+
end
|
24
|
+
use CloudKit::Service, :collections => [:items, :things]
|
25
|
+
run echo_text('nothing')
|
26
|
+
}
|
27
|
+
response = Rack::MockRequest.new(app).request('REJUXTAPOSE', '/items')
|
18
28
|
assert_equal 501, response.status
|
19
29
|
end
|
20
30
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Crosby
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-31 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -82,6 +82,16 @@ dependencies:
|
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 1.1.3
|
84
84
|
version:
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: sqlite3-ruby
|
87
|
+
type: :runtime
|
88
|
+
version_requirement:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.2.4
|
94
|
+
version:
|
85
95
|
description: An Open Web JSON Appliance.
|
86
96
|
email: jon@joncrosby.me
|
87
97
|
executables: []
|
@@ -92,11 +102,11 @@ extra_rdoc_files: []
|
|
92
102
|
|
93
103
|
files:
|
94
104
|
- CHANGES
|
95
|
-
- cloudkit.gemspec
|
96
105
|
- COPYING
|
97
106
|
- README
|
98
107
|
- Rakefile
|
99
108
|
- TODO
|
109
|
+
- cloudkit.gemspec
|
100
110
|
- doc/curl.html
|
101
111
|
- doc/images/example-code.gif
|
102
112
|
- doc/images/json-title.gif
|
@@ -119,6 +129,7 @@ files:
|
|
119
129
|
- lib/cloudkit/openid_filter.rb
|
120
130
|
- lib/cloudkit/openid_store.rb
|
121
131
|
- lib/cloudkit/rack/builder.rb
|
132
|
+
- lib/cloudkit/rack/lint.rb
|
122
133
|
- lib/cloudkit/rack/router.rb
|
123
134
|
- lib/cloudkit/request.rb
|
124
135
|
- lib/cloudkit/service.rb
|