Googstr/extension/popup.js
Jason Tudisco fcfaec675a Add NIP-46 signer, optional NIP-07 extension, passkey protection, backups
- NIP-46 remote signer in the page (bunker:// and nostrconnect:// pairing)
- Chrome extension (NIP-07) with per-site permission prompts, unlocked by
  the site via externally_connectable; downloadable from the page
- Passkey (WebAuthn PRF) encryption of the Drive key file
- NIP-49 backups: download or save to Drive; reveal nsec
- Fix: oldest key file wins when two devices sign up at once
- Fix: never overwrite an existing kind-0 because a relay was slow
- Fix: EOSE tracking; relays reconnect with backoff; verify event signatures
- One-click re-sign-in (consent only the first time)
- Vendored, pinned nostr-tools; CSP; no third-party scripts but Google's

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:33:02 -06:00

31 lines
1.2 KiB
JavaScript

const $ = (id) => document.getElementById(id);
const send = (msg) => chrome.runtime.sendMessage(msg);
async function render() {
const s = await send({ type: "popup-state" });
$("locked").classList.toggle("hidden", !!s.npub);
$("unlocked").classList.toggle("hidden", !s.npub);
if (!s.npub) return;
$("name").textContent = s.profile?.name || "Your nostr identity";
$("npub").textContent = s.npub;
const sites = Object.keys(s.perms);
$("no-sites").classList.toggle("hidden", sites.length > 0);
$("sites").replaceChildren(...sites.map((origin) => {
const li = document.createElement("li");
const span = document.createElement("span");
span.className = "mono";
span.textContent = origin;
const btn = document.createElement("button");
btn.className = "small";
btn.textContent = "Revoke";
btn.onclick = async () => { await send({ type: "revoke", origin }); render(); };
li.append(span, btn);
return li;
}));
}
$("unlock").onclick = async () => { await send({ type: "open-goostr" }); window.close(); };
$("lock").onclick = async () => { await send({ type: "lock" }); render(); };
chrome.storage.session.onChanged.addListener(render);
render();