Remove requesting SMS login codes and signing up

This commit is contained in:
Tulir Asokan 2023-02-10 21:02:13 +02:00
parent acfde7132b
commit 6bb0ee081f

View File

@ -25,7 +25,7 @@ class AuthMethods:
bot_token: str = None, bot_token: str = None,
force_sms: bool = False, force_sms: bool = False,
code_callback: typing.Callable[[], typing.Union[str, int]] = None, code_callback: typing.Callable[[], typing.Union[str, int]] = None,
first_name: str = 'New User', first_name: str = '',
last_name: str = '', last_name: str = '',
max_attempts: int = 3) -> 'TelegramClient': max_attempts: int = 3) -> 'TelegramClient':
""" """
@ -34,11 +34,9 @@ class AuthMethods:
By default, this method will be interactive (asking for By default, this method will be interactive (asking for
user input if needed), and will handle 2FA if enabled too. user input if needed), and will handle 2FA if enabled too.
If the phone doesn't belong to an existing account (and will hence If the phone doesn't belong to an existing account, an error
`sign_up` for a new one), **you are agreeing to Telegram's will be raised, as Telegram requires using an official mobile
Terms of Service. This is required and your account client for signing up.
will be banned otherwise.** See https://telegram.org/tos
and https://core.telegram.org/api/terms.
If the event loop is already running, this method returns a If the event loop is already running, this method returns a
coroutine that you should await on your own code; otherwise coroutine that you should await on your own code; otherwise
@ -62,8 +60,8 @@ class AuthMethods:
one of either allowed). one of either allowed).
force_sms (`bool`, optional): force_sms (`bool`, optional):
Whether to force sending the code request as SMS. Deprecated: third-party clients aren't allowed to request SMS anymore.
This only makes sense when signing in with a `phone`. This parameter does nothing.
code_callback (`callable`, optional): code_callback (`callable`, optional):
A callable that will be used to retrieve the Telegram A callable that will be used to retrieve the Telegram
@ -71,11 +69,12 @@ class AuthMethods:
The argument may be a coroutine. The argument may be a coroutine.
first_name (`str`, optional): first_name (`str`, optional):
The first name to be used if signing up. This has no Deprecated: Signing up is no longer supported.
effect if the account already exists and you sign in. This parameter does nothing.
last_name (`str`, optional): 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): max_attempts (`int`, optional):
How many times the code/password callback should be How many times the code/password callback should be
@ -103,6 +102,10 @@ class AuthMethods:
with client: with client:
pass 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: if code_callback is None:
def code_callback(): def code_callback():
return input('Please enter the code you received: ') return input('Please enter the code you received: ')
@ -123,10 +126,7 @@ class AuthMethods:
phone=phone, phone=phone,
password=password, password=password,
bot_token=bot_token, bot_token=bot_token,
force_sms=force_sms,
code_callback=code_callback, code_callback=code_callback,
first_name=first_name,
last_name=last_name,
max_attempts=max_attempts max_attempts=max_attempts
) )
return ( return (
@ -135,8 +135,8 @@ class AuthMethods:
) )
async def _start( async def _start(
self: 'TelegramClient', phone, password, bot_token, force_sms, self: 'TelegramClient', phone, password, bot_token,
code_callback, first_name, last_name, max_attempts): code_callback, max_attempts):
if not self.is_connected(): if not self.is_connected():
await self.connect() await self.connect()
@ -187,8 +187,7 @@ class AuthMethods:
attempts = 0 attempts = 0
two_step_detected = False two_step_detected = False
await self.send_code_request(phone, force_sms=force_sms) await self.send_code_request(phone)
sign_up = False # assume login
while attempts < max_attempts: while attempts < max_attempts:
try: try:
value = code_callback() value = code_callback()
@ -201,19 +200,14 @@ class AuthMethods:
if not value: if not value:
raise errors.PhoneCodeEmptyError(request=None) raise errors.PhoneCodeEmptyError(request=None)
if sign_up:
me = await self.sign_up(value, first_name, last_name)
else:
# Raises SessionPasswordNeededError if 2FA enabled # Raises SessionPasswordNeededError if 2FA enabled
me = await self.sign_in(phone, code=value) me = await self.sign_in(phone, code=value)
break break
except errors.SessionPasswordNeededError: except errors.SessionPasswordNeededError:
two_step_detected = True two_step_detected = True
break break
except errors.PhoneNumberOccupiedError:
sign_up = False
except errors.PhoneNumberUnoccupiedError: except errors.PhoneNumberUnoccupiedError:
sign_up = True raise RuntimeError("Phone number not registered. Sign up using an official mobile client first.")
except (errors.PhoneCodeEmptyError, except (errors.PhoneCodeEmptyError,
errors.PhoneCodeExpiredError, errors.PhoneCodeExpiredError,
errors.PhoneCodeHashEmptyError, errors.PhoneCodeHashEmptyError,
@ -374,101 +368,6 @@ class AuthMethods:
return await self._on_login(result.user) 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): async def _on_login(self, user):
""" """
Callback called whenever the login or sign up process completes. 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. The phone to which the code will be sent.
force_sms (`bool`, optional): 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 Returns
An instance of :tl:`SentCode`. An instance of :tl:`SentCode`.
@ -510,11 +410,10 @@ class AuthMethods:
sent = await client.send_code_request(phone) sent = await client.send_code_request(phone)
print(sent) 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 = utils.parse_phone(phone) or self._phone
phone_hash = self._phone_code_hash.get(phone)
if not phone_hash:
try: try:
result = await self(functions.auth.SendCodeRequest( result = await self(functions.auth.SendCodeRequest(
phone, self.api_id, self.api_hash, types.CodeSettings())) phone, self.api_id, self.api_hash, types.CodeSettings()))
@ -522,43 +421,18 @@ class AuthMethods:
if _retry_count > 2: if _retry_count > 2:
raise raise
return await self.send_code_request( return await self.send_code_request(
phone, force_sms=force_sms, _retry_count=_retry_count+1) phone, _retry_count=_retry_count+1)
# TODO figure out when/if/how this can happen # TODO figure out when/if/how this can happen
if isinstance(result, types.auth.SentCodeSuccess): if isinstance(result, types.auth.SentCodeSuccess):
raise RuntimeError('logged in right after sending the code') 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) # phone_code_hash may be empty, if it is, do not save it (#1283)
if result.phone_code_hash: if result.phone_code_hash:
self._phone_code_hash[phone] = phone_hash = result.phone_code_hash self._phone_code_hash[phone] = result.phone_code_hash
else:
force_sms = True
self._phone = phone 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 return result
async def qr_login(self: 'TelegramClient', ignored_ids: typing.List[int] = None) -> custom.QRLogin: async def qr_login(self: 'TelegramClient', ignored_ids: typing.List[int] = None) -> custom.QRLogin: