mirror of
https://git.stupid.fish/teidesu/scripts.git
synced 2026-01-12 23:21:08 +11:00
Compare commits
30 commits
ef375d1188
...
da3ca48244
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da3ca48244 | ||
|
|
171ba5de7a | ||
|
|
261c7eefa0 | ||
|
|
96ca247fcb | ||
|
|
728699b3ec | ||
|
|
ccc5f98f34 | ||
|
|
2b73e3b411 | ||
|
|
3057b2a78c | ||
|
|
8c04afc6d2 | ||
|
|
25d88cb28b | ||
|
|
2d46db9c77 | ||
|
|
a2b73a9982 | ||
|
|
68a2d17239 | ||
|
|
96426d01c1 | ||
|
|
ce9f435ef2 | ||
|
|
874e1952e3 | ||
|
|
a7f1118602 | ||
|
|
655e5a8e15 | ||
|
|
f02ccb6029 | ||
|
|
c118bcbfc3 | ||
|
|
bb5311f828 | ||
|
|
c2410ec787 | ||
|
|
75cc539786 | ||
|
|
fd6cfba726 | ||
|
|
67a6238632 | ||
|
|
090a502ece | ||
|
|
2423324540 | ||
|
|
9891d7734d | ||
|
|
e7c9507247 | ||
|
|
e0109980c0 |
1 changed files with 365 additions and 0 deletions
365
scripts/misc/twitch-autoreg.ts
Normal file
365
scripts/misc/twitch-autoreg.ts
Normal file
|
|
@ -0,0 +1,365 @@
|
||||||
|
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<string, string> = {
|
||||||
|
'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<string, any> = {
|
||||||
|
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--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue