mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 10:15:48 +00:00
197 lines
6.2 KiB
JavaScript
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";
|
|
}
|