fea: nicer permissions

This commit is contained in:
Vlad Stan
2026-07-09 16:36:05 +03:00
parent 597a65c45f
commit 3ddce73834
5 changed files with 149 additions and 9 deletions
+34
View File
@@ -1,9 +1,43 @@
import json
from dataclasses import dataclass
from typing import Any, Literal
from pydantic import BaseModel, Field, root_validator
@dataclass(frozen=True)
class ExtensionAPIMethodExport:
method_id: str
namespace: str
name: str
host_interface: str
host_name: str
sdk_name: str
description: str
required_permission: str | None = None
require_auth: bool = True
@dataclass(frozen=True)
class ExtensionAPIMethod:
method_id: str
namespace: str
name: str
python_name: str
host_interface: str
host_name: str
sdk_name: str
description: str
request_model: type[BaseModel]
response_model: type[BaseModel]
required_permission: str | None = None
require_auth: bool = True
@property
def sdk_qualified_name(self) -> str:
return f"{self.namespace}.{self.sdk_name}"
class EmptyRequest(BaseModel):
pass
+1 -1
View File
File diff suppressed because one or more lines are too long
+11
View File
@@ -522,6 +522,17 @@ window.localisation.en = {
extension_permissions_title: 'Grant extension permissions',
extension_permissions_request: 'This extension requests these permissions:',
extension_permissions_grant_install: 'Grant and install',
extension_permissions_high_risk_warning:
'This extension requests permissions that can move funds.',
extension_permission_risk_low: 'Low risk',
extension_permission_risk_medium: 'Medium risk',
extension_permission_risk_high: 'High risk',
extension_permission_warning_wallet_pay_invoice:
'Can spend funds from wallets available to your account.',
extension_permission_warning_extension_api_request_write:
'Can write data or trigger actions in approved extensions.',
extension_permission_warning_http_request:
'Can send data to external services.',
extension_permission_ext_storage_read: 'Read extension storage',
extension_permission_ext_storage_read_public: 'Read public extension storage',
extension_permission_ext_storage_write: 'Write extension storage',
+69 -1
View File
@@ -724,6 +724,11 @@ window.PageExtensions = {
resolve(grantedPermissions)
}
},
permissionGrantHasHighRisk() {
return this.permissionGrantDisplayItems().some(
permission => permission.risk.level === 'high'
)
},
permissionGrantDisplayItems() {
const permissions = this.permissionGrant.permissions || []
const permissionsById = new Map(
@@ -781,6 +786,7 @@ window.PageExtensions = {
label: isReadWriteStorage
? this.$t('extension_permission_ext_storage_read_write')
: this.permissionLabel(permission),
risk: this.permissionRisk(permissions),
badges: [],
descriptions,
fieldGroups: [],
@@ -805,6 +811,68 @@ window.PageExtensions = {
return item
},
permissionRisk(permissions) {
const risks = permissions.map(permission =>
this.permissionRiskForPermission(permission)
)
const highestRisk = risks.find(risk => risk.level === 'high')
if (highestRisk) return highestRisk
return risks.find(risk => risk.level === 'medium') || this.lowRisk()
},
permissionRiskForPermission(permission) {
if (permission.id === 'wallet.pay_invoice') {
return this.highRisk('extension_permission_warning_wallet_pay_invoice')
}
if (permission.id === 'extension.api.request') {
const hasWriteAccess = this.extensionApiPermissionTargets(
permission
).some(target => target.access.includes('write'))
return hasWriteAccess
? this.highRisk(
'extension_permission_warning_extension_api_request_write'
)
: this.mediumRisk()
}
if (permission.id === 'http.request') {
return this.highRisk('extension_permission_warning_http_request')
}
if (
[
'wallet.list',
'wallet.balance.read',
'wallet.create_invoice_public',
'ext.storage.read_public',
'payments.watch'
].includes(permission.id)
) {
return this.mediumRisk()
}
return this.lowRisk()
},
lowRisk() {
return {
level: 'low',
color: 'grey-6',
label: this.$t('extension_permission_risk_low'),
warning: ''
}
},
mediumRisk() {
return {
level: 'medium',
color: 'warning',
label: this.$t('extension_permission_risk_medium'),
warning: ''
}
},
highRisk(warningKey) {
return {
level: 'high',
color: 'negative',
label: this.$t('extension_permission_risk_high'),
warning: this.$t(warningKey)
}
},
permissionOrderIndex(permissionId) {
const order = [
'wallet.pay_invoice',
@@ -815,8 +883,8 @@ window.PageExtensions = {
'ext.storage.read',
'ext.storage.write',
'ext.storage.read_public',
'wallet.create_invoice',
'wallet.create_invoice_public',
'wallet.create_invoice',
'utils.basic'
]
const index = order.indexOf(permissionId)
+34 -7
View File
@@ -467,6 +467,16 @@
class="text-body2 q-mt-sm"
v-text="$t('extension_permissions_request')"
></div>
<q-banner
v-if="permissionGrantHasHighRisk()"
dense
class="bg-red-1 text-red-10 q-mt-md"
>
<template v-slot:avatar>
<q-icon name="warning" color="negative"></q-icon>
</template>
<span v-text="$t('extension_permissions_high_risk_warning')"></span>
</q-banner>
</q-card-section>
<q-list bordered separator class="q-mt-md">
@@ -475,27 +485,44 @@
:key="permission.id"
dense
expand-separator
class="q-pt-xs"
>
<template v-slot:header>
<q-item-section>
<q-item-label
class="text-weight-medium"
v-text="permission.label"
></q-item-label>
<q-item-label v-if="permission.badges.length" caption>
<q-item-label class="text-weight-medium">
<span v-text="permission.label"></span>
</q-item-label>
</q-item-section>
<q-item-section
v-if="permission.risk.level !== 'low' || permission.badges.length"
side
top
>
<div class="row items-center justify-end q-gutter-xs">
<q-badge
v-for="badge of permission.badges"
:key="badge.key"
outline
color="primary"
class="q-mr-xs q-mt-xs"
v-text="badge.label"
></q-badge>
</q-item-label>
<q-badge
v-if="permission.risk.level !== 'low'"
:color="permission.risk.color"
v-text="permission.risk.label"
></q-badge>
</div>
</q-item-section>
</template>
<div class="q-px-md q-pb-sm">
<div
v-if="permission.risk.warning"
class="row items-center text-negative text-caption q-mb-xs"
>
<q-icon name="warning" size="16px" class="q-mr-xs"></q-icon>
<span v-text="permission.risk.warning"></span>
</div>
<p
v-for="description of permission.descriptions"
:key="description"