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