Modern fork of opentele for Python 3.10–3.14 — no Qt runtime dependency (pure-Python QDataStream replacement). Convert Telegram Desktop tdata to Telethon sessions; supports current TDesktop 5.x–6.x tdata format.
Project description
opentele-ng
Modern fork of thedemons/opentele. Python 3.10 – 3.14 • pure-Python runtime, no Qt dependency • reads current Telegram Desktop 5.x – 6.x tdata format • drop-in
import opentelecompatibility.
Why this fork
Upstream thedemons/opentele was last touched in 2022. By mid-2026 it stopped
working on modern Python (3.13+ broke the metaclass), missed several lskType
keys added to tdata in 2024-2025 (silently dropping data on read), shipped
stale device fingerprints, and required ~50 MB of PyQt5 wheels just to parse
binary streams.
opentele-ng is a clean-room modernization done over 11 release phases with
3-AI code review (OpenAI Codex, Cursor, Google Gemini) at every milestone.
None of the 132 community forks of upstream attempted the pure-Python rewrite —
this one ships it.
Highlights
| Phase | What |
|---|---|
| Phase 5 | Pure-Python QDataStream / QByteArray / QFile / QBuffer — byte-identical to PyQt6 (17 byte-for-byte equivalence tests + 247 integration tests). PyQt6 removed from runtime, install is now telethon + tgcrypto-pyrofork only. |
| Phase 1.5 | Wire-format fixes for lskWebviewTokens (QByteArray, not uint64), lskBotStorages (Dict[PeerId, FileKey] map, not single key), lskPrefs 0x1E (missed by every upstream fork — verified against TDesktop C++ source). |
| Phase 2 | 2026 device fingerprints: iPhone 17 / Air, M5 / M5 Pro / M5 Max Macs, Galaxy S25 / S26 series, Pixel 10 / 10 Pro / 10 Pro XL, Android SDK 33-37 (Android 13 → 17 beta), macOS 26 Tahoe, iOS 26. Deterministic _generate_tdesktop_app_version(unique_id) for stable fingerprints across runs. |
| Phase 3 | kMaxAccounts = 6 (was 3, matches TDesktop's kPremiumMaxAccounts). **kwargs forward in FromTelethon → QRLoginToNewClient for proxy/connection/timeout. Nuitka-compatible sharemethod. Ruff lint replaces broken upstream pylint workflow. |
| Phase 4 | 168 → 247 tests: QDataStream golden bytes, hypothesis property-based fuzzing (~1000 cases/run), real TDesktop.SaveTData → load roundtrip through MapData.prepareToWrite(). |
| Phase 1.0.3 | Security: 6 DoS guards on attacker-controlled count fields in MapData.read / _setMtpAuthorization.readKeys / account-list. Pre-loop cap by bytesAvailable() // pair_size + hard regression tests (no fail-open xfail). |
Install
PyPI
pip install opentele-ng
from opentele.td import TDesktop
from opentele.tl import TelegramClient
from opentele.api import API, CreateNewSession
Runtime deps: telethon>=1.36,<2, tgcrypto-pyrofork>=1.2.7. No Qt.
System libraries (libgl1, libegl1, libxkbcommon-x11-0, etc.) are not
required — you can deploy on Alpine, distroless, serverless, or any minimal
Linux container.
Docker (v1.2.0+)
Multi-arch image at ghcr.io/stufently/opentele-ng (linux/amd64 + linux/arm64), ~140 MB, runs as non-root, opentele-ng is the entrypoint:
docker run --rm \
-v "/path/to/Telegram/tdata:/tdata:ro" \
ghcr.io/stufently/opentele-ng:latest info /tdata
See docs/examples/docker.md for batch / convert / air-gapped / Sigstore verification.
CLI — one-shot workflows (v1.1.0+)
# Read-only inspection of a tdata folder
opentele-ng info /path/to/Telegram/tdata
# Convert tdata → Telethon .session file
opentele-ng convert /path/to/Telegram/tdata --output ./me.session
See docs/examples/cli-quick-start.md for flags and exit codes.
Quick start (Python API)
import asyncio
from opentele.api import API, CreateNewSession
from opentele.td import TDesktop
from opentele.tl import TelegramClient
async def main() -> None:
# 1. Load tdata produced by Telegram Desktop.
tdata_path = r"C:\Users\<user>\AppData\Roaming\Telegram Desktop\tdata"
tdesk = TDesktop(tdata_path)
# 2. Pick an official API (TelegramIOS / TelegramAndroid / TelegramDesktop / TelegramMacOS).
# .Generate() builds a deterministic-or-random device fingerprint.
api = API.TelegramIOS.Generate(unique_id="my-host")
# 3. Convert TDesktop session → Telethon. CreateNewSession links a new
# device via QR code on the existing TDesktop session (no phone OTP).
client: TelegramClient = await tdesk.ToTelethon(
"new_session.session", CreateNewSession, api
)
async with client:
await client.PrintSessions()
asyncio.run(main())
Examples
docs/examples/qr-login.md— QR-code login flow with 2FA +**kwargsproxy forwarding.docs/examples/convert-tdata-to-telethon.mddocs/examples/convert-telethon-to-tdata.mddocs/examples/using-official-apis.md
Configuration
| Env var | Default | Effect |
|---|---|---|
OPENTELE_EXTEND_STRICT |
1 |
@extend_class raises TypeError on attribute conflicts. Set to 0 to fall back to RuntimeWarning (legacy upstream behaviour). |
OPENTELE_REAL_TDATA_PATH |
unset | When set to an absolute path of a production tdata folder, enables the opt-in real-data smoke test in tests/integration/test_real_tdata_smoke.py. CI never sets it. |
Status
- Latest:
v1.2.1(2026-05-20). PyPI:opentele-ng/ Docker:ghcr.io/stufently/opentele-ng(now on Python 3.14). Production-ready. 1.2.1 addsQFile.bytesAvailable(), CLI integration tests on real fixture tdata, expanded coverage gate to the whole package (was just.td), and cleanup of stale upstream docs. - 270 tests pass on Python 3.10 / 3.11 / 3.12 / 3.13 / 3.14 (Docker matrix + GitHub Actions matrix × Ubuntu / macOS / Windows).
- Coverage: 83.48% on the whole
opentelepackage (CI gate 80% on full package, was 90% onopentele.tdonly — that subset is still 94.83%). - See CHANGELOG.md for the full per-release breakdown.
Security
opentele-ng accepts attacker-influenced binary blobs (tdata files from the
filesystem), and version 1.0.3 added bounded-count guards on every loop that
reads a count field from a decrypted payload. If you find a malformed tdata
input that bypasses these guards or causes the library to read unbounded
memory or CPU, please report it privately: see SECURITY.md.
Differences from upstream
- Import name unchanged (
import opentele) — drop-in for code that already usesthedemons/opentele. - PyPI dist name is
opentele-ngto avoid collision with the original package. kMaxAccountsis6(Telegram's premium limit), not 3.@extend_classraises on attribute conflicts by default; setOPENTELE_EXTEND_STRICT=0for the old warning-only behaviour._settingsKeyisFileKey(0)by default; the upstreamFileKey(1851671142505648812)magic was removed in 1.0.1 (proper AES block padding added toStorage.PrepareEncryptedinstead).PyQt6is NOT a runtime dependency —opentele.td.qdatastreamprovides byte-compatible pure-Python replacements forQDataStream,QByteArray,QBuffer,QFile,QDir,QSysInfo.
Authorization
opentele-ng keeps the upstream's ability to use official APIs through
the API class (API.TelegramDesktop, API.TelegramAndroid,
API.TelegramAndroidX, API.TelegramIOS, API.TelegramMacOS,
API.TelegramWeb_K, API.TelegramWeb_Z).
Per Telegram Terms of Service:
All accounts that sign up or log in using unofficial Telegram API clients are automatically put under observation to avoid violations of the Terms of Service.
Using an official API id/hash + lang_pack="tdesktop" (or ios, android,
etc.) makes the session indistinguishable from the corresponding official
client, which reduces spam-detection risk.
Credits
See ACKNOWLEDGMENTS.md.
License
MIT (same as upstream). See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opentele_ng-1.2.1.tar.gz.
File metadata
- Download URL: opentele_ng-1.2.1.tar.gz
- Upload date:
- Size: 125.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0589a36cb2f64aa9ce02dee6c81fe7185a6906b8c921e6b720d4caf0c8a76670
|
|
| MD5 |
e8ed123514f214566895e699de8a6ada
|
|
| BLAKE2b-256 |
99cc425027d797333e54433db4dd9de71a829e6e544cd2bdc93dd7258d31d3a2
|
Provenance
The following attestation bundles were made for opentele_ng-1.2.1.tar.gz:
Publisher:
publish.yml on stufently/opentele
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opentele_ng-1.2.1.tar.gz -
Subject digest:
0589a36cb2f64aa9ce02dee6c81fe7185a6906b8c921e6b720d4caf0c8a76670 - Sigstore transparency entry: 1582609594
- Sigstore integration time:
-
Permalink:
stufently/opentele@c6c404fc02c828dd5d76efd651c8d885320027a0 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/stufently
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c6c404fc02c828dd5d76efd651c8d885320027a0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file opentele_ng-1.2.1-py3-none-any.whl.
File metadata
- Download URL: opentele_ng-1.2.1-py3-none-any.whl
- Upload date:
- Size: 102.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9600cbbb199f9e416412fc58f2ccb3318852a4d9bed041bda39f0138bab8f815
|
|
| MD5 |
a5b9ed308dc560b7e5027f0abc9e1258
|
|
| BLAKE2b-256 |
5fcf0c4fd8626bec834d932e918a383997e0650d1f0b3215027a3092d42b21a4
|
Provenance
The following attestation bundles were made for opentele_ng-1.2.1-py3-none-any.whl:
Publisher:
publish.yml on stufently/opentele
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opentele_ng-1.2.1-py3-none-any.whl -
Subject digest:
9600cbbb199f9e416412fc58f2ccb3318852a4d9bed041bda39f0138bab8f815 - Sigstore transparency entry: 1582609798
- Sigstore integration time:
-
Permalink:
stufently/opentele@c6c404fc02c828dd5d76efd651c8d885320027a0 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/stufently
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c6c404fc02c828dd5d76efd651c8d885320027a0 -
Trigger Event:
push
-
Statement type: