gram-js / gramjs

NodeJS/Browser MTProto API Telegram client library,
MIT License
1.28k stars 179 forks source link

InviteToChannel throws accessHash incorrect error #131

Closed Asjas closed 3 years ago

Asjas commented 3 years ago

I am using the Telegram API (gramjs) to invite a user to a private channel when they click on a keyboard button of a telegram bot that we are using.

I am creating a session with my phone number and I'm saving it to disk. When I need to make the API call I restore the session from disk.

I'm getting a wrong type for accessHash error message, do you know if this is an issue or something that I should ignore?

I've gotten these random accessHash error a few times before and I don't know if it's random and whether I should ignore it or whether it shows a bigger problem that I need to fix. 🙂

This is the error message.

CastError: Found wrong type for accessHash. expected bigInt but received -2245008065968966897.If you think this is a mistake please report it.
    at VirtualClass.assertType (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/tl/api.js:403:33)
    at VirtualClass.validate (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/tl/api.js:345:30)
    at VirtualClass.getBytes (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/tl/api.js:412:26)
    at argToBytes (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/tl/api.js:149:22)
    at VirtualClass.getBytes (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/tl/api.js:477:33)
    at new RequestState (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/network/RequestState.ts:20:29)
    at MTProtoSender.send (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/network/MTProtoSender.ts:278:23)
    at Object.<anonymous> (/Users/asjas/git/mellins-bot-server/node_modules/gramjs/client/users.ts:35:44)
    at Generator.next (<anonymous>)
    at fulfilled (/Users/asjas/git/mellins-bot-server/node_modules/telegram/client/users.js:5:58)

This is my code for the InviteToChannel API call. I am using the telegram id of a user since not all users will have usernames configured.

Am I perhaps using the wrong API function to get the User? Looking at the TypeScript in my code editor and it shows that users should be passed an array of EntityLike.

import dotenv from "dotenv";
import { Api, TelegramClient } from "telegram";
import { Logger } from "telegram/extensions/index.js";
import { StoreSession } from "telegram/sessions/index.js";

dotenv.config();

const { TELEGRAM_APP_ID, TELEGRAM_APP_HASH } = process.env;

const apiId = Number(TELEGRAM_APP_ID);
const apiHash = TELEGRAM_APP_HASH;

async function inviteUserToChannel(telegramId: number) {
  // restore saved telegram session
  const storeSession = new StoreSession(".telegram_session");

  const client = new TelegramClient(storeSession, apiId, apiHash, {
    connectionRetries: 5,
  });

  Logger.setLevel("error");

  try {
    await client.connect();

    await client.invoke(
      new Api.channels.InviteToChannel({
        channel: -1001198053895,
        users: [new Api.PeerUser({ userId: telegramId })],
      }),
    );

    await client.disconnect();
  } catch (err) {
    console.error(err);
    await client.disconnect();
  }
}

This is the code I'm using to generate and save the session to disk (if that matters).

// This CLI is used to authenticate to the Telegram API and stores the session
// in a folder named `.telegram_session` so that we only have to authenticate once.

// This Session and the Telegram API is used so that we can query
// the Telegram API without having to manually authenticate each time.

import { TelegramClient } from "telegram";
import { StoreSession } from "telegram/sessions/index.js";
import dotenv from "dotenv";
import input from "input";

dotenv.config();

const { TELEGRAM_APP_ID, TELEGRAM_APP_HASH } = process.env;

const apiId = Number(TELEGRAM_APP_ID);
const apiHash = TELEGRAM_APP_HASH;

const storeSession = new StoreSession(".telegram_session");
const client = new TelegramClient(storeSession, apiId, apiHash, {
  connectionRetries: 5,
});

(async function run() {
  try {
    await client.start({
      phoneNumber: async () => await input.text("number ?"),
      password: async () => await input.text("password ?"),
      phoneCode: async () => await input.text("code ?"),
      onError: (err) => console.log(err),
    });

    await client.connect();

    // save current session so that I don't get prompted for my phoneNumber every time I launch this
    client.session.save();
  } catch (err) {
    console.error(err);
  }

  await client.disconnect();
  process.exit(0);
})();
painor commented 3 years ago

where are you getting these telegramIds from? you also need to know the access hash of a user to use it in any API call.

Asjas commented 3 years ago

The telegram ID is coming from the bot ctx.

When the user clicks on the keyboard button I listen for it using the bot, I then get the user id from the ctx and I call that function with the telegram id of the user.

  1. How do I get the access hash of a user? Do I need to call an API function to get it?
  2. Could it be caused by me using the bot for accessing the user id but I'm using my phone number to invoke the telegram API?

This is what the code looks like that calls the function.

import type TelegrafPKG from "telegraf";
import type { Update } from "typegram";
import type MyContext from "../types/telegram";

import * as keyboards from "../messages/botKeyboards";
import { botReply } from "./reply";

import inviteUserToChannel from "../services/inviteUserToChannel";

export default function JoinChannelCommand(bot: TelegrafPKG.Telegraf<TelegrafPKG.Context<Update>>) {
  bot.hears("Join Channel", async (ctx: MyContext) => {
    try {
      const { id: telegramId } = ctx.message.from;

      await inviteUserToChannel(telegramId);

      await botReply(
        ctx,
        "Thank you, you've successfully joined the Telegram Channel.",
        keyboards.fullBotKeyboard(ctx),
      );
    } catch (err) {
      console.error(err);
    }
  });
}
painor commented 3 years ago

did this ever work for you? The id on its own is somewhat useless for accounts. They also need to see the access hash of the user which is unique per account.

So you would need to forward a user's message to the user account so they can see the access hash then the library will save it in the store folder (it's a .accessHash field). If the user account has never seen the user's profile it can't do anything with it.

As for the warning it should be fixed in 1.8.1

Asjas commented 3 years ago

This hasn't ever worked for me because this is the first time I'm trying this.