identity-toolkit-ruby-client 0.1.0

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.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +66 -0
  3. data/lib/gitkit_client.rb +289 -0
  4. data/lib/rpc_helper.rb +209 -0
  5. metadata +103 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c99e7fd2191547c175870cb9656f018696d29a94
4
+ data.tar.gz: 6eb020bd9c8d326ca1790c175ce703528a67e1f1
5
+ SHA512:
6
+ metadata.gz: 5a2657585eef66bde0f66fb1e18af4ccef23ff5b7829d094a6e6a2fe60dcbc315ba7bb2930aaf546f5c2a9adde3f72eaba39696f44c3e72660c4ffbedfe93d14
7
+ data.tar.gz: 424ace8fdd5c630d0767ac4d31a2f360c468563532b8c686d087e0e79105b1d94d26240ad6795bb00eb1ce43282d7bf22064b75828cea2716534ee6a434f197a
data/README.rdoc ADDED
@@ -0,0 +1,66 @@
1
+ = Google Identity Toolkit Ruby Client
2
+
3
+ Google Identity Toolkit (Gitkit) ruby client library is for third party sites to easily integrate with Gitkit service.
4
+
5
+ === Installation
6
+
7
+ gem install identity_toolkit_ruby_client
8
+
9
+ === Examples
10
+
11
+ require 'gitkit_client'
12
+
13
+ # Create a server config file or download it from Google Developer Console
14
+ # The config file contains Gitkit library config in json format
15
+ # {
16
+ # "clientId" : "oauth2-web-client-id.apps.googleusercontent.com",
17
+ # "serviceAccountEmail" : "service-account-email@developer.gserviceaccount.com",
18
+ # "serviceAccountPrivateKeyFile" : "path-to-service-account-private-key-file.p12",
19
+ # "widgetUrl" : "full-url-of-gitkit-widget-on-your-site",
20
+ # "cookieName" : "gtoken",
21
+ # "serverKey" : "devconsole-server-key"
22
+ # }
23
+
24
+ # Create a Gitkit client
25
+ gitkit_client = GitkitLib::GitkitClient.create_from_config_file 'gitkit-server-config.json'
26
+
27
+ # Verify the Gitkit token in the incoming http request
28
+ token = request.cookies["gtoken"]
29
+ user = gitkit_client.verify_gitkit_token token
30
+
31
+ # Upload passwords
32
+ def calc_sha1(key, plain_text, salt)
33
+ hmac = OpenSSL::HMAC.new key, 'sha1'
34
+ hmac << plain_text
35
+ hmac << salt
36
+ hmac.digest
37
+ end
38
+
39
+ hash_key = 'hash-key'
40
+
41
+ user1 = GitkitLib::GitkitUser.new
42
+ user1.email = '1234@example.com'
43
+ user1.user_id = '1234'
44
+ user1.salt = 'salt-1'
45
+ user1.password_hash = calc_sha1(hash_key, '1111', 'salt-1')
46
+
47
+ user2 = GitkitLib::GitkitUser.new
48
+ user2.email = '5678@example.com'
49
+ user2.user_id = '5678'
50
+ user2.salt = 'salt-2'
51
+ user2.password_hash = calc_sha1(hash_key, '5555', 'salt-2')
52
+ user2.name = '56 78'
53
+
54
+ gitkit_client.upload_users 'HMAC_SHA1', hash_key, [user1, user2]
55
+
56
+ # Get user by email
57
+ user = gitkit_client.get_user_by_email('1234@example.com')
58
+
59
+ # Get user by id
60
+ user = gitkit_client.get_user_by_id('5678')
61
+
62
+ # Delete a user
63
+ gitkit_client.delete_user '5678'
64
+
65
+ # Download all accounts
66
+ gitkit_client.get_all_users(2) { |account| pp account}
@@ -0,0 +1,289 @@
1
+ # Copyright 2014 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'addressable/uri'
16
+ require 'jwt'
17
+ require 'json'
18
+ require 'rpc_helper'
19
+ require 'uri'
20
+
21
+ module GitkitLib
22
+
23
+ class GitkitClient
24
+
25
+ # Create a client from json config file
26
+ #
27
+ # @param [String] file file name of the json-format config
28
+ def self.create_from_config_file(file)
29
+ config = JSON.parse File.open(file, 'rb') { |io| io.read }
30
+ p12key = File.open(config['serviceAccountPrivateKeyFile'], 'rb') {
31
+ |io| io.read }
32
+ new(
33
+ config['clientId'],
34
+ config['serviceAccountEmail'],
35
+ p12key,
36
+ config['widgetUrl'],
37
+ config['serverApiKey'])
38
+ end
39
+
40
+ # Initializes a GitkitClient.
41
+ #
42
+ # @param [String] client_id Google oauth2 web client id of this site
43
+ # @param [String] service_account_email Google service account email
44
+ # @param [String] service_account_key Google service account private p12 key
45
+ # @param [String] widget_url url to host the Gitkit widget
46
+ # @param [String] server_api_key server-side Google API key
47
+ def initialize(client_id, service_account_email, service_account_key,
48
+ widget_url, server_api_key = nil)
49
+ @client_id = client_id
50
+ @widget_url = widget_url
51
+ @rpc_helper = RpcHelper.new(service_account_email, service_account_key,
52
+ server_api_key)
53
+ @certificates = {}
54
+ end
55
+
56
+ # Verifies a Gitkit token
57
+ #
58
+ # @param [String] token_string the token to be verified
59
+ # @return [GitkitUser, nil] for valid token, [nil, String] otherwise with
60
+ # error_message.
61
+ def verify_gitkit_token(token_string)
62
+ if token_string.nil?
63
+ return nil, 'no token'
64
+ end
65
+ begin
66
+ key_finder = lambda {|header|
67
+ key_id = header['kid']
68
+ unless @certificates.has_key? key_id
69
+ @certificates = Hash[get_certs.map {|key,cert|
70
+ [key, OpenSSL::X509::Certificate.new(cert)]}]
71
+ end
72
+ @certificates[key_id].public_key }
73
+ parsed_token = JWT.decode(token_string, nil, true, &key_finder).first
74
+ # check expiration time
75
+ if Time.new.to_i > parsed_token['exp']
76
+ return nil, 'token expired'
77
+ end
78
+ # check audience
79
+ if parsed_token['aud'] != @client_id
80
+ return nil, 'audience mismatch'
81
+ end
82
+ GitkitUser.parse_from_api_response parsed_token
83
+ rescue JWT::DecodeError => e
84
+ return nil, e.message
85
+ end
86
+ end
87
+
88
+ # Gets Gitkit public certs
89
+ #
90
+ # @api private
91
+ def get_certs
92
+ @rpc_helper.get_gitkit_certs()
93
+ end
94
+
95
+ # Gets user info by email
96
+ #
97
+ # @param [String] email user email
98
+ # @return [GitkitUser] for the email
99
+ def get_user_by_email(email)
100
+ response = @rpc_helper.get_user_by_email email
101
+ GitkitUser.parse_from_api_response response.fetch('users', [{}])[0]
102
+ end
103
+
104
+ # Gets user info by user id
105
+ #
106
+ # @param [String] id user id
107
+ # @return [GitkitUser] for the id
108
+ def get_user_by_id(id)
109
+ response = @rpc_helper.get_user_by_id id
110
+ GitkitUser.parse_from_api_response response.fetch('users', [{}])[0]
111
+ end
112
+
113
+ # Downloads all user accounts from Gitkit service
114
+ #
115
+ # @param [Fixnum] max_results pagination size of each request
116
+ # @yield [GitkitUser] individual user account
117
+ def get_all_users(max_results = 10)
118
+ next_page_token = nil
119
+ while true
120
+ next_page_token, accounts = @rpc_helper.download_account(
121
+ next_page_token, max_results)
122
+ accounts.each { |account|
123
+ yield GitkitUser.parse_from_api_response account }
124
+ if not next_page_token or accounts.length == 0
125
+ break
126
+ end
127
+ end
128
+ end
129
+
130
+ # Uploads multiple accounts to Gitkit service
131
+ #
132
+ # @param [String] hash_algorithm password hash algorithm
133
+ # @param [String] hash_key key of the hash algorithm
134
+ # @param [Array<GitkitUser>] accounts user accounts to be uploaded
135
+ def upload_users(hash_algorithm, hash_key, accounts)
136
+ account_request = accounts.collect { |account| account.to_request }
137
+ @rpc_helper.upload_account hash_algorithm, JWT.base64url_encode(hash_key),
138
+ account_request
139
+ end
140
+
141
+ # Deletes a user account from Gitkit service
142
+ #
143
+ # @param [String] local_id user id to be deleted
144
+ def delete_user(local_id)
145
+ @rpc_helper.delete_account local_id
146
+ end
147
+
148
+ # Get one-time out-of-band code for ResetPassword/ChangeEmail request
149
+ #
150
+ # @param [String] full_url the full URL of incoming request
151
+ # @param [Hash{String=>String}] param dict of HTTP POST params
152
+ # @param [String] user_ip end user's IP address
153
+ # @param [String] gitkit_token the gitkit token if user logged in
154
+ #
155
+ # @return [Hash] {
156
+ # email: user email who is asking reset password
157
+ # oobLink: the generated link to be send to user's email
158
+ # action: OobAction
159
+ # response_body: the http body to be returned
160
+ # }
161
+ def get_oob_result(full_url, param, user_ip, gitkit_token=nil)
162
+ if param.has_key? 'action'
163
+ begin
164
+ if param['action'] == 'resetPassword'
165
+ oob_link = build_oob_link(full_url,
166
+ password_reset_request(param, user_ip),
167
+ param['action'])
168
+ return password_reset_response(oob_link, param)
169
+ elsif param['action'] == 'changeEmail'
170
+ unless gitkit_token
171
+ return failure_msg('login is required')
172
+ end
173
+ oob_link = build_oob_link(full_url,
174
+ change_email_request(param, user_ip, gitkit_token),
175
+ param['action'])
176
+ return email_change_response(oob_link, param)
177
+ end
178
+ rescue GitkitClientError => error
179
+ return failure_msg(error.message)
180
+ end
181
+ end
182
+ failure_msg('unknown request type')
183
+ end
184
+
185
+ def password_reset_request(param, user_ip)
186
+ {
187
+ 'email' => param['email'],
188
+ 'userIp' => user_ip,
189
+ 'challenge' => param['challenge'],
190
+ 'captchaResp' => param['response'],
191
+ 'requestType' => 'PASSWORD_RESET'
192
+ }
193
+ end
194
+
195
+ def change_email_request(param, user_ip, gitkit_token)
196
+ {
197
+ 'email' => param['oldEmail'],
198
+ 'newEmail' => param['newEmail'],
199
+ 'userIp' => user_ip,
200
+ 'idToken' => gitkit_token,
201
+ 'requestType' => 'NEW_EMAIL_ACCEPT'
202
+ }
203
+ end
204
+
205
+ def build_oob_link(full_url, param, mode)
206
+ code = @rpc_helper.get_oob_code(param)
207
+ if code
208
+ oob_link = Addressable::URI.parse full_url
209
+ oob_link.path = @widget_url
210
+ oob_link.query_values = { 'mode' => mode, 'oobCode' => code}
211
+ return oob_link.to_s
212
+ end
213
+ nil
214
+ end
215
+
216
+ def failure_msg(msg)
217
+ {:response_body => {'error' => msg}}.to_json
218
+ end
219
+
220
+ def email_change_response(oob_link, param)
221
+ {
222
+ :oldEmail => param['email'],
223
+ :newEmail => param['newEmail'],
224
+ :oobLink => oob_link,
225
+ :action => :CHANGE_EMAIL,
226
+ :response_body => {'success' => true}.to_json
227
+ }
228
+ end
229
+
230
+ def password_reset_response(oob_link, param)
231
+ {
232
+ :email => param['email'],
233
+ :oobLink => oob_link,
234
+ :action => :RESET_PASSWORD,
235
+ :response_body => {'success' => true}.to_json
236
+ }
237
+ end
238
+ end
239
+
240
+ class GitkitUser
241
+ attr_accessor :email, :user_id, :name, :photo_url, :provider_id,
242
+ :email_verified, :password_hash, :salt, :password, :provider_info
243
+
244
+ def self.parse_from_api_response(api_response)
245
+ user = self.new
246
+ user.email = api_response.fetch('email', nil)
247
+ user.user_id = api_response.fetch('user_id',
248
+ api_response.fetch('localId', nil))
249
+ user.name = api_response.fetch('displayName', nil)
250
+ user.photo_url = api_response.fetch('photoUrl', nil)
251
+ user.provider_id = api_response.fetch('provider_id',
252
+ api_response.fetch('providerId', nil))
253
+ user.email_verified = api_response.fetch('emailVerified',
254
+ api_response.fetch('verified', nil))
255
+ user.password_hash = api_response.fetch('passwordHash', nil)
256
+ user.salt = api_response.fetch('salt', nil)
257
+ user.password = api_response.fetch('password', nil)
258
+ user.provider_info = api_response.fetch('providerUserInfo', {})
259
+ user
260
+ end
261
+
262
+ # Convert to gitkit api request (a dict)
263
+ def to_request
264
+ request = {}
265
+ request['email'] = @email if @email
266
+ request['localId'] = @user_id if @user_id
267
+ request['displayName'] = @name if @name
268
+ request['photoUrl'] = @photo_url if @photo_url
269
+ request['emailVerified'] = @email_verified if @email_verified != nil
270
+ request['passwordHash'] =
271
+ JWT.base64url_encode @password_hash if @password_hash
272
+ request['salt'] = JWT.base64url_encode @salt if @salt
273
+ request['providerUserInfo'] = @provider_info if @provider_info != nil
274
+ request
275
+ end
276
+ end
277
+
278
+ class GitkitClientError < StandardError
279
+ def initialize(message)
280
+ super
281
+ end
282
+ end
283
+
284
+ class GitkitServerError < StandardError
285
+ def initialize(message)
286
+ super
287
+ end
288
+ end
289
+ end
data/lib/rpc_helper.rb ADDED
@@ -0,0 +1,209 @@
1
+ # Copyright 2014 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'jwt'
16
+ require 'json'
17
+ require 'faraday'
18
+ require 'gitkit_client'
19
+ require 'openssl'
20
+
21
+ module GitkitLib
22
+ class RpcHelper
23
+ attr_accessor :access_token, :token_issued_at, :token_duration
24
+
25
+ TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
26
+ GITKIT_SCOPE = 'https://www.googleapis.com/auth/identitytoolkit'
27
+ GITKIT_API_URL =
28
+ 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/'
29
+
30
+ def initialize(service_account_email, service_account_key, server_api_key,
31
+ google_token_endpoint = TOKEN_ENDPOINT)
32
+ @service_account_email = service_account_email
33
+ @google_api_url = google_token_endpoint
34
+ @connection = Faraday::Connection.new
35
+ @service_account_key =
36
+ OpenSSL::PKCS12.new(service_account_key, 'notasecret').key
37
+ @server_api_key = server_api_key
38
+ @token_duration = 3600
39
+ @token_issued_at = 0
40
+ @access_token = nil
41
+ end
42
+
43
+ # GetAccountInfo by email
44
+ #
45
+ # @api private
46
+ # @param [String] email account email to be queried
47
+ # @return [JSON] account info
48
+ def get_user_by_email(email)
49
+ invoke_gitkit_api('getAccountInfo', {'email' => [email]})
50
+ end
51
+
52
+ # GetAccountInfo by id
53
+ #
54
+ # @api private
55
+ # @param [String] id account id to be queried
56
+ # @return [JSON] account info
57
+ def get_user_by_id(id)
58
+ invoke_gitkit_api('getAccountInfo', {'localId' => [id]})
59
+ end
60
+
61
+ # Get out-of-band code for ResetPassword/ChangeEmail etc. operation
62
+ #
63
+ # @api private
64
+ # @param [Hash<String, String>] request the oob request
65
+ # @return <String> the oob code
66
+ def get_oob_code(request)
67
+ response = invoke_gitkit_api('getOobConfirmationCode', request)
68
+ response.fetch('oobCode', nil)
69
+ end
70
+
71
+ # Download all accounts
72
+ #
73
+ # @api private
74
+ # @param [String] next_page_token pagination token for next page
75
+ # @param [Fixnum] max_results pagination size
76
+ # @return [Array<JSON>] user account info
77
+ def download_account(next_page_token, max_results)
78
+ param = {}
79
+ if next_page_token
80
+ param['nextPageToken'] = next_page_token
81
+ end
82
+ if max_results
83
+ param['maxResults'] = max_results
84
+ end
85
+ response = invoke_gitkit_api('downloadAccount', param)
86
+ return response.fetch('nextPageToken', nil), response.fetch('users', {})
87
+ end
88
+
89
+ # Delete an account
90
+ #
91
+ # @api private
92
+ # @param <String> local_id user id to be deleted
93
+ def delete_account(local_id)
94
+ invoke_gitkit_api('deleteAccount', {'localId' => local_id})
95
+ end
96
+
97
+ # Upload batch accounts
98
+ #
99
+ # @api private
100
+ # @param <String> hash_algorithm hash algorithm
101
+ # @param <String> hash_key hash key
102
+ # @param <Array<GitkitUser>> accounts account to be uploaded
103
+ def upload_account(hash_algorithm, hash_key, accounts)
104
+ param = {
105
+ 'hashAlgorithm' => hash_algorithm,
106
+ 'signerKey' => hash_key,
107
+ 'users' => accounts
108
+ }
109
+ invoke_gitkit_api('uploadAccount', param)
110
+ end
111
+
112
+ # Creates a signed jwt assertion
113
+ #
114
+ # @api private
115
+ # @return [String] jwt assertion
116
+ def sign_assertion
117
+ now = Time.new
118
+ assertion = {
119
+ 'iss' => @service_account_email,
120
+ 'scope' => GITKIT_SCOPE,
121
+ 'aud' => @google_api_url,
122
+ 'exp' => (now + @token_duration).to_i,
123
+ 'iat' => now.to_i
124
+ }
125
+ JWT.encode(assertion, @service_account_key, 'RS256')
126
+ end
127
+
128
+ # Get an access token, from Google server if cached one is expired
129
+ #
130
+ # @api private
131
+ def fetch_access_token
132
+ if is_token_expired
133
+ assertion = sign_assertion
134
+ post_body = {
135
+ 'assertion' => assertion,
136
+ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'}
137
+ headers = {'Content-type' => 'application/x-www-form-urlencoded'}
138
+ response = @connection.post(RpcHelper::TOKEN_ENDPOINT, post_body,
139
+ headers)
140
+ @access_token = JSON.parse(response.env[:body])['access_token']
141
+ @token_issued_at = Time.new.to_i
142
+ end
143
+ @access_token
144
+ end
145
+
146
+ # Check whether the cached access token is expired
147
+ #
148
+ # @api private
149
+ # @return <Boolean> whether the access token is expired
150
+ def is_token_expired
151
+ @access_token == nil ||
152
+ Time.new.to_i > @token_issued_at + @token_duration - 30
153
+ end
154
+
155
+ # Invoke Gitkit API, with optional access token for service account
156
+ # operations
157
+ #
158
+ # @api private
159
+ # @param [String] method Gitkit API method name
160
+ # @param [Hash<String, String>] params api request params
161
+ # @param [bool] need_service_account whether the request needs to be
162
+ # authenticated
163
+ # @return <JSON> the Gitkit api response
164
+ def invoke_gitkit_api(method, params, need_service_account=true)
165
+ post_body = JSON.generate(params)
166
+ headers = {'Content-type' => 'application/json'}
167
+ if need_service_account
168
+ @connection.authorization :Bearer, fetch_access_token
169
+ end
170
+ response = @connection.post(GITKIT_API_URL + method, post_body, headers)
171
+ check_gitkit_error JSON.parse(response.env[:body])
172
+ end
173
+
174
+ # Download the Gitkit public certs
175
+ #
176
+ # @api private
177
+ # @return <JSON> the public certs
178
+ def get_gitkit_certs
179
+ if @server_api_key.nil?
180
+ @connection.authorization :Bearer, fetch_access_token
181
+ response = @connection.get(GITKIT_API_URL + 'publicKeys')
182
+ else
183
+ response = @connection.get [GITKIT_API_URL, 'publicKeys?key=',
184
+ @server_api_key].join
185
+ end
186
+ MultiJson.load response.body
187
+ end
188
+
189
+ # Checks the Gitkit response
190
+ #
191
+ # @api private
192
+ # @param [JSON] response the response received
193
+ # @return [JSON] the response if no error
194
+ def check_gitkit_error(response)
195
+ if response.has_key? 'error'
196
+ error = response['error']
197
+ if error.has_key? 'code'
198
+ code = error['code']
199
+ raise GitkitClientError, error['message'] if code.to_s.match(/^4/)
200
+ raise GitkitServerError, error['message']
201
+ else
202
+ raise GitkitServerError, 'null error code from Gitkit server'
203
+ end
204
+ else
205
+ response
206
+ end
207
+ end
208
+ end
209
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: identity-toolkit-ruby-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jin Liu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: addressable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.3.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: multi_json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: jwt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.0
69
+ description: Google Identity Toolkit Ruby client library
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - README.rdoc
75
+ files:
76
+ - README.rdoc
77
+ - lib/gitkit_client.rb
78
+ - lib/rpc_helper.rb
79
+ homepage: https://developers.google.com/identity-toolkit/v3
80
+ licenses:
81
+ - Apache 2.0
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.2.2
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Google Identity Toolkit Ruby client
103
+ test_files: []