mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-18 04:20:57 +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