Commits

Jesper Nøhr committed 0d50041

changing a few keys/urls

  • Participants
  • Parent commits 1f4273a

Comments (0)

Files changed (6)

File bitbucket_oauth/apps/main/helpers.py

         
     return resp
 
-def get_unauthorised_request_token():
+def get_unauthorised_request_token(request):
+    protocol = request.is_secure() and 'https://' or 'http://'
+    host = protocol+request.get_host()
+    callback = host+reverse('oauth-return', args=[])
+
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(
-        consumer, http_url=settings.REQUEST_TOKEN_URL)
+        consumer, http_url=settings.REQUEST_TOKEN_URL, callback=callback)
 
     oauth_request.sign_request(signature_method, consumer, None)
 
     return token
 
 def get_authorisation_url(token, request):
-    protocol = request.is_secure() and 'https://' or 'http://'
-    host = protocol+request.get_host()
-
-    params = { 'oauth_callback': host+reverse('oauth-return', args=[])}
-
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(
-        consumer, token=token, http_url=settings.AUTHORIZATION_URL, parameters=params)
+        consumer, token=token, http_url=settings.AUTHORIZATION_URL)
 
     oauth_request.sign_request(signature_method, consumer, token)
 
     return oauth_request.to_url()
 
-def exchange_request_token_for_access_token(request_token):
+def exchange_request_token_for_access_token(request_token, verifier=None):
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(
-        consumer, token=request_token, http_url=settings.ACCESS_TOKEN_URL)
+        consumer, token=request_token, http_url=settings.ACCESS_TOKEN_URL,
+        verifier=verifier)
+        
+    print "trying to exchange with verifier", verifier
 
     oauth_request.sign_request(signature_method, consumer, request_token)
     resp = get_response(oauth_request, connection)

File bitbucket_oauth/apps/main/views.py

         RequestContext(request))
 
 def signin(request):
-    token = helpers.get_unauthorised_request_token()
+    token = helpers.get_unauthorised_request_token(request)
     auth_url = helpers.get_authorisation_url(token, request)
 
     if request.COOKIES.has_key('access_token'):
         return HttpResponse("No un-authed token cookie")
 
     token = oauth.OAuthToken.from_string(unauthed_token)   
+    verifier = request.GET.get('oauth_verifier', 'oob')
 
     if token.key != request.GET.get('oauth_token', 'no-token'):
         return HttpResponse("Something went wrong! Tokens do not match.")
 
-    access_token = helpers.exchange_request_token_for_access_token(token)
+    access_token = helpers.exchange_request_token_for_access_token(token, verifier)
 
     response = HttpResponseRedirect(reverse('oauth-authorized'))
     response.set_cookie('access_token', access_token.to_string())

File bitbucket_oauth/lib/bbapi.py

-import urllib, httplib2, yaml, urlparse, oauth
+import urllib, httplib2, yaml, urlparse, oauth, copy
 from django.utils import simplejson
 
 class APIError(Exception):
     status = property(get_status)
 
     def __unicode__(self):
-        return "%s %s" % (str(self.status), self.response.splitlines()[0])
+        message = ''
+        
+        if isinstance(self.response, basestring):
+            if self.response.startswith("Piston"):
+                message += self.response
+            else:
+                message += self.response.splitlines()[0]
+
+        return "%s %s" % (str(self.status), message)
 
 class BitbucketAPI(object):
     FORMAT = 'json' # xml, json, yaml
     ENDPOINT = 'http://api.bitbucket.org/1.0/'
 
-    def __init__(self, key, secret, endpoint=ENDPOINT, format=FORMAT):
+    def __init__(self, key='DrugDaimsIk7', secret='yinCobvokyijyaf', endpoint=ENDPOINT, format=FORMAT):
         self.http = httplib2.Http()
         self._endpoint = endpoint
         self._format = format
         
     def request(self, url, method='GET', body={ }, headers={ }):
         token = self.get_token()
+        local_body = copy.copy(body)
 
         # Lets keep 'format' in body while we sign the request. We'll pop after.
-        body.update({ 'format': self.format })
+        local_body.update({ 'format': self.format })
         
         if token:
             oauth_req = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=token, 
