diff --git a/lib/config.ts b/lib/config.ts index 2f1793201..816a68a0a 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -261,6 +261,7 @@ export type Config = { oauthTokenSecrets?: string[]; username?: string; password?: string; + authenticationSecret?: string; cookie?: string; }; weibo: { @@ -613,6 +614,7 @@ const calculateValue = () => { oauthTokenSecrets: envs.TWITTER_OAUTH_TOKEN_SECRET?.split(','), username: envs.TWITTER_USERNAME, password: envs.TWITTER_PASSWORD, + authenticationSecret: envs.TWITTER_AUTHENTICATION_SECRET, cookie: envs.TWITTER_COOKIE, }, weibo: { diff --git a/lib/routes/twitter/api/mobile-api/login.ts b/lib/routes/twitter/api/mobile-api/login.ts index acf622747..fe7feb9a3 100644 --- a/lib/routes/twitter/api/mobile-api/login.ts +++ b/lib/routes/twitter/api/mobile-api/login.ts @@ -6,12 +6,14 @@ import ofetch from '@/utils/ofetch'; import crypto from 'crypto'; import { config } from '@/config'; import { v5 as uuidv5 } from 'uuid'; +import { authenticator } from 'otplib'; 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; +const authenticationSecret = config.twitter.authenticationSecret; let authentication = null; @@ -133,38 +135,37 @@ async function login() { }); logger.debug('Twitter login 5 finished: AccountDuplicationCheck.'); - for (const subtask of task4.data?.subtasks || []) { + for await (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); + 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.'); + 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; - // } - // } + for (const subtask of task5.data?.subtasks || []) { + if (subtask.open_account) { + authentication = subtask.open_account; + break; + } + } break; } } diff --git a/lib/routes/twitter/namespace.ts b/lib/routes/twitter/namespace.ts index ace8355e7..38f1269e0 100644 --- a/lib/routes/twitter/namespace.ts +++ b/lib/routes/twitter/namespace.ts @@ -40,8 +40,8 @@ generates Currently supports two authentication methods: -- Using TWITTER_COOKIE (recommended): Configure the cookies of logged-in Twitter Web, at least including the fields auth_token and ct0. RSSHub will use this information to directly access Twitter's web API to obtain data. +- Using \`TWITTER_COOKIE\` (recommended): Configure the cookies of logged-in Twitter Web, at least including the fields auth_token and ct0. RSSHub will use this information to directly access Twitter's web API to obtain data. -- Using TWITTER_USERNAME TWITTER_PASSWORD: Configure the Twitter username and password. RSSHub will use this information to log in to Twitter and obtain data using the mobile API. Please note that if you have not logged in with the current IP address before, it is easy to trigger Twitter's risk control mechanism. +- Using \`TWITTER_USERNAME\` \`TWITTER_PASSWORD\` and \`TWITTER_AUTHENTICATION_SECRET\`: Configure the Twitter username and password. RSSHub will use this information to log in to Twitter and obtain data using the mobile API. Please note that if you have not logged in with the current IP address before, it is easy to trigger Twitter's risk control mechanism. `, }; diff --git a/lib/routes/twitter/user.ts b/lib/routes/twitter/user.ts index c53469392..6d78b8f15 100644 --- a/lib/routes/twitter/user.ts +++ b/lib/routes/twitter/user.ts @@ -21,6 +21,11 @@ export const route: Route = { name: 'TWITTER_PASSWORD', description: 'Please see above for details.', }, + { + name: 'TWITTER_AUTHENTICATION_SECRET', + description: 'TOTP 2FA secret, please see above for details.', + optional: true, + }, { name: 'TWITTER_COOKIE', description: 'Please see above for details.',