haixunMaster/extension/haixun-threads-sync/storage-state.js

111 lines
3.0 KiB
JavaScript

/** @typedef {{ name: string; value: string; domain: string; path: string; expires: number; httpOnly: boolean; secure: boolean; sameSite: string }} PlaywrightCookie */
const COOKIE_DOMAINS = [
"threads.com",
"threads.net",
"instagram.com",
"facebook.com",
];
const THREADS_TAB_URLS = [
"https://www.threads.com/*",
"https://threads.com/*",
"https://www.threads.net/*",
"https://threads.net/*",
];
function mapSameSite(sameSite) {
if (sameSite === "no_restriction") return "None";
if (sameSite === "lax") return "Lax";
if (sameSite === "strict") return "Strict";
return "Lax";
}
/** @param {chrome.cookies.Cookie} cookie */
function toPlaywrightCookie(cookie) {
return {
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
path: cookie.path || "/",
expires: cookie.expirationDate ?? -1,
httpOnly: cookie.httpOnly ?? false,
secure: cookie.secure ?? false,
sameSite: mapSameSite(cookie.sameSite),
};
}
export async function collectThreadsCookies() {
/** @type {PlaywrightCookie[]} */
const merged = [];
const seen = new Set();
for (const domain of COOKIE_DOMAINS) {
const batch = await chrome.cookies.getAll({ domain });
for (const cookie of batch) {
const key = `${cookie.domain}|${cookie.path}|${cookie.name}`;
if (seen.has(key)) continue;
seen.add(key);
merged.push(toPlaywrightCookie(cookie));
}
}
// Some Chrome builds store Meta login cookies only on exact host URLs.
const urls = [
"https://www.threads.com/",
"https://www.threads.net/",
"https://www.instagram.com/",
];
for (const url of urls) {
const batch = await chrome.cookies.getAll({ url });
for (const cookie of batch) {
const key = `${cookie.domain}|${cookie.path}|${cookie.name}`;
if (seen.has(key)) continue;
seen.add(key);
merged.push(toPlaywrightCookie(cookie));
}
}
return merged;
}
export async function collectThreadsLocalStorage() {
const tabs = await chrome.tabs.query({ url: THREADS_TAB_URLS });
if (!tabs.length || tabs[0].id == null) {
return [];
}
const [injection] = await chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: () => {
const localStorageItems = [];
for (let i = 0; i < localStorage.length; i += 1) {
const name = localStorage.key(i);
if (!name) continue;
localStorageItems.push({ name, value: localStorage.getItem(name) ?? "" });
}
return { origin: location.origin, localStorage: localStorageItems };
},
});
const payload = injection?.result;
if (!payload || !Array.isArray(payload.localStorage)) {
return [];
}
return [payload];
}
export async function buildStorageState() {
const cookies = await collectThreadsCookies();
const origins = await collectThreadsLocalStorage();
if (!cookies.length) {
throw new Error(
"找不到 Threads / Instagram cookies。請先在 Chrome 開啟 threads.com 或 threads.net 並完成登入"
);
}
return JSON.stringify({ cookies, origins });
}