-                                http_method=method, http_url=self.url(url), parameters=body)
+                                http_method=method, http_url=self.url(url), parameters=local_body)
 
             oauth_req.sign_request(self.hmac_sig, self.consumer, token)
         
             headers.update(oauth_req.to_header())
         
-        # Get rid of 'body', we don't need it any longer.
-        body.pop('format')
+        # Get rid of 'body', we don't need it any more.
+        local_body.pop('format')
         
         url = self.url(url)
-        body = urllib.urlencode(body)
+        local_body = urllib.urlencode(local_body)
             
-        return self.http.request(url, method, body, headers)
+        return self.http.request(url, method, local_body, headers)
 
     # -- 
     
     def method_factory(req_type):
 
         def method(self, body={ }, headers={ }, **kwargs):
-            if kwargs and isinstance(body, dict):
-                body.update(kwargs)
+            local_body = copy.copy(body)
+
+            ignore_hateoas = kwargs.pop('ignore_hateoas', False)
+
+            if kwargs and isinstance(local_body, dict):
+                local_body.update(kwargs)
 
             url = self._endpoint
 
             if req_type == 'GET' and kwargs:
                 url += "&"+urllib.urlencode(kwargs)
 
-            r, resp = self.request(url, req_type, body, headers)
+            r, resp = self.request(url, req_type, local_body, headers)
             ctype = r.get('content-type', 'text/plain')
             cloc = r.get('content-location', None)
 
                     
             # Did the URI change?
             if int(r.get('status', 0)) == 200:
-                if isinstance(resp, dict):
+                if isinstance(resp, dict) and not ignore_hateoas:
                     new_endpoint = resp.get('resource_uri', None)
                     
                     if new_endpoint:
             
                 return resp
             else:
+                print resp
                 raise APIError(r, resp)
                         
         return method

File bitbucket_oauth/lib/oauth.py

+"""
+The MIT License
+
+Copyright (c) 2007 Leah Culver
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
 import cgi
 import urllib
 import time
 import random
 import urlparse
 import hmac
-import base64
+import binascii
+
 
 VERSION = '1.0' # Hi Blaine!
 HTTP_METHOD = 'GET'
 SIGNATURE_METHOD = 'PLAINTEXT'
 
-# Generic exception class
+
 class OAuthError(RuntimeError):
+    """Generic exception class."""
     def __init__(self, message='OAuth error occured.'):
         self.message = message
 
-# optional WWW-Authenticate header (401 error)
 def build_authenticate_header(realm=''):
+    """Optional WWW-Authenticate header (401 error)"""
     return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
 
-# url escape
 def escape(s):
-    # escape '/' too
+    """Escape a URL including any /."""
     return urllib.quote(s, safe='~')
 
-# util function: current timestamp
-# seconds since epoch (UTC)
+def _utf8_str(s):
+    """Convert unicode to utf-8."""
+    if isinstance(s, unicode):
+        return s.encode("utf-8")
+    else:
+        return str(s)
+
 def generate_timestamp():
+    """Get seconds since epoch (UTC)."""
     return int(time.time())
 
-# util function: nonce
-# pseudorandom number
 def generate_nonce(length=8):
-    return ''.join(str(random.randint(0, 9)) for i in range(length))
+    """Generate pseudorandom number."""
+    return ''.join([str(random.randint(0, 9)) for i in range(length)])
 
-# OAuthConsumer is a data type that represents the identity of the Consumer
-# via its shared secret with the Service Provider.
+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.
+
+    OAuthConsumer is a data type that represents the identity of the Consumer
+    via its shared secret with the Service Provider.
+
+    """
     key = None
     secret = None
 
         self.key = key
         self.secret = secret
 
-# OAuthToken is a data type that represents an End User via either an access
-# or request token.     
+
 class OAuthToken(object):
-    # access tokens and request tokens
+    """OAuthToken is a data type that represents an End User via either an access
+    or request token.
+    
+    key -- the token
+    secret -- the token secret
+
+    """
     key = None
     secret = None
+    callback = None
+    callback_confirmed = None
+    verifier = None
 
-    '''
-    key = the token
-    secret = the token secret
-    '''
     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})
