rsshub
Version:
Make RSS Great Again!
74 lines (68 loc) • 3.19 kB
text/typescript
import { authenticator } from 'otplib';
import logger from '@/utils/logger';
import cache from '@/utils/cache';
import { RateLimiterMemory, RateLimiterRedis, RateLimiterQueue } from 'rate-limiter-flexible';
import puppeteer from '@/utils/puppeteer';
import { CookieJar } from 'tough-cookie';
const loginLimiter = cache.clients.redisClient
? new RateLimiterRedis({
points: 1,
duration: 20,
execEvenly: true,
storeClient: cache.clients.redisClient,
})
: new RateLimiterMemory({
points: 1,
duration: 20,
execEvenly: true,
});
const loginLimiterQueue = new RateLimiterQueue(loginLimiter);
async function login({ username, password, authenticationSecret }) {
if (!username || !password) {
return;
}
try {
await loginLimiterQueue.removeTokens(1);
const cookieJar = new CookieJar();
const browser = await puppeteer();
const page = await browser.newPage();
await page.goto('https://x.com/i/flow/login');
await page.waitForSelector('input[autocomplete="username"]');
await page.type('input[autocomplete="username"]', username);
const buttons = await page.$$('button');
await buttons[3]?.click();
await page.waitForSelector('input[autocomplete="current-password"]');
await page.type('input[autocomplete="current-password"]', password);
(await page.waitForSelector('button[data-testid="LoginForm_Login_Button"]'))?.click();
if (authenticationSecret) {
await page.waitForSelector('input[inputmode="numeric"]');
const token = authenticator.generate(authenticationSecret);
await page.type('input[inputmode="numeric"]', token);
(await page.waitForSelector('button[data-testid="ocfEnterTextNextButton"]'))?.click();
}
const waitForRequest = new Promise<string>((resolve) => {
page.on('response', async (response) => {
if (response.url().includes('/HomeTimeline')) {
const data = await response.json();
const message = data?.data?.home?.home_timeline_urt?.instructions?.[0]?.entries?.[0]?.entryId;
if (message === 'messageprompt-suspended-prompt') {
logger.error(`twitter debug: twitter username ${username} login failed: messageprompt-suspended-prompt`);
resolve('');
}
const cookies = await page.cookies();
for (const cookie of cookies) {
cookieJar.setCookieSync(`${cookie.name}=${cookie.value}`, 'https://x.com');
}
logger.debug(`twitter debug: twitter username ${username} login success`);
resolve(JSON.stringify(cookieJar.serializeSync()));
}
});
});
const cookieString = await waitForRequest;
await browser.close();
return cookieString;
} catch (error) {
logger.error(`twitter debug: twitter username ${username} login failed:`, error);
}
}
export default login;