From 7b8b4874365691f0700bec37068e080c8018a2ac Mon Sep 17 00:00:00 2001 From: KernelDeimos <7225168+KernelDeimos@users.noreply.github.com> Date: Tue, 20 Jan 2026 12:10:30 -0500 Subject: [PATCH 1/2] fix(backend): update protected app perm implicator The permission implicator for protected apps was written before changes to the permission system that affect the conditions under which a user is allowed to grant and revoke permissions; specifically this is the `manage:` set of permissions, which now needs to be granted to the owner of a protected app. Additionally, the "level" component of the permission is ignored because the owner of a protected all is implied to have all the permissions pertaining to that protected app. --- src/backend/src/modules/apps/ProtectedAppService.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/backend/src/modules/apps/ProtectedAppService.js b/src/backend/src/modules/apps/ProtectedAppService.js index 7b17644350..5adc302b18 100644 --- a/src/backend/src/modules/apps/ProtectedAppService.js +++ b/src/backend/src/modules/apps/ProtectedAppService.js @@ -59,7 +59,7 @@ class ProtectedAppService extends BaseService { // Owner of procted app has implicit permission to access it svc_permission.register_implicator(PermissionImplicator.create({ matcher: permission => { - return permission.startsWith('app:'); + return permission.startsWith('app:') || permission.startsWith('manage:app'); }, checker: async ({ actor, permission }) => { if ( ! (actor.type instanceof UserActorType) ) { @@ -67,10 +67,12 @@ class ProtectedAppService extends BaseService { } const parts = PermissionUtil.split(permission); - if ( parts.length !== 3 ) return undefined; - const [_, uid_part, lvl] = parts; - if ( lvl !== 'access' ) return undefined; + if ( parts[0] === 'manage' ) parts.shift(); + + if ( parts.length < 2 ) return undefined; + + const [_, uid_part] = parts; // track: slice a prefix const uid = uid_part.slice('uid#'.length); From 1b0c0c375de07eb30e5d594f5bf92b2af8bce053 Mon Sep 17 00:00:00 2001 From: KernelDeimos <7225168+KernelDeimos@users.noreply.github.com> Date: Tue, 20 Jan 2026 15:31:24 -0500 Subject: [PATCH 2/2] fix(perms): fix revokePermission for "flat" impl The "flat" implementation of permissions was broken because revokePermission tried to delete entries by calling `.set` with an option called "delete". I'm not sure if this has ever existed on the puter-kvstore interface, so it's weird that it was called like that. --- src/backend/src/services/auth/PermissionService.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index d55d6f8a08..88bd867288 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -887,9 +887,7 @@ class PermissionService extends BaseService { // DELETE permission await this.services.get('su').sudo(() => - this.kvService.set(PermissionUtil.join(PERM_KEY_PREFIX, user.id, permission), { - deleted: true, - })); + this.kvService.del({ key: PermissionUtil.join(PERM_KEY_PREFIX, user.id, permission) })); } /**