Files
2026-05-24 11:27:02 +07:00

197 lines
6.2 KiB
JavaScript

const state = {
tab: null,
originPattern: "",
cookies: [],
};
const els = {
gatewayUrl: document.getElementById("gatewayUrl"),
token: document.getElementById("token"),
userId: document.getElementById("userId"),
agentId: document.getElementById("agentId"),
grant: document.getElementById("grant"),
refresh: document.getElementById("refresh"),
selectAll: document.getElementById("selectAll"),
sync: document.getElementById("sync"),
cookies: document.getElementById("cookies"),
status: document.getElementById("status"),
};
init().catch((err) => setStatus(err.message, true));
async function init() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
state.tab = tab;
state.originPattern = originPatternFor(tab?.url || "");
const settings = await chrome.storage.local.get(["gatewayUrl", "token", "userId", "agentId"]);
els.gatewayUrl.value = settings.gatewayUrl || "http://localhost:18790";
els.token.value = settings.token || "";
els.userId.value = settings.userId || "";
els.agentId.value = settings.agentId || "default";
bindEvents();
await loadCookies();
}
function bindEvents() {
for (const input of [els.gatewayUrl, els.token, els.userId, els.agentId]) {
input.addEventListener("change", saveSettings);
}
els.grant.addEventListener("click", requestSiteAccess);
els.refresh.addEventListener("click", loadCookies);
els.selectAll.addEventListener("click", selectAllCookies);
els.sync.addEventListener("click", syncSelected);
}
async function saveSettings() {
await chrome.storage.local.set({
gatewayUrl: els.gatewayUrl.value.trim(),
token: els.token.value,
userId: els.userId.value.trim(),
agentId: els.agentId.value.trim(),
});
}
async function requestSiteAccess() {
if (!state.originPattern) {
setStatus("Active tab is not an HTTP site.", true);
return;
}
const granted = await chrome.permissions.request({ origins: [state.originPattern] });
if (!granted) {
setStatus("Site access not granted.", true);
return;
}
await loadCookies();
}
async function loadCookies() {
if (!state.tab?.url || !state.originPattern) {
setStatus("Open an HTTP site tab first.", true);
return;
}
const hasPermission = await chrome.permissions.contains({ origins: [state.originPattern] });
if (!hasPermission) {
state.cookies = [];
renderCookies();
setStatus("Grant access for this site before reading cookies.");
return;
}
state.cookies = await chrome.cookies.getAll({ url: state.tab.url });
renderCookies();
setStatus(`${state.cookies.length} cookies available for this site.`);
}
function renderCookies() {
els.cookies.textContent = "";
if (state.cookies.length === 0) {
const empty = document.createElement("div");
empty.className = "cookie-meta";
empty.textContent = "No cookies loaded.";
els.cookies.append(empty);
return;
}
for (const cookie of state.cookies) {
const row = document.createElement("label");
row.className = "cookie-row";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.dataset.cookieKey = cookieKey(cookie);
const body = document.createElement("div");
const name = document.createElement("div");
name.className = "cookie-name";
name.textContent = cookie.name;
const meta = document.createElement("div");
meta.className = "cookie-meta";
meta.textContent = `${cookie.domain}${cookie.path || "/"}${cookie.httpOnly ? " · HttpOnly" : ""}${cookie.secure ? " · Secure" : ""}`;
body.append(name, meta);
row.append(checkbox, body);
els.cookies.append(row);
}
}
function selectAllCookies() {
for (const checkbox of els.cookies.querySelectorAll("input[type='checkbox']")) {
checkbox.checked = true;
}
}
async function syncSelected() {
await saveSettings();
const selectedKeys = new Set(
[...els.cookies.querySelectorAll("input[type='checkbox']:checked")].map((el) => el.dataset.cookieKey),
);
const cookies = state.cookies.filter((cookie) => selectedKeys.has(cookieKey(cookie)));
if (cookies.length === 0) {
setStatus("Select at least one cookie.", true);
return;
}
const gatewayUrl = els.gatewayUrl.value.trim().replace(/\/+$/, "");
const userId = els.userId.value.trim();
const agentId = els.agentId.value.trim();
if (!gatewayUrl || !userId || !agentId) {
setStatus("Gateway URL, User ID, and Agent ID are required.", true);
return;
}
if (!(await ensureOriginPermission(gatewayUrl))) {
setStatus("Gateway access not granted.", true);
return;
}
const headers = {
"Content-Type": "application/json",
"X-GoClaw-User-Id": userId,
};
if (els.token.value) {
headers.Authorization = `Bearer ${els.token.value}`;
}
const response = await fetch(`${gatewayUrl}/v1/browser/cookies/sync`, {
method: "POST",
headers,
body: JSON.stringify({
agent_id: agentId,
source: "chrome-selected-cookie-sync",
cookies: cookies.map((cookie) => ({
domain: cookie.domain,
name: cookie.name,
path: cookie.path,
value: cookie.value,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
sameSite: cookie.sameSite,
expirationDate: cookie.expirationDate,
})),
}),
});
const data = await response.json().catch(() => ({}));
if (!response.ok) {
setStatus(data.error || `Sync failed with HTTP ${response.status}.`, true);
return;
}
setStatus(`Synced ${data.synced ?? cookies.length} cookies.`);
}
async function ensureOriginPermission(rawUrl) {
const pattern = originPatternFor(rawUrl);
if (!pattern) return false;
if (await chrome.permissions.contains({ origins: [pattern] })) return true;
return chrome.permissions.request({ origins: [pattern] });
}
function originPatternFor(rawUrl) {
try {
const url = new URL(rawUrl);
if (url.protocol !== "http:" && url.protocol !== "https:") return "";
return `${url.protocol}//${url.host}/*`;
} catch {
return "";
}
}
function cookieKey(cookie) {
return `${cookie.domain}\n${cookie.path}\n${cookie.name}`;
}
function setStatus(message, isError = false) {
els.status.textContent = message;
els.status.style.color = isError ? "#b42318" : "#526074";
}