Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an application that will listen to a telegram channel

First of all please note that this is not about creating a bot.

My goal is to create an application that will simply listen to any number of telegram channels that the account I will provide it with is subscribed to and retrieve all messages sent to those channels (as if I was a normal user). My guess is that I will need to

  • Authenticate myself using my account's phone number
  • Be able to setup a callback listener either per channel or a general listener for all incoming messages

I've been looking around the telegram api for a couple of days now and I am extremely confused as to how it works. After giving up on it, I started looking at readymade implementations, mostly for NodeJS but was still not able to find a concrete solution. I'm testing some things with the telegram-js api but running it directly using node didn't work. Does it need to run in a browser? Is there any more streamlined approach to this? Preferably something with good documentation.

PS: I'm fluent in Java and Javascript mostly so I've prioritized libraries based on those languages.

EDIT:

Here is the code that I've written (essentially copied an example)

var { Telegram } = require("../libs/telegram");
var TypeLanguage = require("telegram-tl-node") ;
var MTProto = require("telegram-mt-node");

var schema = require("../libs/api-schema.json");

const APP_ID = "111111";
const APP_HASH = "fb6da8f6abdf876abd6a9d7bf6";
const SERVER = { host: "111.111.111.11", port: "443" };
const config = {
  id: APP_ID,
  hash: APP_HASH,
  version: '0.0.1',
  lang_code: 'en',
  authKey: null
};

let telegram = new Telegram(MTProto, TypeLanguage);
telegram.useSchema(schema);
addPublicKeys(telegram);

let connection = new MTProto.net.HttpConnection(SERVER);

let client = telegram.createClient();
client.setConnection(connection);

connection.connect(function() {
  let ready = client.setup(config);
  ready.then(function(client) {
    // it never resolves this promise
    function callback(response) {
      console.log(response);
    }
    client.callApi("help.getConfig").then(callback, callback);
  });
});

It uses those 2 libs: telegram-mt-node telegram-tl-node

like image 267
PentaKon Avatar asked Dec 14 '17 09:12

PentaKon


2 Answers

Late answer but might help others.

You can utilize mtproto-core to authenticate with a regular telegram account and listen to updates (or do anything you can with telegram clients, really)

Here is a sample script I've written that listens to new messages from channels/supergroups the user is subscribed to:

const { MTProto, getSRPParams } = require('@mtproto/core');
const prompts = require('prompts');

const api_id = ...; // insert api_id here
const api_hash = ' ... '; // insert api_hash here

async function getPhone() {
    return (await prompts({
        type: 'text',
        name: 'phone',
        message: 'Enter your phone number:'
    })).phone
}

async function getCode() {
    // you can implement your code fetching strategy here
    return (await prompts({
        type: 'text',
        name: 'code',
        message: 'Enter the code sent:',
    })).code
}

async function getPassword() {
    return (await prompts({
        type: 'text',
        name: 'password',
        message: 'Enter Password:',
    })).password
}


const mtproto = new MTProto({
    api_id,
    api_hash,
});

function startListener() {
    console.log('[+] starting listener')
    mtproto.updates.on('updates', ({ updates }) => {
        const newChannelMessages = updates.filter((update) => update._ === 'updateNewChannelMessage').map(({ message }) => message) // filter `updateNewChannelMessage` types only and extract the 'message' object

        for (const message of newChannelMessages) {
            // printing new channel messages
            console.log(`[${message.to_id.channel_id}] ${message.message}`)
        }
    });
}


// checking authentication status
mtproto
    .call('users.getFullUser', {
        id: {
            _: 'inputUserSelf',
        },
    })
    .then(startListener) // means the user is logged in -> so start the listener
    .catch(async error => {

        // The user is not logged in
        console.log('[+] You must log in')
        const phone_number = await getPhone()

        mtproto.call('auth.sendCode', {
            phone_number: phone_number,
            settings: {
                _: 'codeSettings',
            },
        })
            .catch(error => {
                if (error.error_message.includes('_MIGRATE_')) {
                    const [type, nextDcId] = error.error_message.split('_MIGRATE_');

                    mtproto.setDefaultDc(+nextDcId);

                    return sendCode(phone_number);
                }
            })
            .then(async result => {
                return mtproto.call('auth.signIn', {
                    phone_code: await getCode(),
                    phone_number: phone_number,
                    phone_code_hash: result.phone_code_hash,
                });
            })
            .catch(error => {
                if (error.error_message === 'SESSION_PASSWORD_NEEDED') {
                    return mtproto.call('account.getPassword').then(async result => {
                        const { srp_id, current_algo, srp_B } = result;
                        const { salt1, salt2, g, p } = current_algo;

                        const { A, M1 } = await getSRPParams({
                            g,
                            p,
                            salt1,
                            salt2,
                            gB: srp_B,
                            password: await getPassword(),
                        });

                        return mtproto.call('auth.checkPassword', {
                            password: {
                                _: 'inputCheckPasswordSRP',
                                srp_id,
                                A,
                                M1,
                            },
                        });
                    });
                }
            })
            .then(result => {
                console.log('[+] successfully authenticated');
                // start listener since the user has logged in now
                startListener()
            });
    })

You can find the values for api_id and api_hash from https://my.telegram.org.

On the first run the script prompts the user for phone_number, code, and password.

[+] You must log in
√ Enter your phone number: ... <phone_number>
√ Enter the code sent: ... <code>
√ Enter Password: ... <2FA password>

and after the authentication is over a sample run outputs:

[+] starting listener
[13820XXXXX] Ja
[13820XXXXX] Bis bald guys��
[13820XXXXX] Ja. �
[13820XXXXX] Bis später
[13820XXXXX] Jaaa�

The way I've checked the authentication status was taken from here.

Alternative libraries worth checking out that are active the time of writing (and can be used to create the same behavior with): Airgram (tdlib) and GramJs

like image 183
Tibebes. M Avatar answered Oct 02 '22 00:10

Tibebes. M


I used gram.js library and essentially did this:

import { TelegramClient } from 'telegram'
TelegramClient().addEventHandler(handler, { chats: [1234567890] })

The bot does NOT need to be a member of the channel you want to listen to.

My code runs as a Node.js app.

You need to first create a token by talking to @BotFather with Telegram.

like image 34
Steven Almeroth Avatar answered Oct 01 '22 23:10

Steven Almeroth