-
-    # return a token from something like:
-    # oauth_token_secret=digg&oauth_token=digg
-    @staticmethod   
+        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:
+        oauth_token_secret=xxx&oauth_token=xxx
+        """
         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):
         return self.to_string()
 
-# OAuthRequest represents the request and can be serialized
+
 class OAuthRequest(object):
-    '''
+    """OAuthRequest represents the request and can be serialized.
+
     OAuth parameters:
         - oauth_consumer_key 
         - oauth_token
         - oauth_timestamp 
         - oauth_nonce
         - oauth_version
+        - oauth_verifier
         ... any additional parameters, as defined by the Service Provider.
-    '''
-    parameters = None # oauth parameters
+    """
+    parameters = None # OAuth parameters.
     http_method = HTTP_METHOD
     http_url = None
     version = VERSION
             raise OAuthError('Parameter not found: %s' % parameter)
 
     def _get_timestamp_nonce(self):
-        return self.get_parameter('oauth_timestamp'), self.get_parameter('oauth_nonce')
+        return self.get_parameter('oauth_timestamp'), self.get_parameter(
+            'oauth_nonce')
 
-    # get any non-oauth parameters
     def get_nonoauth_parameters(self):
+        """Get any non-OAuth parameters."""
         parameters = {}
         for k, v in self.parameters.iteritems():
-            # ignore oauth parameters
+            # Ignore oauth parameters.
             if k.find('oauth_') < 0:
                 parameters[k] = v
         return parameters
 
-    # serialize as a header for an HTTPAuth request
     def to_header(self, realm=''):
+        """Serialize as a header for an HTTPAuth request."""
         auth_header = 'OAuth realm="%s"' % realm
-        # add the oauth parameters
+        # Add the oauth parameters.
         if self.parameters:
             for k, v in self.parameters.iteritems():
-                auth_header += ', %s="%s"' % (k, escape(str(v)))
+                if k[:6] == 'oauth_':
+                    auth_header += ', %s="%s"' % (k, escape(str(v)))
         return {'Authorization': auth_header}
 
-    # serialize as post data for a POST request
     def to_postdata(self):
-        return '&'.join('%s=%s' % (escape(str(k)), escape(str(v))) for k, v in self.parameters.iteritems())
+        """Serialize as post data for a POST request."""
+        return '&'.join(['%s=%s' % (escape(str(k)), escape(str(v))) \
+            for k, v in self.parameters.iteritems()])
 
-    # serialize as a url for a GET request
     def to_url(self):
+        """Serialize as a URL for a GET request."""
         return '%s?%s' % (self.get_normalized_http_url(), self.to_postdata())
 
-    # return a string that consists of all the parameters that need to be signed
     def get_normalized_parameters(self):
+        """Return a string that contains the parameters that must be signed."""
         params = self.parameters
         try:
-            # exclude the signature if it exists
+            # Exclude the signature if it exists.
             del params['oauth_signature']
         except:
             pass
-        key_values = params.items()
-        # sort lexicographically, first after key, then after value
+        # Escape key values before sorting.
+        key_values = [(escape(_utf8_str(k)), escape(_utf8_str(v))) \
+            for k,v in params.items()]
+        # Sort lexicographically, first after key, then after value.
         key_values.sort()
-        # combine key value pairs in string and escape
-        return '&'.join('%s=%s' % (escape(str(k)), escape(str(v))) for k, v in key_values)
+        # Combine key value pairs into a string.
+        return '&'.join(['%s=%s' % (k, v) for k, v in key_values])
 
-    # just uppercases the http method
     def get_normalized_http_method(self):
+        """Uppercases the http method."""
         return self.http_method.upper()
 
-    # parses the url and rebuilds it to be scheme://host/path
     def get_normalized_http_url(self):
+        """Parses the URL and rebuilds it to be scheme://host/path."""
         parts = urlparse.urlparse(self.http_url)
-        url_string = '%s://%s%s' % (parts[0], parts[1], parts[2]) # scheme, netloc, path
-        return url_string
-        
-    # set the signature parameter to the result of build_signature
+        scheme, netloc, path = parts[:3]
+        # Exclude default port numbers.
+        if scheme == 'http' and netloc[-3:] == ':80':
+            netloc = netloc[:-3]
+        elif scheme == 'https' and netloc[-4:] == ':443':
+            netloc = netloc[:-4]
+        return '%s://%s%s' % (scheme, netloc, path)
+
     def sign_request(self, signature_method, consumer, token):
-        # set the signature method
-        self.set_parameter('oauth_signature_method', signature_method.get_name())
-        # set the signature
-        self.set_parameter('oauth_signature', self.build_signature(signature_method, consumer, token))
+        """Set the signature parameter to the result of build_signature."""
+        # Set the signature method.
+        self.set_parameter('oauth_signature_method',
+            signature_method.get_name())
+        # Set the signature.
+        self.set_parameter('oauth_signature',
+            self.build_signature(signature_method, consumer, token))
 
     def build_signature(self, signature_method, consumer, token):
-        # call the build signature method within the signature method
+        """Calls the build signature method within the signature method."""
         return signature_method.build_signature(self, consumer, token)
 
-    @staticmethod
-    def from_request(http_method, http_url, headers=None, parameters=None, query_string=None):
-        # combine multiple parameter sources
+    def from_request(http_method, http_url, headers=None, parameters=None,
+            query_string=None):
+        """Combines multiple parameter sources."""
         if parameters is None:
             parameters = {}
 
-        # headers
-        if headers and 'HTTP_AUTHORIZATION' in headers:
-            auth_header = headers['HTTP_AUTHORIZATION']
-            # check that the authorization header is OAuth
-            if auth_header.index('OAuth') > -1:
+        # Headers
+        if headers and 'Authorization' in headers:
+            auth_header = headers['Authorization']
+            # Check that the authorization header is OAuth.
+            if auth_header[:6] == 'OAuth ':
+                auth_header = auth_header[6:]
                 try:
-                    # get the parameters from the header
+                    # Get the parameters from the header.
                     header_params = OAuthRequest._split_header(auth_header)
                     parameters.update(header_params)
                 except:
-                    raise OAuthError('Unable to parse OAuth parameters from Authorization header.')
+                    raise OAuthError('Unable to parse OAuth parameters from '
+                        'Authorization header.')
 
-        # GET or POST query string
+        # GET or POST query string.
         if query_string:
             query_params = OAuthRequest._split_url_string(query_string)
             parameters.update(query_params)
 
-        # URL parameters
+        # URL parameters.
         param_str = urlparse.urlparse(http_url)[4] # query
         url_params = OAuthRequest._split_url_string(param_str)
         parameters.update(url_params)
             return OAuthRequest(http_method, http_url, parameters)
 
         return None
+    from_request = staticmethod(from_request)
 
-    @staticmethod
-    def from_consumer_and_token(oauth_consumer, token=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
+    def from_consumer_and_token(oauth_consumer, token=None,
+            callback=None, verifier=None, http_method=HTTP_METHOD,
+            http_url=None, parameters=None):
         if not parameters:
             parameters = {}
 
 
         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)
 
-    @staticmethod
-    def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
+    def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD,
+            http_url=None, parameters=None):
         if not parameters:
             parameters = {}
 
         parameters['oauth_token'] = token.key
 
         if callback:
-            parameters['oauth_callback'] = escape(callback)
+            parameters['oauth_callback'] = callback
 
         return OAuthRequest(http_method, http_url, parameters)
+    from_token_and_callback = staticmethod(from_token_and_callback)
 
-    # util function: turn Authorization: header into parameters, has to do some unescaping
-    @staticmethod
     def _split_header(header):
+        """Turn Authorization: header into parameters."""
         params = {}
         parts = header.split(',')
         for param in parts:
-            # ignore realm parameter
-            if param.find('OAuth realm') > -1:
+            # Ignore realm parameter.
+            if param.find('realm') > -1:
                 continue
-            # remove whitespace
+            # Remove whitespace.
             param = param.strip()
-            # split key-value
+            # Split key-value.
             param_parts = param.split('=', 1)
-            # remove quotes and unescape the value
+            # Remove quotes and unescape the value.
             params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
         return params
-    
-    # util function: turn url string into parameters, has to do some unescaping
-    @staticmethod
+    _split_header = staticmethod(_split_header)
+
     def _split_url_string(param_str):
+        """Turn URL string into parameters."""
         parameters = cgi.parse_qs(param_str, keep_blank_values=False)
         for k, v in parameters.iteritems():
             parameters[k] = urllib.unquote(v[0])
         return parameters
+    _split_url_string = staticmethod(_split_url_string)
 
-# OAuthServer is a worker to check a requests validity against a data store
 class OAuthServer(object):
-    timestamp_threshold = 300 # in seconds, five minutes
+    """A worker to check the validity of a request against a data store."""
+    timestamp_threshold = 300 # In seconds, five minutes.
     version = VERSION
     signature_methods = None
     data_store = None
         self.data_store = data_store
         self.signature_methods = signature_methods or {}
 
-    def set_data_store(self, oauth_data_store):
+    def set_data_store(self, data_store):
         self.data_store = data_store
 
     def get_data_store(self):
         self.signature_methods[signature_method.get_name()] = signature_method
         return self.signature_methods
 
-    # process a request_token request
-    # returns the request token on success
     def fetch_request_token(self, oauth_request):
+        """Processes a request_token request and returns the
+        request token on success.
+        """
         try:
-            # get the request token for authorization
+            # Get the request token for authorization.
             token = self._get_token(oauth_request, 'request')
         except OAuthError:
-            # no token required for the initial token request
+            # 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)
+            # Fetch a new token.
+            token = self.data_store.fetch_request_token(consumer, callback)
         return token
 
-    # process an access_token request
-    # returns the access token on success
     def fetch_access_token(self, oauth_request):
+        """Processes an access_token request and returns the
+        access token on success.
+        """
         version = self._get_version(oauth_request)
         consumer = self._get_consumer(oauth_request)
-        # get the request token
+        verifier = self._get_verifier(oauth_request)
+        # Get the request token.
         token = self._get_token(oauth_request, 'request')
+        print "about to check signature, we have token", token, "consumer", consumer, "and verifier", verifier
         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
 
-    # verify an api call, checks all the parameters
     def verify_request(self, oauth_request):
+        """Verifies an api call and checks all the parameters."""
         # -> consumer and token
         version = self._get_version(oauth_request)
         consumer = self._get_consumer(oauth_request)
-        # get the access token
+        # Get the access token.
         token = self._get_token(oauth_request, 'access')
         self._check_signature(oauth_request, consumer, token)
         parameters = oauth_request.get_nonoauth_parameters()
         return consumer, token, parameters
 
-    # authorize a request token
     def authorize_token(self, token, user):
+        """Authorize a request token."""
         return self.data_store.authorize_request_token(token, user)
-    
-    # get the callback url
+
     def get_callback(self, oauth_request):
+        """Get the callback URL."""
         return oauth_request.get_parameter('oauth_callback')
-
-    # optional support for the authenticate header   
+ 
     def build_authenticate_header(self, realm=''):
+        """Optional support for the authenticate header."""
         return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
 
-    # verify the correct version request for this server
     def _get_version(self, oauth_request):
+        """Verify the correct version request for this server."""
         try:
             version = oauth_request.get_parameter('oauth_version')
         except:
             raise OAuthError('OAuth version %s not supported.' % str(version))
         return version
 
-    # figure out the signature with some defaults
     def _get_signature_method(self, oauth_request):
+        """Figure out the signature with some defaults."""
         try:
-            signature_method = oauth_request.get_parameter('oauth_signature_method')
+            signature_method = oauth_request.get_parameter(
+                'oauth_signature_method')
         except:
             signature_method = SIGNATURE_METHOD
         try:
-            # get the signature method object
+            # Get the signature method object.
             signature_method = self.signature_methods[signature_method]
         except:
             signature_method_names = ', '.join(self.signature_methods.keys())
-            raise OAuthError('Signature method %s not supported try one of the following: %s' % (signature_method, signature_method_names))
+            raise OAuthError('Signature method %s not supported try one of the '
+                'following: %s' % (signature_method, signature_method_names))
 
         return signature_method
 
     def _get_consumer(self, oauth_request):
         consumer_key = oauth_request.get_parameter('oauth_consumer_key')
-        if not consumer_key:
-            raise OAuthError('Invalid consumer key.')
         consumer = self.data_store.lookup_consumer(consumer_key)
         if not consumer:
             raise OAuthError('Invalid consumer.')
         return consumer
 
-    # try to find the token for the provided request token key
     def _get_token(self, oauth_request, token_type='access'):
+        """Try to find the token for the provided request token key."""
         token_field = oauth_request.get_parameter('oauth_token')
         token = self.data_store.lookup_token(token_type, token_field)
         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()
             signature = oauth_request.get_parameter('oauth_signature')
         except:
             raise OAuthError('Missing signature.')
-        # validate the signature
-        valid_sig = signature_method.check_signature(oauth_request, consumer, token, signature)
+        # Validate the signature.
+        valid_sig = signature_method.check_signature(oauth_request, consumer,
+            token, signature)
         if not valid_sig:
-            key, base = signature_method.build_signature_base_string(oauth_request, consumer, token)
-            raise OAuthError('Invalid signature. Expected signature base string: %s' % base)
+            key, base = signature_method.build_signature_base_string(
+                oauth_request, consumer, token)
+            raise OAuthError('Invalid signature. Expected signature base '
+                'string: %s' % base)
         built = signature_method.build_signature(oauth_request, consumer, token)
 
     def _check_timestamp(self, timestamp):
-        # verify that timestamp is recentish
+        """Verify that timestamp is recentish."""
         timestamp = int(timestamp)
         now = int(time.time())
         lapsed = now - timestamp
         if lapsed > self.timestamp_threshold:
-            raise OAuthError('Expired timestamp: given %d and now %s has a greater difference than threshold %d' % (timestamp, now, self.timestamp_threshold))
+            raise OAuthError('Expired timestamp: given %d and now %s has a '
+                'greater difference than threshold %d' %
+                (timestamp, now, self.timestamp_threshold))
 
     def _check_nonce(self, consumer, token, nonce):
-        # verify that the nonce is uniqueish
+        """Verify that the nonce is uniqueish."""
         nonce = self.data_store.lookup_nonce(consumer, token, nonce)
         if nonce:
             raise OAuthError('Nonce already used: %s' % str(nonce))
 
-# OAuthClient is a worker to attempt to execute a request
+
 class OAuthClient(object):
+    """OAuthClient is a worker to attempt to execute a request."""
     consumer = None
     token = None
 
         return self.token
 
     def fetch_request_token(self, oauth_request):
-        # -> OAuthToken
+        """-> OAuthToken."""
         raise NotImplementedError
 
     def fetch_access_token(self, oauth_request):
-        # -> OAuthToken
+        """-> OAuthToken."""
         raise NotImplementedError
 
     def access_resource(self, oauth_request):
-        # -> some protected resource
+        """-> Some protected resource."""
         raise NotImplementedError
 
-# OAuthDataStore is a database abstraction used to lookup consumers and tokens
+
 class OAuthDataStore(object):
+    """A database abstraction used to lookup consumers and tokens."""
 
     def lookup_consumer(self, key):
-        # -> OAuthConsumer
+        """-> OAuthConsumer."""
         raise NotImplementedError
 
     def lookup_token(self, oauth_consumer, token_type, token_token):
-        # -> OAuthToken
+        """-> OAuthToken."""
         raise NotImplementedError
 
-    def lookup_nonce(self, oauth_consumer, oauth_token, nonce, timestamp):
-        # -> OAuthToken
+    def lookup_nonce(self, oauth_consumer, oauth_token, nonce):
+        """-> OAuthToken."""
         raise NotImplementedError
 
-    def fetch_request_token(self, oauth_consumer):
-        # -> OAuthToken
+    def fetch_request_token(self, oauth_consumer, oauth_callback):
+        """-> OAuthToken."""
         raise NotImplementedError
 
-    def fetch_access_token(self, oauth_consumer, oauth_token):
-        # -> OAuthToken
+    def fetch_access_token(self, oauth_consumer, oauth_token, oauth_verifier):
+        """-> OAuthToken."""
         raise NotImplementedError
 
     def authorize_request_token(self, oauth_token, user):
-        # -> OAuthToken
+        """-> OAuthToken."""
         raise NotImplementedError
 
-# OAuthSignatureMethod is a strategy class that implements a signature method
+
 class OAuthSignatureMethod(object):
+    """A strategy class that implements a signature method."""
     def get_name(self):
-        # -> str
+        """-> str."""
         raise NotImplementedError
 
     def build_signature_base_string(self, oauth_request, oauth_consumer, oauth_token):
-        # -> str key, str raw
+        """-> str key, str raw."""
         raise NotImplementedError
 
     def build_signature(self, oauth_request, oauth_consumer, oauth_token):
-        # -> str
+        """-> str."""
         raise NotImplementedError
 
     def check_signature(self, oauth_request, consumer, token, signature):
         built = self.build_signature(oauth_request, consumer, token)
         return built == signature
 
+
 class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
 
     def get_name(self):
         return key, raw
 
     def build_signature(self, oauth_request, consumer, token):
-        # build the base signature string
-        key, raw = self.build_signature_base_string(oauth_request, consumer, token)
+        """Builds the base signature string."""
+        key, raw = self.build_signature_base_string(oauth_request, consumer,
+            token)
 
-        # hmac object
+        # HMAC object.
         try:
             import hashlib # 2.5
             hashed = hmac.new(key, raw, hashlib.sha1)
         except:
-            import sha # deprecated
+            import sha # Deprecated
             hashed = hmac.new(key, raw, sha)
 
-        # calculate the digest base 64
-        return base64.b64encode(hashed.digest())
+        # Calculate the digest base 64.
+        return binascii.b2a_base64(hashed.digest())[:-1]
+
 
 class OAuthSignatureMethod_PLAINTEXT(OAuthSignatureMethod):
 
         return 'PLAINTEXT'
 
     def build_signature_base_string(self, oauth_request, consumer, token):
-        # concatenate the consumer key and secret
-        sig = escape(consumer.secret) + '&'
+        """Concatenates the consumer key and secret."""
+        sig = '%s&' % escape(consumer.secret)
         if token:
             sig = sig + escape(token.secret)
-        return sig
+        return sig, sig
 
     def build_signature(self, oauth_request, consumer, token):
-        return self.build_signature_base_string(oauth_request, consumer, token)
+        key, raw = self.build_signature_base_string(oauth_request, consumer,
+            token)
+        return key

File bitbucket_oauth/settings.py

     'bitbucket_oauth.apps.main',
 )
 
-API_SERVER = ('127.0.0.1', 8000)
+API_SERVER = ('api.bitbucket.org', 80)
 
-ENDPOINT = 'http://127.0.0.1:8000/api/1.0/'
+ENDPOINT = 'http://api.bitbucket.org/1.0/'
 
 REQUEST_TOKEN_URL = ENDPOINT+'oauth/request_token/'
 AUTHORIZATION_URL = ENDPOINT+'oauth/authenticate/'
 ACCESS_TOKEN_URL =  ENDPOINT+'oauth/access_token/'
 
-CONSUMER_KEY = 'DrugDaimsIk7'
-CONSUMER_SECRET = 'yinCobvokyijyaf'
+CONSUMER_KEY = 'PhretsavhiDesht9'
+CONSUMER_SECRET = 'mahoahaujThurmay'
 
+#CONSUMER_KEY = 'DrugDaimsIk7'
+#CONSUMER_SECRET = 'yinCobvokyijyaf'
+

File bitbucket_oauth/templates/repo.html

 		This repository is from {{ repo.created_on }}, and has a size of {{ repo.size|filesizeformat }}.
 	</p>
 
-	<h3>Last 5 changesets</h3>
+	<h3>Last 5 changesets ({{ changesets.count }} total)</h3>
 	
 	<ul>
-	{% for cset in changesets %}
+	{% for cset in changesets.changesets %}
 		<li>
 			r{{ cset.revision }}:{{ cset.node }}: {{ cset.message }} ({{ cset.timestamp }})
 		</li>
 	{% endfor %}
 	</ul>
 	
-	<h3>Last 5 events</h3>
+	<h3>Last 5 events ({{ events.count }} in total)</h3>
 	
 	<ul>
-		{% for event in events %}
+		{% for event in events.events %}
 			<li>{{ event.user.username }} {{ event.event }} {{ event.repository.slug }}{% if event.description %} ({{ event.description }}){% endif %}</li>
 		{% endfor %}
 	</ul>