Repository: yt-dlp/yt-dlp
File: yt_dlp/cookies.py (Python)

Code before:
        """

        following the same approach as the fix in [1]: if cookies fail to decrypt then attempt to decrypt
        with an empty password. The failure detection is not the same as what chromium uses so the
        results won't be perfect

        References:
            - [1] https://chromium.googlesource.com/chromium/src/+/bbd54702284caca1f92d656fdcadf2ccca6f4165%5E%21/
                - a bugfix to try an empty password as a fallback
        """
        version = encrypted_value[:3]
        ciphertext = encrypted_value[3:]

        if version == b'v10':
            self._cookie_counts['v10'] += 1
            plaintext = _decrypt_aes_cbc(ciphertext, self._v10_key, self._logger)
            if plaintext is None:
                plaintext = _decrypt_aes_cbc(ciphertext, self._empty_key, self._logger)
            return plaintext

        elif version == b'v11':
            self._cookie_counts['v11'] += 1
            if self._v11_key is None:
                self._logger.warning('cannot decrypt v11 cookies: no key found', only_once=True)
                return None
            plaintext = _decrypt_aes_cbc(ciphertext, self._v11_key, self._logger)
            if plaintext is None:
                plaintext = _decrypt_aes_cbc(ciphertext, self._empty_key, self._logger)
            return plaintext

        else:
            self._logger.warning(f'unknown cookie version: "{version}"', only_once=True)
            self._cookie_counts['other'] += 1
            return None


class MacChromeCookieDecryptor(ChromeCookieDecryptor):
    def __init__(self, browser_keyring_name, logger):
        self._logger = logger
        password = _get_mac_keyring_password(browser_keyring_name, logger)
        self._v10_key = None if password is None else self.derive_key(password)
        self._cookie_counts = {'v10': 0, 'other': 0}

    @staticmethod
    def derive_key(password):
        # values from
        # https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/sync/os_crypt_mac.mm
        return pbkdf2_sha1(password, salt=b'saltysalt', iterations=1003, key_length=16)

    def decrypt(self, encrypted_value):
        version = encrypted_value[:3]

Review comment (bug):
it would be nice to log unknown prefixes on the other platforms as well to debug issues like https://github.com/yt-dlp/yt-dlp/issues/6880 but because mac and windows sometimes store plaintext cookies the log would be spammed with random values. In the Linux case though there is no valid reason for there to be an unknown prefix so it is helpful to log the value (eg if chromium added a v12 encryption or something)

Code after:
        """

        following the same approach as the fix in [1]: if cookies fail to decrypt then attempt to decrypt
        with an empty password. The failure detection is not the same as what chromium uses so the
        results won't be perfect

        References:
            - [1] https://chromium.googlesource.com/chromium/src/+/bbd54702284caca1f92d656fdcadf2ccca6f4165%5E%21/
                - a bugfix to try an empty password as a fallback
        """
        version = encrypted_value[:3]
        ciphertext = encrypted_value[3:]

        if version == b'v10':
            self._cookie_counts['v10'] += 1
            return _decrypt_aes_cbc_multi(ciphertext, (self._v10_key, self._empty_key), self._logger)

        elif version == b'v11':
            self._cookie_counts['v11'] += 1
            if self._v11_key is None:
                self._logger.warning('cannot decrypt v11 cookies: no key found', only_once=True)
                return None
            return _decrypt_aes_cbc_multi(ciphertext, (self._v11_key, self._empty_key), self._logger)

        else:
            self._logger.warning(f'unknown cookie version: "{version}"', only_once=True)
            self._cookie_counts['other'] += 1
            return None


class MacChromeCookieDecryptor(ChromeCookieDecryptor):
    def __init__(self, browser_keyring_name, logger):
        self._logger = logger
        password = _get_mac_keyring_password(browser_keyring_name, logger)
        self._v10_key = None if password is None else self.derive_key(password)
        self._cookie_counts = {'v10': 0, 'other': 0}

    @staticmethod
    def derive_key(password):
        # values from
        # https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/sync/os_crypt_mac.mm
        return pbkdf2_sha1(password, salt=b'saltysalt', iterations=1003, key_length=16)

    def decrypt(self, encrypted_value):
        version = encrypted_value[:3]
        ciphertext = encrypted_value[3:]

        if version == b'v10':
            self._cookie_counts['v10'] += 1
            if self._v10_key is None:
                self._logger.warning('cannot decrypt v10 cookies: no key found', only_once=True)