Merge upstream 1.0a patch into oauth module.
authorJosh Roesslein <jroesslein@gmail.com>
Thu, 13 Aug 2009 04:06:52 +0000 (23:06 -0500)
committerJosh Roesslein <jroesslein@gmail.com>
Thu, 13 Aug 2009 04:06:52 +0000 (23:06 -0500)
tweepy/auth.py
tweepy/oauth.py

index 49826ee248a9dd09343826b867df716384d2e573..59d502dffd84db065a56b2c02f477967948b1afb 100644 (file)
@@ -45,9 +45,8 @@ class OAuthHandler(AuthHandler):
 
   def _get_request_token(self):
     try:
-      request = oauth.OAuthRequest.from_consumer_and_token(self._consumer, http_url = self.REQUEST_TOKEN_URL)
-      if self.callback:
-        request.set_parameter('oauth_callback', self.callback)
+      request = oauth.OAuthRequest.from_consumer_and_token(self._consumer,
+          http_url = self.REQUEST_TOKEN_URL, callback=self.callback)
       request.sign_request(self._sigmethod, self._consumer, None)
       resp = urlopen(Request(self.REQUEST_TOKEN_URL, headers=request.to_header()))
       return oauth.OAuthToken.from_string(resp.read())
@@ -77,8 +76,7 @@ class OAuthHandler(AuthHandler):
     try:
       # build request
       request = oauth.OAuthRequest.from_consumer_and_token(self._consumer,
-          token=self.request_token, http_url=self.ACCESS_TOKEN_URL)
-      request.set_parameter('oauth_verifier', str(verifier))
+          token=self.request_token, http_url=self.ACCESS_TOKEN_URL, verifier=str(verifier))
       request.sign_request(self._sigmethod, self._consumer, self.request_token)
 
       # send request
index 9a14d5fb561cbda449f0553d767fcd97757a22fe..3a42e20f91ffeb6b4fd7eb60cc4cf20198e108e6 100644 (file)
@@ -64,6 +64,10 @@ def generate_nonce(length=8):
     """Generate pseudorandom number."""
     return ''.join([str(random.randint(0, 9)) for i in range(length)])
 
+def generate_verifier(length=8):
+    """Generate pseudorandom number."""
+    return ''.join([str(random.randint(0, 9)) for i in range(length)])
+
 
 class OAuthConsumer(object):
     """Consumer of OAuth authentication.
@@ -79,7 +83,7 @@ class OAuthConsumer(object):
         self.key = key
         self.secret = secret
 
-   
+
 class OAuthToken(object):
     """OAuthToken is a data type that represents an End User via either an access
     or request token.
@@ -90,14 +94,45 @@ class OAuthToken(object):
     """
     key = None
     secret = None
+    callback = None
+    callback_confirmed = None
+    verifier = None
 
     def __init__(self, key, secret):
         self.key = key
         self.secret = secret
 
+    def set_callback(self, callback):
+        self.callback = callback
+        self.callback_confirmed = 'true'
+
+    def set_verifier(self, verifier=None):
+        if verifier is not None:
+            self.verifier = verifier
+        else:
+            self.verifier = generate_verifier()
+
+    def get_callback_url(self):
+        if self.callback and self.verifier:
+            # Append the oauth_verifier.
+            parts = urlparse.urlparse(self.callback)
+            scheme, netloc, path, params, query, fragment = parts[:6]
+            if query:
+                query = '%s&oauth_verifier=%s' % (query, self.verifier)
+            else:
+                query = 'oauth_verifier=%s' % self.verifier
+            return urlparse.urlunparse((scheme, netloc, path, params,
+                query, fragment))
+        return self.callback
+
     def to_string(self):
-        return urllib.urlencode({'oauth_token': self.key,
-            'oauth_token_secret': self.secret})
+        data = {
+            'oauth_token': self.key,
+            'oauth_token_secret': self.secret,
+        }
+        if self.callback_confirmed is not None:
+            data['oauth_callback_confirmed'] = self.callback_confirmed
+        return urllib.urlencode(data)
  
     def from_string(s):
         """ Returns a token from something like:
