diff --git a/scripts/misc/twitch-autoreg.ts b/scripts/misc/twitch-autoreg.ts deleted file mode 100644 index 37d82e1..0000000 --- a/scripts/misc/twitch-autoreg.ts +++ /dev/null @@ -1,365 +0,0 @@ -import type { Browser } from 'patchright' -import type { EmailVerificationProvider } from '../../utils/temkakit/email-verification.ts' -import { writeFile } from 'node:fs/promises' -import { faker } from '@faker-js/faker' -import { sleep } from '@fuman/utils' -import { load } from 'cheerio' -import { Cookie, CookieJar } from 'tough-cookie' -import { ffetch as ffetchBase } from '../../utils/fetch.ts' -import { AnymessageEmailVerificationProvider } from '../../utils/temkakit/anymessage.ts' -import { solveKasadaSalamoonder } from '../../utils/temkakit/kasada-solver.ts' -import { createLibcurlFetch } from '../../utils/temkakit/libcurl.ts' - -// half broken, unfinished - -function getProxy() { - // return { - // user: 'JaTjXK', - // pass: 'WYsU4C', - // host: '38.152.247.16', - // port: 9785, - // } - return { - user: '', - pass: '', - host: '127.0.0.1', - port: 7891, - } -} - -function proxyToUrl(proxy: { user: string, pass: string, host: string, port: number }) { - return `http://${proxy.user}:${proxy.pass}@${proxy.host}:${proxy.port}` -} - -const THREADS = 1 -const ACCOUNTS_COUNT = 2 - -const TWITCH_PJS = 'https://k.twitchcdn.net/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/p.js' - -async function twitchAutoreg(options: { - // browser: Browser - emailProvider: EmailVerificationProvider - log?: (format: string, ...args: any[]) => void - proxy?: string -}) { - const { - // browser, - proxy, - emailProvider, - log = (fmt, ...args) => console.log(fmt, ...args), - } = options - const jar = new CookieJar() - - log('proxy', proxy) - const ffetch = ffetchBase.extend({ - cookies: jar, - fetch: createLibcurlFetch({ proxy }), - }) - - log('fetching main page') - const mainPage = await ffetch('https://www.twitch.tv/').text() - const twilightBuildId = mainPage.match(/window.__twilightBuildID="([^"]+)"/)?.[1] - if (!twilightBuildId) { - throw new Error('failed to get twilightBuildId') - } - - await jar.setCookie(new Cookie({ - key: 'api_token', - value: `twilight.${faker.string.hexadecimal({ length: 32 })}`, - domain: 'twitch.tv', - path: '/', - secure: true, - sameSite: 'None', - hostOnly: false, - expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), - }), 'https://www.twitch.tv') - await jar.setCookie(new Cookie({ - key: 'experiment_overrides', - value: encodeURIComponent(JSON.stringify({ experiments: {}, disabled: [] })), - domain: 'twitch.tv', - path: '/', - secure: true, - sameSite: 'None', - hostOnly: false, - expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), - }), 'https://www.twitch.tv') - - const deviceId = faker.string.alphanumeric({ length: 32 }) - const sessionId = faker.string.hexadecimal({ length: 16 }) - - log('generating integrity token') - - // const kasadaSolver = await createKasadaSolver({ - // pageUrl: 'https://www.twitch.tv/', - // scriptUrl: '', - // browser, - // beforePageLoad: async (page) => { - // await syncCookiesIntoBrowser(jar, page.context()) - // }, - // requests: [ - // { - // protocol: 'https', - // method: 'POST', - // domain: 'gql.twitch.tv', - // path: '/integrity', - // }, - // { - // protocol: 'https', - // method: 'POST', - // domain: 'passport.twitch.tv', - // path: '/integrity', - // }, - // { - // protocol: 'https', - // method: 'POST', - // domain: 'passport.twitch.tv', - // path: '/protected_register', - // }, - // { - // protocol: 'https', - // method: 'POST', - // domain: 'passport.twitch.tv', - // path: '/protected_login', - // }, - // ], - // }) - - const commonHeaders: Record = { - 'X-Device-Id': deviceId, - 'Client-Id': 'kimne78kx3ncx6brgo4mv6wki5h1ko', - 'Client-Request-Id': faker.string.alphanumeric({ length: 32 }), - 'Client-Session-Id': sessionId, - 'Client-Version': twilightBuildId, - } - - const kasadaSolution = await solveKasadaSalamoonder({ pjs: TWITCH_PJS }) - // const integrityToken = await kasadaSolver.request({ - // url: 'https://gql.twitch.tv/integrity', - // method: 'POST', - // headers: commonHeaders, - // }) as { token: string } - const integrityToken = await ffetch('https://gql.twitch.tv/integrity', { - method: 'POST', - headers: { - ...commonHeaders, - ...kasadaSolution, - }, - }).json() as { token: string } - - const ffetchGql = ffetchBase.extend({ - headers: { - 'Sec-Fetch-Dest': 'empty', - 'Sec-Fetch-Mode': 'cors', - 'Sec-Fetch-Site': 'same-site', - ...commonHeaders, - 'Client-Integrity': integrityToken.token, - }, - }) - - // await syncCookiesFromBrowser(kasadaSolver.page.context(), jar) - - let username - while (true) { - username = faker.internet.username().toLowerCase().replace(/[^a-z0-9]/gi, '') - log('checking username', username) - const r = await ffetchGql.post('https://gql.twitch.tv/gql', { - json: [ - { - operationName: 'UsernameValidator_User', - variables: { username }, - extensions: { - persistedQuery: { - version: 1, - sha256Hash: 'fd1085cf8350e309b725cf8ca91cd90cac03909a3edeeedbd0872ac912f3d660', - }, - }, - }, - ], - }).json() as any - - if (r[0].errors) { - throw new Error(`failed to check username:${JSON.stringify(r[0].errors)}`) - } - - if (r[0].data.isUsernameAvailable) { - log('username is available: %s', username) - break - } - - await sleep(1000) - } - - log('ordering email') - - const email = await emailProvider.getEmail() - - log('got email: %s, registering', email) - - const password = faker.internet.password({ length: 16, pattern: /[a-z0-9]/ }) - const birthday = faker.date.birthdate({ min: 18, max: 25, mode: 'age' }) - const registerBody: Record = { - username, - password, - email, - birthday: { - day: birthday.getDate(), - month: birthday.getMonth() + 1, - year: birthday.getFullYear(), - isOver18: true, - }, - email_marketing_opt_in: false, - client_id: 'kimne78kx3ncx6brgo4mv6wki5h1ko', - is_password_guide: 'nist', - } - - for (let i = 0; i < 5; i++) { - // const r1 = await kasadaSolver.request({ - // url: 'https://passport.twitch.tv/protected_register', - // method: 'POST', - // body: JSON.stringify(registerBody), - // headers: { - // 'Content-Type': 'text/plain;charset=UTF-8', - // 'Accept': '*/*', - // }, - // credentials: 'include', - // }) as { error_code: number } - log('solving kasada') - const kasadaSolution = await solveKasadaSalamoonder({ pjs: TWITCH_PJS }) - const r1 = await ffetch.post('https://passport.twitch.tv/protected_register', { - validateResponse: false, - json: registerBody, - headers: { - ...kasadaSolution, - }, - }).json() as { error_code: number } - - log('r1', r1) - - if (i < 4 && r1.error_code === 5025) { - log('integrity failed, retrying...') - continue - } - - if (r1.error_code !== 2026) { - await emailProvider.dispose() - throw new Error(`failed to register: ${JSON.stringify(r1)}`) - } - - break - } - - log('waiting for code') - const message = await emailProvider.waitForMessage({ timeout: 90_000 }) - const message$ = load(message) - const code = message$('center p[style^=background]').text() // what the fuck is this selector - // const code = await question('code: ') - - if (!code.match(/^\d{6}$/)) { - log('❌ invalid code parsed: %s', code) - log(message) - await emailProvider.dispose() - throw new Error(`invalid code parsed:${code}`) - } - - log('code: %s', code) - - registerBody.email_verification_code = code - for (let i = 0; i < 5; i++) { - // const r2 = await kasadaSolver.request({ - // url: 'https://passport.twitch.tv/protected_register', - // method: 'POST', - // body: JSON.stringify(registerBody), - // headers: { - // 'Content-Type': 'text/plain;charset=UTF-8', - // }, - // credentials: 'include', - // }) as { error_code: number } - log('solving kasada') - const kasadaSolution = await solveKasadaSalamoonder({ pjs: TWITCH_PJS }) - const r2 = await ffetch.post('https://passport.twitch.tv/protected_register', { - json: registerBody, - validateResponse: false, - headers: { - ...kasadaSolution, - }, - }).json() as { error_code: number } - - if (i < 4 && r2.error_code === 5025) { - log('integrity failed, retrying...') - continue - } - - if (r2.error_code) { - await emailProvider.dispose() - throw new Error(`❌ failed to register:${r2.error_code}`) - } - - break - } - - // await syncCookiesFromBrowser(kasadaSolver.page.context(), jar) - - log('авторег работает!') - await emailProvider.dispose() - - return { - username, - password, - email, - cookies: await jar.store.getAllCookies(), - } -} - -let started = 0 -let completed = 0 -await Promise.all(Array.from({ length: THREADS }).map(async (_, idx) => { - const emailProvider = new AnymessageEmailVerificationProvider({ - site: 'twitch.tv', - domain: 'hotmail.com', - }) - - let browser: Browser | null = null - while (true) { - if (started >= ACCOUNTS_COUNT) { - break - } - - started++ - - const log = (fmt: string, ...args: any[]) => console.log(`[worker ${idx}] ${fmt}`, ...args) - - try { - const proxy = getProxy() - - // browser = await chromium.launch({ - // channel: 'chrome', - // headless: false, - // env: { - // TZ: 'Europe/Amsterdam', - // }, - // proxy: { - // server: `http://${proxy.host}:${proxy.port}`, - // username: proxy.user, - // password: proxy.pass, - // }, - // }) - - const acct = await twitchAutoreg({ - // browser, - proxy: proxyToUrl(proxy), - emailProvider, - log, - }) - - await writeFile('assets/twitch-accs.txt', `${JSON.stringify(acct)}\n`, { flag: 'a' }) - - completed++ - log('completed: %d/%d', completed, ACCOUNTS_COUNT) - } catch (e) { - log('autoreg error: %s', e) - // await browser?.close() - browser = null - started-- - } - } -}))