# https://developers.google.com/accounts/docs/OAuth2ForDevices # https://developers.google.com/drive/web/auth/web-server # https://developers.google.com/google-apps/calendar/v3/reference/calendars # https://developers.google.com/picasa-web/ import sys import urllib try: import httplib # python2 except ImportError: import http.client # python3 import os.path import json import time from oauth2client.client import OAuth2Credentials import gdata.calendar.service import gdata.docs.service import gdata.photos.service, gdata.photos from apiclient.discovery import build import httplib2 from apiclient.discovery import build import datetime import ssl class OAuth: def __init__(self, client_id, client_secret): print "Initializing oauth token..." self.client_id = client_id self.client_secret = client_secret #print 'Client id: %s' % (client_id) #print 'Client secret: %s' % (client_secret) self.token = None self.device_code = None self.verfication_url = None self.token_file = 'client_secrets.json' self.scope = [ #'https://www.googleapis.com/auth/calendar', #'https://www.googleapis.com/auth/drive', 'https://docs.google.com/feeds', 'https://www.googleapis.com/auth/calendar.readonly', 'https://picasaweb.google.com/data/', 'https://photos.googleapis.com/data/', #'http://picasaweb.google.com/data/', #'https://www.google.com/calendar/feeds/', ] self.host = 'accounts.google.com' self.reset_connection() self.load_token() self.last_action = 0 self.ssl_ctx = None # this setup is isolated because it eventually generates a BadStatusLine # exception, after which we always get httplib.CannotSendRequest errors. # When this happens, we try re-creating the exception. def reset_connection(self): self.ssl_ctx = ssl.create_default_context(cafile='/usr/local/etc/ssl/cert.pem') httplib.HTTPConnection.debuglevel = 2 self.conn = httplib.HTTPSConnection(self.host, context=self.ssl_ctx) def load_token(self): token = None if os.path.isfile(self.token_file): f = open(self.token_file) json_token = f.read() self.token = json.loads(json_token) f.close() def save_token(self): f = open(self.token_file, 'w') f.write(json.dumps(self.token)) f.close() def has_token(self): if self.token != None: print "We have a token!" else: print "We have no token." return self.token != None def get_user_code(self): self.conn.request( "POST", "/o/oauth2/device/code", urllib.urlencode({ 'client_id': self.client_id, 'scope' : ' '.join(self.scope) }), {"Content-type": "application/x-www-form-urlencoded"}) response = self.conn.getresponse() if response.status == 200: data = json.loads(response.read()) self.device_code = data['device_code'] self.user_code = data['user_code'] self.verification_url = data['verification_url'] self.retry_interval = data['interval'] else: print response.status print response.read() sys.exit() return self.user_code def get_new_token(self): # call get_device_code if not already set if not self.user_code: print "getting user code" self.get_user_code() while self.token == None: self.conn.request( "POST", "/o/oauth2/token", urllib.urlencode({ 'client_id' : self.client_id, 'client_secret' : self.client_secret, 'code' : self.device_code, 'grant_type' : 'http://oauth.net/grant_type/device/1.0' }), {"Content-type": "application/x-www-form-urlencoded"}) response = self.conn.getresponse() if response.status == 200: data = json.loads(response.read()) if 'access_token' in data: self.token = data self.save_token() else: time.sleep(self.retry_interval + 2) else: print "failed to get token" print response.status print response.read() def refresh_token(self): if self.checking_too_often(): print "Not refreshing yet, too soon..." return False else: print 'Trying to refresh oauth token...' self.reset_connection() refresh_token = self.token['refresh_token'] self.conn.request( "POST", "/o/oauth2/token", urllib.urlencode({ 'client_id' : self.client_id, 'client_secret' : self.client_secret, 'refresh_token' : refresh_token, 'grant_type' : 'refresh_token' }), {"Content-type": "application/x-www-form-urlencoded"}) response = self.conn.getresponse() self.last_action = time.time() if response.status == 200: data = json.loads(response.read()) if 'access_token' in data: self.token = data # in fact we NEVER get a new refresh token at this point if not 'refresh_token' in self.token: self.token['refresh_token'] = refresh_token self.save_token() return True print "Unexpected response %d to renewal request" % response.status print response.read() return False def checking_too_often(self): now = time.time() return (now - self.last_action) <= 30 # https://developers.google.com/picasa-web/ def photos_service(self): headers = { "Authorization": "%s %s" % (self.token['token_type'], self.token['access_token']) } client = gdata.photos.service.PhotosService(additional_headers=headers) return client # https://developers.google.com/drive/ def docs_service(self): cred = OAuth2Credentials(self.token['access_token'], self.client_id, self.client_secret, self.token['refresh_token'], datetime.datetime.now(), 'http://accounts.google.com/o/oauth2/token', 'KitchenKiosk/0.9') http = httplib2.Http(disable_ssl_certificate_validation=True) http = cred.authorize(http) service = build('drive', 'v2', http) return service # https://developers.google.com/google-apps/calendar/ def calendar_service(self): cred = OAuth2Credentials(self.token['access_token'], self.client_id, self.client_secret, self.token['refresh_token'], datetime.datetime.now(), 'http://accounts.google.com/o/oauth2/token', 'KitchenKiosk/0.9') http = httplib2.Http(disable_ssl_certificate_validation=True) http = cred.authorize(http) service = build('calendar', 'v3', http) return service