alik0211 / mtproto-core

Telegram API JS (MTProto) client library for Node.js and browser
https://mtproto-core.js.org
GNU General Public License v3.0
632 stars 116 forks source link

Getting AUTH_KEY_UNREGISTERED and PHONE_CODE_INVALID after some period #143

Closed geekysrm closed 3 years ago

geekysrm commented 3 years ago

Auth data is located in /home/runner/.local/share/@mtproto/core, but the app keeps signing out. Means, after some time it sends new code to Telegram and if I input it in the code and restart the server, then only it works.

Is there a way how it doesn't ask for login again after specific time?

My code:

const { MTProto, getSRPParams } = require("@mtproto/core");
const api = require("./lib.js");
const { customAlphabet } = require("nanoid");

const nanoid = customAlphabet("1234567890", 10);

const api_id = "xxx";
const api_hash = "xxx";

// 1. Create an instance
const mtproto = new MTProto({
  api_id,
  api_hash,
});

// 2. Provide params for initConnection method (optional)
mtproto.updateInitConnectionParams({
  app_version: "10.0.0",
});

async function getUser() {
  try {
    const user = await api.call("users.getFullUser", { // I think the error occurs here according to error message
      id: {
        _: "inputUserSelf",
      },
    });

    return user;
  } catch (error) {
    return null;
  }
}

function sendCode(phone) {
  return api.call("auth.sendCode", {
    phone_number: phone,
    settings: {
      _: "codeSettings",
    },
  });
}

function signIn({ code, phone, phone_code_hash }) {
  return api.call("auth.signIn", {
    phone_code: code,
    phone_number: phone,
    phone_code_hash: phone_code_hash,
  });
}

function getPassword() {
  return api.call("account.getPassword");
}

function checkPassword({ srp_id, A, M1 }) {
  return api.call("auth.checkPassword", {
    password: {
      _: "inputCheckPasswordSRP",
      srp_id,
      A,
      M1,
    },
  });
}

const phone = "xxxx";
const code = "xxxx";
const password = "PASSWORD";

(async () => {
  const user = await getUser();

  if (!user) {
    const { phone_code_hash } = await sendCode(phone);

    try {
      const authResult = await signIn({
        code,
        phone,
        phone_code_hash,
      });

      console.log(`authResult:`, authResult);
    } catch (error) {
      if (error.error_message !== "SESSION_PASSWORD_NEEDED") {
        return;
      }

      // 2FA

      const { srp_id, current_algo, srp_B } = await getPassword();
      const { g, p, salt1, salt2 } = current_algo;

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

      const authResult = await checkPassword({ srp_id, A, M1 });

      console.log(`authResult:`, authResult);
    }
  }
})();

async function sendQuestionThenPoll(problemsToPost) {

    for (const { fields } of problemsToPost) {
        const { number, topic, title, link } = fields;
        // Send question
        await mtproto
          .call("messages.sendMessage", {
            peer: {
              _: "inputPeerChannel",
              channel_id: xxxx,
              access_hash: xxxx,
            },
            message: `#${number} ${topic
              .split(" ")
              .map((w) => w[0].toUpperCase() + w.substr(1).toLowerCase())
              .join(" ")}: ${title}\n${link}`,
            random_id: nanoid(),
          })
          .then((data) => {
            console.log(data);
          })
          .catch((errror) => {
            console.log(errror);
          });

        // Send Poll
        await mtproto
          .call("messages.sendMedia", {
            peer: {
              _: "inputPeerChannel",
              channel_id: xxx,
              access_hash: xxxxx,
            },
            media: {
              _: "inputMediaPoll",
              poll: {
                _: "poll",
                id: nanoid(),
                public_voters: true,
                question: "Problem solved:",
                answers: [
                  {
                    _: "pollAnswer",
                    text: "Done",
                    option: "done",
                  },
                  {
                    _: "pollAnswer",
                    text: "Not Done",
                    option: "notDone",
                  },
                ],
              },
            },
            random_id: nanoid(),
          })
          .then((data) => {
            console.log(data);
          })
          .catch((errror) => {
            console.log(errror);
          });
    }

}

module.exports = sendQuestionThenPoll;

lib.js:

const { MTProto } = require("@mtproto/core");
const { sleep } = require("@mtproto/core/src/utils/common");

const mtproto = new MTProto({
  api_id: "xx",
  api_hash: "xxxxxx",
});

const api = {
  call(method, params, options = {}) {
    return mtproto.call(method, params, options).catch(async (error) => {
      console.log(`${method} error:`, error);

      const { error_code, error_message } = error;

      if (error_code === 420) {
        const seconds = +error_message.split("FLOOD_WAIT_")[1];
        const ms = seconds * 1000;

        await sleep(ms);

        return this.call(method, params, options);
      }

      if (error_code === 303) {
        const [type, dcId] = error_message.split("_MIGRATE_");

        // If auth.sendCode call on incorrect DC need change default DC, because call auth.signIn on incorrect DC return PHONE_CODE_EXPIRED error
        if (type === "PHONE") {
          await mtproto.setDefaultDc(+dcId);
        } else {
          options = {
            ...options,
            dcId: +dcId,
          };
        }

        return this.call(method, params, options);
      }

      return Promise.reject(error);
    });
  },
};

module.exports = api;
alik0211 commented 3 years ago

The file with auth data is probably being changed