{`
{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(generateSecretKey()))
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 = bytesToHex(data)
} catch (_) {
showMessage('Invalid private key format.')
return
}
await browser.storage.local.set({
private_key: hexOrEmptyKey
})
showMessage('Private Key has been saved.')
}
function isKeyValid() {
if (privKey === '') 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([])
}
}
render(, document.getElementById('main'))