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.mt = new MtClient({
...this.params, ...this.params,
logger: this.log.create('mtproto'), 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) { if (!params.disableUpdates && params.updates !== false) {

View file

@ -393,11 +393,20 @@ export interface TelegramClient extends ITelegramClient {
* *
* **Available**: 👤 users only * **Available**: 👤 users only
* *
* @param password Your Two-Step verification password
* @returns The authorized user * @returns The authorized user
* @throws BadRequestError In case the password is invalid * @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. * Get your Two-Step Verification password hint.
* *
@ -4543,7 +4552,9 @@ export interface TelegramClient extends ITelegramClient {
* @returns Whether the action was successful * @returns Whether the action was successful
*/ */
acceptStarGift( acceptStarGift(
params: InputMessageId & { params: {
/** ID of the message containing the gift */
message: number | Message
/** /**
* Action to perform on the gift. * Action to perform on the gift.
* - `save` - save the gift to your profile * - `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 { ITelegramClient } from '../../client.types.js'
import type { User } from '../../types/index.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 * Check your Two-Step verification password and log in
* *
* @param password Your Two-Step verification password
* @returns The authorized user * @returns The authorized user
* @throws BadRequestError In case the password is invalid * @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({ const res = await client.call({
_: 'auth.checkPassword', _: 'auth.checkPassword',
password: await client.computeSrpParams( password: await client.computeSrpParams(
await client.call({ passwordObj,
_: 'account.getPassword', opts.password,
}),
password,
), ),
}) }, { abortSignal: opts.abortSignal })
return _onAuthorization(client, res) return _onAuthorization(client, res)
} }

View file

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

View file

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

View file

@ -213,8 +213,6 @@ export class MtClient {
return res return res
}) })
private _emitError?: (err: unknown) => void
readonly log: Logger readonly log: Logger
readonly network: NetworkManager readonly network: NetworkManager
@ -226,7 +224,7 @@ export class MtClient {
readonly onNetworkChanged: Emitter<boolean> = new Emitter() readonly onNetworkChanged: Emitter<boolean> = new Emitter()
readonly onUpdate: Emitter<tl.TypeUpdates> = 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) this.log = params.logger ?? new LogManager(undefined, params.platform)
if (params.logLevel !== undefined) { if (params.logLevel !== undefined) {
@ -278,7 +276,7 @@ export class MtClient {
storage: this.storage, storage: this.storage,
testMode: Boolean(params.testMode), testMode: Boolean(params.testMode),
transport: params.transport, transport: params.transport,
emitError: this.emitError.bind(this), emitError: params.onError,
isPremium: false, isPremium: false,
useIpv6: Boolean(params.useIpv6), useIpv6: Boolean(params.useIpv6),
enableErrorReporting: params.enableErrorReporting ?? false, 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 () => { private _prepare = asyncResettable(async () => {
await this.crypto.initialize?.() await this.crypto.initialize?.()
await this.storage.load() await this.storage.load()
@ -375,13 +365,4 @@ export class MtClient {
): Promise<tl.RpcCallReturn[T['_']] | mtp.RawMt_rpc_error> { ): Promise<tl.RpcCallReturn[T['_']] | mtp.RawMt_rpc_error> {
return this.network.call(message, params) 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 // there happened a little trolling
this.log.warn('transport error 404, reauthorizing') this.log.warn('transport error 404, reauthorizing')
this.onError.emit(error)
this._session.resetAuthKey() this._session.resetAuthKey()
this._resetSession() this._resetSession()
this.onKeyChange.emit(null) this.onKeyChange.emit(null)