diff options
Diffstat (limited to 'packages/tweetdeck/tests/python.ts')
| -rw-r--r-- | packages/tweetdeck/tests/python.ts | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/packages/tweetdeck/tests/python.ts b/packages/tweetdeck/tests/python.ts new file mode 100644 index 0000000..73a174b --- /dev/null +++ b/packages/tweetdeck/tests/python.ts @@ -0,0 +1,150 @@ +import { TransactionIdGenerator as TransactionIdGenerator } from "../src/lib/fetching/python"; + +export const cookie = `auth_token=651d779cb99b54e7ce81bf8f8050e597c452b50b;gt=1868678280205029867;guest_id=v1%3A176150648682600359;__cf_bm=mfj12NkVbU0uPRz84om3BecRhAwv.8CCo.w0B4Gw45o-1761513085.2856057-1.0.1.1-gHPgX0w_GRneFL_GLZ5kPSXd7VCe4EuZnxN9FeKlpRg5PR5CCFrHazEjrE_EM53YxTbd1hDJoaWNXSU.Abr7FmBF5aCso.Jqn6M1ycwSXLhvQ3nTdZXRfiGpDrQugR6q;twid=u%3D1710606417324015616;g_state={"i_p":1733335699025,"i_l":1};external_referer=8e8t2xd8A2w%3D|0|F8C7rVpldvH1T6C9tW%2FBRRUSYlUEkKIshjiEn%2Br%2F70sqqRYvQQ%2FYUQ%3D%3D;auth_multi="1761426801275097088:f10fe04281e0bdf50e9dba703e2cba86adb84847";lang=en;night_mode=2;__cf_bm=koa1LKRskRZYwhHNG6YcIcSFN87JPc24Tb3umQqxxxU-1761507653-1.0.1.1-9OQutUp3hCAW8o5Sr8S0h.uE0eTWkxGRYiiESZu6WW9Q_Y_out9M6G9FqS5n9BVn1svlAUT97_FyLZosboQ45Q0M_HZ4F_rYtd3ojsAm6n8;__cuid=b4c86e91126647b5b7e07dadeac8ec2b;ct0=678e86afdb647f32835e25d1204c99af50b95d0e9ebcaf9db2d837fb9c4e48759a0e218c4845337f429c10e8d95f8a97cb9a7cee84c1bc5a7b522f440d5b6824466b6f4b62c328cc32d980a22fb00745;dnt=1;guest_id_ads=v1%3A176150648682600359;guest_id_marketing=v1%3A176150648682600359;kdt=camHTtNmw0pQUK0ZHaYd6jJnJRRYihbuZ0Ii7yN2;personalization_id="v1_KKOJ4dZoYTZuKLY9eadfIg=="`; + +async function initTransactionIdGenerator(): Promise<TransactionIdGenerator> { + const MAX_REDIRECTS = 5; + let currentUrl = "https://x.com"; + let html = ""; + const headers: Record<string, string> = { + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "Accept-Language": "en-US,en;q=0.9", + Cookie: cookie, + }; + + try { + for ( + let redirectCount = 0; + redirectCount < MAX_REDIRECTS; + redirectCount++ + ) { + const response = await fetch(currentUrl, { headers }); + headers["Cookie"] = cookie; + + if (!response.ok) { + throw new Error( + `Failed fetching ${currentUrl}: ${response.status} ${response.statusText}`, + ); + } + + html = await response.text(); + + // Check for meta refresh redirect + const metaRefreshMatch = html.match( + /<meta\s+http-equiv=["']refresh["']\s+content=["'][^;]+;\s*url=([^"']+)/i, + ); + const migrationRedirectionRegex = + /(http(?:s)?:\/\/(?:www\.)?(?:twitter|x)\.com(?:\/x)?\/migrate(?:[\/?])?tok=[a-zA-Z0-9%\-_]+)/i; + const bodyMatch = html.match(migrationRedirectionRegex); + let migrationUrl = metaRefreshMatch?.[1] || bodyMatch?.[0]; + + if (migrationUrl) { + currentUrl = migrationUrl; + continue; + } + + // Handle migration form + const formMatch = html.match( + /<form[^>]*?(?:name=["']f["']|action=["']https:\/\/x\.com\/x\/migrate["'])[^>]*>([\s\S]*?)<\/form>/i, + ); + if (formMatch) { + const formContent = formMatch[1]; + const actionMatch = formMatch[0].match(/action=["']([^"']+)["']/i); + const methodMatch = formMatch[0].match(/method=["']([^"']+)["']/i); + + const formAction = actionMatch?.[1] || "https://x.com/x/migrate"; + const formMethod = methodMatch?.[1]?.toUpperCase() || "POST"; + const formUrl = new URL(formAction, currentUrl); + if (!formUrl.searchParams.has("mx")) { + formUrl.searchParams.set("mx", "2"); + } + + const payload = new URLSearchParams(); + const inputRegex = + /<input[^>]*?name=["']([^"']+)["'][^>]*?(?:value=["']([^"']*)["'])?[^>]*?>/gi; + let inputMatch; + while ((inputMatch = inputRegex.exec(formContent!)) !== null) { + payload.append(inputMatch[1]!, inputMatch[2] || ""); + } + + const formHeaders = { + ...headers, + "Content-Type": "application/x-www-form-urlencoded", + Referer: currentUrl, + }; + + const response = await fetch(formUrl.toString(), { + method: formMethod, + headers: formHeaders, + body: payload, + redirect: "manual", + }); + headers["Cookie"] = cookie; + + if ( + response.status >= 300 && + response.status < 400 && + response.headers.has("location") + ) { + currentUrl = new URL( + response.headers.get("location")!, + currentUrl, + ).toString(); + continue; + } + + if (!response.ok) { + throw new Error( + `Migration form submission failed: ${response.status} ${response.statusText}`, + ); + } + + html = await response.text(); + + const subsequentMetaRefresh = html.match( + /<meta\s+http-equiv=["']refresh["']\s+content=["'][^;]+;\s*url=([^"']+)/i, + ); + const subsequentBodyMatch = html.match(migrationRedirectionRegex); + + if (subsequentMetaRefresh?.[1] || subsequentBodyMatch?.[0]) { + currentUrl = subsequentMetaRefresh?.[1] || subsequentBodyMatch![0]; + if (!currentUrl.startsWith("http")) { + currentUrl = new URL(currentUrl, response.url).toString(); + } + continue; + } + } + + break; + } + + if (!html) { + throw new Error("Failed to retrieve HTML after potential migrations."); + } + + const transactionIdGenerator = new TransactionIdGenerator(html); + return transactionIdGenerator; + } catch (error: any) { + throw new Error( + `Transaction ID initialization failed: ${error.message || error}`, + ); + } +} + +async function generateTransactionId( + method: string, + path: string, +): Promise<string> { + const gen = new TransactionIdGenerator(""); + await gen.init(); + // const gen = await initTransactionIdGenerator(); + + return gen.getTransactionId(method, path); +} + +const res = await generateTransactionId( + "GET", + "i/api/graphql/2AtIgw7Kz26sV6sEBrQjSQ/UsersByRestIds", +); +console.log({ res }); |
