cloudkit 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|