fix(core): gracefully handle wrong password in qr login
This commit is contained in:
parent
323bdb2ad9
commit
4d9e089643
3 changed files with 50 additions and 2 deletions
|
@ -732,6 +732,14 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
/** Password for 2FA */
|
/** Password for 2FA */
|
||||||
password?: MaybeDynamic<string>
|
password?: MaybeDynamic<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that will be called after the server has rejected the password.
|
||||||
|
*
|
||||||
|
* Note that in case {@link password} is not a function,
|
||||||
|
* this callback will never be called, and an error will be thrown instead.
|
||||||
|
*/
|
||||||
|
invalidPasswordCallback?: () => MaybePromise<void>
|
||||||
|
|
||||||
/** Abort signal */
|
/** Abort signal */
|
||||||
abortSignal?: AbortSignal
|
abortSignal?: AbortSignal
|
||||||
}): Promise<User>
|
}): Promise<User>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import { getPlatform } from '../../../platform.js'
|
import { getPlatform } from '../../../platform.js'
|
||||||
|
import { MaybePromise } from '../../../types/utils.js'
|
||||||
import { ControllablePromise, createControllablePromise } from '../../../utils/controllable-promise.js'
|
import { ControllablePromise, createControllablePromise } from '../../../utils/controllable-promise.js'
|
||||||
import { sleepWithAbort } from '../../../utils/misc-utils.js'
|
import { sleepWithAbort } from '../../../utils/misc-utils.js'
|
||||||
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
@ -29,6 +30,14 @@ export async function signInQr(
|
||||||
/** Password for 2FA */
|
/** Password for 2FA */
|
||||||
password?: MaybeDynamic<string>
|
password?: MaybeDynamic<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that will be called after the server has rejected the password.
|
||||||
|
*
|
||||||
|
* Note that in case {@link password} is not a function,
|
||||||
|
* this callback will never be called, and an error will be thrown instead.
|
||||||
|
*/
|
||||||
|
invalidPasswordCallback?: () => MaybePromise<void>
|
||||||
|
|
||||||
/** Abort signal */
|
/** Abort signal */
|
||||||
abortSignal?: AbortSignal
|
abortSignal?: AbortSignal
|
||||||
},
|
},
|
||||||
|
@ -59,6 +68,34 @@ export async function signInQr(
|
||||||
waiter?.reject(abortSignal.reason)
|
waiter?.reject(abortSignal.reason)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function handle2fa(input: MaybeDynamic<string>) {
|
||||||
|
const isDynamic = typeof input === 'function'
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const password = await resolveMaybeDynamic(input)
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await checkPassword(client, password)
|
||||||
|
} catch (e) {
|
||||||
|
if (tl.RpcError.is(e, 'PASSWORD_HASH_INVALID')) {
|
||||||
|
if (!isDynamic) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.invalidPasswordCallback) {
|
||||||
|
await params.invalidPasswordCallback?.()
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('Invalid password. Please try again')
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { id, hash } = await client.getApiCrenetials()
|
const { id, hash } = await client.getApiCrenetials()
|
||||||
const platform = getPlatform()
|
const platform = getPlatform()
|
||||||
|
@ -78,7 +115,7 @@ export async function signInQr(
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
||||||
return checkPassword(client, await resolveMaybeDynamic(params.password))
|
return handle2fa(params.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
|
@ -109,7 +146,7 @@ export async function signInQr(
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
if (tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED') && params.password) {
|
||||||
return checkPassword(client, await resolveMaybeDynamic(params.password))
|
return handle2fa(params.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
|
|
|
@ -274,6 +274,9 @@ export async function start(
|
||||||
return await signInQr(client, {
|
return await signInQr(client, {
|
||||||
onUrlUpdated: params.qrCodeHandler,
|
onUrlUpdated: params.qrCodeHandler,
|
||||||
password: params.password,
|
password: params.password,
|
||||||
|
invalidPasswordCallback: params.invalidCodeCallback ?
|
||||||
|
() => params.invalidCodeCallback!('password') :
|
||||||
|
undefined,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue