]>
Commit | Line | Data |
---|---|---|
1 | from twitter.auth import Auth | |
2 | ||
3 | from time import time | |
4 | from random import getrandbits | |
5 | from time import time | |
6 | import urllib | |
7 | import hashlib | |
8 | import hmac | |
9 | import base64 | |
10 | ||
11 | def write_token_file(filename, oauth_token, oauth_token_secret): | |
12 | """ | |
13 | Write a token file to hold the oauth token and oauth token secret. | |
14 | """ | |
15 | oauth_file = open(filename, 'w') | |
16 | print >> oauth_file, oauth_token | |
17 | print >> oauth_file, oauth_token_secret | |
18 | oauth_file.close() | |
19 | ||
20 | def read_token_file(filename): | |
21 | """ | |
22 | Read a token file and return the oauth token and oauth token secret. | |
23 | """ | |
24 | f = open(filename) | |
25 | return f.readline().strip(), f.readline().strip() | |
26 | ||
27 | ||
28 | class OAuth(Auth): | |
29 | """ | |
30 | An OAuth authenticator. | |
31 | """ | |
32 | def __init__(self, token, token_secret, consumer_key, consumer_secret): | |
33 | """ | |
34 | Create the authenticator. If you are in the initial stages of | |
35 | the OAuth dance and don't yet have a token or token_secret, | |
36 | pass empty strings for these params. | |
37 | """ | |
38 | self.token = token | |
39 | self.token_secret = token_secret | |
40 | self.consumer_key = consumer_key | |
41 | self.consumer_secret = consumer_secret | |
42 | ||
43 | def encode_params(self, base_url, method, params): | |
44 | params = params.copy() | |
45 | ||
46 | if self.token: | |
47 | params['oauth_token'] = self.token | |
48 | ||
49 | params['oauth_consumer_key'] = self.consumer_key | |
50 | params['oauth_signature_method'] = 'HMAC-SHA1' | |
51 | params['oauth_version'] = '1.0' | |
52 | params['oauth_timestamp'] = str(int(time())) | |
53 | params['oauth_nonce'] = str(getrandbits(64)) | |
54 | ||
55 | enc_params = urlencode_noplus(sorted(params.iteritems())) | |
56 | ||
57 | key = self.consumer_secret + "&" + urllib.quote(self.token_secret, '') | |
58 | ||
59 | message = '&'.join( | |
60 | urllib.quote(i, '') for i in [method.upper(), base_url, enc_params]) | |
61 | ||
62 | signature = (base64.b64encode(hmac.new( | |
63 | key.encode('ascii'), message.encode('ascii'), hashlib.sha1) | |
64 | .digest())) | |
65 | return enc_params + "&" + "oauth_signature=" + urllib.quote(signature, '') | |
66 | ||
67 | def generate_headers(self): | |
68 | return {} | |
69 | ||
70 | # apparently contrary to the HTTP RFCs, spaces in arguments must be encoded as | |
71 | # %20 rather than '+' when constructing an OAuth signature (and therefore | |
72 | # also in the request itself.) | |
73 | # So here is a specialized version which does exactly that. | |
74 | def urlencode_noplus(query): | |
75 | if hasattr(query,"items"): | |
76 | # mapping objects | |
77 | query = query.items() | |
78 | ||
79 | encoded_bits = [] | |
80 | for n, v in query: | |
81 | # and do unicode here while we are at it... | |
82 | if isinstance(n, unicode): | |
83 | n = n.encode('utf-8') | |
84 | else: | |
85 | n = str(n) | |
86 | if isinstance(v, unicode): | |
87 | v = v.encode('utf-8') | |
88 | else: | |
89 | v = str(v) | |
90 | encoded_bits.append("%s=%s" % (urllib.quote(n, ""), urllib.quote(v, ""))) | |
91 | return "&".join(encoded_bits) |