- 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>
40 lines
1.5 KiB
JavaScript
40 lines
1.5 KiB
JavaScript
// Runs in the page's own JavaScript world and defines window.nostr (NIP-07).
|
|
// Calls are forwarded to content.js with postMessage, then to the background
|
|
// worker, which asks the user before any site can use the key.
|
|
(() => {
|
|
if (window.nostr) return; // another signer extension got here first
|
|
|
|
const pending = new Map();
|
|
let seq = 0;
|
|
|
|
window.addEventListener("message", (e) => {
|
|
if (e.source !== window || e.data?.__goostr !== "res") return;
|
|
const p = pending.get(e.data.id);
|
|
if (!p) return;
|
|
pending.delete(e.data.id);
|
|
if (e.data.error) p.reject(new Error(e.data.error));
|
|
else p.resolve(e.data.result);
|
|
});
|
|
|
|
const call = (method, params) =>
|
|
new Promise((resolve, reject) => {
|
|
const id = `goostr-${++seq}-${Math.random().toString(36).slice(2)}`;
|
|
pending.set(id, { resolve, reject });
|
|
window.postMessage({ __goostr: "req", id, method, params }, location.origin);
|
|
});
|
|
|
|
window.nostr = {
|
|
getPublicKey: () => call("getPublicKey"),
|
|
signEvent: (event) => call("signEvent", { event }),
|
|
getRelays: () => call("getRelays"),
|
|
nip04: {
|
|
encrypt: (pubkey, plaintext) => call("nip04.encrypt", { pubkey, plaintext }),
|
|
decrypt: (pubkey, ciphertext) => call("nip04.decrypt", { pubkey, ciphertext }),
|
|
},
|
|
nip44: {
|
|
encrypt: (pubkey, plaintext) => call("nip44.encrypt", { pubkey, plaintext }),
|
|
decrypt: (pubkey, ciphertext) => call("nip44.decrypt", { pubkey, ciphertext }),
|
|
},
|
|
};
|
|
})();
|