Compare commits

..

2 commits

Author SHA1 Message Date
9a79f8d3d0
feat(core): improved checkPassword method
All checks were successful
Tests / test-node (node22) (push) Successful in 1m48s
Tests / test-node (node18) (push) Successful in 1m53s
Tests / test-bun (push) Successful in 1m51s
Tests / test-deno (push) Successful in 1m49s
Tests / test-node (node20) (push) Successful in 1m55s
Tests / test-web (chromium) (push) Successful in 1m54s
Tests / test-web (firefox) (push) Successful in 1m21s
Docs / build (push) Successful in 6m15s
Tests / lint (push) Successful in 6m55s
Tests / e2e-deno (push) Successful in 50s
Tests / e2e (push) Successful in 47s
2025-01-11 04:41:30 +03:00
9fe04a904b
fix(core): fixed error propagation 2025-01-11 04:37:26 +03:00
7 changed files with 60 additions and 39 deletions

View file

@ -70,6 +70,13 @@ export class BaseTelegramClient implements ITelegramClient {
this.mt = new MtClient({
...this.params,
logger: this.log.create('mtproto'),
onError: (err) => {
if (this.onError.length > 0) {
this.onError.emit(unknownToError(err))
} else if (this._connect.finished()) {
this.log.error('unhandled error:', err)
}
},
})
if (!params.disableUpdates && params.updates !== false) {

View file

@ -393,11 +393,20 @@ export interface TelegramClient extends ITelegramClient {
*
* **Available**: 👤 users only
*
* @param password Your Two-Step verification password
* @returns The authorized user
* @throws BadRequestError In case the password is invalid
*/
checkPassword(password: string): Promise<User>
checkPassword(
options: string | {
/** Your Two-Step verification password */
password: string
/** Existing response from `account.getPassword`, if available (to avoid extra API calls) */
passwordObj?: tl.account.TypePassword
/** Abort signal */
abortSignal?: AbortSignal
}): Promise<User>
/**
* Get your Two-Step Verification password hint.
*
@ -4543,7 +4552,9 @@ export interface TelegramClient extends ITelegramClient {
* @returns Whether the action was successful
*/
acceptStarGift(
params: InputMessageId & {
params: {
/** ID of the message containing the gift */
message: number | Message
/**
* Action to perform on the gift.
* - `save` - save the gift to your profile

View file

@ -1,3 +1,4 @@
import type { tl } from '@mtcute/tl'
import type { ITelegramClient } from '../../client.types.js'
import type { User } from '../../types/index.js'
@ -6,20 +7,34 @@ import { _onAuthorization } from './utils.js'
/**
* Check your Two-Step verification password and log in
*
* @param password Your Two-Step verification password
* @returns The authorized user
* @throws BadRequestError In case the password is invalid
*/
export async function checkPassword(client: ITelegramClient, password: string): Promise<User> {
export async function checkPassword(
client: ITelegramClient,
options: string | {
/** Your Two-Step verification password */
password: string
/** Existing response from `account.getPassword`, if available (to avoid extra API calls) */
passwordObj?: tl.account.TypePassword
/** Abort signal */
abortSignal?: AbortSignal
},
): Promise<User> {
const opts = typeof options === 'string' ? { password: options } : options
const passwordObj = opts.passwordObj ?? await client.call({
_: 'account.getPassword',
}, { abortSignal: opts.abortSignal })
const res = await client.call({
_: 'auth.checkPassword',
password: await client.computeSrpParams(
await client.call({
_: 'account.getPassword',
}),
password,
passwordObj,
opts.password,
),
})
}, { abortSignal: opts.abortSignal })
return _onAuthorization(client, res)
}

View file

@ -76,7 +76,10 @@ export async function signInQr(
const password = await resolveMaybeDynamic(input)
try {
return await checkPassword(client, password)
return await checkPassword(client, {
password,
abortSignal,
})
} catch (e) {
if (tl.RpcError.is(e, 'PASSWORD_HASH_INVALID')) {
if (!isDynamic) {

View file

@ -266,7 +266,10 @@ export async function start(
const password = await resolveMaybeDynamic(params.password)
try {
return await checkPassword(client, password)
return await checkPassword(client, {
password,
abortSignal,
})
} catch (e) {
if (typeof params.password !== 'function') {
throw new MtArgumentError('Provided password was invalid')

View file

@ -213,8 +213,6 @@ export class MtClient {
return res
})
private _emitError?: (err: unknown) => void
readonly log: Logger
readonly network: NetworkManager
@ -226,7 +224,7 @@ export class MtClient {
readonly onNetworkChanged: Emitter<boolean> = new Emitter()
readonly onUpdate: Emitter<tl.TypeUpdates> = new Emitter()
constructor(readonly params: MtClientOptions) {
constructor(readonly params: MtClientOptions & { onError: (err: unknown) => void }) {
this.log = params.logger ?? new LogManager(undefined, params.platform)
if (params.logLevel !== undefined) {
@ -278,7 +276,7 @@ export class MtClient {
storage: this.storage,
testMode: Boolean(params.testMode),
transport: params.transport,
emitError: this.emitError.bind(this),
emitError: params.onError,
isPremium: false,
useIpv6: Boolean(params.useIpv6),
enableErrorReporting: params.enableErrorReporting ?? false,
@ -294,14 +292,6 @@ export class MtClient {
)
}
emitError(err: unknown): void {
if (this._emitError) {
this._emitError(err)
} else if (this._connect.finished()) {
this.log.error('unhandled error:', err)
}
}
private _prepare = asyncResettable(async () => {
await this.crypto.initialize?.()
await this.storage.load()
@ -375,13 +365,4 @@ export class MtClient {
): Promise<tl.RpcCallReturn[T['_']] | mtp.RawMt_rpc_error> {
return this.network.call(message, params)
}
/**
* Register an error handler for the client
*
* @param handler Error handler.
*/
onError(handler: (err: unknown) => void): void {
this._emitError = handler
}
}

View file

@ -275,6 +275,7 @@ export class SessionConnection extends PersistentConnection {
// there happened a little trolling
this.log.warn('transport error 404, reauthorizing')
this.onError.emit(error)
this._session.resetAuthKey()
this._resetSession()
this.onKeyChange.emit(null)