opentele2._native
The extension module compiled from the Rust core; every module of the package computes through
it. It is typed by its _native.pyi stub. Its names are lower-level than the modules above; the
guides load folders and print string sessions with them.
from opentele2._native import TData, mtcute_string_session, telethon_string_sessionThe signatures below come from _native.pyi, with read-only properties shown as attributes;
_Bytes is bytes | bytearray, _Passcode is bytes | bytearray | str and _Path is
str | os.PathLike[str].
Errors
class CoreError(Exception):
code: str
message: str
legacy_message: str
detail_code: str | None
def __init__(self, code: str, message: str, legacy_message: str | None = None) -> None: ...
def core_error_classes() -> dict[str, str]: ...Every failure of the module raises CoreError. code is the stable SCREAMING_SNAKE code (for
example TDATA_WRONG_PASSCODE or SRP_BAD_B), message the human-readable text, which may
change between releases, legacy_message the stable message of the matching
opentele2.exception class, and detail_code the code of a
context raised differently from the rest of code, such as BAD_ACCOUNTS_COUNT.
core_error_classes() maps each code to the class name raised for it.
tdata
SAVE_FAILED_MESSAGE: str
MAX_ACCOUNT_LIMIT_MESSAGE: str
TDF_MAGIC: bytes
@final
class Account:
def __new__(cls, index: int, user_id: int, main_dc: int,
keys: Iterable[tuple[int, _Bytes]], config: _Bytes | None = None) -> Account: ...
index: int # read only
user_id: int
main_dc: int
auth_key: bytes
keys: list[tuple[int, bytes]]
config: bytes | None
@final
class TData:
MAX_ACCOUNTS: int
@staticmethod
def load(path: _Path, passcode: _Passcode = b"", key_file: str | None = None) -> TData: ...
@staticmethod
def new(accounts: Sequence[Account], passcode: _Passcode = b"",
performance_mode: bool = True, active_index: int = -1,
draws: Iterable[_Bytes] | None = None) -> TData: ...
def save(self, path: _Path, performance_mode: bool | None = None,
draws: Iterable[_Bytes] | None = None) -> None: ...
def migrate(self, draws: Iterable[_Bytes] | None = None) -> bool: ...
def add_account(self, user_id: int, main_dc: int, auth_key: _Bytes) -> int: ...
accounts: list[Account] # settable
active_index: int # settable
performance_mode: bool # settable
app_version: int
local_key: bytes
passcode_key: bytes
main_account: Account | None
key_file: str # settable
legacy_key_file: bool
def load_many(requests: Iterable[_LoadRequest], threads: int | None = None) -> list[TData | CoreError]: ...
def draw_plan(operation: Literal["new", "migrate", "save"], target: TData | DrawPlanParams) -> list[int]: ...| Name | Description |
|---|---|
TData. | Loads a folder; a wrong passcode raises TDATA_BAD_DECRYPT_KEY, a missing key file TFILE_NOT_FOUND. |
TData. | A new folder for accounts, with keys from the OS random source (fixed keys in performance mode without a passcode). |
TData.save(path, ...) | Writes the folder; with performance mode on no configs files are written. |
TData.migrate() | Installs 7.3 key data in place of a pre-7.3 key file and returns whether it did. |
TData. | Adds an account at the lowest free index and returns it; a full folder raises MAX_ACCOUNT_LIMIT. |
TData.main_account | The account at the active index, else the first one. |
load_ | Loads many folders on a thread pool and returns, in input order, a TData or the CoreError of each; a request is a path or a (path, tuple. |
draw_ | The sizes of the random draws "new", "migrate" or "save" would make, for replaying recorded draws through draws. |
repr() of Account and TData never shows key bytes.
MTP config
MTP_FLAG_IPV6: int
MTP_FLAG_MEDIA_ONLY: int
MTP_FLAG_TCPO_ONLY: int
MTP_FLAG_CDN: int
MTP_FLAG_STATIC: int
MTP_FLAG_THIS_PORT_ONLY: int
MTP_FLAG_SECRET: int
def account_mtp_config(account: Account | None = None) -> MtpConfig: ...
def account_endpoints(account: Account | None = None, dc_id: int | None = None) -> Endpoints | None: ...account_mtp_config is the account’s stored config parsed, or the production default; its dict
has environment, dcs, cdn_public_keys and fields. account_endpoints gives the endpoints
of a DC (the main DC by default) by family and protocol, None for a DC the config does not list.
The flags are the endpoint bits Telegram Desktop stores. Account.MtpConfig in
opentele2.td wraps both.
Sessions
def telethon_string_session(account: Account, ipv6: bool = False) -> str: ...
def mtcute_string_session(account: Account) -> str: ...
TELETHON_SESSION_VERSION: int # 8
TELETHON_SESSION_SUFFIX: str # ".session"
TELETHON_JSON_SUFFIX: str # ".json"
def telethon_schema() -> list[TelethonTable]: ...
def telethon_session_rows(account: Account, ipv6: bool = False) -> TelethonSessionRows: ...
def session_pair_paths(base: _Path) -> tuple[str, str]: ...
def session_path(path: _Path) -> str: ...
def session_companion_json(profile: ApiProfile, extra: dict[str, Any] | None = None) -> dict[str, Any]: ...
def read_session_companion(text: str) -> tuple[ApiProfile | None, dict[str, Any]]: ...
def write_session_file(path: _Path, dc_id: int, server_address: str, port: int,
auth_key: _Bytes, takeout_id: int | None = None) -> str: ...
def read_session_file(path: _Path) -> TelethonSessionRows: ...
def py_json_text(obj: object) -> str: ...| Function | Description |
|---|---|
telethon_ | The Telethon string session (version 1) of the account’s main DC. |
mtcute_ | The mtcute v3 string session of the account. |
telethon_schema() | The tables of the version 8 .session layout, with their DDL and columns. |
telethon_ | The sessions row a .session file stores for the account. |
session_ | The .session and .json paths of a pair: one trailing .session, then one .json, is removed and each suffix added back. |
session_path(path) | path with .session appended unless it ends with it. |
session_ | The .json companion object for a profile. |
read_ | The profile (None when its keys are not in strict form) and the whole object of companion text; raises INVALID_INPUT for text that is not a session JSON. |
write_ | Writes a version 8 .session file over the bundled SQLite and returns its path. |
read_ | Reads the sessions row of a version 8 file. |
py_json_text(obj) | json., the companion’s text form. |
Profiles and devices
def profile(client: _Client, versions: _VersionsArg | None = None) -> ApiProfile: ...
def generate(client: _Client, seed: str | int | None = None,
system: _DesktopSystem | None = None,
versions: _VersionsArg | None = None) -> ApiProfile: ...
def profile_from_session_json(json: str | dict[str, Any]) -> ApiProfile: ...
def profile_to_session_json(profile: ApiProfile, extra: dict[str, Any] | None = None) -> dict[str, Any]: ...
def profiles_equal(a: ApiProfile, b: ApiProfile) -> bool: ...
def format_app_version(version: int) -> str: ...
SESSION_JSON_FIELDS: list[tuple[str, str, str | None, str | None]]
DEFAULT_EXTRA_FIELDS: list[tuple[str, str | bool | None]]
def catalog_entries(platform: _Platform) -> list[CatalogEntry]: ...
def device_models(platform: _Platform) -> list[str]: ...
def system_versions(platform: _Platform) -> list[str]: ...
WEB_BROWSER_WEIGHTS: dict[str, int]_Client is one of "TelegramDesktop", "TelegramAndroid", "TelegramAndroidX",
"TelegramIOS", "TelegramMacOS", "TelegramWeb_A", "TelegramWeb_K" and "Webogram";
_DesktopSystem is "windows", "macos" or "linux"; _Platform is "windows", "linux",
"macos", "android", "ios", "web_a" or "web_k". An ApiProfile is a dict with api_id,
api_hash, device_model, system_version, app_version, lang_code, system_lang_code and
lang_pack.
| Function | Description |
|---|---|
profile( | The default profile of a client, with versions overriding the offline versions. |
generate( | The profile API.<client>.Generate returns for seed. |
profile_ / profile_ | APIData.from_json and APIData.to_json on dicts. |
profiles_equal(a, b) | Equality on api_id, api_hash, device_model, system_version and app_version. |
format_ | A packed desktop version as text: 7003001 is "7.3.1". |
SESSION_JSON_FIELDS / DEFAULT_EXTRA_FIELDS | The profile keys of the session JSON as (key,, and the account keys as (key, default). |
catalog_entries, device_models, system_versions | A catalog’s weighted pairs, models and system versions. |
Versions
DEFAULT_TIMEOUT: float
def platform_versions(overrides: _VersionsArg | None = None) -> PlatformVersions: ...
def fetch_versions(timeout: float = ...) -> dict[str, str | int]: ...
def apply_versions_patch(versions: _VersionsArg | None,
patch: VersionsPatch | Mapping[str, str | int | None]) -> PlatformVersions: ...platform_versions is the offline set with overrides applied. fetch_versions queries the
release feeds (each request bounded by timeout seconds, DEFAULT_TIMEOUT by default) and returns
the fields that answered; it never raises for the network. apply_versions_patch writes a patch
onto a version set, leaving desktop_app_version bound to the tdata version.
Fingerprint checks
LAYER: int
STRICT_MODES: tuple[StrictMode, ...]
FINGERPRINT_CONFIG_DEFAULTS: FingerprintConfigDefaults
MSG_ID_OFFSET_MAX: int
def tz_offset(offset_seconds: int) -> float: ...
def validate_init_params(profile: ApiProfile, versions: _VersionsArg | None = None,
mode: StrictMode = "warn") -> list[Issue]: ...
def check_versions(profile: ApiProfile, versions: _VersionsArg | None = None) -> list[Issue]: ...
def issues_message(issues: Iterable[Issue]) -> str: ...
def msg_id_offset() -> int: ...
def is_valid_msg_id(msg_id: int, from_client: bool, now_unix: float) -> bool: ...
def fingerprint_config(*, strict_mode: StrictMode | None = None, auto_validate: bool | None = None,
preferred_transport: str | None = None,
warn_on_layer_mismatch: bool | None = None,
layer_override: int | None = None,
randomize_msg_id_offset: bool | None = None,
msg_id_offset: int | None = None) -> FingerprintConfig: ...
def validate_fingerprint(config: FingerprintConfig, profile: ApiProfile,
versions: _VersionsArg | None = None) -> list[Issue]: ...
def effective_layer(config: FingerprintConfig) -> int: ...
def layer_mismatch_warning(library_layer: int) -> str | None: ...An Issue is a dict with kind (UnknownLangPack, ShortLangCode, MissingRegion,
EmptyDeviceModel, EmptySystemVersion, EmptyAppVersion, ApiIdMismatch, AppVersionMajor,
AndroidSdkRange), severity (note, warning, error) and message. validate_init_params
checks a profile under a mode; check_versions is the strict version check alone;
issues_message is the text FingerprintConfig.validate_params warns or raises with. The
opentele2.fingerprint module wraps these.
Browser
SUPPORTED_BROWSERS: tuple[str, ...]
SUPPORTED_OPERATING_SYSTEMS: tuple[str, ...]
SUPPORTED_DEVICES: tuple[str, ...]
SUPPORTED_HTTP_VERSIONS: tuple[Literal["1", "2"], ...]
def generate_headers(options: HeaderOptions | None = None, *, seed: str | int | None = None,
**kwargs: Unpack[HeaderOptions]) -> dict[str, str]: ...
def generate_fingerprint(options: FingerprintOptions | None = None, *, seed: str | int | None = None,
**kwargs: Unpack[FingerprintOptions]) -> FingerprintData: ...The dict forms of opentele2.browser: HeaderOptions has
browser, os, device, locale, http_version, strict, user_agent and
request_dependent_headers; FingerprintOptions has screen, strict, mock_webrtc, slim
and header. Unsatisfiable or invalid options raise ValueError, an unknown key TypeError.
Crypto
def key_id(auth_key: _Bytes) -> int: ...
def prepare_aes_oldmtp(auth_key: _Bytes, msg_key: _Bytes, send: bool = False) -> tuple[bytes, bytes]: ...
def aes_ige_encrypt(data: _Bytes, key: _Bytes, iv: _Bytes) -> bytes: ...
def aes_ige_decrypt(data: _Bytes, key: _Bytes, iv: _Bytes) -> bytes: ...
def encrypt_local(data: _Bytes, local_key: _Bytes) -> bytes: ...
def decrypt_local(encrypted: _Bytes, local_key: _Bytes) -> bytes: ...
def create_local_key(passcode: _Passcode, salt: _Bytes) -> bytes: ...
def create_legacy_local_key(passcode: _Passcode, salt: _Bytes) -> bytes: ...
def argon2id(passcode: _Passcode, salt: _Bytes, memory_kib: int, time: int, lanes: int) -> bytes: ...
def sha1(data: _Bytes) -> bytes: ...
def sha256(data: _Bytes) -> bytes: ...
def hmac_sha256(key: _Bytes, data: _Bytes) -> bytes: ...
def pbkdf2(password: _Passcode, salt: _Bytes, iterations: int, key_len: int = 64,
digest: str = "sha512") -> bytes: ...
def factorize_pq(pq: _Bytes) -> tuple[bytes, bytes]: ...
def random_bytes(size: int) -> bytes: ...
def gzip(data: _Bytes, max_size: int | None = None) -> bytes | None: ...
def gunzip(data: _Bytes) -> bytes: ...
@final
class AesCtr:
def __new__(cls, key: _Bytes, iv: _Bytes) -> AesCtr: ...
def process(self, data: _Bytes) -> bytes: ...
cryptg: _Cryptg # encrypt_ige(data, key, iv), decrypt_ige(data, key, iv)Bad lengths raise CoreError BAD_LENGTH; pbkdf2 with zero iterations or a digest other than
sha1, sha256 and sha512 raises INVALID_INPUT. factorize_pq takes 1 to 8 big-endian bytes
and returns p <= q. AesCtr keeps its keystream across process calls. cryptg is the
cryptg 0.6.0 interface, also importable as opentele2._native.cryptg, which import opentele2
registers as the top-level cryptg when no real one is installed.
Login, session admin and consistency
def qr_login_url(token: _Bytes) -> str: ...
def srp_inputs(srp_id: int | None = None, srp_b: _Bytes | None = None) -> tuple[int, bytes]: ...
def srp_check(params: SrpParams, password: str,
exponents: Iterable[_Bytes] | None = None) -> SrpCheck: ...
def post_login_steps(lang_pack: str) -> list[PostLoginStep]: ...
def random_delay_ms(min_ms: int, max_ms: int) -> int: ...
def session_row(authorization: _Authorization) -> SessionRow: ...
def format_sessions(rows: Iterable[SessionRow]) -> str: ...
def format_table(headers: Sequence[str], rows: Sequence[Sequence[str]],
add_split: Sequence[int] | None = None) -> str: ...
def is_official_api_id(api_id: int) -> bool: ...
def consistency_checks() -> list[str]: ...
def consistency_expectations(profile: ApiProfile,
versions: _VersionsArg | None = None) -> ConsistencyExpectations: ...
def consistency_report(outcomes: Iterable[CheckOutcome]) -> ConsistencyReport: ...
def consistency_summary(results: Iterable[CheckResult]) -> str: ...
def layer_result(library_layer: int, advertised_layer: int | None = None) -> CheckResult: ...
OFFICIAL_API_IDS: tuple[int, ...]
SESSION_COLUMNS: tuple[str, ...]
LAYER_TOLERANCE: int
QR_LOGIN_ATTEMPTS: int
QR_EXPIRE_SAFETY_SECONDS: int
POST_LOGIN_STEPS: tuple[PostLoginStep, ...]| Name | Description |
|---|---|
qr_login_url(token) | tg://login?token= and the token in URL-safe base64 without padding, as Telethon’s QRLogin.url. |
srp_inputs / srp_check | The srp_id and srp_B rule and the inputCheckPasswordSRP values of Telethon’s password.compute_check; refusals raise SRP_, SRP_BAD_B or SRP_NO_GOOD_RANDOM. |
post_ | The requests an official client sends after login, with the sleep range before each. |
session_row, format_sessions, format_table | The row PrintSessions shows for an authorization, and the table it prints. |
is_ | Whether api_id is one of OFFICIAL_API_IDS (2040, 6, 21724, 10840, 2834, 2496). |
consistency_checks() | The names of the seven checks, in order. |
consistency_ | What the seven checks expect from a session with profile. |
consistency_ / consistency_ | The report and its text from one outcome per check. |
layer_ | The layer_match result: passes within LAYER_TOLERANCE (15) of LAYER. |
The module also carries the message constants and detail builders of these flows
(NO_PASSWORD_PROVIDED, FRESH_RESET_FORBIDDEN, HASH_INVALID, QR_LOGIN_TIMEOUT,
EXISTING_SESSION_KEPT, EXISTING_SESSION_REPLACED, get_config_detail, lang_pack_detail and
the rest), which the Python modules use to word their warnings and errors.