gitkit-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gitkit-ruby (0.0.1)
5
+ addressable (~> 2.2)
6
+ httparty (~> 0.8)
7
+ json (~> 1.4.6)
8
+ rack (~> 1.3)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ addressable (2.2.6)
14
+ hoe (2.12.4)
15
+ rake (~> 0.8)
16
+ httparty (0.8.1)
17
+ multi_json
18
+ multi_xml
19
+ json (1.4.6)
20
+ multi_json (1.0.3)
21
+ multi_xml (0.4.1)
22
+ rack (1.3.4)
23
+ rack-test (0.6.1)
24
+ rack (>= 1.0)
25
+ rake (0.9.2)
26
+ rr (1.0.4)
27
+ test-unit (1.2.3)
28
+ hoe (>= 1.5.1)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ gitkit-ruby!
35
+ rack-test (~> 0.6)
36
+ rake (~> 0.9)
37
+ rr (~> 1.0)
38
+ test-unit (~> 1.2)
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'bundler'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ FileList['tasks/**/*.rake'].each { |task| import task }
8
+
9
+ """
10
+ require 'bundle/gem_tasks'
11
+ begin
12
+ gem 'jeweler', '~> 1.6.4'
13
+ require 'jeweler'
14
+
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = 'gitkit-ruby'
17
+ gem.summary = 'Rack middleware for Google Identity Toolkit'
18
+ gem.description = gem.summary
19
+ gem.email = 'sqrrrl@gmail.com'
20
+ gem.homepage = 'http://code.google.com/p/%s' % gem.name
21
+ gem.authors = [ 'Steve Bazyl' ]
22
+
23
+ #gem.rubyforge_project = 'gitkit-ruby'
24
+ end
25
+
26
+ Jeweler::GemcutterTasks.new
27
+
28
+ rescue LoadError
29
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler -v 1.6.4'
30
+ end
31
+ """
32
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "google/identity_toolkit/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gitkit-ruby"
7
+ s.version = Google::IdentityToolkit::VERSION
8
+ s.authors = ["Steven Bazyl"]
9
+ s.email = ["sqrrrl@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Rack middleware for Google Identity Toolkit}
12
+ s.description = %q{Rack middleware for Google Identity Toolkit}
13
+
14
+ s.rubyforge_project = "gitkit-ruby"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'rack','~> 1.3'
22
+ s.add_dependency 'json', '~> 1.4.6'
23
+ s.add_dependency 'httparty', '~> 0.8'
24
+ s.add_dependency 'addressable', '~> 2.2'
25
+
26
+ s.add_development_dependency 'rake', '~> 0.9'
27
+ s.add_development_dependency 'rack-test', '~> 0.6'
28
+ s.add_development_dependency 'test-unit', '~> 1.2'
29
+ s.add_development_dependency 'rr', '~> 1.0'
30
+
31
+ end
@@ -0,0 +1,298 @@
1
+ require "rack"
2
+ require "json"
3
+ require "google/identity_toolkit/api"
4
+ require "google/identity_toolkit/helpers"
5
+ require "addressable/uri"
6
+
7
+ module Google
8
+ CONTENT_TYPE = 'Content-Type'
9
+ CONTENT_TYPE_HTML = 'text/html'
10
+ CONTENT_TYPE_JSON = 'application/json'
11
+ STATUS_SUCCESS = 'success'
12
+ STATUS_INVALID_EMAIL = 'invalidAssertionEmail'
13
+ STATUS_ACCOUNT_MISMATCH = 'accountMismatch'
14
+
15
+ ##
16
+ # Rack middleware for using the Google Identity Kit for federated login
17
+ # @see http://code.google.com/apis/identitytoolkit/
18
+ class IdentityToolkit
19
+ attr_accessor :api_key
20
+ attr_accessor :path
21
+ attr_accessor :app
22
+ attr_accessor :api
23
+ attr_accessor :callback_url
24
+ attr_accessor :federated_signup_url
25
+ attr_accessor :signup_url
26
+ attr_accessor :home_url
27
+
28
+ ##
29
+ # Creates the Identity toolkit middleware. Requires defining a block
30
+ # to configure the API and define callback methods for loading & authenticating
31
+ # users.
32
+ #
33
+ # @example
34
+ # use Google::IdentityToolkit, do |toolkit|
35
+ # toolkit.api_key = "..."
36
+ # def fetch_user(email, assertion = nil)
37
+ # # Load the user for the given email, optionally registering
38
+ # # the user if assertion is provided and '
39
+ # end
40
+ #
41
+ # def password_valid?(email, password)
42
+ # # Validates the user id/password
43
+ # end
44
+ # end
45
+ def initialize(app, &block)
46
+ @path = '/_gitkit'
47
+ @callback_url = nil
48
+ @app = app
49
+ instance_eval(&block) if block_given?
50
+ end
51
+
52
+ ##
53
+ # Static method for fetching the API key from thread-local storage. Only valid for threads
54
+ # intercepted by the rack module. Use by helper methods rendering the login button.
55
+ #
56
+ # @return [String] API Key
57
+ def self.api_key
58
+ env[:gitkit_api_key]
59
+ end
60
+
61
+ ##
62
+ # Static method for fetching the current user from thread-local storage. Only valid for threads
63
+ # intercepted by the rack module. Use by helper methods rendering the login button.
64
+ #
65
+ # @return [Hash] Hash representing the user
66
+ def self.current_user
67
+ env[:gitkit_user]
68
+ end
69
+
70
+ ##
71
+ # Static method for fetching the callback URL from thread-local storage. Only valid for threads
72
+ # intercepted by the rack module. Use by helper methods rendering the login button.
73
+ #
74
+ # @return [Hash] Hash representing the user
75
+ def self.callback_url
76
+ env[:gitkit_callback_url]
77
+ end
78
+
79
+ ##
80
+ # Get (and lazy init) the API client
81
+ #
82
+ # @return [Google::IdentityToolkit::Api]
83
+ # API client
84
+ def api
85
+ @api ||= Google::IdentityToolkit::Api.new(@api_key)
86
+ end
87
+
88
+ ##
89
+ # Handles web requests for identity toolkit callbacks
90
+ #
91
+ # @param [Hash] env
92
+ # Rack request context
93
+ # @return [Array]
94
+ # HTTP response
95
+ def call(env)
96
+ request = Rack::Request.new(env)
97
+ env[:gitkit_api_key] = @api_key
98
+ env[:gitkit_callback_url] = callback_url(request)
99
+ env[:gitkit_user] = request.session[:git_user]
100
+ Thread.current[:gitkit_rack_env] = env
101
+ begin
102
+ return @app.call(env) unless request.path == @path
103
+ case request.params['rp_target']
104
+ when "callback"
105
+ body = callback(request)
106
+ [200, {CONTENT_TYPE => CONTENT_TYPE_HTML}, [body]]
107
+ when "login"
108
+ data = login(request)
109
+ [200, {CONTENT_TYPE => CONTENT_TYPE_JSON}, [data.to_json]]
110
+ when "userStatus"
111
+ data = status(request)
112
+ [200, {CONTENT_TYPE => CONTENT_TYPE_JSON}, [data.to_json]]
113
+ end
114
+ ensure
115
+ Thread.current[:gitkit_rack_env] = nil
116
+ end
117
+ end
118
+
119
+ ##
120
+ # Handles IDP responses during login
121
+ #
122
+ # @param [Rack::Request] request
123
+ # current request
124
+ # @return [String]
125
+ # HTML boilerplate to close popup & notify parent window
126
+ def callback(request)
127
+ render_method = !!request.params['mobile'] ? :build_mobile_html : :build_notify_html
128
+ begin
129
+ assertion = api.verify_assertion(request.url, request.body)
130
+ input_email = request.params['rp_input_email']
131
+ email = assertion['verifiedEmail']
132
+ return send(render_method, STATUS_INVALID_EMAIL, {}) if email.nil?
133
+ return send(render_method, STATUS_ACCOUNT_MISMATCH, {
134
+ "inputEmail" => input_email,
135
+ "validatedEmail" => email
136
+ }) unless input_email.nil? or input_email == email
137
+
138
+ user = fetch_user(email, assertion)
139
+ if user.nil?
140
+ # Save the assertion for use in signup page
141
+ request.session[:gitkit_assertion] = assertion unless session.nil?
142
+ send(render_method, STATUS_SUCCESS, {
143
+ "email" => email,
144
+ "registered" => false,
145
+ "displayName" => assertion["displayName"],
146
+ "photoUrl" => assertion["photoUrl"]
147
+ })
148
+ else
149
+ # User exits, login
150
+ upgrade_user(email)
151
+ handle_login(user)
152
+ send(render_method, STATUS_SUCCESS, {
153
+ "email" => email,
154
+ "registered" => true,
155
+ "displayName" => assertion["displayName"],
156
+ "photoUrl" => assertion["photoUrl"]
157
+ })
158
+ end
159
+ rescue Exception => e
160
+ send(render_method, 'invalidAssertion', {})
161
+ end
162
+ end
163
+
164
+ ##
165
+ # Handles authentication requests for non-federated users
166
+ #
167
+ # @param [Rack::Request] request
168
+ # current request
169
+ # @return [Hash]
170
+ # Result of login. Currently just sets the value of :status in the hash
171
+ def login(request)
172
+ user = fetch_user(request.params["email"])
173
+ if user.nil?
174
+ {:status => "emailNotExist"}
175
+ elsif user[:federated]
176
+ {:status => "federated"}
177
+ else
178
+ if password_valid?(request.params["email"], request.params["password"])
179
+ user = fetch_user(request.params["email"])
180
+ handle_login(user)
181
+ {:status => "OK"}
182
+ else
183
+ {:status => "passwordError"}
184
+ end
185
+ end
186
+ end
187
+
188
+ ##
189
+ # Checks the status of a user
190
+ #
191
+ # @param [Rack::Request] request
192
+ # current request
193
+ # @return [Hash]
194
+ # Status of user
195
+ def status(request)
196
+ user = fetch_user(request.params["email"])
197
+ #referrer = request.params["referrer"]
198
+ { "registered" => !!user,
199
+ "legacy" => !(user && user[:federated]) }
200
+ end
201
+
202
+ ##
203
+ # Log the user after either a successful assertion or password validation
204
+ # @param [Hash]
205
+ # User (from find_user)
206
+ # @param [Rack::Request] request
207
+ # Current request
208
+ def handle_login(user)
209
+ unless session.nil?
210
+ request.session[:git_user] = user
211
+ on_login(user)
212
+ end
213
+ end
214
+
215
+ ##
216
+ # Renders boilerplate HTML for closing popups after login
217
+ #
218
+ # @param [String] status
219
+ # Status of callback -- either success, or one of the gitkit supported error messages
220
+ # @param [Hash] data
221
+ # user data from assertion if successful login
222
+ # @return [String] HTML
223
+ def build_notify_html(status, data)
224
+ html = <<-EOF
225
+ <script type='text/javascript' src='https://ajax.googleapis.com/jsapi'></script>
226
+ <script type='text/javascript'>google.load("identitytoolkit", "1.0", {packages: ["notify"]});</script>
227
+ <script type='text/javascript'>
228
+ EOF
229
+ case status
230
+ when STATUS_SUCCESS
231
+ html << "window.google.identitytoolkit.notifyFederatedSuccess(#{data.to_json});"
232
+ else
233
+ html << "window.google.identitytoolkit.notifyFederatedError('#{status}', #{data.to_json});"
234
+ end
235
+ html << "</script>"
236
+ end
237
+
238
+ ##
239
+ # Renders boilerplate HTML for non-poup mobile UI
240
+ #
241
+ # @param [String] status
242
+ # Status of callback -- either success, or one of the gitkit supported error messages
243
+ # @param [Hash] data
244
+ # user data from assertion if successful login
245
+ # @return [String] HTML
246
+ def build_mobile_html(status, data)
247
+ html = "<script type='text/javascript'>"
248
+ if status == STATUS_SUCCESS
249
+ if data["registered"]
250
+ html << "window.location = '#{home_url}';"
251
+ else
252
+ target = Addressable::URI.parse(signup_url)
253
+ target.query_values = target.query_values.merge("email" => data["email"])
254
+ html << "window.location = '#{target}';"
255
+ end
256
+ else
257
+ target = Addressable::URI.parse(login_url)
258
+ target.query_values = target.query_values.merge("error" => status)
259
+ html << "window.location = '#{login_url}';"
260
+ end
261
+ html << "</script>"
262
+ end
263
+
264
+ # Get the callback URL for use in the javascript helpers.
265
+ #
266
+ # @param [Rack::Request] request
267
+ # current request object
268
+ # @return [String]
269
+ # callback URL for verifying assertions
270
+ def callback_url(request = nil)
271
+ return @callback_url unless @callback_url.nil?
272
+ scheme = request.scheme
273
+ if (scheme == 'http' && request.port == 80 ||
274
+ scheme == 'https' && request.port == 443)
275
+ port = ""
276
+ else
277
+ port = ":#{request.port}"
278
+ end
279
+ "#{scheme}://#{request.host}#{port}#{request.script_name}#{@path}"
280
+ end
281
+
282
+ def self.env
283
+ Thread.current[:gitkit_rack_env]
284
+ end
285
+
286
+ def env
287
+ Thread.current[:gitkit_rack_env]
288
+ end
289
+
290
+ def request
291
+ Rack::Request.new(env)
292
+ end
293
+
294
+ def session
295
+ request.session
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,53 @@
1
+ require 'httparty'
2
+ require 'google/identity_toolkit/errors'
3
+ require 'json'
4
+
5
+ module Google
6
+ class IdentityToolkit
7
+
8
+ ##
9
+ # Server API for creating login requests & verifying assertions
10
+ class Api
11
+ include HTTParty
12
+ format :json
13
+ headers "Content-Type" => "application/json"
14
+
15
+ ##
16
+ # Initializes the API
17
+ #
18
+ # @param [String] api_key
19
+ # API key from developer console
20
+ def initialize(api_key)
21
+ @api_key = api_key
22
+ end
23
+
24
+ ##
25
+ # Sends an IDP response for verification, returning an assertion
26
+ # if the response is valid
27
+ #
28
+ # @param [String] request_uri
29
+ # URL of the current request
30
+ # @param [StringIO] body
31
+ # Request body (if post)
32
+ #
33
+ # @return [Hash]
34
+ # Assertion of user identity
35
+ #
36
+ # @raise [ApiError]
37
+ # if assertion not valid
38
+ def verify_assertion(request_uri, body=nil)
39
+ request = {
40
+ "requestUri" => request_uri
41
+ }
42
+ request["postBody"] = body.gets unless body.nil?
43
+ response = Api.post('https://www.googleapis.com/identitytoolkit/v1/relyingparty/verifyAssertion',
44
+ :query => { "key" => @api_key }, :body => request.to_json )
45
+ raise ApiError.new("Error #{response.code} when verifying the assertion") unless response.code == 200
46
+ response.parsed_response
47
+ end
48
+
49
+
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,11 @@
1
+ module Google
2
+ class IdentityToolkit
3
+ ##
4
+ # General exception for failed API calls when verifiying assertions
5
+ class ApiError < StandardError
6
+ def initialize(s)
7
+ super(s)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ require 'addressable/uri'
2
+
3
+ module Google
4
+ class IdentityToolkit
5
+ module Helpers
6
+
7
+ ##
8
+ # Generate javascript for configuring the identity toolkit button
9
+ #
10
+ # @param [String] element_id
11
+ # Id of element that will contain the login button
12
+ # @param [Hash] options
13
+ # Configuration options
14
+ # @option options [String] :api_key
15
+ # APIKey from developer console
16
+ # @option options [String] :company_name
17
+ # Name of site to display on login pages
18
+ # @option options [String] :base_url
19
+ #
20
+ # @return [String] Block of javascript (must be wrapped in <script> tag)
21
+
22
+ def account_chooser(element_id, options = {})
23
+ callback_url = Addressable::URI.parse(options[:callback_url] || Google::IdentityToolkit.callback_url)
24
+ params = callback_url.query_values || {}
25
+ callback_url.query_values = params.merge("mobile" => "1") if options[:mobile]
26
+ js = <<-EOF
27
+ window.google.identitytoolkit.setConfig({
28
+ developerKey: "#{options[:api_key] || Google::IdentityToolkit.api_key}",
29
+ companyName: "#{options[:site_name]}",
30
+ callbackUrl: "#{callback_url}",
31
+ userStatusUrl: "#{callback_url}",
32
+ loginUrl: "#{callback_url}",
33
+ federatedSignupUrl: "#{options[:federated_signup_url] || options[:signup_url] || '/signup' }",
34
+ signupUrl: "#{options[:signup_url] || '/signup'}",
35
+ homeUrl: "#{options[:home_url] || '/' }",
36
+ logoutUrl: "#{options[:logout_url] || '/logout'}",
37
+ realm: "#{options[:realm]}",
38
+ language: "#{options[:language] || 'en'}",
39
+ idps: ["Gmail", "AOL", "Hotmail", "Yahoo"],
40
+ tryFederatedFirst: #{options[:try_federated_first] || false},
41
+ useCachedUserStatus: #{options[:use_cached_status] || false}
42
+ });
43
+ $('#{element_id}').accountChooser();
44
+ EOF
45
+ end
46
+
47
+ def show_current_user(options={})
48
+ js = ""
49
+ user = options[:user] || Google::IdentityToolkit.current_user
50
+ if user
51
+ js = <<-EOF
52
+ window.google.identitytoolkit.updateSavedAccount({
53
+ email: '#{user[:email]}',
54
+ displayName: '#{user[:display_name]}',
55
+ photoUrl: '#{user[:photo_url]}'
56
+ });
57
+ window.google.identitytoolkit.showSavedAccount('#{user[:email]}');
58
+ EOF
59
+ end
60
+ js
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ module Google
2
+ class IdentityToolkit
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'rake/testtask'
3
+
4
+ desc "Run basic tests"
5
+ Rake::TestTask.new("test") { |t|
6
+ t.pattern = 'test/*_test.rb'
7
+ t.verbose = true
8
+ t.warning = true
9
+ }
10
+ rescue LoadError
11
+ task :yard do
12
+ abort 'testunit is not available. In order to run yard, you must: gem install testunit'
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+
4
+ YARD::Rake::YardocTask.new
5
+ rescue LoadError
6
+ task :yard do
7
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
8
+ end
9
+ end
@@ -0,0 +1,115 @@
1
+ $: << (File.dirname(__FILE__) + '/../lib')
2
+
3
+ require "rr"
4
+ require "test/unit"
5
+ require 'rack/test'
6
+ require "google/identity_toolkit"
7
+
8
+ module MockCallbacks
9
+ def fetch_user(email, assertion = nil)
10
+ return {"verifiedEmail" => email} if email.start_with?("exist") || email.start_with?("unregistered")
11
+ end
12
+
13
+ def password_valid?(email, password)
14
+ "ok" == password
15
+ end
16
+
17
+ def upgrade_user(user)
18
+ end
19
+
20
+ def on_login(user)
21
+ end
22
+ end
23
+
24
+ class GITKit_Test < Test::Unit::TestCase
25
+ include Rack::Test::Methods
26
+ include RR::Adapters::TestUnit
27
+
28
+ attr_accessor :app
29
+
30
+ def setup
31
+ inner_app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello']] }
32
+ @app = Google::IdentityToolkit.new(inner_app) do |git|
33
+ git.api_key = "AIzaSyBs1gLwB1_QZ-EXgFqBrrLY1MPXzB3G6ZU"
34
+ extend MockCallbacks
35
+ end
36
+ end
37
+
38
+ def teardown
39
+ # Do nothing
40
+ end
41
+
42
+ def test_passthrough
43
+ get '/test'
44
+ assert_equal 'hello', last_response.body
45
+ end
46
+
47
+ def test_valid_login
48
+ post '/_gitkit', "rp_target" => "login", "email" => "exists@bar.com", "password" => "ok"
49
+ data = JSON.parse(last_response.body)
50
+ assert_equal("OK", data["status"])
51
+ end
52
+
53
+ def test_invalid_login
54
+ post '/_gitkit', "rp_target" => "login", "email" => "exists@bar.com", "password" => "badpassword"
55
+ data = JSON.parse(last_response.body)
56
+ assert_equal("passwordError", data["status"])
57
+ end
58
+
59
+ def test_user_exists
60
+ post '/_gitkit', "rp_target" => "userStatus", "email" => "exists@foo.com"
61
+ data = JSON.parse(last_response.body)
62
+ assert_equal(true, data["registered"])
63
+ end
64
+
65
+ def test_user_not_exists
66
+ post '/_gitkit', "rp_target" => "userStatus", "email" => "nobody@foo.com"
67
+ data = JSON.parse(last_response.body)
68
+ assert_equal(false, data["registered"])
69
+ end
70
+
71
+ def test_callback_registered_user
72
+ mock(@app.api).verify_assertion(is_a(String), anything) {
73
+ { "kind" => "identitytoolkit#relyingparty",
74
+ "identifier" => "12345",
75
+ "authority" => "google.com",
76
+ "verifiedEmail" => "existing@foo.com",
77
+ "firstName" => "Test",
78
+ "lastName" => "User",
79
+ "fullName" => "Test User",
80
+ "nickName" => "test",
81
+ "language" => "en",
82
+ "timeZone" => "PST" }
83
+ }
84
+ post '/_gitkit?rp_target=callback', "some long assertion...."
85
+ assert_equal(200, last_response.status)
86
+ assert_match(/.*"registered":true.*/, last_response.body)
87
+ end
88
+
89
+ def test_callback_unregistered_user
90
+ mock(@app.api).verify_assertion(is_a(String), anything) {
91
+ { "kind" => "identitytoolkit#relyingparty",
92
+ "identifier" => "12345",
93
+ "authority" => "google.com",
94
+ "verifiedEmail" => "new@foo.com",
95
+ "firstName" => "Test",
96
+ "lastName" => "User",
97
+ "fullName" => "Test User",
98
+ "nickName" => "test",
99
+ "language" => "en",
100
+ "timeZone" => "PST" }
101
+ }
102
+ post '/_gitkit?rp_target=callback', "some long assertion..."
103
+ assert_equal(200, last_response.status)
104
+ assert_match(/.*"registered":false.*/, last_response.body)
105
+ end
106
+
107
+ def test_callback_invalid_response
108
+ mock(@app.api).verify_assertion(is_a(String), anything) {
109
+ raise ApiError("Invalid assertion")
110
+ }
111
+ post '/_gitkit?rp_target=callback', "garbage"
112
+ assert_equal(200, last_response.status)
113
+ assert_match(/.*notifyFederatedError.*/, last_response.body)
114
+ end
115
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitkit-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Steven Bazyl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-16 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &70358498379620 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70358498379620
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ requirement: &70358498378900 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.4.6
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70358498378900
36
+ - !ruby/object:Gem::Dependency
37
+ name: httparty
38
+ requirement: &70358498377960 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '0.8'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70358498377960
47
+ - !ruby/object:Gem::Dependency
48
+ name: addressable
49
+ requirement: &70358498376820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.2'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70358498376820
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: &70358498375600 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '0.9'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70358498375600
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: &70358498373840 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '0.6'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70358498373840
80
+ - !ruby/object:Gem::Dependency
81
+ name: test-unit
82
+ requirement: &70358498371760 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '1.2'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70358498371760
91
+ - !ruby/object:Gem::Dependency
92
+ name: rr
93
+ requirement: &70358498370780 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: '1.0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70358498370780
102
+ description: Rack middleware for Google Identity Toolkit
103
+ email:
104
+ - sqrrrl@gmail.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - Gemfile
110
+ - Gemfile.lock
111
+ - Rakefile
112
+ - VERSION
113
+ - gitkit-ruby.gemspec
114
+ - lib/google/identity_toolkit.rb
115
+ - lib/google/identity_toolkit/api.rb
116
+ - lib/google/identity_toolkit/errors.rb
117
+ - lib/google/identity_toolkit/helpers.rb
118
+ - lib/google/identity_toolkit/version.rb
119
+ - tasks/test.rake
120
+ - tasks/yard.rake
121
+ - test/gitkit_test.rb
122
+ homepage: ''
123
+ licenses: []
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ segments:
135
+ - 0
136
+ hash: 442708502916154574
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ segments:
144
+ - 0
145
+ hash: 442708502916154574
146
+ requirements: []
147
+ rubyforge_project: gitkit-ruby
148
+ rubygems_version: 1.8.10
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Rack middleware for Google Identity Toolkit
152
+ test_files:
153
+ - test/gitkit_test.rb