mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-11-04 09:57:29 +03:00 
			
		
		
		
	Remove broken CdnDecrypter
This commit is contained in:
		
							parent
							
								
									b3c23e343a
								
							
						
					
					
						commit
						3bc46e8072
					
				| 
						 | 
				
			
			@ -249,3 +249,9 @@ The TelegramClient is no longer made out of mixins
 | 
			
		|||
If you were relying on any of the individual mixins that made up the client, such as
 | 
			
		||||
``UserMethods`` inside the ``telethon.client`` subpackage, those are now gone.
 | 
			
		||||
There is a single ``TelegramClient`` class now, containing everything you need.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CdnDecrypter has been removed
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
It was not really working and was more intended to be an implementation detail than anything else.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -428,31 +428,26 @@ def _auth_key_callback(self: 'TelegramClient', auth_key):
 | 
			
		|||
    self.session.save()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def _get_dc(self: 'TelegramClient', dc_id, cdn=False):
 | 
			
		||||
async def _get_dc(self: 'TelegramClient', dc_id):
 | 
			
		||||
    """Gets the Data Center (DC) associated to 'dc_id'"""
 | 
			
		||||
    cls = self.__class__
 | 
			
		||||
    if not cls._config:
 | 
			
		||||
        cls._config = await self(_tl.fn.help.GetConfig())
 | 
			
		||||
 | 
			
		||||
    if cdn and not self._cdn_config:
 | 
			
		||||
        cls._cdn_config = await self(_tl.fn.help.GetCdnConfig())
 | 
			
		||||
        for pk in cls._cdn_config.public_keys:
 | 
			
		||||
            rsa.add_key(pk.public_key)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        return next(
 | 
			
		||||
            dc for dc in cls._config.dc_options
 | 
			
		||||
            if dc.id == dc_id
 | 
			
		||||
            and bool(dc.ipv6) == self._use_ipv6 and bool(dc.cdn) == cdn
 | 
			
		||||
            and bool(dc.ipv6) == self._use_ipv6 and not dc.cdn
 | 
			
		||||
        )
 | 
			
		||||
    except StopIteration:
 | 
			
		||||
        self._log[__name__].warning(
 | 
			
		||||
            'Failed to get DC %s (cdn = %s) with use_ipv6 = %s; retrying ignoring IPv6 check',
 | 
			
		||||
            dc_id, cdn, self._use_ipv6
 | 
			
		||||
            'Failed to get DC %swith use_ipv6 = %s; retrying ignoring IPv6 check',
 | 
			
		||||
            dc_id, self._use_ipv6
 | 
			
		||||
        )
 | 
			
		||||
        return next(
 | 
			
		||||
            dc for dc in cls._config.dc_options
 | 
			
		||||
            if dc.id == dc_id and bool(dc.cdn) == cdn
 | 
			
		||||
            if dc.id == dc_id and not dc.cdn
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
async def _create_exported_sender(self: 'TelegramClient', dc_id):
 | 
			
		||||
| 
						 | 
				
			
			@ -538,29 +533,3 @@ async def _clean_exported_senders(self: 'TelegramClient'):
 | 
			
		|||
                # Disconnect should never raise
 | 
			
		||||
                await sender.disconnect()
 | 
			
		||||
                state.mark_disconnected()
 | 
			
		||||
 | 
			
		||||
async def _get_cdn_client(self: 'TelegramClient', cdn_redirect):
 | 
			
		||||
    """Similar to ._borrow_exported_client, but for CDNs"""
 | 
			
		||||
    # TODO Implement
 | 
			
		||||
    raise NotImplementedError
 | 
			
		||||
    session = self._exported_sessions.get(cdn_redirect.dc_id)
 | 
			
		||||
    if not session:
 | 
			
		||||
        dc = await _get_dc(self, cdn_redirect.dc_id, cdn=True)
 | 
			
		||||
        session = self.session.clone()
 | 
			
		||||
        await session.set_dc(dc.id, dc.ip_address, dc.port)
 | 
			
		||||
        self._exported_sessions[cdn_redirect.dc_id] = session
 | 
			
		||||
 | 
			
		||||
    self._log[__name__].info('Creating new CDN client')
 | 
			
		||||
    client = TelegramBaseClient(
 | 
			
		||||
        session, self.api_id, self.api_hash,
 | 
			
		||||
        proxy=self._sender.connection.conn.proxy,
 | 
			
		||||
        timeout=self._sender.connection.get_timeout()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # This will make use of the new RSA keys for this specific CDN.
 | 
			
		||||
    #
 | 
			
		||||
    # We won't be calling GetConfig because it's only called
 | 
			
		||||
    # when needed by ._get_dc, and also it's static so it's likely
 | 
			
		||||
    # set already. Avoid invoking non-CDN methods by not syncing updates.
 | 
			
		||||
    client.connect(_sync_updates=False)
 | 
			
		||||
    return client
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2761,7 +2761,6 @@ class TelegramClient:
 | 
			
		|||
 | 
			
		||||
    # Cached server configuration (with .dc_options), can be "global"
 | 
			
		||||
    _config = None
 | 
			
		||||
    _cdn_config = None
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self: 'TelegramClient',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,4 +7,3 @@ from .aes import AES
 | 
			
		|||
from .aesctr import AESModeCTR
 | 
			
		||||
from .authkey import AuthKey
 | 
			
		||||
from .factorization import Factorization
 | 
			
		||||
from .cdndecrypter import CdnDecrypter
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,104 +0,0 @@
 | 
			
		|||
"""
 | 
			
		||||
This module holds the CdnDecrypter utility class.
 | 
			
		||||
"""
 | 
			
		||||
from hashlib import sha256
 | 
			
		||||
 | 
			
		||||
from .. import _tl
 | 
			
		||||
from .._crypto import AESModeCTR
 | 
			
		||||
from ..errors import CdnFileTamperedError
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CdnDecrypter:
 | 
			
		||||
    """
 | 
			
		||||
    Used when downloading a file results in a 'FileCdnRedirect' to
 | 
			
		||||
    both prepare the redirect, decrypt the file as it downloads, and
 | 
			
		||||
    ensure the file hasn't been tampered. https://core.telegram.org/cdn
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, cdn_client, file_token, cdn_aes, cdn_file_hashes):
 | 
			
		||||
        """
 | 
			
		||||
        Initializes the CDN decrypter.
 | 
			
		||||
 | 
			
		||||
        :param cdn_client: a client connected to a CDN.
 | 
			
		||||
        :param file_token: the token of the file to be used.
 | 
			
		||||
        :param cdn_aes: the AES CTR used to decrypt the file.
 | 
			
		||||
        :param cdn_file_hashes: the hashes the decrypted file must match.
 | 
			
		||||
        """
 | 
			
		||||
        self.client = cdn_client
 | 
			
		||||
        self.file_token = file_token
 | 
			
		||||
        self.cdn_aes = cdn_aes
 | 
			
		||||
        self.cdn_file_hashes = cdn_file_hashes
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    async def prepare_decrypter(client, cdn_client, cdn_redirect):
 | 
			
		||||
        """
 | 
			
		||||
        Prepares a new CDN decrypter.
 | 
			
		||||
 | 
			
		||||
        :param client: a TelegramClient connected to the main servers.
 | 
			
		||||
        :param cdn_client: a new client connected to the CDN.
 | 
			
		||||
        :param cdn_redirect: the redirect file object that caused this call.
 | 
			
		||||
        :return: (CdnDecrypter, first chunk file data)
 | 
			
		||||
        """
 | 
			
		||||
        cdn_aes = AESModeCTR(
 | 
			
		||||
            key=cdn_redirect.encryption_key,
 | 
			
		||||
            # 12 first bytes of the IV..4 bytes of the offset (0, big endian)
 | 
			
		||||
            iv=cdn_redirect.encryption_iv[:12] + bytes(4)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # We assume that cdn_redirect.cdn_file_hashes are ordered by offset,
 | 
			
		||||
        # and that there will be enough of these to retrieve the whole file.
 | 
			
		||||
        decrypter = CdnDecrypter(
 | 
			
		||||
            cdn_client, cdn_redirect.file_token,
 | 
			
		||||
            cdn_aes, cdn_redirect.cdn_file_hashes
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        cdn_file = await cdn_client(_tl.fn.upload.GetCdnFile(
 | 
			
		||||
            file_token=cdn_redirect.file_token,
 | 
			
		||||
            offset=cdn_redirect.cdn_file_hashes[0].offset,
 | 
			
		||||
            limit=cdn_redirect.cdn_file_hashes[0].limit
 | 
			
		||||
        ))
 | 
			
		||||
        if isinstance(cdn_file, _tl.upload.CdnFileReuploadNeeded):
 | 
			
		||||
            # We need to use the original client here
 | 
			
		||||
            await client(_tl.fn.upload.ReuploadCdnFile(
 | 
			
		||||
                file_token=cdn_redirect.file_token,
 | 
			
		||||
                request_token=cdn_file.request_token
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
            # We want to always return a valid upload.CdnFile
 | 
			
		||||
            cdn_file = decrypter.get_file()
 | 
			
		||||
        else:
 | 
			
		||||
            cdn_file.bytes = decrypter.cdn_aes.encrypt(cdn_file.bytes)
 | 
			
		||||
            cdn_hash = decrypter.cdn_file_hashes.pop(0)
 | 
			
		||||
            decrypter.check(cdn_file.bytes, cdn_hash)
 | 
			
		||||
 | 
			
		||||
        return decrypter, cdn_file
 | 
			
		||||
 | 
			
		||||
    def get_file(self):
 | 
			
		||||
        """
 | 
			
		||||
        Calls GetCdnFile and decrypts its bytes.
 | 
			
		||||
        Also ensures that the file hasn't been tampered.
 | 
			
		||||
 | 
			
		||||
        :return: the CdnFile result.
 | 
			
		||||
        """
 | 
			
		||||
        if self.cdn_file_hashes:
 | 
			
		||||
            cdn_hash = self.cdn_file_hashes.pop(0)
 | 
			
		||||
            cdn_file = self.client(_tl.fn.upload.GetCdnFile(
 | 
			
		||||
                self.file_token, cdn_hash.offset, cdn_hash.limit
 | 
			
		||||
            ))
 | 
			
		||||
            cdn_file.bytes = self.cdn_aes.encrypt(cdn_file.bytes)
 | 
			
		||||
            self.check(cdn_file.bytes, cdn_hash)
 | 
			
		||||
        else:
 | 
			
		||||
            cdn_file = _tl.upload.CdnFile(bytes(0))
 | 
			
		||||
 | 
			
		||||
        return cdn_file
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def check(data, cdn_hash):
 | 
			
		||||
        """
 | 
			
		||||
        Checks the integrity of the given data.
 | 
			
		||||
        Raises CdnFileTamperedError if the integrity check fails.
 | 
			
		||||
 | 
			
		||||
        :param data: the data to be hashed.
 | 
			
		||||
        :param cdn_hash: the expected hash.
 | 
			
		||||
        """
 | 
			
		||||
        if sha256(data).digest() != cdn_hash.hash:
 | 
			
		||||
            raise CdnFileTamperedError()
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user