diff options
Diffstat (limited to 'gallery_dl/extractor/oauth.py')
| -rw-r--r-- | gallery_dl/extractor/oauth.py | 163 |
1 files changed, 92 insertions, 71 deletions
diff --git a/gallery_dl/extractor/oauth.py b/gallery_dl/extractor/oauth.py index d6628c4..9270f33 100644 --- a/gallery_dl/extractor/oauth.py +++ b/gallery_dl/extractor/oauth.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright 2017-2022 Mike Fährmann +# Copyright 2017-2023 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 @@ -68,11 +68,19 @@ class OAuthBase(Extractor): def open(self, url, params, recv=None): """Open 'url' in browser amd return response parameters""" - import webbrowser url += "?" + urllib.parse.urlencode(params) - if not self.config("browser", True) or not webbrowser.open(url): - stdout_write( - "Please open this URL in your browser:\n\n" + url + "\n\n") + + browser = self.config("browser", True) + if browser: + import webbrowser + browser = webbrowser.get() + + if browser and browser.open(url): + self.log.info("Opening URL in %s:", browser.name.capitalize()) + else: + self.log.info("Please open this URL in your browser:") + + stdout_write("\n{}\n\n".format(url)) return (recv or self.recv)() def error(self, msg): @@ -80,8 +88,18 @@ class OAuthBase(Extractor): "Remote server reported an error:\n\n{}\n".format(msg)) def _oauth1_authorization_flow( - self, request_token_url, authorize_url, access_token_url): + self, default_key, default_secret, + request_token_url, authorize_url, access_token_url): """Perform the OAuth 1.0a authorization flow""" + + api_key = self.oauth_config("api-key") or default_key + api_secret = self.oauth_config("api-secret") or default_secret + self.session = oauth.OAuth1Session(api_key, api_secret) + + self.log.info("Using %s %s API key (%s)", + "default" if api_key == default_key else "custom", + self.subcategory, api_key) + # get a request token params = {"oauth_callback": self.redirect_uri} data = self.session.get(request_token_url, params=params).text @@ -112,11 +130,18 @@ class OAuthBase(Extractor): )) def _oauth2_authorization_code_grant( - self, client_id, client_secret, auth_url, token_url, *, - scope="read", key="refresh_token", auth=True, - cache=None, instance=None): + self, client_id, client_secret, default_id, default_secret, + auth_url, token_url, *, scope="read", duration="permanent", + key="refresh_token", auth=True, cache=None, instance=None): """Perform an OAuth2 authorization code grant""" + client_id = str(client_id) if client_id else default_id + client_secret = client_secret or default_secret + + self.log.info("Using %s %s client ID (%s)", + "default" if client_id == default_id else "custom", + instance or self.subcategory, client_id) + state = "gallery-dl_{}_{}".format( self.subcategory, oauth.nonce(8), @@ -127,7 +152,7 @@ class OAuthBase(Extractor): "response_type": "code", "state" : state, "redirect_uri" : self.redirect_uri, - "duration" : "permanent", + "duration" : duration, "scope" : scope, } @@ -137,13 +162,12 @@ class OAuthBase(Extractor): # check authorization response if state != params.get("state"): self.send("'state' mismatch: expected {}, got {}.\n".format( - state, params.get("state") - )) + state, params.get("state"))) return if "error" in params: return self.error(params) - # exchange the authorization code for a token + # exchange authorization code for a token data = { "grant_type" : "authorization_code", "code" : params["code"], @@ -208,81 +232,36 @@ class OAuthBase(Extractor): return msg -class OAuthDeviantart(OAuthBase): - subcategory = "deviantart" - pattern = "oauth:deviantart$" - redirect_uri = REDIRECT_URI_HTTPS - - def items(self): - yield Message.Version, 1 - - self._oauth2_authorization_code_grant( - self.oauth_config( - "client-id", deviantart.DeviantartOAuthAPI.CLIENT_ID), - self.oauth_config( - "client-secret", deviantart.DeviantartOAuthAPI.CLIENT_SECRET), - "https://www.deviantart.com/oauth2/authorize", - "https://www.deviantart.com/oauth2/token", - scope="browse user.manage", - cache=deviantart._refresh_token_cache, - ) - +# -------------------------------------------------------------------- +# OAuth 1.0a class OAuthFlickr(OAuthBase): subcategory = "flickr" pattern = "oauth:flickr$" redirect_uri = REDIRECT_URI_HTTPS - def __init__(self, match): - OAuthBase.__init__(self, match) - self.session = oauth.OAuth1Session( - self.oauth_config("api-key", flickr.FlickrAPI.API_KEY), - self.oauth_config("api-secret", flickr.FlickrAPI.API_SECRET), - ) - def items(self): yield Message.Version, 1 self._oauth1_authorization_flow( + flickr.FlickrAPI.API_KEY, + flickr.FlickrAPI.API_SECRET, "https://www.flickr.com/services/oauth/request_token", "https://www.flickr.com/services/oauth/authorize", "https://www.flickr.com/services/oauth/access_token", ) -class OAuthReddit(OAuthBase): - subcategory = "reddit" - pattern = "oauth:reddit$" - - def items(self): - yield Message.Version, 1 - - self.session.headers["User-Agent"] = reddit.RedditAPI.USER_AGENT - self._oauth2_authorization_code_grant( - self.oauth_config("client-id", reddit.RedditAPI.CLIENT_ID), - "", - "https://www.reddit.com/api/v1/authorize", - "https://www.reddit.com/api/v1/access_token", - scope="read history", - cache=reddit._refresh_token_cache, - ) - - class OAuthSmugmug(OAuthBase): subcategory = "smugmug" pattern = "oauth:smugmug$" - def __init__(self, match): - OAuthBase.__init__(self, match) - self.session = oauth.OAuth1Session( - self.oauth_config("api-key", smugmug.SmugmugAPI.API_KEY), - self.oauth_config("api-secret", smugmug.SmugmugAPI.API_SECRET), - ) - def items(self): yield Message.Version, 1 self._oauth1_authorization_flow( + smugmug.SmugmugAPI.API_KEY, + smugmug.SmugmugAPI.API_SECRET, "https://api.smugmug.com/services/oauth/1.0a/getRequestToken", "https://api.smugmug.com/services/oauth/1.0a/authorize", "https://api.smugmug.com/services/oauth/1.0a/getAccessToken", @@ -293,23 +272,61 @@ class OAuthTumblr(OAuthBase): subcategory = "tumblr" pattern = "oauth:tumblr$" - def __init__(self, match): - OAuthBase.__init__(self, match) - self.session = oauth.OAuth1Session( - self.oauth_config("api-key", tumblr.TumblrAPI.API_KEY), - self.oauth_config("api-secret", tumblr.TumblrAPI.API_SECRET), - ) - def items(self): yield Message.Version, 1 self._oauth1_authorization_flow( + tumblr.TumblrAPI.API_KEY, + tumblr.TumblrAPI.API_SECRET, "https://www.tumblr.com/oauth/request_token", "https://www.tumblr.com/oauth/authorize", "https://www.tumblr.com/oauth/access_token", ) +# -------------------------------------------------------------------- +# OAuth 2.0 + +class OAuthDeviantart(OAuthBase): + subcategory = "deviantart" + pattern = "oauth:deviantart$" + redirect_uri = REDIRECT_URI_HTTPS + + def items(self): + yield Message.Version, 1 + + self._oauth2_authorization_code_grant( + self.oauth_config("client-id"), + self.oauth_config("client-secret"), + deviantart.DeviantartOAuthAPI.CLIENT_ID, + deviantart.DeviantartOAuthAPI.CLIENT_SECRET, + "https://www.deviantart.com/oauth2/authorize", + "https://www.deviantart.com/oauth2/token", + scope="browse user.manage", + cache=deviantart._refresh_token_cache, + ) + + +class OAuthReddit(OAuthBase): + subcategory = "reddit" + pattern = "oauth:reddit$" + + def items(self): + yield Message.Version, 1 + + self.session.headers["User-Agent"] = reddit.RedditAPI.USER_AGENT + self._oauth2_authorization_code_grant( + self.oauth_config("client-id"), + "", + reddit.RedditAPI.CLIENT_ID, + "", + "https://www.reddit.com/api/v1/authorize", + "https://www.reddit.com/api/v1/access_token", + scope="read history", + cache=reddit._refresh_token_cache, + ) + + class OAuthMastodon(OAuthBase): subcategory = "mastodon" pattern = "oauth:mastodon:(?:https?://)?([^/?#]+)" @@ -330,6 +347,8 @@ class OAuthMastodon(OAuthBase): self._oauth2_authorization_code_grant( application["client-id"], application["client-secret"], + application["client-id"], + application["client-secret"], "https://{}/oauth/authorize".format(self.instance), "https://{}/oauth/token".format(self.instance), instance=self.instance, @@ -362,6 +381,8 @@ class OAuthMastodon(OAuthBase): return data +# -------------------------------------------------------------------- + class OAuthPixiv(OAuthBase): subcategory = "pixiv" pattern = "oauth:pixiv$" |
