-
Notifications
You must be signed in to change notification settings - Fork 0
/
oauth_receiver.py
108 lines (91 loc) · 3.13 KB
/
oauth_receiver.py
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
# oauth_receiver.py
# (c) 2012 Matt Ginzton, [email protected]
#
# Python class to implement a short-lived HTTP server suitable for embedding
# in a local application that needs to receive an OAuth callback.
#
# Changelog:
# - basic functionality: 2012/10/15
import BaseHTTPServer
import cgi
import threading
import time
import urllib
import urlparse
try:
parse_qs = urlparse.parse_qs
except AttributeError:
parse_qs = cgi.parse_qs
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
request = urlparse.urlparse(self.path)
(response, body) = (404, None)
if request.path == '/oauth_receiver':
query = parse_qs(request.query)
try:
token = query['oauth_token'][0]
if token == self.server.receiver.oauth_token:
if query.has_key('oauth_verifier'):
self.server.receiver.oauth_verifier = query['oauth_verifier'][0]
(response, body) = (200, '<html><body>Thanks! Evernote Palm Importer is authorized to do what it needs. You may close this browser tab or window now.</body></html>')
else:
(response, body) = (200, '<html><body>Authentication request has been canceled. Evernote Palm Importer is not authorized to do what it needs. You may close this browser tab or window now.</body></html>')
else:
response = 400 # Bad request
except:
response = 400 # Bad request
elif request.path == '/oauth_receiver/cancel':
response = 200
self.send_response(response)
self.end_headers()
if body:
self.wfile.write(body)
if response == 200:
self.server.receiver.thread.running = False
def log_message(self, format, *args):
pass
class ReceiverThread(threading.Thread):
daemon = True
running = True
def __init__(self, httpd):
super(ReceiverThread, self).__init__(name = 'oauth_receiver')
self.httpd = httpd
def run(self):
while self.running:
self.httpd.handle_request()
class OAuthReceiver:
def __init__(self):
self.oauth_token = None
self.oauth_verifier = None
local_address = ('127.0.0.1', 0)
self.httpd = BaseHTTPServer.HTTPServer(local_address, RequestHandler)
self.httpd.receiver = self
self.url = 'http://%s:%d/oauth_receiver' % (self.httpd.server_address[0], self.httpd.server_port)
self.thread = None
def start(self, token):
print 'listening as %s' % self.url
self.thread = ReceiverThread(self.httpd)
self.oauth_token = token
self.thread.start()
def wait(self, config):
# XXX in an ideal world, this wouldn't exist; we wouldn't loop at this
# layer; EvernoteManager would use continuations, the CLI could have
# this synchronous loop with a KeyboardInterrupt handler setting
# config.canceled, and the GUI already sets config.canceled. But this
# app doesn't justify the additional effort; this works well enough.
try:
while self.thread.running:
if config.canceled:
urllib.urlopen(self.url + '/cancel')
else:
print 'waiting for authorization...'
time.sleep(1)
except KeyboardInterrupt:
print 'Interrupted; never mind'
urllib.urlopen(self.url + '/cancel')
return self.oauth_verifier
# unit test harness
if __name__ == '__main__':
receiver = OAuthReceiver()
receiver.start()
receiver.wait()