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/
7 import urllib.request, urllib.parse, urllib.error
9 import http.client # python2
11 import http.client # python3
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 googleapiclient.discovery import build
21 from googleapiclient.discovery import build
26 def __init__(self, client_id, client_secret):
27 print("gdata: initializing oauth token...")
28 self.client_id = client_id
29 self.client_secret = client_secret
31 #print 'Client id: %s' % (client_id)
32 #print 'Client secret: %s' % (client_secret)
34 self.device_code = None
35 self.verfication_url = None
36 self.token_file = 'client_secrets.json'
38 #'https://www.googleapis.com/auth/calendar',
39 #'https://www.googleapis.com/auth/drive',
40 #'https://docs.google.com/feeds',
41 #'https://www.googleapis.com/auth/calendar.readonly',
42 #'https://picasaweb.google.com/data/',
43 'https://www.googleapis.com/auth/photoslibrary.readonly',
44 #'http://picasaweb.google.com/data/',
45 #'https://www.google.com/calendar/feeds/',
47 self.host = 'accounts.google.com'
48 self.reset_connection()
53 # this setup is isolated because it eventually generates a BadStatusLine
54 # exception, after which we always get httplib.CannotSendRequest errors.
55 # When this happens, we try re-creating the exception.
56 def reset_connection(self):
57 self.ssl_ctx = ssl.create_default_context(cafile='/usr/local/etc/ssl/cert.pem')
58 http.client.HTTPConnection.debuglevel = 2
59 self.conn = http.client.HTTPSConnection(self.host, context=self.ssl_ctx)
63 if os.path.isfile(self.token_file):
64 f = open(self.token_file)
66 self.token = json.loads(json_token)
70 f = open(self.token_file, 'w')
71 f.write(json.dumps(self.token))
75 if self.token != None:
76 print("gdata: we have a token!")
78 print("gdata: we have no token.")
79 return self.token != None
81 def get_user_code(self):
84 "/o/oauth2/device/code",
85 urllib.parse.urlencode({
86 'client_id': self.client_id,
87 'scope' : ' '.join(self.scope)
89 {"Content-type": "application/x-www-form-urlencoded"})
90 response = self.conn.getresponse()
91 if response.status == 200:
92 data = json.loads(response.read())
93 self.device_code = data['device_code']
94 self.user_code = data['user_code']
95 self.verification_url = data['verification_url']
96 self.retry_interval = data['interval']
98 print(("gdata: %d" % response.status))
99 print((response.read()))
101 return self.user_code
103 def get_new_token(self):
104 # call get_device_code if not already set
105 if self.user_code == None:
106 print("gdata: getting user code")
109 while self.token == None:
113 urllib.parse.urlencode({
114 'client_id' : self.client_id,
115 'client_secret' : self.client_secret,
116 'code' : self.device_code,
117 'grant_type' : 'http://oauth.net/grant_type/device/1.0'
119 {"Content-type": "application/x-www-form-urlencoded"})
120 response = self.conn.getresponse()
121 if response.status == 200:
122 data = json.loads(response.read())
123 if 'access_token' in data:
127 time.sleep(self.retry_interval + 2)
129 print("gdata: failed to get token")
130 print((response.status))
131 print((response.read()))
133 def refresh_token(self):
134 if self.checking_too_often():
135 print("gdata: not refreshing yet, too soon...")
138 print('gdata: trying to refresh oauth token...')
139 self.reset_connection()
140 refresh_token = self.token['refresh_token']
144 urllib.parse.urlencode({
145 'client_id' : self.client_id,
146 'client_secret' : self.client_secret,
147 'refresh_token' : refresh_token,
148 'grant_type' : 'refresh_token'
150 {"Content-type": "application/x-www-form-urlencoded"})
152 response = self.conn.getresponse()
153 self.last_action = time.time()
154 if response.status == 200:
155 data = json.loads(response.read())
156 if 'access_token' in data:
158 # in fact we NEVER get a new refresh token at this point
159 if not 'refresh_token' in self.token:
160 self.token['refresh_token'] = refresh_token
163 print(("gdata: unexpected response %d to renewal request" % response.status))
164 print((response.read()))
167 def checking_too_often(self):
169 return (now - self.last_action) <= 30
171 # https://developers.google.com/picasa-web/
172 def photos_service(self):
174 "Authorization": "%s %s" % (self.token['token_type'], self.token['access_token'])
176 client = gdata.photos.service.PhotosService(additional_headers=headers)
179 # https://developers.google.com/drive/
180 def docs_service(self):
181 cred = OAuth2Credentials(self.token['access_token'],
184 self.token['refresh_token'],
185 datetime.datetime.now(),
186 'http://accounts.google.com/o/oauth2/token',
188 http = httplib2.Http(disable_ssl_certificate_validation=True)
189 http = cred.authorize(http)
190 service = build('drive', 'v2', http)
193 # https://developers.google.com/google-apps/calendar/
194 def calendar_service(self):
195 cred = OAuth2Credentials(self.token['access_token'],
198 self.token['refresh_token'],
199 datetime.datetime.now(),
200 'http://accounts.google.com/o/oauth2/token',
202 http = httplib2.Http(disable_ssl_certificate_validation=True)
203 http = cred.authorize(http)
204 service = build('calendar', 'v3', http)