124 lines
3.4 KiB
JavaScript
124 lines
3.4 KiB
JavaScript
"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) {
|
|
rows.replaceChildren();
|
|
if (!clients.length) {
|
|
const tr = document.createElement("tr");
|
|
const td = document.createElement("td");
|
|
td.colSpan = 4;
|
|
td.className = "muted";
|
|
td.textContent = "No clients yet. Generate a secret to get started.";
|
|
tr.appendChild(td);
|
|
rows.appendChild(tr);
|
|
return;
|
|
}
|
|
for (const client of clients) {
|
|
const tr = document.createElement("tr");
|
|
for (const text of [client.name, client.created || "", client.last_used || "never"]) {
|
|
const td = document.createElement("td");
|
|
td.textContent = text;
|
|
tr.appendChild(td);
|
|
}
|
|
const action = document.createElement("td");
|
|
const btn = document.createElement("button");
|
|
btn.type = "button";
|
|
btn.textContent = "Revoke";
|
|
btn.dataset.revoke = client.id;
|
|
action.appendChild(btn);
|
|
tr.appendChild(action);
|
|
rows.appendChild(tr);
|
|
}
|
|
}
|
|
|
|
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));
|