summaryrefslogtreecommitdiffstats
path: root/gallery_dl/extractor/common.py
diff options
context:
space:
mode:
Diffstat (limited to 'gallery_dl/extractor/common.py')
-rw-r--r--gallery_dl/extractor/common.py183
1 files changed, 104 insertions, 79 deletions
diff --git a/gallery_dl/extractor/common.py b/gallery_dl/extractor/common.py
index 52e5199..1d81dfc 100644
--- a/gallery_dl/extractor/common.py
+++ b/gallery_dl/extractor/common.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright 2014-2021 Mike Fährmann
+# Copyright 2014-2022 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
@@ -38,6 +38,7 @@ class Extractor():
request_interval = 0.0
request_interval_min = 0.0
request_timestamp = 0.0
+ tls12 = True
def __init__(self, match):
self.log = logging.getLogger(self.category)
@@ -219,14 +220,7 @@ class Extractor():
self.session = session = requests.Session()
headers = session.headers
headers.clear()
-
- source_address = self.config("source-address")
- if source_address:
- if isinstance(source_address, str):
- source_address = (source_address, 0)
- else:
- source_address = (source_address[0], source_address[1])
- session.mount("http://", SourceAdapter(source_address))
+ ssl_options = ssl_ciphers = 0
browser = self.config("browser") or self.browser
if browser and isinstance(browser, str):
@@ -243,12 +237,21 @@ class Extractor():
platform = "Macintosh; Intel Mac OS X 11.5"
if browser == "chrome":
- _emulate_browser_chrome(session, platform, source_address)
+ if platform.startswith("Macintosh"):
+ platform = platform.replace(".", "_") + "_2"
else:
- _emulate_browser_firefox(session, platform, source_address)
+ browser = "firefox"
+
+ for key, value in HTTP_HEADERS[browser]:
+ if value and "{}" in value:
+ headers[key] = value.format(platform)
+ else:
+ headers[key] = value
+
+ ssl_options |= (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
+ ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
+ ssl_ciphers = SSL_CIPHERS[browser]
else:
- if source_address:
- session.mount("https://", SourceAdapter(source_address))
headers["User-Agent"] = self.config("user-agent", (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; "
"rv:91.0) Gecko/20100101 Firefox/91.0"))
@@ -260,11 +263,31 @@ class Extractor():
if custom_headers:
headers.update(custom_headers)
- ciphers = self.config("ciphers")
- if ciphers:
- if isinstance(ciphers, list):
- ciphers = ":".join(ciphers)
- session.mount("https://", HTTPSAdapter(ciphers))
+ custom_ciphers = self.config("ciphers")
+ if custom_ciphers:
+ if isinstance(custom_ciphers, list):
+ ssl_ciphers = ":".join(custom_ciphers)
+ else:
+ ssl_ciphers = custom_ciphers
+
+ source_address = self.config("source-address")
+ if source_address:
+ if isinstance(source_address, str):
+ source_address = (source_address, 0)
+ else:
+ source_address = (source_address[0], source_address[1])
+
+ tls12 = self.config("tls12")
+ if tls12 is None:
+ tls12 = self.tls12
+ if not tls12:
+ ssl_options |= ssl.OP_NO_TLSv1_2
+ self.log.debug("TLS 1.2 disabled.")
+
+ adapter = _build_requests_adapter(
+ ssl_options, ssl_ciphers, source_address)
+ session.mount("https://", adapter)
+ session.mount("http://", adapter)
def _init_proxies(self):
"""Update the session's proxy map"""
@@ -615,29 +638,10 @@ class BaseExtractor(Extractor):
)
-class SourceAdapter(HTTPAdapter):
+class RequestsAdapter(HTTPAdapter):
- def __init__(self, source_address):
- self.source_address = source_address
- HTTPAdapter.__init__(self)
-
- def init_poolmanager(self, *args, **kwargs):
- kwargs["source_address"] = self.source_address
- return HTTPAdapter.init_poolmanager(self, *args, **kwargs)
-
- def proxy_manager_for(self, *args, **kwargs):
- kwargs["source_address"] = self.source_address
- return HTTPAdapter.proxy_manager_for(self, *args, **kwargs)
-
-
-class HTTPSAdapter(HTTPAdapter):
-
- def __init__(self, ciphers, source_address=None):
- context = self.ssl_context = ssl.create_default_context()
- context.options |= (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
- context.set_ecdh_curve("prime256v1")
- context.set_ciphers(ciphers)
+ def __init__(self, ssl_context=None, source_address=None):
+ self.ssl_context = ssl_context
self.source_address = source_address
HTTPAdapter.__init__(self)
@@ -652,19 +656,59 @@ class HTTPSAdapter(HTTPAdapter):
return HTTPAdapter.proxy_manager_for(self, *args, **kwargs)
-def _emulate_browser_firefox(session, platform, source_address):
- headers = session.headers
- headers["User-Agent"] = ("Mozilla/5.0 (" + platform + "; rv:91.0) "
- "Gecko/20100101 Firefox/91.0")
- headers["Accept"] = ("text/html,application/xhtml+xml,"
- "application/xml;q=0.9,image/webp,*/*;q=0.8")
- headers["Accept-Language"] = "en-US,en;q=0.5"
- headers["Accept-Encoding"] = "gzip, deflate"
- headers["Referer"] = None
- headers["Upgrade-Insecure-Requests"] = "1"
- headers["Cookie"] = None
+def _build_requests_adapter(ssl_options, ssl_ciphers, source_address):
+ key = (ssl_options, ssl_ciphers, source_address)
+ try:
+ return _adapter_cache[key]
+ except KeyError:
+ pass
- session.mount("https://", HTTPSAdapter(
+ if ssl_options or ssl_ciphers:
+ ssl_context = ssl.create_default_context()
+ if ssl_options:
+ ssl_context.options |= ssl_options
+ if ssl_ciphers:
+ ssl_context.set_ecdh_curve("prime256v1")
+ ssl_context.set_ciphers(ssl_ciphers)
+ else:
+ ssl_context = None
+
+ adapter = _adapter_cache[key] = RequestsAdapter(
+ ssl_context, source_address)
+ return adapter
+
+
+_adapter_cache = {}
+
+
+HTTP_HEADERS = {
+ "firefox": (
+ ("User-Agent", "Mozilla/5.0 ({}; rv:91.0) "
+ "Gecko/20100101 Firefox/91.0"),
+ ("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,"
+ "image/avif,*/*;q=0.8"),
+ ("Accept-Language", "en-US,en;q=0.5"),
+ ("Accept-Encoding", "gzip, deflate"),
+ ("Referer", None),
+ ("Connection", "keep-alive"),
+ ("Upgrade-Insecure-Requests", "1"),
+ ("Cookie", None),
+ ),
+ "chrome": (
+ ("Upgrade-Insecure-Requests", "1"),
+ ("User-Agent", "Mozilla/5.0 ({}) AppleWebKit/537.36 (KHTML, "
+ "like Gecko) Chrome/92.0.4515.131 Safari/537.36"),
+ ("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,"
+ "image/webp,image/apng,*/*;q=0.8"),
+ ("Referer", None),
+ ("Accept-Encoding", "gzip, deflate"),
+ ("Accept-Language", "en-US,en;q=0.9"),
+ ("Cookie", None),
+ ),
+}
+
+SSL_CIPHERS = {
+ "firefox": (
"TLS_AES_128_GCM_SHA256:"
"TLS_CHACHA20_POLY1305_SHA256:"
"TLS_AES_256_GCM_SHA384:"
@@ -678,32 +722,13 @@ def _emulate_browser_firefox(session, platform, source_address):
"ECDHE-ECDSA-AES128-SHA:"
"ECDHE-RSA-AES128-SHA:"
"ECDHE-RSA-AES256-SHA:"
- "DHE-RSA-AES128-SHA:"
- "DHE-RSA-AES256-SHA:"
+ "AES128-GCM-SHA256:"
+ "AES256-GCM-SHA384:"
"AES128-SHA:"
"AES256-SHA:"
- "DES-CBC3-SHA",
- source_address
- ))
-
-
-def _emulate_browser_chrome(session, platform, source_address):
- if platform.startswith("Macintosh"):
- platform = platform.replace(".", "_") + "_2"
-
- headers = session.headers
- headers["Upgrade-Insecure-Requests"] = "1"
- headers["User-Agent"] = (
- "Mozilla/5.0 (" + platform + ") AppleWebKit/537.36 "
- "(KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36")
- headers["Accept"] = ("text/html,application/xhtml+xml,application/xml;"
- "q=0.9,image/webp,image/apng,*/*;q=0.8")
- headers["Referer"] = None
- headers["Accept-Encoding"] = "gzip, deflate"
- headers["Accept-Language"] = "en-US,en;q=0.9"
- headers["Cookie"] = None
-
- session.mount("https://", HTTPSAdapter(
+ "DES-CBC3-SHA"
+ ),
+ "chrome": (
"TLS_AES_128_GCM_SHA256:"
"TLS_AES_256_GCM_SHA384:"
"TLS_CHACHA20_POLY1305_SHA256:"
@@ -719,9 +744,9 @@ def _emulate_browser_chrome(session, platform, source_address):
"AES256-GCM-SHA384:"
"AES128-SHA:"
"AES256-SHA:"
- "DES-CBC3-SHA",
- source_address
- ))
+ "DES-CBC3-SHA"
+ ),
+}
# Undo automatic pyOpenSSL injection by requests