RSSHub/lib/routes/twitter/api/mobile-api/login.ts

185 lines
7.2 KiB
TypeScript

// https://github.com/BANKA2017/twitter-monitor/blob/node/apps/open_account/scripts/login.mjs
import { bearerToken, guestActivateUrl } from './constants';
import got from '@/utils/got';
import ofetch from '@/utils/ofetch';
import crypto from 'crypto';
import { config } from '@/config';
import { v5 as uuidv5 } from 'uuid';
import logger from '@/utils/logger';
import cache from '@/utils/cache';
const NAMESPACE = 'd41d092b-b007-48f7-9129-e9538d2d8fe9';
const username = config.twitter.username;
const password = config.twitter.password;
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() {
return await cache.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 ofetch.raw(
'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(),
{
method: 'POST',
headers,
body: {
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.get('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
);
}
export default login;