fix: add explicit handling for access token in ACL
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test-backend (24.x) (push) Has been cancelled
test / API tests (node env, api-test) (24.x) (push) Has been cancelled
test / puterjs (node env, vitest) (24.x) (push) Has been cancelled

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.
This commit is contained in:
KernelDeimos
2026-02-09 18:09:57 -05:00
committed by Eric Dubé
parent e2ccaadf2f
commit e5750d8eb7
+32 -2
View File
@@ -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