Skip to Content

tdata

Load, create, edit and save Telegram Desktop 7.3.1 tdata folders. A TData keeps its keys in Rust; accounts, localKey and passcodeKey copy key bytes out into new buffers.

tdata.mjs
import { loadTdata, saveTdata } from 'opentele2' const tdata = await loadTdata('tdata') // loadTdata('tdata', 'passcode') for a locked folder console.log(String(tdata), tdata.mainAccount?.userId, tdata.mainAccount?.mainDc) await saveTdata(tdata, 'tdata_copy')

Functions

index.d.ts
function loadTdata(path: string, passcode?: string | Uint8Array | null, keyFile?: string | null): Promise<TData> function loadMany(requests: Array<string | LoadRequest>, threads?: number | null): Promise<Array<TData | Error>> function newTdata(accounts: Array<AccountInput>, passcode?: string | Uint8Array | null, performanceMode?: boolean | null, activeIndex?: number | null, draws?: Array<Uint8Array> | null): Promise<TData> function saveTdata(tdata: TData, path: string, performanceMode?: boolean | null, draws?: Array<Uint8Array> | null): Promise<void> function migrateTdata(tdata: TData, draws?: Array<Uint8Array> | null): Promise<boolean> function addTdataAccount(tdata: TData, userId: bigint, mainDc: number, authKey: Uint8Array): number function setTdataAccounts(tdata: TData, accounts: Array<AccountInput>): void function drawPlan(operation: 'new' | 'migrate' | 'save', target: TData | NewDrawPlan): Array<number>
FunctionDescription
loadTdata(path, passcode, keyFile)Loads the folder; a string passcode is UTF-8 encoded and keyFile defaults to "data". A wrong passcode rejects with OT_TDATA_BAD_DECRYPT_KEY, a missing folder with OT_TFILE_NOT_FOUND.
loadMany(requests, threads)Loads many folders on a dedicated thread pool and resolves, in input order, to a TData or the Error of each; threads caps the pool (about 64 MiB of Argon2id memory per thread).
newTdata(accounts, ...)A new folder for accounts the way SaveTData creates one, keys from the OS random source; performanceMode (default true) skips the configs files, activeIndex defaults to -1.
saveTdata(tdata, path, performanceMode)Writes the folder into path; performanceMode applies to this save only.
migrateTdata(tdata)Installs 7.3 key data in place of a pre-7.3 key file, as the first save would, and resolves to whether it did; a 7.3 key file is left alone.
addTdataAccount(tdata, userId, mainDc, authKey)Adds an account with authKey as the key of mainDc at the lowest free index and returns it; a full folder throws OT_MAX_ACCOUNT_LIMIT, a key that is not 256 bytes OT_BAD_LENGTH.
setTdataAccounts(tdata, accounts)Replaces the accounts later saves write, keeping the local key; more than TDATA_MAX_ACCOUNTS (or than were loaded) throw OT_MAX_ACCOUNT_LIMIT, two of one index OT_TDATA_SAVE_FAILED.
drawPlan(operation, target)The sizes of the random draws an operation will make, so recorded draws can be replayed through draws; nothing is drawn or written.

draws, a testing hook, replaces the OS random source with exactly these byte arrays in order; a draw of another size, a missing draw or an unused one rejects with ERR_INVALID_ARG_VALUE.

TData

index.d.ts
class TData { get accounts(): Array<Account> get activeIndex(): number set activeIndex(value: number) get performanceMode(): boolean set performanceMode(value: boolean) get appVersion(): number get localKey(): Buffer get passcodeKey(): Buffer get mainAccount(): Account | null get keyFile(): string set keyFile(value: string) get legacyKeyFile(): boolean toString(): string }
MemberDescription
accountsThe accounts, in accounts-info order.
activeIndexThe active index stored in the accounts info; saving writes it.
performanceModeWhen on, saving writes no configs files; loading turns it on.
appVersionThe Telegram Desktop version in the key file’s TDF$ header; saving always writes 7003001.
localKeyThe 256-byte local key every file but the key file is encrypted with.
passcodeKeyThe 256-byte open or passcode key the local key is wrapped under.
mainAccountThe account at the active index, else the first one; null without accounts.
keyFileThe key file data name; setting it renames the key file and account files of later saves, and an empty name throws OT_TDATA_SAVE_FAILED.
legacyKeyFileWhether the key file has the pre-7.3 layout.
toString()The account count and active index; never key bytes.

Accounts

index.d.ts
interface Account { index: number userId: bigint mainDc: number authKey: Buffer keys: Array<DcKey> config?: Buffer } interface AccountInput { index: number userId: bigint mainDc: number authKey?: Uint8Array keys?: Array<DcKeyInput> config?: Uint8Array } interface DcKey { dcId: number; authKey: Buffer } interface DcKeyInput { dcId: number; authKey: Uint8Array } interface LoadRequest { path: string; passcode?: string | Uint8Array; keyFile?: string } interface NewDrawPlan { hasPasscode?: boolean; performanceMode?: boolean } const TDATA_MAX_ACCOUNTS: number // 6 const TDF_MAGIC: string // "TDF$"

An AccountInput is what newTdata and the session functions take; every Account is one. With keys present, authKey is ignored; otherwise authKey is the one key, of mainDc. config is the serialized MTP config the folder stored for the account, absent when there is none.

MTP config

index.d.ts
function accountMtpConfig(account?: AccountInput | null): MtpConfig function accountEndpoints(account?: AccountInput | null, dcId?: number | null): Endpoints | null const MTP_FLAG_IPV6: number const MTP_FLAG_MEDIA_ONLY: number const MTP_FLAG_TCPO_ONLY: number const MTP_FLAG_CDN: number const MTP_FLAG_STATIC: number const MTP_FLAG_THIS_PORT_ONLY: number const MTP_FLAG_SECRET: number
tdata-types.d.ts
interface Endpoint { id: number; flags: number; ip: string; port: number; secret: Buffer } interface ProtocolEndpoints { tcp: Array<Endpoint>; http: Array<Endpoint> } interface Endpoints { ipv4: ProtocolEndpoints ipv6: ProtocolEndpoints selectedIpv4?: Endpoint selectedIpv6?: Endpoint } interface DcEndpoints { dcId: number; endpoints: Array<Endpoint> } interface RsaPublicKey { dcId: number; n: Buffer; e: Buffer } interface MtpConfig { environment: 'production' | 'test' dcs: Array<DcEndpoints> cdnPublicKeys: Array<RsaPublicKey> fields: MtpConfigFields }

accountMtpConfig is the account’s stored config parsed, or the production default when there is none, it does not parse, or no account is given. accountEndpoints gives the endpoints of dcId (the main DC by default) by family and protocol, null for a DC the config does not list. MtpConfigFields holds the scalar config fields in camelCase (chatSizeMax, editTimeLimit, internalLinksDomain, … reactionDefaultCustom as a bigint). The MTP_FLAG_* constants are the endpoint flag bits: IPv6, media only, TCP only, CDN, built-in, this port only, has a secret.

Last updated on