X-Git-Url: https://jfr.im/git/z_archive/twitter.git/blobdiff_plain/3930cc7bae58f738b4984ef090c4384e50a42b1f..11534bd21fb1b4ab6647ba8d2430549bcdedbc25:/twitter/oauth.py diff --git a/twitter/oauth.py b/twitter/oauth.py index be47e96..f13ef22 100644 --- a/twitter/oauth.py +++ b/twitter/oauth.py @@ -1,19 +1,61 @@ -from __future__ import print_function +""" +Visit the Twitter developer page and create a new application: + + https://dev.twitter.com/apps/new + +This will get you a CONSUMER_KEY and CONSUMER_SECRET. + +When users run your application they have to authenticate your app +with their Twitter account. A few HTTP calls to twitter are required +to do this. Please see the twitter.oauth_dance module to see how this +is done. If you are making a command-line app, you can use the +oauth_dance() function directly. + +Performing the "oauth dance" gets you an ouath token and oauth secret +that authenticate the user with Twitter. You should save these for +later so that the user doesn't have to do the oauth dance again. + +read_token_file and write_token_file are utility methods to read and +write OAuth token and secret key values. The values are stored as +strings in the file. Not terribly exciting. + +Finally, you can use the OAuth authenticator to connect to Twitter. In +code it all goes like this:: -from twitter.auth import Auth + MY_TWITTER_CREDS = os.path.expanduser('~/.my_app_credentials') + if not os.path.exists(MY_TWITTER_CREDS): + oauth_dance("My App Name", CONSUMER_KEY, CONSUMER_SECRET, + MY_TWITTER_CREDS) + + oauth_token, oauth_secret = read_token_file(MY_TWITTER_CREDS) + + twitter = Twitter(auth=OAuth( + oauth_token, oauth_token_secret, CONSUMER_KEY, CONSUMER_SECRET)) + + # Now work with Twitter + twitter.statuses.update(status='Hello, world!') + +""" + +from __future__ import print_function from time import time from random import getrandbits try: import urllib.parse as urllib_parse + from urllib.parse import urlencode + PY3 = True except ImportError: import urllib2 as urllib_parse + from urllib import urlencode + PY3 = False import hashlib import hmac import base64 +from .auth import Auth def write_token_file(filename, oauth_token, oauth_token_secret): @@ -62,15 +104,15 @@ class OAuth(Auth): enc_params = urlencode_noplus(sorted(params.items())) - key = self.consumer_secret + "&" + urllib_parse.quote(self.token_secret, '') + key = self.consumer_secret + "&" + urllib_parse.quote(self.token_secret, safe='~') message = '&'.join( - urllib_parse.quote(i, '') for i in [method.upper(), base_url, enc_params]) + urllib_parse.quote(i, safe='~') for i in [method.upper(), base_url, enc_params]) signature = (base64.b64encode(hmac.new( key.encode('ascii'), message.encode('ascii'), hashlib.sha1) .digest())) - return enc_params + "&" + "oauth_signature=" + urllib_parse.quote(signature, '') + return enc_params + "&" + "oauth_signature=" + urllib_parse.quote(signature, safe='~') def generate_headers(self): return {} @@ -79,21 +121,18 @@ class OAuth(Auth): # %20 rather than '+' when constructing an OAuth signature (and therefore # also in the request itself.) # So here is a specialized version which does exactly that. +# In Python2, since there is no safe option for urlencode, we force it by hand def urlencode_noplus(query): - if hasattr(query,"items"): - # mapping objects - query = list(query.items()) - - encoded_bits = [] - for n, v in query: - # and do unicode here while we are at it... - if isinstance(n, str): - n = n.encode('utf-8') - else: - n = str(n) - if isinstance(v, str): - v = v.encode('utf-8') - else: - v = str(v) - encoded_bits.append("%s=%s" % (urllib_parse.quote(n, ""), urllib_parse.quote(v, ""))) - return "&".join(encoded_bits) + if not PY3: + new_query = [] + TILDE = '____TILDE-PYTHON-TWITTER____' + for k,v in query: + if type(k) is unicode: k = k.encode('utf-8') + k = str(k).replace("~", TILDE) + if type(v) is unicode: v = v.encode('utf-8') + v = str(v).replace("~", TILDE) + new_query.append((k, v)) + query = new_query + return urlencode(query).replace(TILDE, "~").replace("+", "%20") + + return urlencode(query, safe='~').replace("+", "%20")