"use strict";
const rows = document.getElementById("rows");
const nameInput = document.getElementById("name");
const createBtn = document.getElementById("create");
const errorEl = document.getElementById("error");
const statusEl = document.getElementById("status");
const portInput = document.getElementById("port");
const savePortBtn = document.getElementById("save-port");
const modal = document.getElementById("secret-modal");
const secretEl = document.getElementById("secret");
const copyBtn = document.getElementById("copy");
const closeBtn = document.getElementById("close");
function applyStatus(info) {
if (info && info.listenPort) {
portInput.value = String(info.listenPort);
}
if (info && info.bindError) {
statusEl.textContent = `Could not listen on ${info.listenPort}: ${info.bindError}`;
return;
}
statusEl.textContent = info && info.hostUp
? `This add-on is ready on 127.0.0.1:${info.listenPort} while Firefox is open.`
: "You can issue and revoke secrets here anytime.";
}
function showError(text) {
errorEl.hidden = !text;
errorEl.textContent = text || "";
}
function render(clients) {
if (!clients.length) {
rows.innerHTML = '
| No clients yet. Generate a secret to get started. |
';
return;
}
rows.innerHTML = "";
for (const client of clients) {
const tr = document.createElement("tr");
tr.innerHTML = `
${escapeHtml(client.name)} |
${escapeHtml(client.created || "")} |
${escapeHtml(client.last_used || "never")} |
| `;
rows.appendChild(tr);
}
}
function escapeHtml(value) {
return String(value)
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """);
}
async function refresh() {
render(await listClients());
try {
applyStatus(await browser.runtime.sendMessage({ type: "status" }));
} catch (err) {
statusEl.textContent = "You can issue and revoke secrets here anytime.";
}
}
savePortBtn.addEventListener("click", async () => {
showError("");
try {
applyStatus(await browser.runtime.sendMessage({ type: "set-port", port: portInput.value }));
} catch (err) {
showError(err.message);
}
});
createBtn.addEventListener("click", async () => {
showError("");
try {
const created = await createClient(nameInput.value.trim());
nameInput.value = "";
secretEl.value = created.token;
modal.showModal();
await refresh();
} catch (err) {
showError(err.message);
}
});
rows.addEventListener("click", async (event) => {
const id = event.target && event.target.getAttribute("data-revoke");
if (!id) {
return;
}
showError("");
try {
await revokeClient(id);
await refresh();
} catch (err) {
showError(err.message);
}
});
copyBtn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(secretEl.value);
copyBtn.textContent = "Copied";
} catch (err) {
showError(err.message);
}
});
closeBtn.addEventListener("click", () => {
secretEl.value = "";
copyBtn.textContent = "Copy";
modal.close();
});
refresh().catch((err) => showError(err.message));