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