From e5750d8eb7e30fe5799ed66024023cdfee95000c Mon Sep 17 00:00:00 2001 From: KernelDeimos <7225168+KernelDeimos@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:09:57 -0500 Subject: [PATCH] fix: add explicit handling for access token in ACL For reasons still unknown, there are circumstances where the permission scanner denies permission to access tokens that should have been granted permission. This change de-abstracts/flattens the logic for checking access tokens so that it is easier to understand and maintain. The newly implemented code does not suffer from the same issue. --- src/backend/src/services/auth/ACLService.js | 34 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 5e21383c2..3199cbbb4 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -25,6 +25,7 @@ const { Context } = require('../../util/context'); const { Endpoint } = require('../../util/expressutil'); const BaseService = require('../BaseService'); const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require('./Actor'); +const { DB_READ } = require('../database/consts'); const { MANAGE_PERM_PREFIX } = require('./permissionConts.mjs'); const { PermissionUtil } = require('./permissionUtils.mjs'); @@ -422,11 +423,40 @@ class ACLService extends BaseService { if ( is_public ) return true; } - // Access tokens only work if the authorizer has permission + // Access tokens: allow if token has permission via DB and authorizer has permission if ( actor.type instanceof AccessTokenActorType ) { - const authorizer = actor.type.authorizer; + const { authorizer, token } = actor.type; const authorizer_perm = await this._check_fsNode(authorizer, fsNode, mode); if ( ! authorizer_perm ) return false; + + // We check access token permissions manually here and skip PermissionService + const db = this.services.get('database').get(DB_READ, 'auth'); + let perm_fsNode = fsNode; + + // Iterate up the directory tree (towards root directory) + while ( !(await perm_fsNode.get('is-root')) ) { + const uid = await perm_fsNode.get('uid'); + // DRY: second occurance of this code + const permission = mode === MANAGE_PERM_PREFIX + ? PermissionUtil.join(MANAGE_PERM_PREFIX, 'fs', uid) + : PermissionUtil.join('fs', uid, mode); + const rows = await db.read( + 'SELECT * FROM `access_token_permissions` WHERE `token_uid` = ? AND `permission` = ?', + [token, permission], + ); + + // We already checked that the authorizer has the required permission, + // so if the access token has the required permission as well we can + // return true immediately. + if ( rows[0] ) return true; + + // ...iterate + perm_fsNode = await perm_fsNode.getParent(); + } + + // If we reach here, the authorizer has permission to access the requested + // file/directory but the access token does not + return false; } // Hard rule: if app-under-user is accessing appdata directory, allow