RSSHub/lib/v2/twitter/web-api/login.js

184 lines
7.1 KiB
JavaScript

// https://github.com/BANKA2017/twitter-monitor/blob/node/apps/open_account/scripts/login.mjs
const { bearerToken, guestActivateUrl } = require('./constants');
const got = require('@/utils/got');
const crypto = require('crypto');
const config = require('@/config').value;
const { v5: uuidv5 } = require('uuid');
const { authenticator } = require('otplib');
const logger = require('@/utils/logger');
const NAMESPACE = 'd41d092b-b007-48f7-9129-e9538d2d8fe9';
const username = config.twitter.username;
const password = config.twitter.password;
const authenticationSecret = config.twitter.authenticationSecret;
let authentication = null;
const headers = {
'User-Agent': 'TwitterAndroid/10.21.0-release.0 (310210000-r-0) ONEPLUS+A3010/9 (OnePlus;ONEPLUS+A3010;OnePlus;OnePlus3;0;;1;2016)',
'X-Twitter-API-Version': 5,
'X-Twitter-Client': 'TwitterAndroid',
'X-Twitter-Client-Version': '10.21.0-release.0',
'OS-Version': '28',
'System-User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3010 Build/PKQ1.181203.001)',
'X-Twitter-Active-User': 'yes',
'Content-Type': 'application/json',
Authorization: bearerToken,
};
async function login(tryGet) {
return await tryGet(
`twitter:authentication:${username}`,
async () => {
logger.debug('Twitter login start.');
const android_id = uuidv5(username, NAMESPACE);
headers['X-Twitter-Client-DeviceID'] = android_id;
const ct0 = crypto.randomUUID().replaceAll('-', '');
const guestToken = await got(guestActivateUrl, {
headers: {
authorization: bearerToken,
'x-csrf-token': ct0,
cookie: 'ct0=' + ct0,
},
method: 'POST',
});
logger.debug('Twitter login 1 finished: guest token.');
headers['x-guest-token'] = guestToken.data.guest_token;
const task1 = await got.post(
'https://api.twitter.com/1.1/onboarding/task.json?' +
new URLSearchParams({
flow_name: 'login',
api_version: '1',
known_device_token: '',
sim_country_code: 'us',
}).toString(),
{
headers,
json: {
flow_token: null,
input_flow_data: {
country_code: null,
flow_context: {
referrer_context: {
referral_details: 'utm_source=google-play&utm_medium=organic',
referrer_url: '',
},
start_location: {
location: 'deeplink',
},
},
requested_variant: null,
target_user_id: 0,
},
},
}
);
logger.debug('Twitter login 2 finished: login flow.');
headers.att = task1.headers.att;
const task2 = await got.post('https://api.twitter.com/1.1/onboarding/task.json', {
headers,
json: {
flow_token: task1.data.flow_token,
subtask_inputs: [
{
enter_text: {
suggestion_id: null,
text: username,
link: 'next_link',
},
subtask_id: 'LoginEnterUserIdentifier',
},
],
},
});
logger.debug('Twitter login 3 finished: LoginEnterUserIdentifier.');
const task3 = await got.post('https://api.twitter.com/1.1/onboarding/task.json', {
headers,
json: {
flow_token: task2.data.flow_token,
subtask_inputs: [
{
enter_password: {
password,
link: 'next_link',
},
subtask_id: 'LoginEnterPassword',
},
],
},
});
logger.debug('Twitter login 4 finished: LoginEnterPassword.');
const task4 = await got.post('https://api.twitter.com/1.1/onboarding/task.json', {
headers,
json: {
flow_token: task3.data.flow_token,
subtask_inputs: [
{
check_logged_in_account: {
link: 'AccountDuplicationCheck_false',
},
subtask_id: 'AccountDuplicationCheck',
},
],
},
});
logger.debug('Twitter login 5 finished: AccountDuplicationCheck.');
for (const subtask of task4.data?.subtasks || []) {
if (subtask.open_account) {
authentication = subtask.open_account;
break;
} else if (subtask.subtask_id === 'LoginTwoFactorAuthChallenge') {
const token = authenticator.generate(authenticationSecret);
// eslint-disable-next-line no-await-in-loop
const task5 = await got.post('https://api.twitter.com/1.1/onboarding/task.json', {
headers,
json: {
flow_token: task4.data.flow_token,
subtask_inputs: [
{
enter_text: {
suggestion_id: null,
text: token,
link: 'next_link',
},
subtask_id: 'LoginTwoFactorAuthChallenge',
},
],
},
});
logger.debug('Twitter login 6 finished: LoginTwoFactorAuthChallenge.');
for (const subtask of task5.data?.subtasks || []) {
if (subtask.open_account) {
authentication = subtask.open_account;
break;
}
}
break;
}
}
if (authentication) {
logger.debug('Twitter login success.');
} else {
logger.error(`Twitter login failed. ${JSON.stringify(task4.data?.subtasks, null, 2)}`);
}
return authentication;
},
60 * 60 * 24 * 30, // 30 days
false
);
}
module.exports = login;