2012-03-02 16:06:08 +00:00
|
|
|
# Copyright 2010 Google Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
2012-08-30 09:15:59 +00:00
|
|
|
require 'compat/multi_json'
|
2012-03-02 16:06:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
module Google
|
|
|
|
class APIClient
|
|
|
|
##
|
2012-09-28 19:07:11 +00:00
|
|
|
# Manages the persistence of client configuration data and secrets. Format
|
|
|
|
# inspired by the Google API Python client.
|
|
|
|
#
|
|
|
|
# @see https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
|
|
|
|
#
|
|
|
|
# @example
|
|
|
|
# {
|
|
|
|
# "web": {
|
|
|
|
# "client_id": "asdfjasdljfasdkjf",
|
|
|
|
# "client_secret": "1912308409123890",
|
|
|
|
# "redirect_uris": ["https://www.example.com/oauth2callback"],
|
|
|
|
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
|
|
# "token_uri": "https://accounts.google.com/o/oauth2/token"
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# @example
|
|
|
|
# {
|
|
|
|
# "installed": {
|
|
|
|
# "client_id": "837647042410-75ifg...usercontent.com",
|
|
|
|
# "client_secret":"asdlkfjaskd",
|
|
|
|
# "redirect_uris": ["http://localhost", "urn:ietf:oauth:2.0:oob"],
|
|
|
|
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
|
|
# "token_uri": "https://accounts.google.com/o/oauth2/token"
|
|
|
|
# }
|
|
|
|
# }
|
2012-03-02 16:06:08 +00:00
|
|
|
class ClientSecrets
|
2012-09-28 19:07:11 +00:00
|
|
|
##
|
|
|
|
# Reads client configuration from a file
|
|
|
|
#
|
|
|
|
# @param [String] filename
|
|
|
|
# Path to file to load
|
|
|
|
#
|
|
|
|
# @return [Google::APIClient::ClientSecrets]
|
|
|
|
# OAuth client settings
|
2012-03-02 16:06:08 +00:00
|
|
|
def self.load(filename=nil)
|
|
|
|
if filename && File.directory?(filename)
|
|
|
|
search_path = File.expand_path(filename)
|
|
|
|
filename = nil
|
|
|
|
end
|
|
|
|
while filename == nil
|
|
|
|
search_path ||= File.expand_path('.')
|
2014-09-17 14:55:52 +00:00
|
|
|
if File.exists?(File.join(search_path, 'client_secrets.json'))
|
2012-03-02 16:06:08 +00:00
|
|
|
filename = File.join(search_path, 'client_secrets.json')
|
|
|
|
elsif search_path == '/' || search_path =~ /[a-zA-Z]:[\/\\]/
|
|
|
|
raise ArgumentError,
|
|
|
|
'No client_secrets.json filename supplied ' +
|
|
|
|
'and/or could not be found in search path.'
|
|
|
|
else
|
|
|
|
search_path = File.expand_path(File.join(search_path, '..'))
|
|
|
|
end
|
|
|
|
end
|
2012-04-24 11:39:25 +00:00
|
|
|
data = File.open(filename, 'r') { |file| MultiJson.load(file.read) }
|
2012-03-02 16:06:08 +00:00
|
|
|
return self.new(data)
|
|
|
|
end
|
|
|
|
|
2012-09-28 19:07:11 +00:00
|
|
|
##
|
2015-08-19 16:02:37 +00:00
|
|
|
# Initialize OAuth client settings.
|
2012-09-28 19:07:11 +00:00
|
|
|
#
|
|
|
|
# @param [Hash] options
|
|
|
|
# Parsed client secrets files
|
2012-03-02 16:06:08 +00:00
|
|
|
def initialize(options={})
|
|
|
|
# Client auth configuration
|
|
|
|
@flow = options[:flow] || options.keys.first.to_s || 'web'
|
|
|
|
fdata = options[@flow]
|
|
|
|
@client_id = fdata[:client_id] || fdata["client_id"]
|
|
|
|
@client_secret = fdata[:client_secret] || fdata["client_secret"]
|
|
|
|
@redirect_uris = fdata[:redirect_uris] || fdata["redirect_uris"]
|
2014-12-16 21:47:26 +00:00
|
|
|
@redirect_uris ||= [fdata[:redirect_uri] || fdata["redirect_uri"]].compact
|
2012-03-02 16:06:08 +00:00
|
|
|
@javascript_origins = (
|
|
|
|
fdata[:javascript_origins] ||
|
|
|
|
fdata["javascript_origins"]
|
|
|
|
)
|
2014-12-16 21:47:26 +00:00
|
|
|
@javascript_origins ||= [fdata[:javascript_origin] || fdata["javascript_origin"]].compact
|
2012-03-02 16:06:08 +00:00
|
|
|
@authorization_uri = fdata[:auth_uri] || fdata["auth_uri"]
|
|
|
|
@authorization_uri ||= fdata[:authorization_uri]
|
|
|
|
@token_credential_uri = fdata[:token_uri] || fdata["token_uri"]
|
|
|
|
@token_credential_uri ||= fdata[:token_credential_uri]
|
|
|
|
|
|
|
|
# Associated token info
|
|
|
|
@access_token = fdata[:access_token] || fdata["access_token"]
|
|
|
|
@refresh_token = fdata[:refresh_token] || fdata["refresh_token"]
|
|
|
|
@id_token = fdata[:id_token] || fdata["id_token"]
|
|
|
|
@expires_in = fdata[:expires_in] || fdata["expires_in"]
|
|
|
|
@expires_at = fdata[:expires_at] || fdata["expires_at"]
|
|
|
|
@issued_at = fdata[:issued_at] || fdata["issued_at"]
|
|
|
|
end
|
|
|
|
|
|
|
|
attr_reader(
|
|
|
|
:flow, :client_id, :client_secret, :redirect_uris, :javascript_origins,
|
|
|
|
:authorization_uri, :token_credential_uri, :access_token,
|
|
|
|
:refresh_token, :id_token, :expires_in, :expires_at, :issued_at
|
|
|
|
)
|
|
|
|
|
2012-09-28 19:07:11 +00:00
|
|
|
##
|
|
|
|
# Serialize back to the original JSON form
|
|
|
|
#
|
|
|
|
# @return [String]
|
|
|
|
# JSON
|
2012-03-02 16:06:08 +00:00
|
|
|
def to_json
|
2014-12-16 21:47:26 +00:00
|
|
|
return MultiJson.dump(to_hash)
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_hash
|
|
|
|
{
|
2012-03-02 16:06:08 +00:00
|
|
|
self.flow => ({
|
|
|
|
'client_id' => self.client_id,
|
|
|
|
'client_secret' => self.client_secret,
|
|
|
|
'redirect_uris' => self.redirect_uris,
|
|
|
|
'javascript_origins' => self.javascript_origins,
|
|
|
|
'auth_uri' => self.authorization_uri,
|
|
|
|
'token_uri' => self.token_credential_uri,
|
|
|
|
'access_token' => self.access_token,
|
|
|
|
'refresh_token' => self.refresh_token,
|
|
|
|
'id_token' => self.id_token,
|
|
|
|
'expires_in' => self.expires_in,
|
|
|
|
'expires_at' => self.expires_at,
|
|
|
|
'issued_at' => self.issued_at
|
|
|
|
}).inject({}) do |accu, (k, v)|
|
|
|
|
# Prunes empty values from JSON output.
|
|
|
|
unless v == nil || (v.respond_to?(:empty?) && v.empty?)
|
|
|
|
accu[k] = v
|
|
|
|
end
|
|
|
|
accu
|
|
|
|
end
|
2014-12-16 21:47:26 +00:00
|
|
|
}
|
2012-03-02 16:06:08 +00:00
|
|
|
end
|
2012-10-05 09:07:42 +00:00
|
|
|
|
|
|
|
def to_authorization
|
2013-08-06 17:46:11 +00:00
|
|
|
gem 'signet', '>= 0.4.0'
|
2012-10-05 09:07:42 +00:00
|
|
|
require 'signet/oauth_2/client'
|
|
|
|
# NOTE: Do not rely on this default value, as it may change
|
|
|
|
new_authorization = Signet::OAuth2::Client.new
|
|
|
|
new_authorization.client_id = self.client_id
|
|
|
|
new_authorization.client_secret = self.client_secret
|
|
|
|
new_authorization.authorization_uri = (
|
|
|
|
self.authorization_uri ||
|
|
|
|
'https://accounts.google.com/o/oauth2/auth'
|
|
|
|
)
|
|
|
|
new_authorization.token_credential_uri = (
|
|
|
|
self.token_credential_uri ||
|
|
|
|
'https://accounts.google.com/o/oauth2/token'
|
|
|
|
)
|
|
|
|
new_authorization.redirect_uri = self.redirect_uris.first
|
|
|
|
|
|
|
|
# These are supported, but unlikely.
|
|
|
|
new_authorization.access_token = self.access_token
|
|
|
|
new_authorization.refresh_token = self.refresh_token
|
|
|
|
new_authorization.id_token = self.id_token
|
|
|
|
new_authorization.expires_in = self.expires_in
|
|
|
|
new_authorization.issued_at = self.issued_at if self.issued_at
|
|
|
|
new_authorization.expires_at = self.expires_at if self.expires_at
|
|
|
|
return new_authorization
|
|
|
|
end
|
2012-03-02 16:06:08 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|