import browser from "webextension-polyfill"; export const NO_PERMISSIONS_REQUIRED = { replaceURL: true, peekPublicKey: true, }; export const PERMISSION_NAMES = Object.fromEntries([ ["getPublicKey", "read your public key"], ["signEvent", "sign events using your private key"], ["nip04.encrypt", "encrypt messages to peers"], ["nip04.decrypt", "decrypt messages from peers"], ["nip44.encrypt", "encrypt messages to peers"], ["nip44.decrypt", "decrypt messages from peers"], ]); function matchConditions(conditions, event) { if (conditions?.kinds) { if (event.kind in conditions.kinds) return true; else return false; } return true; } export async function getPermissionStatus(host, type, event) { const { policies } = await browser.storage.local.get("policies"); const answers = [true, false]; for (let i = 0; i < answers.length; i++) { const accept = answers[i]; const { conditions } = policies?.[host]?.[accept]?.[type] || {}; if (conditions) { if (type === "signEvent") { if (matchConditions(conditions, event)) { return accept; // may be true or false } else { } } else { return accept; // may be true or false } } } return undefined; } export async function updatePermission(host, type, accept, conditions) { const { policies = {} } = await browser.storage.local.get("policies"); // if the new conditions is "match everything", override the previous if (Object.keys(conditions).length === 0) { conditions = {}; } else { // if we already had a policy for this, merge the conditions const existingConditions = policies[host]?.[accept]?.[type]?.conditions; if (existingConditions) { if (existingConditions.kinds && conditions.kinds) { Object.keys(existingConditions.kinds).forEach((kind) => { conditions.kinds[kind] = true; }); } } } // if we have a reverse policy (accept / reject) that is exactly equal to this, remove it const other = !accept; const reverse = policies?.[host]?.[other]?.[type]; if ( reverse && JSON.stringify(reverse.conditions) === JSON.stringify(conditions) ) { delete policies[host][other][type]; } // insert our new policy policies[host] = policies[host] || {}; policies[host][accept] = policies[host][accept] || {}; policies[host][accept][type] = { conditions, // filter that must match the event (in case of signEvent) created_at: Math.round(Date.now() / 1000), }; browser.storage.local.set({ policies }); } export async function removePermissions(host, accept, type) { const { policies = {} } = await browser.storage.local.get("policies"); delete policies[host]?.[accept]?.[type]; browser.storage.local.set({ policies }); } export async function showNotification(host, answer, type, params) { const { notifications } = await browser.storage.local.get("notifications"); if (notifications) { const action = answer ? "allowed" : "denied"; browser.notifications.create(undefined, { type: "basic", title: `${type} ${action} for ${host}`, message: JSON.stringify( params?.event ? { kind: params.event.kind, content: params.event.content, tags: params.event.tags, } : params, null, 2 ), iconUrl: "icons/48x48.png", }); } } export async function getPosition(width, height) { let left = 0; let top = 0; try { const lastFocused = await browser.windows.getLastFocused(); if ( lastFocused && lastFocused.top !== undefined && lastFocused.left !== undefined && lastFocused.width !== undefined && lastFocused.height !== undefined ) { top = Math.round(lastFocused.top + (lastFocused.height - height) / 2); left = Math.round(lastFocused.left + (lastFocused.width - width) / 2); } else { console.error("Last focused window properties are undefined."); } } catch (error) { console.error("Error getting window position:", error); } return { top, left, }; }