tdata to mtcute
Open the account of a Telegram Desktop tdata folder in mtcute : an mtcute v3
string session for the account, initConnectionOptions that make mtcute announce the Telegram
Desktop profile, and an ICryptoProvider whose every primitive runs on the opentele2 core. mtcute
runs in Node; Python and Rust can produce the same string for a Node process.
Work on a copy of the folder. The string session is the logged-in account: never share it, never commit it and keep it out of logs.
Install
pip install opentele2Python 3.8+ · abi3 wheels · works over Telethon
npm install opentele2 @mtcute/nodeopentele2/mtcute needs @mtcute/node 0.32 or newer next to opentele2
cargo add opentele2-coreAlso opentele2-browser, opentele2-versions and opentele2-grammers
Get the string session
The mtcute string session (version 3) holds the primary DC and its address, the self user id, the test-mode flag and the auth key.
from opentele2._native import TData, mtcute_string_session
folder = TData.load("tdata") # TData.load("tdata", "passcode") for a locked folder
print(mtcute_string_session(folder.main_account)) # hand this to an mtcute client in NodeThere is no mtcute in Python; use Telethon to connect from Python.
import { loadTdata } from 'opentele2'
import { toStringSession } from 'opentele2/mtcute'
const tdata = await loadTdata('tdata') // loadTdata('tdata', passcode) for a locked folder
const session = toStringSession(tdata.mainAccount)toStringSession is the same string as mtcuteStringSession from the main entry point.
use opentele2_core::session::mtcute;
use opentele2_core::tdata::TData;
fn main() -> opentele2_core::Result<()> {
let tdata = TData::load("tdata", b"", None)?;
let account = tdata.main_account().expect("folder has an account");
println!("{}", mtcute::StringSession::from_account(account, false)?.encode());
Ok(())
}There is no mtcute in Rust; use grammers to connect from Rust.
Build the client
Pass the profile’s apiId and apiHash to mtcute, initConnectionOptions(profile) as its
initConnectionOptions and createCryptoProvider() as its crypto. For a tdesktop profile the
options carry params with tz_offset, computed from the local UTC offset when they are built.
mtcute is a Node library. Python connects through Telethon, which takes the Telegram Desktop profile from opentele2's TelegramClient; Rust connects through grammers with opentele2_grammers::connection_params.
import { TelegramClient } from '@mtcute/node'
import { loadTdata, profile } from 'opentele2'
import { createCryptoProvider, initConnectionOptions, toStringSession } from 'opentele2/mtcute'
const tdata = await loadTdata('tdata')
const desktop = profile('TelegramDesktop')
const client = new TelegramClient({
apiId: desktop.apiId,
apiHash: desktop.apiHash,
initConnectionOptions: initConnectionOptions(desktop),
crypto: await createCryptoProvider(),
})
await client.importSession(toStringSession(tdata.mainAccount))
await client.connect()initConnectionOptions gives deviceModel, systemVersion, appVersion, systemLangCode,
langPack, langCode and, for tdesktop, params. Build it again before a reconnect that should
pick up a daylight saving change.
mtcute is a Node library. Python connects through Telethon, which takes the Telegram Desktop profile from opentele2's TelegramClient; Rust connects through grammers with opentele2_grammers::connection_params.
Know what the crypto provider covers
createCryptoProvider() resolves to a complete mtcute ICryptoProvider on the core: SHA-1,
SHA-256, HMAC, PBKDF2, AES-256-CTR and -IGE, pq factorisation, gzip and the OS random source. It
needs neither Node’s crypto module nor @mtcute/node, and its initialize has nothing to load.
Its gzip writes a gzip stream where mtcute’s own Node provider writes zlib. See
the crypto core.
The crypto provider is the mtcute side of the core. Telethon reaches the core through cryptg and a bridge, both set up by import opentele2; grammers runs grammers-crypto, which the core uses too.
import { createCryptoProvider } from 'opentele2/mtcute'
const crypto = await createCryptoProvider()
console.log(typeof crypto.sha256, typeof crypto.createAesIge) // function functionThe crypto provider is the mtcute side of the core. Telethon reaches the core through cryptg and a bridge, both set up by import opentele2; grammers runs grammers-crypto, which the core uses too.
Pick another device
One session should keep one device. For several accounts, give each a device of its own with
generate, seeded by an id you store with the account; the same id always gives the same device.
from opentele2.api import API
desktop = API.TelegramDesktop.Generate("windows", "my-id")
print(desktop.device_model, desktop.system_version) # Vostro 3520 Windows 11 x64import { generate } from 'opentele2'
import { initConnectionOptions } from 'opentele2/mtcute'
const desktop = generate('TelegramDesktop', 'my-id', 'windows') // seed, then the platform
console.log(desktop.deviceModel, desktop.systemVersion) // Vostro 3520 Windows 11 x64
const options = initConnectionOptions(desktop)use opentele2_core::api::{self, Versions};
fn main() -> opentele2_core::Result<()> {
let desktop = api::generate_desktop(Some("windows"), Some("my-id"), &Versions::offline())?;
println!("{} {}", desktop.device_model, desktop.system_version); // Vostro 3520 Windows 11 x64
Ok(())
}A session copied out of tdata already exists on Telegram Desktop’s device. To run it on a new
device, log a new session in by QR code instead of reusing the key: see
client to tdata, which uses qrLoginToNewClient.
Next
- Sessions: the mtcute string format and the other sessions.
- initConnection fingerprints: what
initConnectionOptionssends. - Reference: Python · Node · Rust.