You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.2 KiB
141 lines
4.2 KiB
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
oauthlib.utils
|
|
~~~~~~~~~~~~~~
|
|
|
|
This module contains utility methods used by various parts of the OAuth
|
|
spec.
|
|
"""
|
|
|
|
import string
|
|
import time
|
|
import urllib2
|
|
from random import getrandbits, choice
|
|
|
|
from oauthlib.common import quote, unquote
|
|
|
|
UNICODE_ASCII_CHARACTER_SET = (string.ascii_letters.decode('ascii') +
|
|
string.digits.decode('ascii'))
|
|
|
|
|
|
def filter_params(target):
|
|
"""Decorator which filters params to remove non-oauth_* parameters
|
|
|
|
Assumes the decorated method takes a params dict or list of tuples as its
|
|
first argument.
|
|
"""
|
|
def wrapper(params, *args, **kwargs):
|
|
params = filter_oauth_params(params)
|
|
return target(params, *args, **kwargs)
|
|
|
|
wrapper.__doc__ = target.__doc__
|
|
return wrapper
|
|
|
|
|
|
def filter_oauth_params(params):
|
|
"""Removes all non oauth parameters from a dict or a list of params."""
|
|
is_oauth = lambda kv: kv[0].startswith(u"oauth_")
|
|
if isinstance(params, dict):
|
|
return filter(is_oauth, params.items())
|
|
else:
|
|
return filter(is_oauth, params)
|
|
|
|
|
|
def generate_timestamp():
|
|
"""Get seconds since epoch (UTC).
|
|
|
|
Per `section 3.3`_ of the spec.
|
|
|
|
.. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3
|
|
"""
|
|
return unicode(int(time.time()))
|
|
|
|
|
|
def generate_nonce():
|
|
"""Generate pseudorandom nonce that is unlikely to repeat.
|
|
|
|
Per `section 3.3`_ of the spec.
|
|
|
|
A random 64-bit number is appended to the epoch timestamp for both
|
|
randomness and to decrease the likelihood of collisions.
|
|
|
|
.. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3
|
|
"""
|
|
return unicode(getrandbits(64)) + generate_timestamp()
|
|
|
|
|
|
def generate_token(length=20, chars=UNICODE_ASCII_CHARACTER_SET):
|
|
"""Generates a generic OAuth token
|
|
|
|
According to `section 2`_ of the spec, the method of token
|
|
construction is undefined. This implementation is simply a random selection
|
|
of `length` choices from `chars`.
|
|
|
|
Credit to Ignacio Vazquez-Abrams for his excellent `Stackoverflow answer`_
|
|
|
|
.. _`Stackoverflow answer` : http://stackoverflow.com/questions/2257441/
|
|
python-random-string-generation-with-upper-case-letters-and-digits
|
|
|
|
"""
|
|
return u''.join(choice(chars) for x in range(length))
|
|
|
|
|
|
def escape(u):
|
|
"""Escape a unicode string in an OAuth-compatible fashion.
|
|
|
|
Per `section 3.6`_ of the spec.
|
|
|
|
.. _`section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6
|
|
|
|
"""
|
|
if not isinstance(u, unicode):
|
|
raise ValueError('Only unicode objects are escapable.')
|
|
# Letters, digits, and the characters '_.-' are already treated as safe
|
|
# by urllib.quote(). We need to add '~' to fully support rfc5849.
|
|
return quote(u, safe='~')
|
|
|
|
|
|
def unescape(u):
|
|
if not isinstance(u, unicode):
|
|
raise ValueError('Only unicode objects are unescapable.')
|
|
return unquote(u)
|
|
|
|
|
|
def urlencode(query):
|
|
"""Encode a sequence of two-element tuples or dictionary into a URL query string.
|
|
|
|
Operates using an OAuth-safe escape() method, in contrast to urllib.urlencode.
|
|
"""
|
|
# Convert dictionaries to list of tuples
|
|
if isinstance(query, dict):
|
|
query = query.items()
|
|
return u"&".join([u'='.join([escape(k), escape(v)]) for k, v in query])
|
|
|
|
|
|
def parse_keqv_list(l):
|
|
"""A unicode-safe version of urllib2.parse_keqv_list"""
|
|
encoded_list = [u.encode('utf-8') for u in l]
|
|
encoded_parsed = urllib2.parse_keqv_list(encoded_list)
|
|
return dict((k.decode('utf-8'),
|
|
v.decode('utf-8')) for k,v in encoded_parsed.items())
|
|
|
|
|
|
def parse_http_list(u):
|
|
"""A unicode-safe version of urllib2.parse_http_list"""
|
|
encoded_str = u.encode('utf-8')
|
|
encoded_list = urllib2.parse_http_list(encoded_str)
|
|
return [s.decode('utf-8') for s in encoded_list]
|
|
|
|
|
|
def parse_authorization_header(authorization_header):
|
|
"""Parse an OAuth authorization header into a list of 2-tuples"""
|
|
auth_scheme = u'OAuth '
|
|
if authorization_header.startswith(auth_scheme):
|
|
authorization_header = authorization_header.replace(auth_scheme, u'', 1)
|
|
items = parse_http_list(authorization_header)
|
|
try:
|
|
return parse_keqv_list(items).items()
|
|
except ValueError:
|
|
raise ValueError('Malformed authorization header')
|
|
|
|
|