From 6bb0ee081fb8cc37a506f6e1c54ba62eb6af6564 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Feb 2023 21:02:13 +0200 Subject: [PATCH] Remove requesting SMS login codes and signing up --- telethon/client/auth.py | 202 ++++++++-------------------------------- 1 file changed, 38 insertions(+), 164 deletions(-) diff --git a/telethon/client/auth.py b/telethon/client/auth.py index 0198faeb..c953e801 100644 --- a/telethon/client/auth.py +++ b/telethon/client/auth.py @@ -25,7 +25,7 @@ class AuthMethods: bot_token: str = None, force_sms: bool = False, code_callback: typing.Callable[[], typing.Union[str, int]] = None, - first_name: str = 'New User', + first_name: str = '', last_name: str = '', max_attempts: int = 3) -> 'TelegramClient': """ @@ -34,11 +34,9 @@ class AuthMethods: By default, this method will be interactive (asking for user input if needed), and will handle 2FA if enabled too. - If the phone doesn't belong to an existing account (and will hence - `sign_up` for a new one), **you are agreeing to Telegram's - Terms of Service. This is required and your account - will be banned otherwise.** See https://telegram.org/tos - and https://core.telegram.org/api/terms. + If the phone doesn't belong to an existing account, an error + will be raised, as Telegram requires using an official mobile + client for signing up. If the event loop is already running, this method returns a coroutine that you should await on your own code; otherwise @@ -62,8 +60,8 @@ class AuthMethods: one of either allowed). force_sms (`bool`, optional): - Whether to force sending the code request as SMS. - This only makes sense when signing in with a `phone`. + Deprecated: third-party clients aren't allowed to request SMS anymore. + This parameter does nothing. code_callback (`callable`, optional): A callable that will be used to retrieve the Telegram @@ -71,11 +69,12 @@ class AuthMethods: The argument may be a coroutine. first_name (`str`, optional): - The first name to be used if signing up. This has no - effect if the account already exists and you sign in. + Deprecated: Signing up is no longer supported. + This parameter does nothing. last_name (`str`, optional): - Similar to the first name, but for the last. Optional. + Deprecated: Signing up is no longer supported. + This parameter does nothing. max_attempts (`int`, optional): How many times the code/password callback should be @@ -103,6 +102,10 @@ class AuthMethods: with client: pass """ + if force_sms: + warnings.warn("force_sms is deprecated and does nothing", DeprecationWarning) + if first_name or last_name: + warnings.warn("first_name and last_name are deprecated and do nothing", DeprecationWarning) if code_callback is None: def code_callback(): return input('Please enter the code you received: ') @@ -123,10 +126,7 @@ class AuthMethods: phone=phone, password=password, bot_token=bot_token, - force_sms=force_sms, code_callback=code_callback, - first_name=first_name, - last_name=last_name, max_attempts=max_attempts ) return ( @@ -135,8 +135,8 @@ class AuthMethods: ) async def _start( - self: 'TelegramClient', phone, password, bot_token, force_sms, - code_callback, first_name, last_name, max_attempts): + self: 'TelegramClient', phone, password, bot_token, + code_callback, max_attempts): if not self.is_connected(): await self.connect() @@ -187,8 +187,7 @@ class AuthMethods: attempts = 0 two_step_detected = False - await self.send_code_request(phone, force_sms=force_sms) - sign_up = False # assume login + await self.send_code_request(phone) while attempts < max_attempts: try: value = code_callback() @@ -201,19 +200,14 @@ class AuthMethods: if not value: raise errors.PhoneCodeEmptyError(request=None) - if sign_up: - me = await self.sign_up(value, first_name, last_name) - else: - # Raises SessionPasswordNeededError if 2FA enabled - me = await self.sign_in(phone, code=value) + # Raises SessionPasswordNeededError if 2FA enabled + me = await self.sign_in(phone, code=value) break except errors.SessionPasswordNeededError: two_step_detected = True break - except errors.PhoneNumberOccupiedError: - sign_up = False except errors.PhoneNumberUnoccupiedError: - sign_up = True + raise RuntimeError("Phone number not registered. Sign up using an official mobile client first.") except (errors.PhoneCodeEmptyError, errors.PhoneCodeExpiredError, errors.PhoneCodeHashEmptyError, @@ -374,101 +368,6 @@ class AuthMethods: return await self._on_login(result.user) - async def sign_up( - self: 'TelegramClient', - code: typing.Union[str, int], - first_name: str, - last_name: str = '', - *, - phone: str = None, - phone_code_hash: str = None) -> 'types.User': - """ - Signs up to Telegram as a new user account. - - Use this if you don't have an account yet. - - You must call `send_code_request` first. - - **By using this method you're agreeing to Telegram's - Terms of Service. This is required and your account - will be banned otherwise.** See https://telegram.org/tos - and https://core.telegram.org/api/terms. - - Arguments - code (`str` | `int`): - The code sent by Telegram - - first_name (`str`): - The first name to be used by the new account. - - last_name (`str`, optional) - Optional last name. - - phone (`str` | `int`, optional): - The phone to sign up. This will be the last phone used by - default (you normally don't need to set this). - - phone_code_hash (`str`, optional): - The hash returned by `send_code_request`. This can be left as - `None` to use the last hash known for the phone to be used. - - Returns - The new created :tl:`User`. - - Example - .. code-block:: python - - phone = '+34 123 123 123' - await client.send_code_request(phone) - - code = input('enter code: ') - await client.sign_up(code, first_name='Anna', last_name='Banana') - """ - me = await self.get_me() - if me: - return me - - # To prevent abuse, one has to try to sign in before signing up. This - # is the current way in which Telegram validates the code to sign up. - # - # `sign_in` will set `_tos`, so if it's set we don't need to call it - # because the user already tried to sign in. - # - # We're emulating pre-layer 104 behaviour so except the right error: - if not self._tos: - try: - return await self.sign_in( - phone=phone, - code=code, - phone_code_hash=phone_code_hash, - ) - except errors.PhoneNumberUnoccupiedError: - pass # code is correct and was used, now need to sign in - - if self._tos and self._tos.text: - if self.parse_mode: - t = self.parse_mode.unparse(self._tos.text, self._tos.entities) - else: - t = self._tos.text - sys.stderr.write("{}\n".format(t)) - sys.stderr.flush() - - phone, phone_code_hash = \ - self._parse_phone_and_hash(phone, phone_code_hash) - - result = await self(functions.auth.SignUpRequest( - phone_number=phone, - phone_code_hash=phone_code_hash, - first_name=first_name, - last_name=last_name - )) - - if self._tos: - await self( - functions.help.AcceptTermsOfServiceRequest(self._tos.id)) - - return await self._on_login(result.user) - async def _on_login(self, user): """ Callback called whenever the login or sign up process completes. @@ -498,7 +397,8 @@ class AuthMethods: The phone to which the code will be sent. force_sms (`bool`, optional): - Whether to force sending as SMS. + Deprecated: third-party clients aren't allowed to request SMS anymore. + This parameter does nothing. Returns An instance of :tl:`SentCode`. @@ -510,55 +410,29 @@ class AuthMethods: sent = await client.send_code_request(phone) print(sent) """ - result = None + if force_sms: + warnings.warn("force_sms is deprecated and does nothing", DeprecationWarning) phone = utils.parse_phone(phone) or self._phone - phone_hash = self._phone_code_hash.get(phone) - if not phone_hash: - try: - result = await self(functions.auth.SendCodeRequest( - phone, self.api_id, self.api_hash, types.CodeSettings())) - except errors.AuthRestartError: - if _retry_count > 2: - raise - return await self.send_code_request( - phone, force_sms=force_sms, _retry_count=_retry_count+1) + try: + result = await self(functions.auth.SendCodeRequest( + phone, self.api_id, self.api_hash, types.CodeSettings())) + except errors.AuthRestartError: + if _retry_count > 2: + raise + return await self.send_code_request( + phone, _retry_count=_retry_count+1) - # TODO figure out when/if/how this can happen - if isinstance(result, types.auth.SentCodeSuccess): - raise RuntimeError('logged in right after sending the code') + # TODO figure out when/if/how this can happen + if isinstance(result, types.auth.SentCodeSuccess): + raise RuntimeError('logged in right after sending the code') - # If we already sent a SMS, do not resend the code (hash may be empty) - if isinstance(result.type, types.auth.SentCodeTypeSms): - force_sms = False - - # phone_code_hash may be empty, if it is, do not save it (#1283) - if result.phone_code_hash: - self._phone_code_hash[phone] = phone_hash = result.phone_code_hash - else: - force_sms = True + # phone_code_hash may be empty, if it is, do not save it (#1283) + if result.phone_code_hash: + self._phone_code_hash[phone] = result.phone_code_hash self._phone = phone - if force_sms: - try: - result = await self( - functions.auth.ResendCodeRequest(phone, phone_hash)) - except errors.PhoneCodeExpiredError: - if _retry_count > 2: - raise - self._phone_code_hash.pop(phone, None) - self._log[__name__].info( - "Phone code expired in ResendCodeRequest, requesting a new code" - ) - return await self.send_code_request( - phone, force_sms=False, _retry_count=_retry_count+1) - - if isinstance(result, types.auth.SentCodeSuccess): - raise RuntimeError('logged in right after resending the code') - - self._phone_code_hash[phone] = result.phone_code_hash - return result async def qr_login(self: 'TelegramClient', ignored_ids: typing.List[int] = None) -> custom.QRLogin: