-
Notifications
You must be signed in to change notification settings - Fork 3
/
base.rb
166 lines (149 loc) · 5.79 KB
/
base.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Base class that does all the work and can be inherited from for goodies.
require 'uri'
require 'net/https'
require 'net/http'
module Google
# Exception raised upon login problem. Most likely incorrect username or
# password but could mean problem with google service.
class LoginError < Exception; end
URL = 'http://www.google.com'
LOGIN_URL = 'https://www.google.com:443/accounts/ClientLogin'
SOURCE = 'Google Auth Base Ruby Gem'
class Base
# Given an email and password it creates a new connection
# which will be used for this class and all sub classes.
#
# Raises Google::LoginError if login fails or if, god forbid,
# google is having issues.
def self.establish_connection(email, password,service="")
@@connection = new(email, password,service)
end
# Returns the current connection
def self.connection
@@connection
end
# Changes the current connection to the one provided.
# If in an app you store the connection in a session,
# you can reuse it instead of establishing a new connection
# with each request.
#
# Usage:
# Google::Base.connection = session[:connection] # => or whatever
def self.connection=(new_connection)
@@connection = new_connection
end
# Makes a get request to a google service using
# the session id from the connection's session
#
# Usage:
# get('http://google.com/some/thing')
# get('http://google.com/some/thing', :query_hash => {:q => 'test', :second => 'another'})
# # makes request to http://google.com/some/thing?q=test&second=another
# get('http://google.com/some/thing?ha=poo', :query_hash => {:q => 'test', :second => 'another'}, :qsi => '&')
# # makes request to http://google.com/some/thing?ha=poo&q=test&second=another
def self.get(url, o={})
options = {
:query_hash => nil,
:qsi => '?'
}.merge(o)
request 'get', url, options
end
# Makes a post request to a google service using
# the session id from the connection's session
#
# Usage:
# post('http://google.com/some/thing', :form_data => {:one => '1', :two => '2'})
# # makes a post request to http://google.com/some/thing with the post data set to one=1&two=2
# post('http://google.com/some/thing', :raw_data => "some=thing&another=thing")
# # makes a post request to http://google.com/some/thing with the post data set to some=thing&another=thing
def self.post(url, o={})
options = {
:form_data => nil,
:raw_data => nil,
}.merge(o)
if options[:raw_data]
url = URI.parse(URI.escape(url))
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true if url.port == 443
result = http.request_post(url.request_uri, options[:raw_data], @@connection.headers)
result.body
else
request 'post', url, options
end
end
# Session id returned from google login request
attr_accessor :sid
# Creates a new instance of the connection class using
# the given email and password and attempts to login
def initialize(email, password ,service)
@email, @password, @service = email, password, service
login
end
# Makes authentication request to google and sets the sid
# to be passed in a cookie with each authenticated request.
#
# Raises Google::LoginError if login is unsuccessful
def login
url = URI.parse(LOGIN_URL)
req = Net::HTTP::Post.new(url.request_uri)
req.set_form_data({
'accountType' => 'HOSTED_OR_GOOGLE',
'Email' => @email,
'Passwd' => @password,
'source' => SOURCE,
'continue' => URL,
'service' => @service,
})
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
result = http.start() { |conn| conn.request(req) }
@sid = extract_sid(result.body)
@auth = extract_auth(result.body)
raise LoginError, "Most likely your username and password are wrong." unless logged_in?
end
# Returns true or false based on whether or not the session id is set
def logged_in?
@sid ? true : false
end
# Outputs the headers that are needed to make an authenticated request
def headers
{'Authorization' => "GoogleLogin auth=#{@auth}"}
end
private
def self.request(method, url, o={})
options = {
:form_data => nil,
:query_hash => nil,
:qsi => '?'
}.merge(o)
url += hash_to_query_string(options[:query_hash], options[:qsi]) unless options[:query_hash].nil?
url = URI.parse(URI.escape(url))
req = if method == 'post'
Net::HTTP::Post.new(url.request_uri, @@connection.headers)
else
Net::HTTP::Get.new(url.request_uri, @@connection.headers)
end
req.set_form_data(options[:form_data]) if options[:form_data]
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true if url.port == 443
result = http.start() { |conn| conn.request(req) }
result.body
end
# Converts a hash to a query string
#
# Usage:
# hash_to_query_string({:q => 'test', :num => 5}) # => '?q=test&num=5&'
# hash_to_query_string({:q => 'test', :num => 5}, '&') # => '&q=test&num=5&'
def self.hash_to_query_string(hash, initial_value="?")
hash.inject(initial_value) { |qs, h| qs += "#{h[0]}=#{h[1]}&"; qs }
end
def extract_sid(body)
matches = body.match(/SID=(.*)/)
matches.nil? ? nil : matches[0].gsub('SID=', '')
end
def extract_auth(body)
matches = body.match(/Auth=(.*)/)
matches.nil? ? nil : matches[0].gsub('Auth=', '')
end
end
end