@@ -106,7 +141,12 @@ class OAuthToken(object):
         params = cgi.parse_qs(s, keep_blank_values=False)
         key = params['oauth_token'][0]
         secret = params['oauth_token_secret'][0]
-        return OAuthToken(key, secret)
+        token = OAuthToken(key, secret)
+        try:
+            token.callback_confirmed = params['oauth_callback_confirmed'][0]
+        except KeyError:
+            pass # 1.0, no callback confirmed.
+        return token
     from_string = staticmethod(from_string)
 
     def __str__(self):
@@ -124,6 +164,7 @@ class OAuthRequest(object):
         - oauth_timestamp 
         - oauth_nonce
         - oauth_version
+        - oauth_verifier
         ... any additional parameters, as defined by the Service Provider.
     """
     parameters = None # OAuth parameters.
@@ -258,7 +299,8 @@ class OAuthRequest(object):
     from_request = staticmethod(from_request)
 
     def from_consumer_and_token(oauth_consumer, token=None,
-            http_method=HTTP_METHOD, http_url=None, parameters=None):
+            callback=None, verifier=None, http_method=HTTP_METHOD,
+            http_url=None, parameters=None):
         if not parameters:
             parameters = {}
 
@@ -274,6 +316,12 @@ class OAuthRequest(object):
 
         if token:
             parameters['oauth_token'] = token.key
+            parameters['oauth_callback'] = token.callback
+            # 1.0a support for verifier.
+            parameters['oauth_verifier'] = verifier
+        elif callback:
+            # 1.0a support for callback in the request token request.
+            parameters['oauth_callback'] = callback
 
         return OAuthRequest(http_method, http_url, parameters)
     from_consumer_and_token = staticmethod(from_consumer_and_token)
@@ -348,9 +396,13 @@ class OAuthServer(object):
             # No token required for the initial token request.
             version = self._get_version(oauth_request)
             consumer = self._get_consumer(oauth_request)
+            try:
+                callback = self.get_callback(oauth_request)
+            except OAuthError:
+                callback = None # 1.0, no callback specified.
             self._check_signature(oauth_request, consumer, None)
             # Fetch a new token.
-            token = self.data_store.fetch_request_token(consumer)
+            token = self.data_store.fetch_request_token(consumer, callback)
         return token
 
     def fetch_access_token(self, oauth_request):
@@ -359,10 +411,11 @@ class OAuthServer(object):
         """
         version = self._get_version(oauth_request)
         consumer = self._get_consumer(oauth_request)
+        verifier = self._get_verifier(oauth_request)
         # Get the request token.
         token = self._get_token(oauth_request, 'request')
         self._check_signature(oauth_request, consumer, token)
-        new_token = self.data_store.fetch_access_token(consumer, token)
+        new_token = self.data_store.fetch_access_token(consumer, token, verifier)
         return new_token
 
     def verify_request(self, oauth_request):
@@ -429,6 +482,9 @@ class OAuthServer(object):
         if not token:
             raise OAuthError('Invalid %s token: %s' % (token_type, token_field))
         return token
+    
+    def _get_verifier(self, oauth_request):
+        return oauth_request.get_parameter('oauth_verifier')
 
     def _check_signature(self, oauth_request, consumer, token):
         timestamp, nonce = oauth_request._get_timestamp_nonce()
@@ -509,11 +565,11 @@ class OAuthDataStore(object):
         """-> OAuthToken."""
         raise NotImplementedError
 
-    def fetch_request_token(self, oauth_consumer):
+    def fetch_request_token(self, oauth_consumer, oauth_callback):
         """-> OAuthToken."""
         raise NotImplementedError
 
-    def fetch_access_token(self, oauth_consumer, oauth_token):
+    def fetch_access_token(self, oauth_consumer, oauth_token, oauth_verifier):
         """-> OAuthToken."""
         raise NotImplementedError