Remove phone and hash from sign in

This commit is contained in:
Lonami Exo 2022-02-16 12:54:41 +01:00
parent df0e710fa1
commit 90bd5de74a
6 changed files with 47 additions and 66 deletions

View File

@ -978,3 +978,7 @@ todo update send_message and send_file docs (well review all functions)
album overhaul. use a list of Message instead. album overhaul. use a list of Message instead.
is_connected is now a property (consistent with the rest of ``is_`` properties) is_connected is now a property (consistent with the rest of ``is_`` properties)
send_code_request now returns a custom type (reducing raw api).
sign_in no longer has phone or phone_hash (these are impl details, and now it's less error prone). also mandatory code=. also no longer is a no-op if already logged in. different error for sign up required.
send code / sign in now only expect a single phone. resend code with new phone is send code, not resend.

View File

@ -196,43 +196,22 @@ async def _start(
return self return self
def _parse_phone_and_hash(self, phone, phone_hash):
"""
Helper method to both parse and validate phone and its hash.
"""
phone = utils.parse_phone(phone) or self._phone
if not phone:
raise ValueError(
'Please make sure to call send_code_request first.'
)
phone_hash = phone_hash or self._phone_code_hash.get(phone, None)
if not phone_hash:
raise ValueError('You also need to provide a phone_code_hash.')
return phone, phone_hash
async def sign_in( async def sign_in(
self: 'TelegramClient', self: 'TelegramClient',
phone: str = None,
code: typing.Union[str, int] = None,
*, *,
code: typing.Union[str, int] = None,
password: str = None, password: str = None,
bot_token: str = None, bot_token: str = None,) -> 'typing.Union[_tl.User, _tl.auth.SentCode]':
phone_code_hash: str = None) -> 'typing.Union[_tl.User, _tl.auth.SentCode]': if code:
me = await self.get_me() if not self._phone_code_hash:
if me: raise ValueError('Must call client.send_code_request before sign in')
return me
if phone and code: phone, phone_code_hash = self._phone_code_hash
phone, phone_code_hash = \
_parse_phone_and_hash(self, phone, phone_code_hash)
# May raise PhoneCodeEmptyError, PhoneCodeExpiredError, # May raise PhoneCodeEmptyError, PhoneCodeExpiredError,
# PhoneCodeHashEmptyError or PhoneCodeInvalidError. # PhoneCodeHashEmptyError or PhoneCodeInvalidError.
request = _tl.fn.auth.SignIn( request = _tl.fn.auth.SignIn(*self._phone_code_hash, str(code))
phone, phone_code_hash, str(code)
)
elif password: elif password:
pwd = await self(_tl.fn.account.GetPassword()) pwd = await self(_tl.fn.account.GetPassword())
request = _tl.fn.auth.CheckPassword( request = _tl.fn.auth.CheckPassword(
@ -244,13 +223,13 @@ async def sign_in(
api_id=self._api_id, api_hash=self._api_hash api_id=self._api_id, api_hash=self._api_hash
) )
else: else:
raise ValueError('You must provide either phone and code, password, or bot_token.') raise ValueError('You must provide code, password, or bot_token.')
result = await self(request) result = await self(request)
if isinstance(result, _tl.auth.AuthorizationSignUpRequired): if isinstance(result, _tl.auth.AuthorizationSignUpRequired):
# Emulate pre-layer 104 behaviour # The method must return the User but we don't have it, so raise instead (matches pre-layer 104 behaviour)
self._tos = result.terms_of_service self._tos = result.terms_of_service
raise errors.PhoneNumberUnoccupiedError(request=request) raise errors.SignUpRequired()
return await _update_session_state(self, result.user) return await _update_session_state(self, result.user)
@ -287,8 +266,10 @@ async def sign_up(
sys.stderr.write("{}\n".format(self._tos.text)) sys.stderr.write("{}\n".format(self._tos.text))
sys.stderr.flush() sys.stderr.flush()
phone, phone_code_hash = \ if not self._phone_code_hash:
_parse_phone_and_hash(self, phone, phone_code_hash) raise ValueError('Must call client.send_code_request before sign up')
phone, phone_code_hash = self._phone_code_hash
result = await self(_tl.fn.auth.SignUp( result = await self(_tl.fn.auth.SignUp(
phone_number=phone, phone_number=phone,
@ -321,6 +302,7 @@ async def _update_session_state(self, user, save=True):
seq=state.seq, seq=state.seq,
) )
self._phone_code_hash = None
return user return user
@ -336,15 +318,10 @@ async def _replace_session_state(self, *, save=True, **changes):
async def send_code_request( async def send_code_request(
self: 'TelegramClient', self: 'TelegramClient',
phone: str) -> 'SentCode': phone: str) -> 'SentCode':
result = None phone = utils.parse_phone(phone)
phone = utils.parse_phone(phone) or self._phone
phone_hash = self._phone_code_hash.get(phone)
if phone_hash: if self._phone_code_hash and phone == self._phone_code_hash[0]:
result = await self( result = await self(_tl.fn.auth.ResendCode(*self._phone_code_hash))
_tl.fn.auth.ResendCode(phone, phone_hash))
self._phone_code_hash[phone] = result.phone_code_hash
else: else:
try: try:
result = await self(_tl.fn.auth.SendCode( result = await self(_tl.fn.auth.SendCode(
@ -353,13 +330,14 @@ async def send_code_request(
return await self.send_code_request(phone) return await self.send_code_request(phone)
# 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 not result.phone_code_hash:
self._phone_code_hash[phone] = phone_hash = result.phone_code_hash # The hash is required to login, so this pretty much means send code failed
raise ValueError('Failed to send code')
self._phone = phone
self._phone_code_hash = (phone, result.phone_code_hash)
return _custom.SentCode._new(result) return _custom.SentCode._new(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:
qr_login = _custom.QRLogin(self, ignored_ids or []) qr_login = _custom.QRLogin(self, ignored_ids or [])
await qr_login.recreate() await qr_login.recreate()

View File

@ -141,7 +141,7 @@ def init(
self._connect_timeout = connect_timeout self._connect_timeout = connect_timeout
self.flood_sleep_threshold = flood_sleep_threshold self.flood_sleep_threshold = flood_sleep_threshold
self._flood_waited_requests = {} # prevent calls that would floodwait entirely self._flood_waited_requests = {} # prevent calls that would floodwait entirely
self._phone_code_hash = {} # used during login to prevent exposing the hash to end users self._phone_code_hash = None # used during login to prevent exposing the hash to end users
# Update handling. # Update handling.
self._catch_up = catch_up self._catch_up = catch_up

View File

@ -395,12 +395,10 @@ class TelegramClient:
@forward_call(auth.sign_in) @forward_call(auth.sign_in)
async def sign_in( async def sign_in(
self: 'TelegramClient', self: 'TelegramClient',
phone: str = None,
code: typing.Union[str, int] = None,
*, *,
code: typing.Union[str, int] = None,
password: str = None, password: str = None,
bot_token: str = None, bot_token: str = None) -> 'typing.Union[_tl.User, _tl.auth.SentCode]':
phone_code_hash: str = None) -> 'typing.Union[_tl.User, _tl.auth.SentCode]':
""" """
Logs in to Telegram to an existing user or bot account. Logs in to Telegram to an existing user or bot account.
@ -411,16 +409,13 @@ class TelegramClient:
In most cases, you should simply use `start()` and not this method. In most cases, you should simply use `start()` and not this method.
Arguments Arguments
phone (`str` | `int`):
The phone to send the code to if no code was provided,
or to override the phone that was previously used with
these requests.
code (`str` | `int`): code (`str` | `int`):
The code that Telegram sent. Note that if you have sent this The code that Telegram sent.
code through the application itself it will immediately
expire. If you want to send the code, obfuscate it somehow. To login to a user account, you must use `client.send_code_request` first.
If you're not doing any of this you can ignore this note.
The code will expire immediately if you send it through the application itself
as a safety measure.
password (`str`): password (`str`):
2FA password, should be used if a previous call raised 2FA password, should be used if a previous call raised
@ -431,22 +426,19 @@ class TelegramClient:
This should be the hash the `@BotFather <https://t.me/BotFather>`_ This should be the hash the `@BotFather <https://t.me/BotFather>`_
gave you. gave you.
phone_code_hash (`str`, optional): You do not need to call `client.send_code_request` to login to a bot account.
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 Returns
The signed in user, or the information about The signed in `User`, if the method did not fail.
:meth:`send_code_request`.
Example Example
.. code-block:: python .. code-block:: python
phone = '+34 123 123 123' phone = '+34 123 123 123'
await client.sign_in(phone) # send code await client.send_code_request(phone) # send code
code = input('enter code: ') code = input('enter code: ')
await client.sign_in(phone, code) await client.sign_in(code=code)
""" """
@forward_call(auth.sign_up) @forward_call(auth.sign_up)

View File

@ -7,6 +7,7 @@ from ._custom import (
CdnFileTamperedError, CdnFileTamperedError,
BadMessageError, BadMessageError,
MultiError, MultiError,
SignUpRequired,
) )
from ._rpcbase import ( from ._rpcbase import (
RpcError, RpcError,

View File

@ -150,3 +150,9 @@ class MultiError(Exception):
self.results = list(result) self.results = list(result)
self.requests = list(requests) self.requests = list(requests)
return self return self
class SignUpRequired(Exception):
"""
Occurs when trying to sign in with a phone number that doesn't have an account registered yet.
"""