jomz-google-api-client 0.7.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/CHANGELOG.md +144 -0
- data/CONTRIBUTING.md +32 -0
- data/Gemfile +41 -0
- data/LICENSE +202 -0
- data/README.md +192 -0
- data/Rakefile +46 -0
- data/lib/cacerts.pem +2183 -0
- data/lib/compat/multi_json.rb +16 -0
- data/lib/google/api_client.rb +672 -0
- data/lib/google/api_client/auth/compute_service_account.rb +28 -0
- data/lib/google/api_client/auth/file_storage.rb +87 -0
- data/lib/google/api_client/auth/installed_app.rb +122 -0
- data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
- data/lib/google/api_client/auth/key_utils.rb +93 -0
- data/lib/google/api_client/auth/pkcs12.rb +41 -0
- data/lib/google/api_client/batch.rb +323 -0
- data/lib/google/api_client/client_secrets.rb +176 -0
- data/lib/google/api_client/discovery.rb +19 -0
- data/lib/google/api_client/discovery/api.rb +300 -0
- data/lib/google/api_client/discovery/media.rb +77 -0
- data/lib/google/api_client/discovery/method.rb +363 -0
- data/lib/google/api_client/discovery/resource.rb +156 -0
- data/lib/google/api_client/discovery/schema.rb +121 -0
- data/lib/google/api_client/environment.rb +42 -0
- data/lib/google/api_client/errors.rb +60 -0
- data/lib/google/api_client/gzip.rb +28 -0
- data/lib/google/api_client/logging.rb +32 -0
- data/lib/google/api_client/media.rb +259 -0
- data/lib/google/api_client/railtie.rb +16 -0
- data/lib/google/api_client/reference.rb +27 -0
- data/lib/google/api_client/request.rb +351 -0
- data/lib/google/api_client/result.rb +253 -0
- data/lib/google/api_client/service.rb +233 -0
- data/lib/google/api_client/service/batch.rb +103 -0
- data/lib/google/api_client/service/request.rb +144 -0
- data/lib/google/api_client/service/resource.rb +40 -0
- data/lib/google/api_client/service/result.rb +162 -0
- data/lib/google/api_client/service/simple_file_store.rb +151 -0
- data/lib/google/api_client/service/stub_generator.rb +59 -0
- data/lib/google/api_client/service_account.rb +18 -0
- data/lib/google/api_client/version.rb +31 -0
- data/lib/google/inflection.rb +28 -0
- data/spec/fixtures/files/privatekey.p12 +0 -0
- data/spec/fixtures/files/sample.txt +33 -0
- data/spec/fixtures/files/secret.pem +19 -0
- data/spec/google/api_client/batch_spec.rb +249 -0
- data/spec/google/api_client/discovery_spec.rb +652 -0
- data/spec/google/api_client/gzip_spec.rb +86 -0
- data/spec/google/api_client/media_spec.rb +179 -0
- data/spec/google/api_client/request_spec.rb +30 -0
- data/spec/google/api_client/result_spec.rb +203 -0
- data/spec/google/api_client/service_account_spec.rb +164 -0
- data/spec/google/api_client/service_spec.rb +586 -0
- data/spec/google/api_client/simple_file_store_spec.rb +137 -0
- data/spec/google/api_client_spec.rb +253 -0
- data/spec/spec_helper.rb +56 -0
- data/tasks/gem.rake +97 -0
- data/tasks/git.rake +45 -0
- data/tasks/metrics.rake +22 -0
- data/tasks/spec.rake +57 -0
- data/tasks/wiki.rake +82 -0
- data/tasks/yard.rake +29 -0
- metadata +309 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright 2010 Google Inc.
|
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 'google/api_client/auth/key_utils'
|
16
|
+
module Google
|
17
|
+
class APIClient
|
18
|
+
##
|
19
|
+
# Helper for loading keys from the PKCS12 files downloaded when
|
20
|
+
# setting up service accounts at the APIs Console.
|
21
|
+
#
|
22
|
+
module PKCS12
|
23
|
+
##
|
24
|
+
# Loads a key from PKCS12 file, assuming a single private key
|
25
|
+
# is present.
|
26
|
+
#
|
27
|
+
# @param [String] keyfile
|
28
|
+
# Path of the PKCS12 file to load. If not a path to an actual file,
|
29
|
+
# assumes the string is the content of the file itself.
|
30
|
+
# @param [String] passphrase
|
31
|
+
# Passphrase for unlocking the private key
|
32
|
+
#
|
33
|
+
# @return [OpenSSL::PKey] The private key for signing assertions.
|
34
|
+
# @deprecated
|
35
|
+
# Use {Google::APIClient::KeyUtils} instead
|
36
|
+
def self.load_key(keyfile, passphrase)
|
37
|
+
KeyUtils.load_from_pkcs12(keyfile, passphrase)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
# Copyright 2012 Google Inc.
|
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 'google/api_client/reference'
|
17
|
+
require 'uuidtools'
|
18
|
+
|
19
|
+
module Google
|
20
|
+
class APIClient
|
21
|
+
|
22
|
+
##
|
23
|
+
# Helper class to contain a response to an individual batched call.
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
class BatchedCallResponse
|
27
|
+
# @return [String] UUID of the call
|
28
|
+
attr_reader :call_id
|
29
|
+
# @return [Fixnum] HTTP status code
|
30
|
+
attr_accessor :status
|
31
|
+
# @return [Hash] HTTP response headers
|
32
|
+
attr_accessor :headers
|
33
|
+
# @return [String] HTTP response body
|
34
|
+
attr_accessor :body
|
35
|
+
|
36
|
+
##
|
37
|
+
# Initialize the call response
|
38
|
+
#
|
39
|
+
# @param [String] call_id
|
40
|
+
# UUID of the original call
|
41
|
+
# @param [Fixnum] status
|
42
|
+
# HTTP status
|
43
|
+
# @param [Hash] headers
|
44
|
+
# HTTP response headers
|
45
|
+
# @param [#read, #to_str] body
|
46
|
+
# Response body
|
47
|
+
def initialize(call_id, status = nil, headers = nil, body = nil)
|
48
|
+
@call_id, @status, @headers, @body = call_id, status, headers, body
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Wraps multiple API calls into a single over-the-wire HTTP request.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
#
|
56
|
+
# client = Google::APIClient.new
|
57
|
+
# urlshortener = client.discovered_api('urlshortener')
|
58
|
+
# batch = Google::APIClient::BatchRequest.new do |result|
|
59
|
+
# puts result.data
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# batch.add(:api_method => urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/foo' })
|
63
|
+
# batch.add(:api_method => urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/bar' })
|
64
|
+
#
|
65
|
+
# client.execute(batch)
|
66
|
+
#
|
67
|
+
class BatchRequest < Request
|
68
|
+
BATCH_BOUNDARY = "-----------RubyApiBatchRequest".freeze
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
# @return [Array<(String,Google::APIClient::Request,Proc)] List of API calls in the batch
|
72
|
+
attr_reader :calls
|
73
|
+
|
74
|
+
##
|
75
|
+
# Creates a new batch request.
|
76
|
+
#
|
77
|
+
# @param [Hash] options
|
78
|
+
# Set of options for this request.
|
79
|
+
# @param [Proc] block
|
80
|
+
# Callback for every call's response. Won't be called if a call defined
|
81
|
+
# a callback of its own.
|
82
|
+
#
|
83
|
+
# @return [Google::APIClient::BatchRequest]
|
84
|
+
# The constructed object.
|
85
|
+
#
|
86
|
+
# @yield [Google::APIClient::Result]
|
87
|
+
# block to be called when result ready
|
88
|
+
def initialize(options = {}, &block)
|
89
|
+
@calls = []
|
90
|
+
@global_callback = block if block_given?
|
91
|
+
@last_auto_id = 0
|
92
|
+
|
93
|
+
# TODO(sgomes): Use SecureRandom.uuid, drop UUIDTools when we drop 1.8
|
94
|
+
@base_id = UUIDTools::UUID.random_create.to_s
|
95
|
+
|
96
|
+
options[:uri] ||= 'https://www.googleapis.com/batch'
|
97
|
+
options[:http_method] ||= 'POST'
|
98
|
+
|
99
|
+
super options
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Add a new call to the batch request.
|
104
|
+
# Each call must have its own call ID; if not provided, one will
|
105
|
+
# automatically be generated, avoiding collisions. If duplicate call IDs
|
106
|
+
# are provided, an error will be thrown.
|
107
|
+
#
|
108
|
+
# @param [Hash, Google::APIClient::Request] call
|
109
|
+
# the call to be added.
|
110
|
+
# @param [String] call_id
|
111
|
+
# the ID to be used for this call. Must be unique
|
112
|
+
# @param [Proc] block
|
113
|
+
# callback for this call's response.
|
114
|
+
#
|
115
|
+
# @return [Google::APIClient::BatchRequest]
|
116
|
+
# the BatchRequest, for chaining
|
117
|
+
#
|
118
|
+
# @yield [Google::APIClient::Result]
|
119
|
+
# block to be called when result ready
|
120
|
+
def add(call, call_id = nil, &block)
|
121
|
+
unless call.kind_of?(Google::APIClient::Reference)
|
122
|
+
call = Google::APIClient::Reference.new(call)
|
123
|
+
end
|
124
|
+
call_id ||= new_id
|
125
|
+
if @calls.assoc(call_id)
|
126
|
+
raise BatchError,
|
127
|
+
'A call with this ID already exists: %s' % call_id
|
128
|
+
end
|
129
|
+
callback = block_given? ? block : @global_callback
|
130
|
+
@calls << [call_id, call, callback]
|
131
|
+
return self
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Processes the HTTP response to the batch request, issuing callbacks.
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
#
|
139
|
+
# @param [Faraday::Response] response
|
140
|
+
# the HTTP response.
|
141
|
+
def process_http_response(response)
|
142
|
+
content_type = find_header('Content-Type', response.headers)
|
143
|
+
boundary = /.*boundary=(.+)/.match(content_type)[1]
|
144
|
+
parts = response.body.split(/--#{Regexp.escape(boundary)}/)
|
145
|
+
parts = parts[1...-1]
|
146
|
+
parts.each do |part|
|
147
|
+
call_response = deserialize_call_response(part)
|
148
|
+
_, call, callback = @calls.assoc(call_response.call_id)
|
149
|
+
result = Google::APIClient::Result.new(call, call_response)
|
150
|
+
callback.call(result) if callback
|
151
|
+
end
|
152
|
+
Google::APIClient::Result.new(self, response)
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Return the request body for the BatchRequest's HTTP request.
|
157
|
+
#
|
158
|
+
# @api private
|
159
|
+
#
|
160
|
+
# @return [String]
|
161
|
+
# the request body.
|
162
|
+
def to_http_request
|
163
|
+
if @calls.nil? || @calls.empty?
|
164
|
+
raise BatchError, 'Cannot make an empty batch request'
|
165
|
+
end
|
166
|
+
parts = @calls.map {|(call_id, call, callback)| serialize_call(call_id, call)}
|
167
|
+
build_multipart(parts, 'multipart/mixed', BATCH_BOUNDARY)
|
168
|
+
super
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
##
|
175
|
+
# Helper method to find a header from its name, regardless of case.
|
176
|
+
#
|
177
|
+
# @api private
|
178
|
+
#
|
179
|
+
# @param [String] name
|
180
|
+
# the name of the header to find.
|
181
|
+
# @param [Hash] headers
|
182
|
+
# the hash of headers and their values.
|
183
|
+
#
|
184
|
+
# @return [String]
|
185
|
+
# the value of the desired header.
|
186
|
+
def find_header(name, headers)
|
187
|
+
_, header = headers.detect do |h, v|
|
188
|
+
h.downcase == name.downcase
|
189
|
+
end
|
190
|
+
return header
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Create a new call ID. Uses an auto-incrementing, conflict-avoiding ID.
|
195
|
+
#
|
196
|
+
# @api private
|
197
|
+
#
|
198
|
+
# @return [String]
|
199
|
+
# the new, unique ID.
|
200
|
+
def new_id
|
201
|
+
@last_auto_id += 1
|
202
|
+
while @calls.assoc(@last_auto_id)
|
203
|
+
@last_auto_id += 1
|
204
|
+
end
|
205
|
+
return @last_auto_id.to_s
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Convert a Content-ID header value to an id. Presumes the Content-ID
|
210
|
+
# header conforms to the format that id_to_header() returns.
|
211
|
+
#
|
212
|
+
# @api private
|
213
|
+
#
|
214
|
+
# @param [String] header
|
215
|
+
# Content-ID header value.
|
216
|
+
#
|
217
|
+
# @return [String]
|
218
|
+
# The extracted ID value.
|
219
|
+
def header_to_id(header)
|
220
|
+
if !header.start_with?('<') || !header.end_with?('>') ||
|
221
|
+
!header.include?('+')
|
222
|
+
raise BatchError, 'Invalid value for Content-ID: "%s"' % header
|
223
|
+
end
|
224
|
+
|
225
|
+
base, call_id = header[1...-1].split('+')
|
226
|
+
return Addressable::URI.unencode(call_id)
|
227
|
+
end
|
228
|
+
|
229
|
+
##
|
230
|
+
# Auxiliary method to split the headers from the body in an HTTP response.
|
231
|
+
#
|
232
|
+
# @api private
|
233
|
+
#
|
234
|
+
# @param [String] response
|
235
|
+
# the response to parse.
|
236
|
+
#
|
237
|
+
# @return [Array<Hash>, String]
|
238
|
+
# the headers and the body, separately.
|
239
|
+
def split_headers_and_body(response)
|
240
|
+
headers = {}
|
241
|
+
payload = response.lstrip
|
242
|
+
while payload
|
243
|
+
line, payload = payload.split("\n", 2)
|
244
|
+
line.sub!(/\s+\z/, '')
|
245
|
+
break if line.empty?
|
246
|
+
match = /\A([^:]+):\s*/.match(line)
|
247
|
+
if match
|
248
|
+
headers[match[1]] = match.post_match
|
249
|
+
else
|
250
|
+
raise BatchError, 'Invalid header line in response: %s' % line
|
251
|
+
end
|
252
|
+
end
|
253
|
+
return headers, payload
|
254
|
+
end
|
255
|
+
|
256
|
+
##
|
257
|
+
# Convert a single batched response into a BatchedCallResponse object.
|
258
|
+
#
|
259
|
+
# @api private
|
260
|
+
#
|
261
|
+
# @param [String] call_response
|
262
|
+
# the request to deserialize.
|
263
|
+
#
|
264
|
+
# @return [Google::APIClient::BatchedCallResponse]
|
265
|
+
# the parsed and converted response.
|
266
|
+
def deserialize_call_response(call_response)
|
267
|
+
outer_headers, outer_body = split_headers_and_body(call_response)
|
268
|
+
status_line, payload = outer_body.split("\n", 2)
|
269
|
+
protocol, status, reason = status_line.split(' ', 3)
|
270
|
+
|
271
|
+
headers, body = split_headers_and_body(payload)
|
272
|
+
content_id = find_header('Content-ID', outer_headers)
|
273
|
+
call_id = header_to_id(content_id)
|
274
|
+
return BatchedCallResponse.new(call_id, status.to_i, headers, body)
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Serialize a single batched call for assembling the multipart message
|
279
|
+
#
|
280
|
+
# @api private
|
281
|
+
#
|
282
|
+
# @param [Google::APIClient::Request] call
|
283
|
+
# the call to serialize.
|
284
|
+
#
|
285
|
+
# @return [Faraday::UploadIO]
|
286
|
+
# the serialized request
|
287
|
+
def serialize_call(call_id, call)
|
288
|
+
method, uri, headers, body = call.to_http_request
|
289
|
+
request = "#{method.to_s.upcase} #{Addressable::URI.parse(uri).request_uri} HTTP/1.1"
|
290
|
+
headers.each do |header, value|
|
291
|
+
request << "\r\n%s: %s" % [header, value]
|
292
|
+
end
|
293
|
+
if body
|
294
|
+
# TODO - CompositeIO if body is a stream
|
295
|
+
request << "\r\n\r\n"
|
296
|
+
if body.respond_to?(:read)
|
297
|
+
request << body.read
|
298
|
+
else
|
299
|
+
request << body.to_s
|
300
|
+
end
|
301
|
+
end
|
302
|
+
Faraday::UploadIO.new(StringIO.new(request), 'application/http', 'ruby-api-request', 'Content-ID' => id_to_header(call_id))
|
303
|
+
end
|
304
|
+
|
305
|
+
##
|
306
|
+
# Convert an id to a Content-ID header value.
|
307
|
+
#
|
308
|
+
# @api private
|
309
|
+
#
|
310
|
+
# @param [String] call_id
|
311
|
+
# identifier of individual call.
|
312
|
+
#
|
313
|
+
# @return [String]
|
314
|
+
# A Content-ID header with the call_id encoded into it. A UUID is
|
315
|
+
# prepended to the value because Content-ID headers are supposed to be
|
316
|
+
# universally unique.
|
317
|
+
def id_to_header(call_id)
|
318
|
+
return '<%s+%s>' % [@base_id, Addressable::URI.encode(call_id)]
|
319
|
+
end
|
320
|
+
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# Copyright 2010 Google Inc.
|
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
|
+
|
16
|
+
require 'multi_json'
|
17
|
+
require 'compat/multi_json'
|
18
|
+
|
19
|
+
|
20
|
+
module Google
|
21
|
+
class APIClient
|
22
|
+
##
|
23
|
+
# Manages the persistence of client configuration data and secrets. Format
|
24
|
+
# inspired by the Google API Python client.
|
25
|
+
#
|
26
|
+
# @see https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# {
|
30
|
+
# "web": {
|
31
|
+
# "client_id": "asdfjasdljfasdkjf",
|
32
|
+
# "client_secret": "1912308409123890",
|
33
|
+
# "redirect_uris": ["https://www.example.com/oauth2callback"],
|
34
|
+
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
35
|
+
# "token_uri": "https://accounts.google.com/o/oauth2/token"
|
36
|
+
# }
|
37
|
+
# }
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# {
|
41
|
+
# "installed": {
|
42
|
+
# "client_id": "837647042410-75ifg...usercontent.com",
|
43
|
+
# "client_secret":"asdlkfjaskd",
|
44
|
+
# "redirect_uris": ["http://localhost", "urn:ietf:oauth:2.0:oob"],
|
45
|
+
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
46
|
+
# "token_uri": "https://accounts.google.com/o/oauth2/token"
|
47
|
+
# }
|
48
|
+
# }
|
49
|
+
class ClientSecrets
|
50
|
+
|
51
|
+
##
|
52
|
+
# Reads client configuration from a file
|
53
|
+
#
|
54
|
+
# @param [String] filename
|
55
|
+
# Path to file to load
|
56
|
+
#
|
57
|
+
# @return [Google::APIClient::ClientSecrets]
|
58
|
+
# OAuth client settings
|
59
|
+
def self.load(filename=nil)
|
60
|
+
if filename && File.directory?(filename)
|
61
|
+
search_path = File.expand_path(filename)
|
62
|
+
filename = nil
|
63
|
+
end
|
64
|
+
while filename == nil
|
65
|
+
search_path ||= File.expand_path('.')
|
66
|
+
if File.exist?(File.join(search_path, 'client_secrets.json'))
|
67
|
+
filename = File.join(search_path, 'client_secrets.json')
|
68
|
+
elsif search_path == '/' || search_path =~ /[a-zA-Z]:[\/\\]/
|
69
|
+
raise ArgumentError,
|
70
|
+
'No client_secrets.json filename supplied ' +
|
71
|
+
'and/or could not be found in search path.'
|
72
|
+
else
|
73
|
+
search_path = File.expand_path(File.join(search_path, '..'))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
data = File.open(filename, 'r') { |file| MultiJson.load(file.read) }
|
77
|
+
return self.new(data)
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Intialize OAuth client settings.
|
82
|
+
#
|
83
|
+
# @param [Hash] options
|
84
|
+
# Parsed client secrets files
|
85
|
+
def initialize(options={})
|
86
|
+
# Client auth configuration
|
87
|
+
@flow = options[:flow] || options.keys.first.to_s || 'web'
|
88
|
+
fdata = options[@flow]
|
89
|
+
@client_id = fdata[:client_id] || fdata["client_id"]
|
90
|
+
@client_secret = fdata[:client_secret] || fdata["client_secret"]
|
91
|
+
@redirect_uris = fdata[:redirect_uris] || fdata["redirect_uris"]
|
92
|
+
@redirect_uris ||= [fdata[:redirect_uri]]
|
93
|
+
@javascript_origins = (
|
94
|
+
fdata[:javascript_origins] ||
|
95
|
+
fdata["javascript_origins"]
|
96
|
+
)
|
97
|
+
@javascript_origins ||= [fdata[:javascript_origin]]
|
98
|
+
@authorization_uri = fdata[:auth_uri] || fdata["auth_uri"]
|
99
|
+
@authorization_uri ||= fdata[:authorization_uri]
|
100
|
+
@token_credential_uri = fdata[:token_uri] || fdata["token_uri"]
|
101
|
+
@token_credential_uri ||= fdata[:token_credential_uri]
|
102
|
+
|
103
|
+
# Associated token info
|
104
|
+
@access_token = fdata[:access_token] || fdata["access_token"]
|
105
|
+
@refresh_token = fdata[:refresh_token] || fdata["refresh_token"]
|
106
|
+
@id_token = fdata[:id_token] || fdata["id_token"]
|
107
|
+
@expires_in = fdata[:expires_in] || fdata["expires_in"]
|
108
|
+
@expires_at = fdata[:expires_at] || fdata["expires_at"]
|
109
|
+
@issued_at = fdata[:issued_at] || fdata["issued_at"]
|
110
|
+
end
|
111
|
+
|
112
|
+
attr_reader(
|
113
|
+
:flow, :client_id, :client_secret, :redirect_uris, :javascript_origins,
|
114
|
+
:authorization_uri, :token_credential_uri, :access_token,
|
115
|
+
:refresh_token, :id_token, :expires_in, :expires_at, :issued_at
|
116
|
+
)
|
117
|
+
|
118
|
+
##
|
119
|
+
# Serialize back to the original JSON form
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
# JSON
|
123
|
+
def to_json
|
124
|
+
return MultiJson.dump({
|
125
|
+
self.flow => ({
|
126
|
+
'client_id' => self.client_id,
|
127
|
+
'client_secret' => self.client_secret,
|
128
|
+
'redirect_uris' => self.redirect_uris,
|
129
|
+
'javascript_origins' => self.javascript_origins,
|
130
|
+
'auth_uri' => self.authorization_uri,
|
131
|
+
'token_uri' => self.token_credential_uri,
|
132
|
+
'access_token' => self.access_token,
|
133
|
+
'refresh_token' => self.refresh_token,
|
134
|
+
'id_token' => self.id_token,
|
135
|
+
'expires_in' => self.expires_in,
|
136
|
+
'expires_at' => self.expires_at,
|
137
|
+
'issued_at' => self.issued_at
|
138
|
+
}).inject({}) do |accu, (k, v)|
|
139
|
+
# Prunes empty values from JSON output.
|
140
|
+
unless v == nil || (v.respond_to?(:empty?) && v.empty?)
|
141
|
+
accu[k] = v
|
142
|
+
end
|
143
|
+
accu
|
144
|
+
end
|
145
|
+
})
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_authorization
|
149
|
+
gem 'signet', '>= 0.4.0'
|
150
|
+
require 'signet/oauth_2/client'
|
151
|
+
# NOTE: Do not rely on this default value, as it may change
|
152
|
+
new_authorization = Signet::OAuth2::Client.new
|
153
|
+
new_authorization.client_id = self.client_id
|
154
|
+
new_authorization.client_secret = self.client_secret
|
155
|
+
new_authorization.authorization_uri = (
|
156
|
+
self.authorization_uri ||
|
157
|
+
'https://accounts.google.com/o/oauth2/auth'
|
158
|
+
)
|
159
|
+
new_authorization.token_credential_uri = (
|
160
|
+
self.token_credential_uri ||
|
161
|
+
'https://accounts.google.com/o/oauth2/token'
|
162
|
+
)
|
163
|
+
new_authorization.redirect_uri = self.redirect_uris.first
|
164
|
+
|
165
|
+
# These are supported, but unlikely.
|
166
|
+
new_authorization.access_token = self.access_token
|
167
|
+
new_authorization.refresh_token = self.refresh_token
|
168
|
+
new_authorization.id_token = self.id_token
|
169
|
+
new_authorization.expires_in = self.expires_in
|
170
|
+
new_authorization.issued_at = self.issued_at if self.issued_at
|
171
|
+
new_authorization.expires_at = self.expires_at if self.expires_at
|
172
|
+
return new_authorization
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|