]> jfr.im git - z_archive/twitter.git/blame - twitter/oauth.py
Encode basestring instead of just str to utf-8
[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
10except ImportError:
11 import urllib2 as urllib_parse
12
568331a9
MH
13import hashlib
14import hmac
a2855195 15import base64
568331a9 16
3930cc7b
MV
17
18
1b31d642 19def 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
28def 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 36class 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.
82def 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...
21942f5c 90 if isinstance(n, basestring):
568331a9
MH
91 n = n.encode('utf-8')
92 else:
93 n = str(n)
21942f5c 94 if isinstance(v, basestring):
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)