GithubHelp home page GithubHelp logo

ruslanuc / piltover Goto Github PK

View Code? Open in Web Editor NEW

This project forked from davidegalilei/piltover

1.0 1.0 0.0 784 KB

An experimental Telegram Server implementation in Python

License: MIT License

JavaScript 0.26% Python 99.65% Dockerfile 0.09%

piltover's Introduction

piltover ๐Ÿณ

An experimental Telegram server written from scratch in Python. Development chat: linked group to @ChameleonGram.

TODO

  • WebK gets stuck on sendCode(). (note to self: inspect the MTProto workers in chrome://inspect/#workers)
  • Multiple sessions handling for: Give correct msg_id/seq_no according to the Telegram specification
  • A Websocket proxy for Telegram Web (WebZ / WebK). A work in progress temporary implementation is in tools/websocket_proxy.js
  • Updates handling: pts, qts, etc.
  • Refactor the TL de/serialization module since the code is messy (e.g. make custom boxed types for list/int/str/bytes).
  • Support multiple server keys to automatically switch to RSA_PAD for official clients, whilst keeping clients like Pyrogram/Telethon working with the old method. Currently handled manually in server.py: old = False
  • Support TL from multiple layers, and layer-based handlers. Add fallbacks eventually.
  • Add a tests/ directory with patched assertions from client libraries.
  • Use custom exceptions instead of Python assertions: assert statements are disabled with python -O, leading to missing important checks.
  • Add missing security checks, e.g., checking of g_a/g_b.
  • Refactor piltover/__main__.py, and use a database for auth keys/messages/users/updates (probably with SQLAlchemy and alembic due to reliable database migrations).
  • MTProxy support maybe? Obfuscation is already implemented, so why not?
  • HTTP/UDP support? Probably Telegram itself forgot those also exist.
  • Switch to hypercorn for the tcp server maybe?
  • Improve the README.

Purpose

This project is currently not meant to be used to host custom Telegram instances, as most security measures are currently barely in place. For now, it can be used by MTProto clients developers to understand why their code fails, whereas Telegram just closes the connection with a -404 error code.

That being said, it is planned in future to make it usable for most basic Telegram features, including but not limited to, sending and receiving text and media messages, media, search.

This can be really useful for bots developers that would like to have a testing sandbox that doesn't ratelimit their bots.

The server is meant to be used as a library, providing 100% control of every answer

Example

An example quick-start (incomplete) code would look like this:

import asyncio
from piltover.server import Server, Client
from piltover.utils import gen_keys
from piltover.tl.types import CoreMessage
from piltover.tl_new import Ping, Pong

async def main():
    pilt = Server(server_keys=gen_keys())
    auth_keys: dict[int, bytes] = {}
    # Running on localhost
    # Port: 4430
    
    @pilt.on_auth_key_set
    async def auth_key_set(auth_key_id: int, auth_key_bytes: bytes) -> None:
        auth_keys[auth_key_id] = auth_key_bytes
    
    @pilt.on_auth_key_get
    async def auth_key_get(auth_key_id: int) -> tuple[int, bytes] | None:
        if (auth_key := auth_keys.get(auth_key_id, None)) is not None:
            return auth_key_id, auth_key

    @pilt.on_message(Ping)
    async def pong(client: Client, request: CoreMessage[Ping], session_id: int):
        print("Received ping:", request.obj)

        return Pong(
          msg_id=request.message_id,
          ping_id=request.obj.ping_id
        )

    await pilt.serve()

asyncio.run(main())
$ poetry install --no-root
$ poetry run python -m piltover.app
# Server running on 127.0.0.1:4430...

Of course, this minimal setup is far from complete, and will only work for auth key generation and pings.

Development setup

General steps

1. Clone the repo:

$ git clone https://github.com/DavideGalilei/piltover
$ cd piltover

2. Install poetry

Follow instructions at: https://python-poetry.org/docs/#installation

3. Initial setup

$ poetry install --no-root
$ poetry run python tools/gen_tl.py update
$ poetry run python -m piltover.app

Now wait until it loads correctly and fire a Ctrl-C to stop the process.

You should see a line looking like this at the beginning

2023-11-05 19:52:31.171 | INFO     | __main__:main:49 - Pubkey fingerprint: -6bff292cf4837025 (9400d6d30b7c8fdb)

Get the fingerprint hex string and save it for later (some clients need it). In this case, the unsigned fingerprint is 9400d6d30b7c8fdb, but only for this example. Do not reuse this key fingerprint, as it will be different in your setup.

4. Extract public key number and exponent

At this point, two files should have been generated in your directory. Namely, data/secrets/privkey.asc and data/secrets/pubkey.asc. Keep in mind that some clients might need the PKCS1 public key in the normal ascii format.

Some others like pyrogram, do not have an RSA key parser and hardcode the number/exponent. To extract it, you can use this command:

$ grep -v -- - data/secrets/pubkey.asc | tr -d \\n | base64 -d | openssl asn1parse -inform DER -i

An example output would look like this:

  0:d=0  hl=4 l= 266 cons:  SEQUENCE          
  4:d=1  hl=4 l= 257 prim:  INTEGER           :C3AE9457FDB44F47B91B9389401933F2D0B27357FE116ED7640798784829FDBC66295169D1D323AB664FD6920EFBAAC8725DA7EACAA491D1F1EEC8259CA68E4CFE86FC6823C903A323DE46C0E64B8DD5C93A188711C1BF78FCBE0C99904227A66C9135241DD8B92A0AD88AB3A6734BC13B57FA38614BB2AA79F3EF0920D577928F7E689B7B5B0A1A8A48DA9D7E4C28F2A8F1AAEDA22AC4DA05324C1CB67538ADFE1AC3201B34A85189B0765E6C79FF443433837B540D6295BF9EE95B8CDA709868C450BE9730C9FCC7442011129AFB45187C2A1913A4974709E9666865C4F06067E981BF57950A0395B45C3A7322FD36F77D803FF97897BC00D5687A3CB575D1
265:d=1  hl=2 l=   3 prim:  INTEGER           :010001

Note the exponent (010001) and the prime number: (C3AE94...B575D1). Save those values for later.

Pyrogram

  • git clone --depth=1 https://github.com/pyrogram/pyrogram
  • Edit this dictionary: https://github.com/pyrogram/pyrogram/blob/b19764d5dc9e2d59a4ccbb7f520f78505800656b/pyrogram/crypto/rsa.py#L33
    • The key is the server fingerprint, the value is formed by this expression: PublicKey(int( prime 16), int( exponent , 16))
    • Replace those values, (optional: delete the rest of the keys)
  • Edit the datacenters ips in this file:
    • Every ip should become "127.0.0.1" (localhost)
    • In the DataCenter.__new__ method below, replace every return with return (ip, 4430 ), instead of ports 80/443
  • Install in development mode with python3 -m pip install -e .
  • Ready to use, run the server and check if test.py works

Telethon

Telegram Desktop

  • Edit this file:
    • As always, replace every ip with 127.0.0.1 (localhost), and every port with 4430
    • Remove the existing rsa keys, and replace them with your own, taken from the data/secrets/pubkey.asc file on your piltover folder. Important: check the newlines thoroughly and make sure they are there, or it won't work.
  • Build the program, ideally with GitHub Actions
  • Put the executable in a folder, e.g. tdesk
  • Since we don't save the auth keys, you should delete the leftover files from tdesktop at every run. You can do this conveniently and run your custom TDesktop with this command:
$ rm -rf tdata/ DebugLogs/ log.txt && c && ./Telegram

Telegram Android (recommended: Owlgram)

Telegram WebK

Telegram WebZ

  • #TODO: WebZ instructions

Nimgram

  • #TODO: the client is currently under active development and refactoring, so I will wait until a working version is released

Telegram X/TDLib

  • #TODO: add instructions. I haven't figured out how it should be done yet.

Make a pull request if you want to add instructions for your own client.

How it works

  • The client connects with TCP sockets to the server (websockets for web clients)
  • The first bytes sent within a new connection determine the used transport
    • 0xef: Abridged
    • 0xeeeeeeee: Intermediate
    • 0xdddddddd: Padded Intermediate
    • [length: 4 bytes][0x00000000]: TCP Full, distinguishable by the empty seq_no (0x00000000)
    • [presumably random bytes]: Usually and Obfuscated transport
    • To distinguish between TCP Full and Obfuscated transports, a buffered reader is needed, to allow for peeking the stream without consuming it.
  • Type Language (TL) Data Serialization (# TODO: json schema is not used)
    • In piltover, the TL de/serialization is JIT (Just In Time), allowing for an easy json-like interface at the cost of slow type checking at runtime (#TODO: do something about this) without complex code-generation parsers
    • The TL parser (tools/gen_tl.py) utility uses jinja2 to generate the api_tl.py / mtproto_tl.py files from the official TDesktop repo. (#TODO retrieve as much old schema layers for multi-layer support)
  • Authorization Key generation
    • Generate random prime numbers for pq decomposition, a proof of work to avoid clients' DoS to the server
    • Either use an old algorithm or RSA_PAD to encrypt the inner data payload
    • The server checks the stuff it needs to check, the client too
    • If everything went correctly, we are authorized
    • It is worth noting that every auth key has its own id (the 8 lower order bytes of SHA1(auth_key))
    • Then key must be registered. It is done by creating auth_key_set server event, which should be overriden in your app (it gives ability to save auth keys anywhere you want (dict, database, etc.)).
    • Apart from the auth key id, every session has its own arbitrary (client provided) session_id, bound to the auth key. #TODO: Piltover doesn't currently check this value
  • Sign in / sign up process
    • Client sends invokeWithLayer(initConnection(getConfig(...)))
    • Client signs in with number / sms
    • Run the server and see the logs to find out more...

Why

One day, my Telegram account stopped working properly due to an internal server error originating from a supposedly corrupted message I forwarded. Every time the client tried to fetch new messages from private chats, it would face a [500 STORE_INVALID_OBJECT_TYPE] error. Hopefully, the bug was fixed in ~1/2 days after being reported, but the fact that it happened at all motivated me enough to try building my own server. In several days, I managed to make it kinda work :)

Miscellaneous

List of other server implementations I found:

Various applications similar to Telegram (probably using a custom MTProto backend):

piltover's People

Contributors

ruslanuc avatar davidegalilei avatar roj1512 avatar penn5 avatar dependabot[bot] avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.