{`
{raw} = anything after the colon, i.e. the full nip19 bech32 string
{hex} = hex pubkey for npub or nprofile, hex event id for note or nevent
{p_or_e} = "p" for npub or nprofile, "e" for note or nevent
{u_or_n} = "u" for npub or nprofile, "n" for note or nevent
{relay0} = first relay in a nprofile or nevent
{relay1} = second relay in a nprofile or nevent
{relay2} = third relay in a nprofile or nevent
{hrp} = human-readable prefix of the nip19 string
examples:
- https://njump.me/{raw}
- https://snort.social/{raw}
- https://nostr.band/{raw}
`}
)}
)}
);
async function handleKeyChange(e) {
const key = e.target.value.toLowerCase().trim();
setPrivKey(key);
addUnsavedChanges("private_key");
}
async function generate() {
setPrivKey(nip19.nsecEncode(generatePrivateKey()));
addUnsavedChanges("private_key");
}
async function saveKey() {
if (!isKeyValid()) {
showMessage("PRIVATE KEY IS INVALID! did not save private key.");
return;
}
let hexOrEmptyKey = privKey;
try {
const { type, data } = nip19.decode(privKey);
if (type === "nsec") hexOrEmptyKey = data;
} catch (_) {}
await browser.storage.local.set({
private_key: hexOrEmptyKey,
});
if (hexOrEmptyKey !== "") {
setPrivKey(nip19.nsecEncode(hexOrEmptyKey));
}
showMessage("saved private key!");
}
function isKeyValid() {
if (privKey === "") return true;
if (privKey.match(/^[a-f0-9]{64}$/)) return true;
try {
if (nip19.decode(privKey).type === "nsec") return true;
} catch (_) {}
return false;
}
function changeRelayURL(i, ev) {
setRelays([
...relays.slice(0, i),
{ url: ev.target.value, policy: relays[i].policy },
...relays.slice(i + 1),
]);
addUnsavedChanges("relays");
}
function toggleRelayPolicy(i, cat) {
setRelays([
...relays.slice(0, i),
{
url: relays[i].url,
policy: { ...relays[i].policy, [cat]: !relays[i].policy[cat] },
},
...relays.slice(i + 1),
]);
addUnsavedChanges("relays");
}
function removeRelay(i) {
setRelays([...relays.slice(0, i), ...relays.slice(i + 1)]);
addUnsavedChanges("relays");
}
function addNewRelay() {
if (newRelayURL.trim() === "") return;
if (!newRelayURL.startsWith("wss://")) return;
relays.push({
url: newRelayURL,
policy: { read: true, write: true },
});
setRelays(relays);
addUnsavedChanges("relays");
setNewRelayURL("");
}
async function handleRevoke(e) {
const { host, accept, type } = e.target.dataset;
if (
window.confirm(
`revoke all ${
accept === "true" ? "accept" : "deny"
} ${type} policies from ${host}?`,
)
) {
await removePermissions(host, accept, type);
showMessage("removed policies");
loadPermissions();
}
}
function handleNotifications() {
setNotifications(!showNotifications);
addUnsavedChanges("notifications");
if (!showNotifications) requestBrowserNotificationPermissions();
}
async function requestBrowserNotificationPermissions() {
const granted = await browser.permissions.request({
permissions: ["notifications"],
});
if (!granted) setNotifications(false);
}
async function saveNotifications() {
await browser.storage.local.set({ notifications: showNotifications });
showMessage("saved notifications!");
}
async function saveRelays() {
await browser.storage.local.set({
relays: Object.fromEntries(
relays
.filter(({ url }) => url.trim() !== "")
.map(({ url, policy }) => [url.trim(), policy]),
),
});
showMessage("saved relays!");
}
function changeShowProtocolHandlerHelp() {
setShowProtocolHandlerHelp(true);
}
function changeHandleNostrLinks() {
if (handleNostrLinks) {
setProtocolHandler("");
addUnsavedChanges("protocol_handler");
} else setShowProtocolHandlerHelp(true);
setHandleNostrLinks(!handleNostrLinks);
}
function handleChangeProtocolHandler(e) {
setProtocolHandler(e.target.value);
addUnsavedChanges("protocol_handler");
}
async function saveNostrProtocolHandlerSettings() {
await browser.storage.local.set({ protocol_handler: protocolHandler });
showMessage("saved protocol handler!");
}
function addUnsavedChanges(section) {
if (!unsavedChanges.find((s) => s === section)) {
unsavedChanges.push(section);
setUnsavedChanges(unsavedChanges);
}
}
async function saveChanges() {
for (const section of unsavedChanges) {
switch (section) {
case "private_key":
await saveKey();
break;
case "relays":
await saveRelays();
break;
case "protocol_handler":
await saveNostrProtocolHandlerSettings();
break;
case "notifications":
await saveNotifications();
break;
}
}
setUnsavedChanges([]);
}
}
const container = document.getElementById("main");
const root = createRoot(container);
root.render();