mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-07-23 20:04:15 +09:00
using hashlib for PBKDF2
This commit is contained in:
parent
5f323b1a94
commit
64c425364e
@ -2,7 +2,7 @@ import unittest
|
|||||||
|
|
||||||
from youtube_dl import cookies
|
from youtube_dl import cookies
|
||||||
from youtube_dl.cookies import LinuxChromeCookieDecryptor, WindowsChromeCookieDecryptor, CRYPTO_AVAILABLE, \
|
from youtube_dl.cookies import LinuxChromeCookieDecryptor, WindowsChromeCookieDecryptor, CRYPTO_AVAILABLE, \
|
||||||
MacChromeCookieDecryptor
|
MacChromeCookieDecryptor, Logger
|
||||||
|
|
||||||
|
|
||||||
class MonkeyPatch:
|
class MonkeyPatch:
|
||||||
@ -23,22 +23,22 @@ class MonkeyPatch:
|
|||||||
@unittest.skipIf(not CRYPTO_AVAILABLE, 'cryptography library not available')
|
@unittest.skipIf(not CRYPTO_AVAILABLE, 'cryptography library not available')
|
||||||
class TestCookies(unittest.TestCase):
|
class TestCookies(unittest.TestCase):
|
||||||
def test_chrome_cookie_decryptor_linux_derive_key(self):
|
def test_chrome_cookie_decryptor_linux_derive_key(self):
|
||||||
key = LinuxChromeCookieDecryptor.derive_key('abc')
|
key = LinuxChromeCookieDecryptor.derive_key(b'abc')
|
||||||
assert key == b'7\xa1\xec\xd4m\xfcA\xc7\xb19Z\xd0\x19\xdcM\x17'
|
assert key == b'7\xa1\xec\xd4m\xfcA\xc7\xb19Z\xd0\x19\xdcM\x17'
|
||||||
|
|
||||||
def test_chrome_cookie_decryptor_mac_derive_key(self):
|
def test_chrome_cookie_decryptor_mac_derive_key(self):
|
||||||
key = MacChromeCookieDecryptor.derive_key('abc')
|
key = MacChromeCookieDecryptor.derive_key(b'abc')
|
||||||
assert key == b'Y\xe2\xc0\xd0P\xf6\xf4\xe1l\xc1\x8cQ\xcb|\xcdY'
|
assert key == b'Y\xe2\xc0\xd0P\xf6\xf4\xe1l\xc1\x8cQ\xcb|\xcdY'
|
||||||
|
|
||||||
def test_chrome_cookie_decryptor_linux_v10(self):
|
def test_chrome_cookie_decryptor_linux_v10(self):
|
||||||
with MonkeyPatch(cookies, '_get_linux_keyring_password', lambda *args, **kwargs: ''):
|
with MonkeyPatch(cookies, '_get_linux_keyring_password', lambda *args, **kwargs: b''):
|
||||||
encrypted_value = b'v10\xccW%\xcd\xe6\xe6\x9fM" \xa7\xb0\xca\xe4\x07\xd6'
|
encrypted_value = b'v10\xccW%\xcd\xe6\xe6\x9fM" \xa7\xb0\xca\xe4\x07\xd6'
|
||||||
value = 'USD'
|
value = 'USD'
|
||||||
decryptor = LinuxChromeCookieDecryptor('Chrome')
|
decryptor = LinuxChromeCookieDecryptor('Chrome')
|
||||||
assert decryptor.decrypt(encrypted_value) == value
|
assert decryptor.decrypt(encrypted_value) == value
|
||||||
|
|
||||||
def test_chrome_cookie_decryptor_linux_v11(self):
|
def test_chrome_cookie_decryptor_linux_v11(self):
|
||||||
with MonkeyPatch(cookies, '_get_linux_keyring_password', lambda *args, **kwargs: ''):
|
with MonkeyPatch(cookies, '_get_linux_keyring_password', lambda *args, **kwargs: b''):
|
||||||
encrypted_value = b'v11#\x81\x10>`w\x8f)\xc0\xb2\xc1\r\xf4\x1al\xdd\x93\xfd\xf8\xf8N\xf2\xa9\x83\xf1\xe9o\x0elVQd'
|
encrypted_value = b'v11#\x81\x10>`w\x8f)\xc0\xb2\xc1\r\xf4\x1al\xdd\x93\xfd\xf8\xf8N\xf2\xa9\x83\xf1\xe9o\x0elVQd'
|
||||||
value = 'tz=Europe.London'
|
value = 'tz=Europe.London'
|
||||||
decryptor = LinuxChromeCookieDecryptor('Chrome')
|
decryptor = LinuxChromeCookieDecryptor('Chrome')
|
||||||
@ -49,11 +49,11 @@ class TestCookies(unittest.TestCase):
|
|||||||
lambda *args, **kwargs: b'Y\xef\xad\xad\xeerp\xf0Y\xe6\x9b\x12\xc2<z\x16]\n\xbb\xb8\xcb\xd7\x9bA\xc3\x14e\x99{\xd6\xf4&'):
|
lambda *args, **kwargs: b'Y\xef\xad\xad\xeerp\xf0Y\xe6\x9b\x12\xc2<z\x16]\n\xbb\xb8\xcb\xd7\x9bA\xc3\x14e\x99{\xd6\xf4&'):
|
||||||
encrypted_value = b'v10T\xb8\xf3\xb8\x01\xa7TtcV\xfc\x88\xb8\xb8\xef\x05\xb5\xfd\x18\xc90\x009\xab\xb1\x893\x85)\x87\xe1\xa9-\xa3\xad='
|
encrypted_value = b'v10T\xb8\xf3\xb8\x01\xa7TtcV\xfc\x88\xb8\xb8\xef\x05\xb5\xfd\x18\xc90\x009\xab\xb1\x893\x85)\x87\xe1\xa9-\xa3\xad='
|
||||||
value = '32101439'
|
value = '32101439'
|
||||||
decryptor = WindowsChromeCookieDecryptor('')
|
decryptor = WindowsChromeCookieDecryptor('', Logger())
|
||||||
assert decryptor.decrypt(encrypted_value) == value
|
assert decryptor.decrypt(encrypted_value) == value
|
||||||
|
|
||||||
def test_chrome_cookie_decryptor_mac_v10(self):
|
def test_chrome_cookie_decryptor_mac_v10(self):
|
||||||
with MonkeyPatch(cookies, '_get_mac_keyring_password', lambda *args, **kwargs: '6eIDUdtKAacvlHwBVwvg/Q=='):
|
with MonkeyPatch(cookies, '_get_mac_keyring_password', lambda *args, **kwargs: b'6eIDUdtKAacvlHwBVwvg/Q=='):
|
||||||
encrypted_value = b'v10\xb3\xbe\xad\xa1[\x9fC\xa1\x98\xe0\x9a\x01\xd9\xcf\xbfc'
|
encrypted_value = b'v10\xb3\xbe\xad\xa1[\x9fC\xa1\x98\xe0\x9a\x01\xd9\xcf\xbfc'
|
||||||
value = '2021-06-01-22'
|
value = '2021-06-01-22'
|
||||||
decryptor = MacChromeCookieDecryptor('')
|
decryptor = MacChromeCookieDecryptor('')
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import ctypes
|
import ctypes
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@ -12,8 +13,6 @@ from youtube_dl.utils import YoutubeDLCookieJar, expand_path
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Protocol.KDF import PBKDF2
|
|
||||||
from Crypto.Hash import SHA1
|
|
||||||
CRYPTO_AVAILABLE = True
|
CRYPTO_AVAILABLE = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
CRYPTO_AVAILABLE = False
|
CRYPTO_AVAILABLE = False
|
||||||
@ -25,7 +24,8 @@ except ImportError:
|
|||||||
KEYRING_AVAILABLE = False
|
KEYRING_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED_BROWSERS = ['firefox', 'chrome', 'chromium', 'brave', 'opera', 'edge']
|
SUPPORTED_BROWSERS = ['brave', 'chrome', 'chromium', 'edge' 'firefox', 'opera']
|
||||||
|
CHROME_LIKE_BROWSERS = {'brave', 'chrome', 'chromium', 'edge' 'opera'}
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
@ -46,7 +46,7 @@ def _is_path(value):
|
|||||||
def extract_cookies_from_browser(browser_name, profile=None, logger=Logger()):
|
def extract_cookies_from_browser(browser_name, profile=None, logger=Logger()):
|
||||||
if browser_name == 'firefox':
|
if browser_name == 'firefox':
|
||||||
return _extract_firefox_cookies(profile, logger)
|
return _extract_firefox_cookies(profile, logger)
|
||||||
elif browser_name in ('chrome', 'chromium', 'brave', 'opera', 'edge'):
|
elif browser_name in CHROME_LIKE_BROWSERS:
|
||||||
return _extract_chrome_cookies(browser_name, profile, logger)
|
return _extract_chrome_cookies(browser_name, profile, logger)
|
||||||
else:
|
else:
|
||||||
raise ValueError('unknown browser: {}'.format(browser_name))
|
raise ValueError('unknown browser: {}'.format(browser_name))
|
||||||
@ -103,32 +103,32 @@ def _get_chrome_like_browser_settings(browser_name):
|
|||||||
if sys.platform in ('linux', 'linux2'):
|
if sys.platform in ('linux', 'linux2'):
|
||||||
config = _config_home()
|
config = _config_home()
|
||||||
browser_dir = {
|
browser_dir = {
|
||||||
|
'brave': os.path.join(config, 'BraveSoftware/Brave-Browser'),
|
||||||
'chrome': os.path.join(config, 'google-chrome'),
|
'chrome': os.path.join(config, 'google-chrome'),
|
||||||
'chromium': os.path.join(config, 'chromium'),
|
'chromium': os.path.join(config, 'chromium'),
|
||||||
'brave': os.path.join(config, 'BraveSoftware/Brave-Browser'),
|
|
||||||
'opera': os.path.join(config, 'opera'),
|
|
||||||
'edge': os.path.join(config, 'microsoft-edge'),
|
'edge': os.path.join(config, 'microsoft-edge'),
|
||||||
|
'opera': os.path.join(config, 'opera'),
|
||||||
}[browser_name]
|
}[browser_name]
|
||||||
|
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
appdata_local = os.path.expandvars('%LOCALAPPDATA%')
|
appdata_local = os.path.expandvars('%LOCALAPPDATA%')
|
||||||
appdata_roaming = os.path.expandvars('%APPDATA%')
|
appdata_roaming = os.path.expandvars('%APPDATA%')
|
||||||
browser_dir = {
|
browser_dir = {
|
||||||
|
'brave': os.path.join(appdata_local, r'BraveSoftware\Brave-Browser'),
|
||||||
'chrome': os.path.join(appdata_local, r'Google\Chrome'),
|
'chrome': os.path.join(appdata_local, r'Google\Chrome'),
|
||||||
'chromium': os.path.join(appdata_local, r'Google\Chromium'),
|
'chromium': os.path.join(appdata_local, r'Google\Chromium'),
|
||||||
'brave': os.path.join(appdata_local, r'BraveSoftware\Brave-Browser'),
|
|
||||||
'opera': os.path.join(appdata_roaming, r'Opera Software\Opera Stable'),
|
|
||||||
'edge': os.path.join(appdata_local, r'Microsoft\Edge'),
|
'edge': os.path.join(appdata_local, r'Microsoft\Edge'),
|
||||||
|
'opera': os.path.join(appdata_roaming, r'Opera Software\Opera Stable'),
|
||||||
}[browser_name]
|
}[browser_name]
|
||||||
|
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
appdata = os.path.expanduser('~/Library/Application Support')
|
appdata = os.path.expanduser('~/Library/Application Support')
|
||||||
browser_dir = {
|
browser_dir = {
|
||||||
|
'brave': os.path.join(appdata, 'BraveSoftware/Brave-Browser'),
|
||||||
'chrome': os.path.join(appdata, 'Google/Chrome'),
|
'chrome': os.path.join(appdata, 'Google/Chrome'),
|
||||||
'chromium': os.path.join(appdata, 'Google/Chromium'),
|
'chromium': os.path.join(appdata, 'Google/Chromium'),
|
||||||
'brave': os.path.join(appdata, 'BraveSoftware/Brave-Browser'),
|
|
||||||
'opera': os.path.join(appdata, 'com.operasoftware.Opera'),
|
|
||||||
'edge': os.path.join(appdata, 'Microsoft Edge'),
|
'edge': os.path.join(appdata, 'Microsoft Edge'),
|
||||||
|
'opera': os.path.join(appdata, 'com.operasoftware.Opera'),
|
||||||
}[browser_name]
|
}[browser_name]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -137,11 +137,11 @@ def _get_chrome_like_browser_settings(browser_name):
|
|||||||
# Linux keyring names can be determined by snooping on dbus while opening the browser in KDE:
|
# Linux keyring names can be determined by snooping on dbus while opening the browser in KDE:
|
||||||
# dbus-monitor "interface='org.kde.KWallet'" "type=method_return"
|
# dbus-monitor "interface='org.kde.KWallet'" "type=method_return"
|
||||||
keyring_name = {
|
keyring_name = {
|
||||||
|
'brave': 'Brave',
|
||||||
'chrome': 'Chrome',
|
'chrome': 'Chrome',
|
||||||
'chromium': 'Chromium',
|
'chromium': 'Chromium',
|
||||||
'brave': 'Brave',
|
|
||||||
'opera': 'Opera' if sys.platform == 'darwin' else 'Chromium',
|
|
||||||
'edge': 'Mirosoft Edge' if sys.platform == 'darwin' else 'Chromium',
|
'edge': 'Mirosoft Edge' if sys.platform == 'darwin' else 'Chromium',
|
||||||
|
'opera': 'Opera' if sys.platform == 'darwin' else 'Chromium',
|
||||||
}[browser_name]
|
}[browser_name]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -253,7 +253,7 @@ class LinuxChromeCookieDecryptor(ChromeCookieDecryptor):
|
|||||||
self._v10_key = None
|
self._v10_key = None
|
||||||
self._v11_key = None
|
self._v11_key = None
|
||||||
if CRYPTO_AVAILABLE:
|
if CRYPTO_AVAILABLE:
|
||||||
self._v10_key = self.derive_key('peanuts')
|
self._v10_key = self.derive_key(b'peanuts')
|
||||||
if KEYRING_AVAILABLE:
|
if KEYRING_AVAILABLE:
|
||||||
self._v11_key = self.derive_key(_get_linux_keyring_password(browser_keyring_name))
|
self._v11_key = self.derive_key(_get_linux_keyring_password(browser_keyring_name))
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ class LinuxChromeCookieDecryptor(ChromeCookieDecryptor):
|
|||||||
def derive_key(password):
|
def derive_key(password):
|
||||||
# values from
|
# values from
|
||||||
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_linux.cc
|
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_linux.cc
|
||||||
return PBKDF2(password, salt=b'saltysalt', dkLen=16, count=1, hmac_hash_module=SHA1)
|
return hashlib.pbkdf2_hmac('sha1', password, salt=b'saltysalt', iterations=1, dklen=16)
|
||||||
|
|
||||||
def decrypt(self, encrypted_value):
|
def decrypt(self, encrypted_value):
|
||||||
version = encrypted_value[:3]
|
version = encrypted_value[:3]
|
||||||
@ -293,7 +293,7 @@ class MacChromeCookieDecryptor(ChromeCookieDecryptor):
|
|||||||
def derive_key(password):
|
def derive_key(password):
|
||||||
# values from
|
# values from
|
||||||
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_mac.mm
|
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_mac.mm
|
||||||
return PBKDF2(password, salt=b'saltysalt', dkLen=16, count=1003, hmac_hash_module=SHA1)
|
return hashlib.pbkdf2_hmac('sha1', password, salt=b'saltysalt', iterations=1003, dklen=16)
|
||||||
|
|
||||||
def decrypt(self, encrypted_value):
|
def decrypt(self, encrypted_value):
|
||||||
version = encrypted_value[:3]
|
version = encrypted_value[:3]
|
||||||
@ -358,12 +358,13 @@ def _get_linux_keyring_password(browser_keyring_name):
|
|||||||
# this may be a bug as the intended behaviour is to generate a random password and store
|
# this may be a bug as the intended behaviour is to generate a random password and store
|
||||||
# it, but that doesn't matter here.
|
# it, but that doesn't matter here.
|
||||||
password = ''
|
password = ''
|
||||||
return password
|
return password.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def _get_mac_keyring_password(browser_keyring_name):
|
def _get_mac_keyring_password(browser_keyring_name):
|
||||||
if KEYRING_AVAILABLE:
|
if KEYRING_AVAILABLE:
|
||||||
return keyring.get_password('{} Safe Storage'.format(browser_keyring_name), browser_keyring_name)
|
password = keyring.get_password('{} Safe Storage'.format(browser_keyring_name), browser_keyring_name)
|
||||||
|
return password.encode('utf-8')
|
||||||
else:
|
else:
|
||||||
proc = subprocess.Popen(['security', 'find-generic-password',
|
proc = subprocess.Popen(['security', 'find-generic-password',
|
||||||
'-w', # write password to stdout
|
'-w', # write password to stdout
|
||||||
@ -373,7 +374,7 @@ def _get_mac_keyring_password(browser_keyring_name):
|
|||||||
stderr=subprocess.DEVNULL)
|
stderr=subprocess.DEVNULL)
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode == 0:
|
if proc.returncode == 0:
|
||||||
return proc.stdout.read().decode('utf-8').strip()
|
return proc.stdout.read().strip()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -511,7 +512,7 @@ def parse_browser_specification(browser_specification):
|
|||||||
if not parts[0] or len(parts) > 2:
|
if not parts[0] or len(parts) > 2:
|
||||||
raise ValueError('invalid browser specification: "{}"'.format(browser_specification))
|
raise ValueError('invalid browser specification: "{}"'.format(browser_specification))
|
||||||
browser_name, profile = parts
|
browser_name, profile = parts
|
||||||
if _is_path(profile):
|
if profile is not None and _is_path(profile):
|
||||||
profile = os.path.expanduser(profile)
|
profile = os.path.expanduser(profile)
|
||||||
return browser_name, profile
|
return browser_name, profile
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user