rework permissions and popup prompts, make each permission fine grained.
This commit is contained in:
@@ -4,90 +4,90 @@ export const NO_PERMISSIONS_REQUIRED = {
|
||||
replaceURL: true
|
||||
}
|
||||
|
||||
export const PERMISSIONS_REQUIRED = {
|
||||
getPublicKey: 1,
|
||||
getRelays: 5,
|
||||
signEvent: 10,
|
||||
'nip04.encrypt': 20,
|
||||
'nip04.decrypt': 20,
|
||||
}
|
||||
export const PERMISSION_NAMES = Object.fromEntries([
|
||||
['getPublicKey', 'read your public key'],
|
||||
['getRelays', 'read your list of preferred relays'],
|
||||
['signEvent', 'sign events using your private key'],
|
||||
['nip04.encrypt', 'encrypt messages to peers'],
|
||||
['nip04.decrypt', 'decrypt messages from peers']
|
||||
])
|
||||
|
||||
const ORDERED_PERMISSIONS = [
|
||||
[1, ['getPublicKey']],
|
||||
[5, ['getRelays']],
|
||||
[10, ['signEvent']],
|
||||
[20, ['nip04.encrypt']],
|
||||
[20, ['nip04.decrypt']]
|
||||
]
|
||||
|
||||
const PERMISSION_NAMES = {
|
||||
getPublicKey: 'read your public key',
|
||||
getRelays: 'read your list of preferred relays',
|
||||
signEvent: 'sign events using your private key',
|
||||
'nip04.encrypt': 'encrypt messages to peers',
|
||||
'nip04.decrypt': 'decrypt messages from peers',
|
||||
}
|
||||
|
||||
export function getAllowedCapabilities(permission) {
|
||||
let requestedMethods = []
|
||||
for (let i = 0; i < ORDERED_PERMISSIONS.length; i++) {
|
||||
let [perm, methods] = ORDERED_PERMISSIONS[i]
|
||||
if (perm > permission) break
|
||||
requestedMethods = requestedMethods.concat(methods)
|
||||
function matchConditions(conditions, event) {
|
||||
if (conditions?.kinds) {
|
||||
if (event.kind in conditions.kinds) return true
|
||||
else return false
|
||||
}
|
||||
|
||||
if (requestedMethods.length === 0) return 'nothing'
|
||||
|
||||
return requestedMethods.map(method => PERMISSION_NAMES[method])
|
||||
return true
|
||||
}
|
||||
|
||||
export function getPermissionsString(permission) {
|
||||
let capabilities = getAllowedCapabilities(permission)
|
||||
export async function getPermissionStatus(host, type, event) {
|
||||
let {policies} = await browser.storage.local.get('policies')
|
||||
|
||||
if (capabilities.length === 0) return 'none'
|
||||
if (capabilities.length === 1) return capabilities[0]
|
||||
let answers = [true, false]
|
||||
for (let i = 0; i < answers.length; i++) {
|
||||
let accept = answers[i]
|
||||
let {conditions} = policies?.[host]?.[accept]?.[type] || {}
|
||||
|
||||
return (
|
||||
capabilities.slice(0, -1).join(', ') +
|
||||
' and ' +
|
||||
capabilities[capabilities.length - 1]
|
||||
)
|
||||
}
|
||||
|
||||
export async function readPermissions() {
|
||||
let {permissions = {}} = await browser.storage.local.get('permissions')
|
||||
|
||||
// delete expired
|
||||
var needsUpdate = false
|
||||
for (let host in permissions) {
|
||||
if (
|
||||
permissions[host].condition === 'expirable' &&
|
||||
permissions[host].created_at < Date.now() / 1000 - 5 * 60
|
||||
) {
|
||||
delete permissions[host]
|
||||
needsUpdate = true
|
||||
if (conditions) {
|
||||
if (type === 'signEvent') {
|
||||
if (matchConditions(conditions, event)) {
|
||||
return accept // may be true or false
|
||||
} else {
|
||||
// if this doesn't match we just continue so it will either match for the opposite answer (reject)
|
||||
// or it will end up returning undefined at the end
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
return accept // may be true or false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needsUpdate) browser.storage.local.set({permissions})
|
||||
|
||||
return permissions
|
||||
return undefined
|
||||
}
|
||||
|
||||
export async function readPermissionLevel(host) {
|
||||
return (await readPermissions())[host]?.level || 0
|
||||
}
|
||||
export async function updatePermission(host, type, accept, conditions) {
|
||||
let {policies = {}} = await browser.storage.local.get('policies')
|
||||
|
||||
export async function updatePermission(host, permission) {
|
||||
let {permissions = {}} = await browser.storage.local.get('permissions')
|
||||
permissions[host] = {
|
||||
...permission,
|
||||
// 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
|
||||
let 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
|
||||
let other = !accept
|
||||
let 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({permissions})
|
||||
|
||||
browser.storage.local.set({policies})
|
||||
}
|
||||
|
||||
export async function removePermissions(host) {
|
||||
let {permissions = {}} = await browser.storage.local.get('permissions')
|
||||
delete permissions[host]
|
||||
browser.storage.local.set({permissions})
|
||||
export async function removePermissions(host, accept, type) {
|
||||
let {policies = {}} = await browser.storage.local.get('policies')
|
||||
delete policies[host]
|
||||
browser.storage.local.set({policies})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user