Initial checking of picasa project.
[picasa.git] / gdata_oauth.py
1 # https://developers.google.com/accounts/docs/OAuth2ForDevices
2 # https://developers.google.com/drive/web/auth/web-server
3 # https://developers.google.com/google-apps/calendar/v3/reference/calendars
4 # https://developers.google.com/picasa-web/
5
6 import sys
7 import urllib
8 try:
9     import httplib     # python2
10 except ImportError:
11     import http.client # python3
12 import os.path
13 import json
14 import time
15 from oauth2client.client import OAuth2Credentials
16 import gdata.calendar.service
17 import gdata.docs.service
18 import gdata.photos.service, gdata.photos
19 from apiclient.discovery import build
20 import httplib2
21 from apiclient.discovery import build
22 import datetime
23 import ssl
24
25 class OAuth:
26     def __init__(self, client_id, client_secret):
27         print "Initializing oauth token..."
28         self.client_id = client_id
29         self.client_secret = client_secret
30         #print 'Client id: %s' % (client_id)
31         #print 'Client secret: %s' % (client_secret)
32         self.token = None
33         self.device_code = None
34         self.verfication_url = None
35         self.token_file = 'client_secrets.json'
36         self.scope = [
37             #'https://www.googleapis.com/auth/calendar',
38             #'https://www.googleapis.com/auth/drive',
39             'https://docs.google.com/feeds',
40             'https://www.googleapis.com/auth/calendar.readonly',
41             'https://picasaweb.google.com/data/',
42             'https://photos.googleapis.com/data/',
43             #'http://picasaweb.google.com/data/',
44             #'https://www.google.com/calendar/feeds/',
45         ]
46         self.host = 'accounts.google.com'
47         self.reset_connection()
48         self.load_token()
49         self.last_action = 0
50         self.ssl_ctx = None
51
52     # this setup is isolated because it eventually generates a BadStatusLine
53     # exception, after which we always get httplib.CannotSendRequest errors.
54     # When this happens, we try re-creating the exception.
55     def reset_connection(self):
56         self.ssl_ctx = ssl.create_default_context(cafile='/usr/local/etc/ssl/cert.pem')
57         httplib.HTTPConnection.debuglevel = 2
58         self.conn = httplib.HTTPSConnection(self.host, context=self.ssl_ctx)
59
60     def load_token(self):
61         token = None
62         if os.path.isfile(self.token_file):
63             f = open(self.token_file)
64             json_token = f.read()
65             self.token = json.loads(json_token)
66             f.close()
67
68     def save_token(self):
69         f = open(self.token_file, 'w')
70         f.write(json.dumps(self.token))
71         f.close()
72
73     def has_token(self):
74         if self.token != None:
75             print "We have a token!"
76         else:
77             print "We have no token."
78         return self.token != None
79
80     def get_user_code(self):
81         self.conn.request(
82             "POST",
83             "/o/oauth2/device/code",
84             urllib.urlencode({
85                 'client_id': self.client_id,
86                 'scope'    : ' '.join(self.scope)
87                 }),
88             {"Content-type": "application/x-www-form-urlencoded"})
89         response = self.conn.getresponse()
90         if response.status == 200:
91             data = json.loads(response.read())
92             self.device_code = data['device_code']
93             self.user_code = data['user_code']
94             self.verification_url = data['verification_url']
95             self.retry_interval = data['interval']
96         else:
97             print response.status
98             print response.read()
99             sys.exit()
100         return self.user_code
101
102     def get_new_token(self):
103         # call get_device_code if not already set
104         if not self.user_code:
105             print "getting user code"
106             self.get_user_code()
107
108         while self.token == None:
109             self.conn.request(
110                 "POST",
111                 "/o/oauth2/token",
112                 urllib.urlencode({
113                     'client_id'     : self.client_id,
114                     'client_secret' : self.client_secret,
115                     'code'          : self.device_code,
116                     'grant_type'    : 'http://oauth.net/grant_type/device/1.0'
117                     }),
118                 {"Content-type": "application/x-www-form-urlencoded"})
119             response = self.conn.getresponse()
120             if response.status == 200:
121                 data = json.loads(response.read())
122                 if 'access_token' in data:
123                     self.token = data
124                     self.save_token()
125                 else:
126                     time.sleep(self.retry_interval + 2)
127             else:
128                 print "failed to get token"
129                 print response.status
130                 print response.read()
131
132     def refresh_token(self):
133         if self.checking_too_often():
134             print "Not refreshing yet, too soon..."
135             return False
136         else:
137             print 'Trying to refresh oauth token...'
138         self.reset_connection()
139         refresh_token = self.token['refresh_token']
140         self.conn.request(
141             "POST",
142             "/o/oauth2/token",
143             urllib.urlencode({
144                 'client_id'     : self.client_id,
145                 'client_secret' : self.client_secret,
146                 'refresh_token' : refresh_token,
147                 'grant_type'    : 'refresh_token'
148                 }),
149             {"Content-type": "application/x-www-form-urlencoded"})
150
151         response = self.conn.getresponse()
152         self.last_action = time.time()
153         if response.status == 200:
154             data = json.loads(response.read())
155             if 'access_token' in data:
156                 self.token = data
157                 # in fact we NEVER get a new refresh token at this point
158                 if not 'refresh_token' in self.token:
159                     self.token['refresh_token'] = refresh_token
160                     self.save_token()
161                 return True
162         print "Unexpected response %d to renewal request" % response.status
163         print response.read()
164         return False
165
166     def checking_too_often(self):
167         now = time.time()
168         return (now - self.last_action) <= 30
169
170     # https://developers.google.com/picasa-web/
171     def photos_service(self):
172         headers = {
173             "Authorization": "%s %s"  % (self.token['token_type'], self.token['access_token'])
174         }
175         client = gdata.photos.service.PhotosService(additional_headers=headers)
176         return client
177
178     # https://developers.google.com/drive/
179     def docs_service(self):
180         cred = OAuth2Credentials(self.token['access_token'],
181                                  self.client_id,
182                                  self.client_secret,
183                                  self.token['refresh_token'],
184                                  datetime.datetime.now(),
185                                  'http://accounts.google.com/o/oauth2/token',
186                                  'KitchenKiosk/0.9')
187         http = httplib2.Http(disable_ssl_certificate_validation=True)
188         http = cred.authorize(http)
189         service = build('drive', 'v2', http)
190         return service
191
192     # https://developers.google.com/google-apps/calendar/
193     def calendar_service(self):
194         cred = OAuth2Credentials(self.token['access_token'],
195                                  self.client_id,
196                                  self.client_secret,
197                                  self.token['refresh_token'],
198                                  datetime.datetime.now(),
199                                  'http://accounts.google.com/o/oauth2/token',
200                                  'KitchenKiosk/0.9')
201         http = httplib2.Http(disable_ssl_certificate_validation=True)
202         http = cred.authorize(http)
203         service = build('calendar', 'v3', http)
204         return service