From 8d5e92f64181d58d825a664e2b0be5854be1c756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Wed, 14 Jun 2017 16:11:18 +0200 Subject: [PATCH] resolve cyclic dependency between oauth and flickr --- gallery_dl/extractor/__init__.py | 2 +- gallery_dl/extractor/flickr.py | 3 +- .../extractor/{oauth.py => oauthhelper.py} | 55 +++---------------- gallery_dl/oauth.py | 54 ++++++++++++++++++ 4 files changed, 63 insertions(+), 51 deletions(-) rename gallery_dl/extractor/{oauth.py => oauthhelper.py} (75%) create mode 100644 gallery_dl/oauth.py diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 4a6c0c97..b42e5c47 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -73,7 +73,7 @@ modules = [ "imagehosts", "directlink", "recursive", - "oauth", + "oauthhelper", "test", ] diff --git a/gallery_dl/extractor/flickr.py b/gallery_dl/extractor/flickr.py index cc5f9301..fdc46c2c 100644 --- a/gallery_dl/extractor/flickr.py +++ b/gallery_dl/extractor/flickr.py @@ -9,8 +9,7 @@ """Extract images from https://www.flickr.com/""" from .common import Extractor, Message -from .. import text, util, exception -from . import oauth +from .. import text, util, oauth, exception import urllib.parse diff --git a/gallery_dl/extractor/oauth.py b/gallery_dl/extractor/oauthhelper.py similarity index 75% rename from gallery_dl/extractor/oauth.py rename to gallery_dl/extractor/oauthhelper.py index 0357722e..29eeb53a 100644 --- a/gallery_dl/extractor/oauth.py +++ b/gallery_dl/extractor/oauthhelper.py @@ -6,57 +6,15 @@ # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. -"""Utility classes to setup OAuth""" +"""Utility classes to setup OAuth and link a users account to gallery-dl""" from .common import Extractor, Message from . import reddit, flickr +from .. import oauth import os -import time -import hmac -import base64 -import random -import string -import hashlib import urllib.parse -class OAuthSession(): - """Minimal wrapper for requests.session objects to support OAuth 1.0""" - def __init__(self, session, consumer_key, consumer_secret, - token=None, token_secret=None): - self.session = session - self.consumer_secret = consumer_secret - self.token_secret = token_secret or "" - self.params = session.params - self.params["oauth_consumer_key"] = consumer_key - self.params["oauth_token"] = token - self.params["oauth_signature_method"] = "HMAC-SHA1" - self.params["oauth_version"] = "1.0" - - def get(self, url, params): - params.update(self.params) - params["oauth_nonce"] = self.nonce(16) - params["oauth_timestamp"] = int(time.time()) - params["oauth_signature"] = self.signature(url, params) - return self.session.get(url, params=params) - - def signature(self, url, params): - """Generate 'oauth_signature' value""" - query = urllib.parse.urlencode(sorted(params.items())) - message = self.concat("GET", url, query).encode() - key = self.concat(self.consumer_secret, self.token_secret).encode() - signature = hmac.new(key, message, hashlib.sha1).digest() - return base64.b64encode(signature).decode() - - @staticmethod - def concat(*args): - return "&".join(urllib.parse.quote(item, "") for item in args) - - @staticmethod - def nonce(N, alphabet=string.ascii_letters): - return "".join(random.choice(alphabet) for _ in range(N)) - - class OAuthBase(Extractor): """Base class for OAuth Helpers""" category = "oauth" @@ -122,7 +80,7 @@ class OAuthReddit(OAuthBase): self.session.headers["User-Agent"] = reddit.RedditAPI.USER_AGENT self.client_id = reddit.RedditAPI.CLIENT_ID self.state = "gallery-dl:{}:{}".format( - self.subcategory, OAuthSession.nonce(8)) + self.subcategory, oauth.OAuthSession.nonce(8)) def items(self): yield Message.Version, 1 @@ -170,9 +128,10 @@ class OAuthFlickr(OAuthBase): def __init__(self, match): OAuthBase.__init__(self) - self.session = OAuthSession(self.session, - flickr.FlickrAPI.API_KEY, - flickr.FlickrAPI.API_SECRET) + self.session = oauth.OAuthSession( + self.session, + flickr.FlickrAPI.API_KEY, flickr.FlickrAPI.API_SECRET + ) del self.session.params["oauth_token"] def items(self): diff --git a/gallery_dl/oauth.py b/gallery_dl/oauth.py new file mode 100644 index 00000000..a27da285 --- /dev/null +++ b/gallery_dl/oauth.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +# Copyright 2017 Mike Fährmann +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +"""Utility classes for OAuth 1.0""" + +import hmac +import time +import base64 +import random +import string +import hashlib +import urllib.parse + + +class OAuthSession(): + """Minimal wrapper for requests.session objects to support OAuth 1.0""" + def __init__(self, session, consumer_key, consumer_secret, + token=None, token_secret=None): + self.session = session + self.consumer_secret = consumer_secret + self.token_secret = token_secret or "" + self.params = session.params + self.params["oauth_consumer_key"] = consumer_key + self.params["oauth_token"] = token + self.params["oauth_signature_method"] = "HMAC-SHA1" + self.params["oauth_version"] = "1.0" + + def get(self, url, params): + params.update(self.params) + params["oauth_nonce"] = self.nonce(16) + params["oauth_timestamp"] = int(time.time()) + params["oauth_signature"] = self.signature(url, params) + return self.session.get(url, params=params) + + def signature(self, url, params): + """Generate 'oauth_signature' value""" + query = urllib.parse.urlencode(sorted(params.items())) + message = self.concat("GET", url, query).encode() + key = self.concat(self.consumer_secret, self.token_secret).encode() + signature = hmac.new(key, message, hashlib.sha1).digest() + return base64.b64encode(signature).decode() + + @staticmethod + def concat(*args): + return "&".join(urllib.parse.quote(item, "") for item in args) + + @staticmethod + def nonce(N, alphabet=string.ascii_letters): + return "".join(random.choice(alphabet) for _ in range(N))