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
10 import http.client # python2
12 import http.client # python3
16 from oauth2client.client import OAuth2Credentials
17 import gdata.calendar.service
18 import gdata.docs.service
19 import gdata.photos.service, gdata.photos
20 from googleapiclient.discovery import build
22 from googleapiclient.discovery import build
28 def __init__(self, client_id, client_secret):
29 print("gdata: initializing oauth token...")
30 self.client_id = client_id
31 self.client_secret = client_secret
33 # print 'Client id: %s' % (client_id)
34 # print 'Client secret: %s' % (client_secret)
36 self.device_code = None
37 self.verfication_url = None
38 self.token_file = "client_secrets.json"
40 #'https://www.googleapis.com/auth/calendar',
41 #'https://www.googleapis.com/auth/drive',
42 #'https://docs.google.com/feeds',
43 #'https://www.googleapis.com/auth/calendar.readonly',
44 #'https://picasaweb.google.com/data/',
45 "https://www.googleapis.com/auth/photoslibrary.readonly",
46 #'http://picasaweb.google.com/data/',
47 #'https://www.google.com/calendar/feeds/',
49 self.host = "accounts.google.com"
50 self.reset_connection()
55 # this setup is isolated because it eventually generates a BadStatusLine
56 # exception, after which we always get httplib.CannotSendRequest errors.
57 # When this happens, we try re-creating the exception.
58 def reset_connection(self):
59 self.ssl_ctx = ssl.create_default_context(cafile="/usr/local/etc/ssl/cert.pem")
60 http.client.HTTPConnection.debuglevel = 2
61 self.conn = http.client.HTTPSConnection(self.host, context=self.ssl_ctx)
65 if os.path.isfile(self.token_file):
66 f = open(self.token_file)
68 self.token = json.loads(json_token)
72 f = open(self.token_file, "w")
73 f.write(json.dumps(self.token))
77 if self.token != None:
78 print("gdata: we have a token!")
80 print("gdata: we have no token.")
81 return self.token != None
83 def get_user_code(self):
86 "/o/oauth2/device/code",
87 urllib.parse.urlencode(
88 {"client_id": self.client_id, "scope": " ".join(self.scope)}
90 {"Content-type": "application/x-www-form-urlencoded"},
92 response = self.conn.getresponse()
93 if response.status == 200:
94 data = json.loads(response.read())
95 self.device_code = data["device_code"]
96 self.user_code = data["user_code"]
97 self.verification_url = data["verification_url"]
98 self.retry_interval = data["interval"]
100 print(("gdata: %d" % response.status))
101 print((response.read()))
103 return self.user_code
105 def get_new_token(self):
106 # call get_device_code if not already set
107 if self.user_code == None:
108 print("gdata: getting user code")
111 while self.token == None:
115 urllib.parse.urlencode(
117 "client_id": self.client_id,
118 "client_secret": self.client_secret,
119 "code": self.device_code,
120 "grant_type": "http://oauth.net/grant_type/device/1.0",
123 {"Content-type": "application/x-www-form-urlencoded"},
125 response = self.conn.getresponse()
126 if response.status == 200:
127 data = json.loads(response.read())
128 if "access_token" in data:
132 time.sleep(self.retry_interval + 2)
134 print("gdata: failed to get token")
135 print((response.status))
136 print((response.read()))
138 def refresh_token(self):
139 if self.checking_too_often():
140 print("gdata: not refreshing yet, too soon...")
143 print("gdata: trying to refresh oauth token...")
144 self.reset_connection()
145 refresh_token = self.token["refresh_token"]
149 urllib.parse.urlencode(
151 "client_id": self.client_id,
152 "client_secret": self.client_secret,
153 "refresh_token": refresh_token,
154 "grant_type": "refresh_token",
157 {"Content-type": "application/x-www-form-urlencoded"},
160 response = self.conn.getresponse()
161 self.last_action = time.time()
162 if response.status == 200:
163 data = json.loads(response.read())
164 if "access_token" in data:
166 # in fact we NEVER get a new refresh token at this point
167 if not "refresh_token" in self.token:
168 self.token["refresh_token"] = refresh_token
171 print(("gdata: unexpected response %d to renewal request" % response.status))
172 print((response.read()))
175 def checking_too_often(self):
177 return (now - self.last_action) <= 30
179 # https://developers.google.com/picasa-web/
180 def photos_service(self):
182 "Authorization": "%s %s"
183 % (self.token["token_type"], self.token["access_token"])
185 client = gdata.photos.service.PhotosService(additional_headers=headers)
188 # https://developers.google.com/drive/
189 def docs_service(self):
190 cred = OAuth2Credentials(
191 self.token["access_token"],
194 self.token["refresh_token"],
195 datetime.datetime.now(),
196 "http://accounts.google.com/o/oauth2/token",
199 http = httplib2.Http(disable_ssl_certificate_validation=True)
200 http = cred.authorize(http)
201 service = build("drive", "v2", http)
204 # https://developers.google.com/google-apps/calendar/
205 def calendar_service(self):
206 cred = OAuth2Credentials(
207 self.token["access_token"],
210 self.token["refresh_token"],
211 datetime.datetime.now(),
212 "http://accounts.google.com/o/oauth2/token",
215 http = httplib2.Http(disable_ssl_certificate_validation=True)
216 http = cred.authorize(http)
217 service = build("calendar", "v3", http)