Skip to content
 
 

Repository files navigation

piltover 🐳

An experimental Telegram server written from scratch in Python. Fork of a DavideGalilei/piltover.

TODO

  • MTProxy support maybe? Obfuscation is already implemented, so why not?
  • HTTP support
    • HTTP MTProto tranport
    • HTTP-specific packets handling (e.g. http_wait)
  • Improve the README:
    • move client setup instructions to a separate files?
    • describe process of downloading official Telegram reactions/languages/etc. into Piltover instance
    • make a list of working/broken/wip/etc. features/methods
  • Move UpdatesManager to separate worker
  • Add unversioned caching of some tl objects (e.g. types.User, types.Chat, types.Message, etc.)?
  • Scheduled messages
  • Bots
  • Secret chats (https://core.telegram.org/api/end-to-end)
    • Secret chats work kind of. Sometimes messages are just not arriving at either both ends or participant (who accepted chat) end.
  • InstallTheme_133, InstallTheme
  • InstallWallPaper
  • Channel admin log
  • Min constructors
  • Channel discussions
  • WebK hangs on some requests, logs errors about wrong auth key id and/or session id???
  • Proper sessions handling:
    • msg_id and seq_no generation MUST be in the session, NOT in the connection
    • when client is disconnected, session should be stored (and receive messages) for up to 10 minutes
    • when client is disconnected and then reconnected, all missed (not-acked) messages should be sent
    • client .send method should enqueue message for sending, not send it right away
    • maybe poll for new client messages? session stores id of the last polled message, when client calls session.poll_messages, it gets all messages with id greater than one that is stored, saves new last id, and returns message list to the client?
  • Top peers
  • Proper contacts implementation (right now user is able to add/remove/import contact, but only contacts for existing users are created).
  • Support S3 as a storage backend
  • Its probably not a bad idea to move State.pts to User model? same with Presence.last_seen
  • Add registration/authorization through Telegram
  • Link previews
  • Message translations (note to myself: look into offline translation libraries like argos-translate, etc.)
  • Dont store user/chat/channel ids related to specific message in database, get them from tl message instead
  • Use separate message id sequence for each user/channel

There is also many # TODO's in code that need to be done.

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.

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.

Right now, project may (although not recommended) be used for basic features like messages/media sending. More complex features such as channels, supergroups, bots, etc. may work with errors.

Setup

Requirements:

  • Python 3.11+
  • Poetry

Setup:

  1. Clone repository:
    git clone https://github.com/RuslanUC/piltover
  2. Install dependencies:
    poetry install
  3. Generate tl classes:
    poetry shell python tools/tl_gen.py
  4. (Optional) Install MariaDB, Redis and RabbitMQ.
  5. (Optional) Set up your own config:
    cp -r config config.custom
    And then edit config values you need
  6. Define paths to config files (if you are on windows - use set instead of export):
    export APP_CONFIG=config.custom/app.toml
    export SYSTEM_CONFIG=config.custom/system.toml
    export GATEWAY_CONFIG=config.custom/gateway.toml
    export WORKER_CONFIG=config.custom/worker.toml
  7. Run:
    poetry run python -m piltover.app.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.

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.

Also, gateway and rpc workers may (although such setup is not tested) be used separately (for this you need rabbitmq and redis running): run both piltover.app.app and piltover.app.worker with --rabbitmq-address and --redis-address.

Pyrogram

  • git clone --depth=1 https://github.com/pyrogram/pyrogram
  • Edit this dictionary:
    • 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

  • git clone --depth=1 https://github.com/LonamiWebs/telethon
  • Edit these variables:
    • DEFAULT_DC_ID = 2
      DEFAULT_IPV4_IP = '127.0.0.1'
      DEFAULT_IPV6_IP = '2001:67c:4e8:f002::a'
      DEFAULT_PORT = 4430
    • Just make sure that the default dc is 2, the ipv4 is localhost, and the default port is 4430. We don't really use ipv6 anyway...
  • Add the rsa public key:
    • Edit this file:
      • Ideally, delete all the existing keys
      • Take your server's public key from the data/secrets/pubkey.asc file, and add it there with add_key(""" key here """, old=False)
  • Install in development mode with python3 -m pip install -e .
  • Ready to use, run the server and check if telethon_test.py works

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

Telegram Android (recommended: Owlgram)

  • Clone the repo and follow the basic setup instructions
  • Edit this file:
    • Replace every ip with your local ip address. It can be 127.0.0.1 (localhost) only in the case you're running the app with an emulator on the same machine the server is running. Otherwise, change it with e.g. 192.168.1.35 (the LAN ip address of your machine).
    • Replace every port with 4430
  • Edit this file:
    • 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. This took me way too much debugging time to realize that the missing newlines was the cause of the app crashes.
  • Build the app, and see if it works.

Telegram WebK

  • Clone repo and install dependencies:
    • $ git clone https://github.com/morethanwords/tweb
      $ cd tweb
      $ npm i -g pnpm
      $ pnpm install
  • Edit the values in this file:
    • Change const chosenServer = `wss://...` to:
    • const chosenServer = `ws://127.0.0.1:3000/proxy`;
    • Change every datacenter ip and port below, respectively to 127.0.0.1 (localhost) and 3000 (websocket proxy port) here.
  • Edit the values in this file:
    • Change the modulus to the lowercase string of prime obtained previously
  • Run the websocket proxy from piltover
    • $ poetry run python tools/websocket_proxy.py
  • Run with npm start
  • Wait some time for the app to compile
  • Open the app in your browser (usually https://0.0.0.0:8080/)

Telegram WebZ

  • Clone repo (at specific api layer, example uses 201) and install dependencies:
    • $ git clone --depth 1 --revision 92d9f0736c3e890af0e1eca37f95fbcee3cd39c3 https://github.com/Ajaxy/telegram-tt
      $ cd telegram-tt
      $ npm i
  • Edit the values in this file:
    • Change every datacenter ip and port below, respectively to 127.0.0.1 (localhost) and 3000 (websocket proxy port) here.
  • Change this._args.useWSS ? 443 : 80 in this line to DC.port
  • Edit the values in this file:
    • Change the fingerprint to decimal unsigned fingerprint obtained previously.
    • Change the n to the decimal string of prime obtained previously.
  • Change line (whole line) starting with connect-src in this file to connect-src *;
  • Run the websocket proxy from piltover
    • $ poetry run python tools/websocket_proxy.py
  • Run with npm run dev
  • Wait some time for the app to compile
  • Open the app in your browser (usually http://127.0.0.1:1234/)

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.

Miscellaneous

List of other server implementations I found:

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

Licensing

This project is licensed under the GNU Affero General Public License v3.0.

It was originally forked from DavideGalilei/piltover, which is licensed under the MIT License. Portions of the original code remain under MIT; see LICENSE.MIT for details.

About

An experimental Telegram Server implementation in Python

Topics

Resources

Stars

15 stars

Watchers

3 watching

Forks

Contributors

Languages