diff --git a/packages/core/src/base-client.ts b/packages/core/src/base-client.ts index dec5e955..e9d84a34 100644 --- a/packages/core/src/base-client.ts +++ b/packages/core/src/base-client.ts @@ -38,6 +38,7 @@ import { ITelegramStorage, MemoryStorage } from './storage' import defaultReaderMap from '@mtcute/tl/binary/reader' import defaultWriterMap from '@mtcute/tl/binary/writer' +import { readStringSession, writeStringSession } from "./utils/string-session"; export namespace BaseTelegramClient { export interface Options { @@ -444,41 +445,23 @@ export class BaseTelegramClient extends EventEmitter { ) if ((this._importForce || !this.primaryConnection.getAuthKey()) && this._importFrom) { - const buf = parseUrlSafeBase64(this._importFrom) - if (buf[0] !== 1) - throw new Error(`Invalid session string (version = ${buf[0]})`) + const data = readStringSession(this._readerMap, this._importFrom) - const reader = new TlBinaryReader(this._readerMap, buf, 1) - - const flags = reader.int() - const hasSelf = flags & 1 - - if (!(flags & 2) !== !this._testMode) { + if (data.testMode !== !this._testMode) { throw new Error( 'This session string is not for the current backend' ) } - const primaryDc = reader.object() - if (primaryDc._ !== 'dcOption') { - throw new Error( - `Invalid session string (dc._ = ${primaryDc._})` - ) + this._primaryDc = this.primaryConnection.params.dc = data.primaryDc + await this.storage.setDefaultDc(data.primaryDc) + + if (data.self) { + await this.storage.setSelf(data.self) } - this._primaryDc = this.primaryConnection.params.dc = primaryDc - await this.storage.setDefaultDc(primaryDc) - - if (hasSelf) { - const selfId = reader.int53() - const selfBot = reader.boolean() - - await this.storage.setSelf({ userId: selfId, isBot: selfBot }) - } - - const key = reader.bytes() - await this.primaryConnection.setupKeys(key) - await this.storage.setAuthKeyFor(primaryDc.id, key) + await this.primaryConnection.setupKeys(data.authKey) + await this.storage.setAuthKeyFor(data.primaryDc.id, data.authKey) await this._saveStorage(true) } @@ -968,35 +951,13 @@ export class BaseTelegramClient extends EventEmitter { if (!this.primaryConnection.getAuthKey()) throw new Error('Auth key is not generated yet') - const writer = TlBinaryWriter.alloc(this._writerMap, 512) - - const self = await this.storage.getSelf() - - const version = 1 - let flags = 0 - - if (self) { - flags |= 1 - } - - if (this._testMode) { - flags |= 2 - } - - writer.buffer[0] = version - writer.pos += 1 - - writer.int(flags) - writer.object(this._primaryDc) - - if (self) { - writer.int53(self.userId) - writer.boolean(self.isBot) - } - - writer.bytes(this.primaryConnection.getAuthKey()!) - - return encodeUrlSafeBase64(writer.result()) + return writeStringSession(this._writerMap, { + version: 1, + self: await this.storage.getSelf(), + testMode: this._testMode, + primaryDc: this._primaryDc, + authKey: this.primaryConnection.getAuthKey()!, + }) } /** diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 7dcd11ce..ca014169 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -19,3 +19,4 @@ export * from './misc-utils' export * from './peer-utils' export * from './sorted-array' export * from './tl-json' +export * from './string-session' diff --git a/packages/core/src/utils/string-session.ts b/packages/core/src/utils/string-session.ts new file mode 100644 index 00000000..3d492c88 --- /dev/null +++ b/packages/core/src/utils/string-session.ts @@ -0,0 +1,89 @@ +import { tl } from '@mtcute/tl' +import { TlBinaryReader, TlBinaryWriter, TlReaderMap, TlWriterMap } from "@mtcute/tl-runtime/dist"; +import { encodeUrlSafeBase64, parseUrlSafeBase64 } from "./buffer-utils"; +import { ITelegramStorage } from '../storage' + +export interface StringSessionData { + version: number + testMode: boolean + primaryDc: tl.TypeDcOption + self?: ITelegramStorage.SelfInfo | null + authKey: Buffer +} + +export function writeStringSession( + writerMap: TlWriterMap, + data: StringSessionData +): string { + const writer = TlBinaryWriter.alloc(writerMap, 512) + + const version = data.version + if (version !== 1) { + throw new Error(`Unsupported string session version: ${version}`) + } + + let flags = 0 + + if (data.self) { + flags |= 1 + } + + if (data.testMode) { + flags |= 2 + } + + writer.buffer[0] = version + writer.pos += 1 + + writer.int(flags) + writer.object(data.primaryDc) + + if (data.self) { + writer.int53(data.self.userId) + writer.boolean(data.self.isBot) + } + + writer.bytes(data.authKey) + + return encodeUrlSafeBase64(writer.result()) +} + +export function readStringSession(readerMap: TlReaderMap, data: string): StringSessionData { + const buf = parseUrlSafeBase64(data) + if (buf[0] !== 1) + throw new Error(`Invalid session string (version = ${buf[0]})`) + + const reader = new TlBinaryReader(readerMap, buf, 1) + + const flags = reader.int() + const hasSelf = flags & 1 + const testMode = !!(flags & 2) + + const primaryDc = reader.object() + if (primaryDc._ !== 'dcOption') { + throw new Error( + `Invalid session string (dc._ = ${primaryDc._})` + ) + } + + let self: ITelegramStorage.SelfInfo | null = null + if (hasSelf) { + const selfId = reader.int53() + const selfBot = reader.boolean() + + self = { + userId: selfId, + isBot: selfBot, + } + } + + const key = reader.bytes() + + return { + version: 1, + testMode, + primaryDc, + self, + authKey: key, + } +}