145 lines
4.8 KiB
Python
145 lines
4.8 KiB
Python
"""
|
|
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 import *
|
|
|
|
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 random import getrandbits
|
|
from time import time
|
|
|
|
from .util import PY_3_OR_HIGHER
|
|
|
|
try:
|
|
import urllib.parse as urllib_parse
|
|
from urllib.parse import urlencode
|
|
except ImportError:
|
|
import urllib2 as urllib_parse
|
|
from urllib import urlencode
|
|
|
|
import hashlib
|
|
import hmac
|
|
import base64
|
|
|
|
from .auth import Auth, MissingCredentialsError
|
|
|
|
|
|
def write_token_file(filename, oauth_token, oauth_token_secret):
|
|
"""
|
|
Write a token file to hold the oauth token and oauth token secret.
|
|
"""
|
|
oauth_file = open(filename, 'w')
|
|
print(oauth_token, file=oauth_file)
|
|
print(oauth_token_secret, file=oauth_file)
|
|
oauth_file.close()
|
|
|
|
def read_token_file(filename):
|
|
"""
|
|
Read a token file and return the oauth token and oauth token secret.
|
|
"""
|
|
f = open(filename)
|
|
return f.readline().strip(), f.readline().strip()
|
|
|
|
|
|
class OAuth(Auth):
|
|
"""
|
|
An OAuth authenticator.
|
|
"""
|
|
def __init__(self, token, token_secret, consumer_key, consumer_secret):
|
|
"""
|
|
Create the authenticator. If you are in the initial stages of
|
|
the OAuth dance and don't yet have a token or token_secret,
|
|
pass empty strings for these params.
|
|
"""
|
|
self.token = token
|
|
self.token_secret = token_secret
|
|
self.consumer_key = consumer_key
|
|
self.consumer_secret = consumer_secret
|
|
|
|
if token_secret is None or consumer_secret is None:
|
|
raise MissingCredentialsError(
|
|
'You must supply strings for token_secret and consumer_secret, not None.')
|
|
|
|
def encode_params(self, base_url, method, params):
|
|
params = params.copy()
|
|
|
|
if self.token:
|
|
params['oauth_token'] = self.token
|
|
|
|
params['oauth_consumer_key'] = self.consumer_key
|
|
params['oauth_signature_method'] = 'HMAC-SHA1'
|
|
params['oauth_version'] = '1.0'
|
|
params['oauth_timestamp'] = str(int(time()))
|
|
params['oauth_nonce'] = str(getrandbits(64))
|
|
|
|
enc_params = urlencode_noplus(sorted(params.items()))
|
|
|
|
key = self.consumer_secret + "&" + urllib_parse.quote(self.token_secret, safe='~')
|
|
|
|
message = '&'.join(
|
|
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, safe='~')
|
|
|
|
def generate_headers(self):
|
|
return {}
|
|
|
|
# apparently contrary to the HTTP RFCs, spaces in arguments must be encoded as
|
|
# %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 not PY_3_OR_HIGHER:
|
|
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")
|