Skip to Content
GuidesValidate a fingerprint

Validate a fingerprint

Before a session connects, check that what it will announce in initConnection looks like the official client it claims to be: an official api_id for the lang_pack, a believable device, a current app version and well-formed language codes. Then get the values an official client adds around those fields: tz_offset, the msg_id offset, the layer and the transport.

Note:

Validation is local: it checks values, sends nothing and needs no account. The consistency checks are the live counterpart, asking the server how it sees a session.

Build a profile

Start from an official profile, or from one with a device generated for the account. See API profiles and devices.

profile.py
from opentele2.api import API api = API.TelegramDesktop.Generate("windows", "my-id") print(api.api_id, api.device_model, api.system_version, api.app_version, api.lang_pack)

Validate the initConnection parameters

Validation always checks the lang pack, the language codes and that the device and app fields are not empty. Strict mode adds the official api_id of the lang_pack and the app version against the known versions.

validate.py
from opentele2.api import API from opentele2.fingerprint import validate_init_connection_params api = API.TelegramDesktop.Generate("windows", "my-id") print(validate_init_connection_params( api.api_id, api.device_model, api.system_version, api.app_version, api.system_lang_code, api.lang_pack, api.lang_code, strict=True, )) # [] print(validate_init_connection_params( 1, "Desktop", "Windows 11 x64", "7.3.1 x64", "en-US", "tdesktop", "en", strict=True )) # ["api_id 1 does not match lang_pack 'tdesktop' (expected 2040)"]

validate_init_connection_params returns the messages. For the issue records, use _native.validate_init_params(profile, versions, mode) on a _native.profile(...) dict.

Read the issues

Every issue has a kind, a severity and a message worded the same in all three packages.

KindCheckedMeans
UnknownLangPackalwayslang_pack is not an official pack
ShortLangCodealwayslang_code has fewer than two characters
MissingRegionalwaysan Android or iOS system_lang_code without a region (en instead of en-US)
EmptyDeviceModel, EmptySystemVersion, EmptyAppVersionalwaysa device or app field is empty
ApiIdMismatchstrictapi_id is not the official id of the lang_pack
AppVersionMajorstrictthe app version’s major differs from the known one
AndroidSdkRangestrictthe Android SDK level is outside the known range

The mode sets the severity, and in Python what FingerprintConfig.validate_params does: off gives notes, warn (the default) warnings through warnings.warn, strict errors raised as ValueError. issues_message / issuesMessage joins issues into that text.

config.py
from opentele2.fingerprint import FingerprintConfig, StrictMode params = dict( api_id=1, device_model="Desktop", system_version="Windows 11 x64", app_version="7.3.1 x64", system_lang_code="en-US", lang_pack="tdesktop", lang_code="en", ) try: FingerprintConfig(strict_mode=StrictMode.STRICT).validate_params(**params) except ValueError as error: print(error) # initConnection fingerprint issues: # - api_id 1 does not match lang_pack 'tdesktop' (expected 2040)

The opentele2 TelegramClient runs validate_params with its fingerprint_config when it is built, so in warn mode a bad profile shows up as a warning. To stop before connecting, call validate_params in strict mode yourself, as above.

Note:

Strict validation compares the app version with a versions record. Validate a profile against the versions it was built with; see Live client versions. check_versions / checkVersions runs that comparison alone.

Get tz_offset

Telegram Desktop sends the local UTC offset in seconds as params.tz_offset, wrapped by whole days into −12 h … +14 h and rounded to a multiple of 900 seconds.

tz.py
from opentele2 import _native from opentele2.fingerprint import tdesktop_tz_offset print(tdesktop_tz_offset()) # this machine's offset, for example 10800.0 print(_native.tz_offset(3 * 3600 + 1000)) # 11700.0

The opentele2 TelegramClient sends it for the tdesktop lang pack and recomputes it on every connect().

Get a msg_id offset

Official clients add a small random offset to their message ids. Draw one in 0..=0xFFFF from the operating system’s random source, and check whether an id is plausible: positive, odd from the client and even from the server, with its upper 32 bits within 300 seconds of now.

msg_id.py
import time from opentele2.fingerprint import generate_msg_id_offset, is_valid_msg_id print(generate_msg_id_offset()) # 0..65535; random.seed does not reproduce it msg_id = (int(time.time()) << 32) | 1 print(is_valid_msg_id(msg_id), is_valid_msg_id(msg_id, from_client=False)) # True False

FingerprintConfig draws its own offset on construction (randomize_msg_id_offset, on by default).

Check the layer and the transport

opentele2 advertises layer 230, the schema of Telegram Desktop 7.3.1. Every official client speaks the obfuscated transport.

transport.py
from opentele2.fingerprint import ( TransportRecommendation, get_advertised_layer, get_recommended_layer, ) print(get_advertised_layer()) # 230 print(get_recommended_layer()) # the installed Telethon's layer; warns when far from 230 print(TransportRecommendation.get_connection_class().__name__) # ConnectionTcpObfuscated print(list(TransportRecommendation.get_available_transports())) # ['full', 'abridged', 'intermediate', 'obfuscated']

The opentele2 TelegramClient uses ConnectionTcpObfuscated unless you pass connection=. FingerprintConfig(layer_override=...) replaces the layer get_effective_layer() reports; a mismatched layer breaks deserialisation.

Next

Last updated on