]> jfr.im git - z_archive/twitter.git/blame - twitter/oauth.py
Merge branch 'master' into py3-2
[z_archive/twitter.git] / twitter / oauth.py
CommitLineData
568331a9
MH
1from twitter.auth import Auth
2
3from time import time
4from random import getrandbits
5from time import time
f7e63802 6import urllib.request, urllib.parse, urllib.error
568331a9
MH
7import hashlib
8import hmac
a2855195 9import base64
568331a9 10
1b31d642 11def write_token_file(filename, oauth_token, oauth_token_secret):
d828f28d
MV
12 """
13 Write a token file to hold the oauth token and oauth token secret.
14 """
1b31d642 15 oauth_file = open(filename, 'w')
f7e63802
MV
16 print(oauth_token, file=oauth_file)
17 print(oauth_token_secret, file=oauth_file)
1b31d642
MV
18 oauth_file.close()
19
20def read_token_file(filename):
d828f28d
MV
21 """
22 Read a token file and return the oauth token and oauth token secret.
23 """
1b31d642
MV
24 f = open(filename)
25 return f.readline().strip(), f.readline().strip()
26
27
568331a9 28class OAuth(Auth):
1cc9ab0b
MV
29 """
30 An OAuth authenticator.
31 """
568331a9 32 def __init__(self, token, token_secret, consumer_key, consumer_secret):
1cc9ab0b
MV
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 """
568331a9
MH
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
6c527e72
MV
46 if self.token:
47 params['oauth_token'] = self.token
48
568331a9
MH
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
f7e63802 55 enc_params = urlencode_noplus(sorted(params.items()))
568331a9 56
f7e63802 57 key = self.consumer_secret + "&" + urllib.parse.quote(self.token_secret, '')
568331a9
MH
58
59 message = '&'.join(
f7e63802 60 urllib.parse.quote(i, '') for i in [method.upper(), base_url, enc_params])
d828f28d 61
a2855195
MV
62 signature = (base64.b64encode(hmac.new(
63 key.encode('ascii'), message.encode('ascii'), hashlib.sha1)
64 .digest()))
f7e63802 65 return enc_params + "&" + "oauth_signature=" + urllib.parse.quote(signature, '')
568331a9
MH
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.
74def urlencode_noplus(query):
75 if hasattr(query,"items"):
76 # mapping objects
f7e63802 77 query = list(query.items())
d828f28d 78
568331a9
MH
79 encoded_bits = []
80 for n, v in query:
81 # and do unicode here while we are at it...
f7e63802 82 if isinstance(n, str):
568331a9
MH
83 n = n.encode('utf-8')
84 else:
85 n = str(n)
f7e63802 86 if isinstance(v, str):
568331a9
MH
87 v = v.encode('utf-8')
88 else:
89 v = str(v)
f7e63802 90 encoded_bits.append("%s=%s" % (urllib.parse.quote(n, ""), urllib.parse.quote(v, "")))
568331a9 91 return "&".join(encoded_bits)