const { TelegramClient } = require('telegram')
const { StringSession } = require('telegram/sessions')
const input = require('input') // npm i input
const apiId = 123456
const apiHash = '123456abcdfg'
const stringSession = new StringSession(''); // fill this later with the value from session.save()
(async () => {
console.log('Loading interactive example...')
const client = new TelegramClient(stringSession, apiId, apiHash, { connectionRetries: 5 })
await client.start({
phoneNumber: async () => await input.text('number ?'),
password: async () => await input.text('password?'),
phoneCode: async () => await input.text('Code ?'), //<<<<<<This line
onError: (err) => console.log(err),
});
console.log('You should now be connected.')
console.log(client.session.save()) // Save this string to avoid logging in again
await client.sendMessage('me', { message: 'Hello!' });
})()
This is the example of authorization with gramjs (https://painor.gitbook.io/gramjs/getting-started/authorization)
I’m trying to setup a nodejs-express environment to render pages that can help the user to setup credentials by submitting through a webpage and save/process it back-end.
Since the above code will wait for user input when calling client.start(), is there any way to break it down to 2 http request that posts the phoneNumber and password, then another http post to post the phoneCode from telegram for authentication?
I tried some Promise but it won’t work..
The idea is to have 2 steps, 1st one is to call /setup and post the initial credentials, then hope the client will call the telegram api to send a phone code to myself. After that I can call /setup API once more and submit the code as well.
The behavior of the following code is that, it can call and receive telegram’s phone code. But the second call to POST /setup API wouldn’t work and got stuck. So I can’t resolve the phone code for the client.
Is there any way that I could ignore the first Promise in the first http post, return a response, then call the API second time or a different route/url and send the data as the first Promise’s resolve?
let code = null;
async function waitForPhoneCode() {
return new Promise(function(resolve, reject) {
while(code==null){
//wait for code to be set on next http post
}
resolve(code);
});
}
app.post('/setup', async (req, res) => {
const setupStep = req.body.setupStep;
const apiId = req.body.apiId;
const apiHash = req.body.apiHash;
const phoneNumber = req.body.phoneNumber;
const password = req.body.password;
const obtainedCode = req.body.code;
credentials = {
"apiId": apiId,
"apiHash": apiHash
}
if(setupStep == 1){
client = new TelegramClient(new StringSession(""), credentials.apiId, credentials.apiHash, {
connectionRetries: 5,
});
res.json({
"status": "ok",
})
client.start({
phoneNumber: phoneNumber,
password: password,
phoneCode: waitForPhoneCode(),
onError: (err) => console.log(err),
});
} else if(setupStep == 2){
code = obtainedCode;
console.log("You should now be connected.");
credentials = {
apiId: apiId,
apiHash: apiHash,
stringSession: new sessionStorage(client.session.save())
}
fs.writeFileSync(credentialsPath, JSON.stringify({
apiId: apiId,
apiHash: apiHash,
stringSession: client.session.save(),
}));
await client.sendMessage("me", { message: "Setup Completed!" });
res.redirect('/');
}
})
2
Answers
Here's the full working example that has @Coxxs's promise implemented. Sleep a few seconds worked too. I tried with some more promise for the
client.start
callbacks and here's the working result. I know I could chain thethen()
method but I think this looked more logically appealing.Thank you so much for your help! I really appreciate that!
Note: If you had tried a lot of times authenticating (testing with a wrong code?), you might get this error and have to wait for a day before testing the code again
FloodWaitError: A wait of 78660 seconds is required (caused by auth.SendCode)
We can save the
resolve
provided by thePromise
to a global variable, and resolve it later.Here’s the fixed code: