]> jfr.im git - z_archive/twitter.git/blame - twitter/oauth.py
Fix a test.
[z_archive/twitter.git] / twitter / oauth.py
CommitLineData
3930cc7b
MV
1from __future__ import print_function
2
568331a9
MH
3from twitter.auth import Auth
4
5from time import time
6from random import getrandbits
3930cc7b
MV
7
8try:
9 import urllib.parse as urllib_parse
aeabd5b8 10 from urllib.parse import urlencode
11 PY3 = True
3930cc7b
MV
12except ImportError:
13 import urllib2 as urllib_parse
aeabd5b8 14 from urllib import urlencode
15 PY3 = False
3930cc7b 16
568331a9
MH
17import hashlib
18import hmac
a2855195 19import base64
568331a9 20
3930cc7b
MV
21
22
1b31d642 23def 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
32def 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 40class 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.
86def 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")