dilame / instagram-private-api

NodeJS Instagram private API SDK. Written in TypeScript.
MIT License
5.93k stars 1.14k forks source link

Auth session error #1212

Closed ElectroMyStyle closed 4 years ago

ElectroMyStyle commented 4 years ago

Hello. I authorize my account and save its session data to a file:

const ig = new IgApi.IgApiClient();
    const IgCheckpointError = IgApi.IgCheckpointError;
    ig.state.generateDevice(login);

    ig.request.end$.subscribe(async () => {
        const serialized = await ig.state.serialize();
        delete serialized.constants; // this deletes the version info, so you'll always use the version provided by the library
        fs.writeFile(sessionUserPath, JSON.stringify(serialized), () => {
            console.log(`Session for account '${login}' saved.`);
        });
    });

    Bluebird.try(async () => {
        const auth = await ig.account.login(login, password);
        console.log(auth);
    }).catch(IgCheckpointError, async () => {
        console.log('Checkpoint:')
        console.log(ig.state.checkpoint); // Checkpoint info here
        await ig.challenge.auto(true); // Requesting sms-code or click "It was me" button
        console.log(ig.state.checkpoint); // Challenge info here
        const { code } = await inquirer.prompt([
            {
                type: 'input',
                name: 'code',
                message: 'Enter checkpoint code',
            },
        ]);

        const checkpointResult = await ig.challenge.sendSecurityCode(code);
        console.log(`Checkpoint result: ${checkpointResult}`);

    }).catch(e => console.log('Could not resolve checkpoint:', e, e.stack));

Then I use the session. Every time I run the script I add it to the object and log in to the account:

try {
            this.ig.state.generateDevice(login);

            const accountSession = await fp.readFile(this.sessionUserPath, 'utf8');

            // JSON string or Object
            await this.ig.state.deserialize(accountSession);

            this.auth = await this.ig.account.login(login, password);
        }
        catch (err) {
            console.error(`Не удалось авторизоваться через сессию за аккаунт ${login}, ошибка ${err.message}`);
            console.error(err.stack);
        }

The session file stores various data, but the problem is with the password encryption key passwordEncryptionPubKey and passwordEncryptionKeyId, or rather their version. Over time, these data are not updated in the session file and the subsequent authorization through session (over a period of time: several days or weeks), when Instagram updated the data on its servers, Instagram sends an error that the authorization data is incorrect and returns a HTTP 400. Since the password is encrypted with the old key from the session file.

At the moment, in the repositories/AccountRepository.js in the method login() line 26 should check for the encryption key, if you remove it and update the key even if it is available, I think the problem will be resolved. However, the login() method is called only when the script is run (often once), and it would not be superfluous to update the key and its version, especially when using old sessions for authorization.

Nerixyz commented 4 years ago

if you remove it and update the key even if it is available

No. This isn't really a good solution. Imo this check shouldn't be there, it's only there so we don't have thousands of issues asking on how to get the key. However I get the problem you're facing and you can pretty much fix it by calling ig.qe.syncLoginExperiments() yourself. Keep in mind repositories are supposed to do one thing, one API call. This is an exception.

ElectroMyStyle commented 4 years ago

Okay, thanks. Can be closed.