summaryrefslogtreecommitdiff
path: root/packages/tweetdeck/tests/python.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tweetdeck/tests/python.ts')
-rw-r--r--packages/tweetdeck/tests/python.ts150
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 });