diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index c0f4105e6..7b8179630 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -188,15 +188,6 @@ class PermissionService extends BaseService { return permission; } - async check () { - const ld = (Context.get('logdent') ?? 0) + 1; - return await Context.get().sub({ logdent: ld }).arun(async () => { - const res = await this.check__(...arguments); - // this.log.noticeme('RETURN ' + res); - return res; - }); - } - async scan (actor, permission_options) { const reading = []; @@ -214,171 +205,6 @@ class PermissionService extends BaseService { return reading; } - async check__ (actor, permission) { - permission = await this._rewrite_permission(permission); - - this.log.info(`checking permission ${permission} for actor ${actor.uid}`, { - actor: actor.uid, - permission, - }); - - // for ( const implicator of this._permission_implicators ) { - // if ( ! implicator.matches(permission) ) continue; - // const implied = await implicator.check({ - // actor, - // permission, - // recurse: this.check.bind(this), - // }); - // if ( implied ) return implied; - // } - - // For now we're only checking driver permissions, and users have all of them - if ( actor.type instanceof UserActorType ) { - return await this.check_user_permission(actor, permission); - } - - if ( actor.type instanceof AccessTokenActorType ) { - // Authorizer must have permission - const authorizer_permission = await this.check(actor.type.authorizer, permission); - if ( ! authorizer_permission ) return false; - - return await this.check_access_token_permission( - actor.type.authorizer, actor.type.token, permission - ); - } - - // Prevent undefined behaviour - if ( actor.type instanceof AppUnderUserActorType ) { - // NEXT: - const app_uid = actor.type.app.uid; - const user_actor = actor.get_related_actor(UserActorType); - // const user_has_permission = await this.check_user_permission(user_actor, permission); - const user_has_permission = await this.check__( - user_actor, permission, - ); - if ( ! user_has_permission ) return undefined; - - // This was a useful log so I'm keeping it here - // console.log('\x1B[36;1m>=== THIS IS HERE ===<\x1B[0m', - // app_uid, - // permission, - // ) - - return await this.check_user_app_permission(actor, app_uid, permission); - } - - if ( actor.type instanceof SiteActorType ) { - return await this.check_site_permission(actor, permission); - } - - console.log ('WHAT ACTOR TYPE THEN???', actor.type); - - throw new Error('unrecognized actor type'); - } - - // TODO: context meta for cycle detection - async check_user_permission (actor, permission) { - return await require('../../structured/sequence/check-user-permission') - .call(this, { - // passed - actor, - permission, - // constants - implicit_user_permissions, - }); - } - - async check_access_token_permission (authorizer, token, permission) { - const rows = await this.db.read( - 'SELECT * FROM `access_token_permissions` ' + - 'WHERE `token_uid` = ? AND `permission` = ?', - [ - token, - permission, - ] - ); - - // Token must have permission - if ( ! rows[0] ) return undefined; - - return rows[0].extra; - } - - async check_user_app_permission (actor, app_uid, permission) { - permission = await this._rewrite_permission(permission); - - let app = await get_app({ uid: app_uid }); - if ( ! app ) app = await get_app({ name: app_uid }); - const app_id = app.id; - - // const parent_perms = this.get_parent_permissions(permission); - const parent_perms = await this.get_higher_permissions(permission); - - for ( const permission of parent_perms ) { - // Check hardcoded permissions - if ( default_implicit_user_app_permissions[permission] ) { - return default_implicit_user_app_permissions[permission]; - } - - // Check implicit permissions - const implicit_permissions = {}; - for ( const implicit_permission of implicit_user_app_permissions ) { - if ( implicit_permission.apps.includes(app_uid) ) { - implicit_permissions[permission] = implicit_permission.permissions[permission]; - } - } - if ( implicit_permissions[permission] ) { - return implicit_permissions[permission]; - } - } - - // My biggest gripe with SQL is doing string manipulation for queries. - // If the grammar for SQL was simpler we could model it, write this as - // data, and even implement macros for common patterns. - let sql_perm = parent_perms.map((perm) => - `\`permission\` = ?`).join(' OR '); - if ( parent_perms.length > 1 ) sql_perm = '(' + sql_perm + ')'; - - // SELECT permission - const rows = await this.db.read( - 'SELECT * FROM `user_to_app_permissions` ' + - 'WHERE `user_id` = ? AND `app_id` = ? AND ' + - sql_perm, - [ - actor.type.user.id, - app_id, - ...parent_perms, - ] - ); - - if ( ! rows[0] ) return undefined; - - return rows[0].extra; - } - - async check_site_permission (actor, permission) { - permission = await this._rewrite_permission(permission); - // const parent_perms = this.get_parent_permissions(permission); - const parent_perms = await this.get_higher_permissions(permission); - - // Check implicit permissions - for ( const parent_perm of parent_perms ) { - if ( implicit_user_permissions[parent_perm] ) { - return implicit_user_permissions[parent_perm]; - } - } - - for ( const implicator of this._permission_implicators ) { - if ( ! implicator.matches(permission) ) continue; - const implied = await implicator.check({ - actor, - permission, - recurse: this.check.bind(this), - }); - if ( implied ) return implied; - } - } - async grant_user_app_permission (actor, app_uid, permission, extra = {}, meta) { permission = await this._rewrite_permission(permission); diff --git a/src/backend/src/structured/sequence/check-user-permission.js b/src/backend/src/structured/sequence/check-user-permission.js deleted file mode 100644 index f28d12a78..000000000 --- a/src/backend/src/structured/sequence/check-user-permission.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -const { Sequence } = require("../../codex/Sequence"); -const { get_user } = require("../../helpers"); -const { Actor, UserActorType } = require("../../services/auth/Actor"); - -module.exports = new Sequence([ - async function grant_if_system (a) { - const { actor } = a.values(); - if ( actor.type.user.username === 'system' ) { - return a.stop({}); - } - }, - async function rewrite_permission (a) { - let { permission } = a.values(); - permission = await a.icall('_rewrite_permission', permission); - a.values({ permission }); - }, - async function explode_permission (a) { - const { permission } = a.values(); - const permission_options = - await a.icall('get_higher_permissions', permission); - a.values({ permission_options }); - }, - async function try_hardcoded_permission (a) { - const { - permission_options, - implicit_user_permissions - } = a.values(); - - for ( const perm of permission_options ) { - if ( implicit_user_permissions[perm] ) { - return a.stop(implicit_user_permissions[perm]); - } - } - }, - async function try_permission_implicators (a) { - // NOTE: it's really weird that we check `permission` only and not - // the `permission_options` list here. I haven't changed this - // to avoid regressions but it's something to consider. - const { actor, permission } = a.values(); - - const _permission_implicators = a.iget('_permission_implicators'); - - for ( const implicator of _permission_implicators ) { - if ( ! implicator.matches(permission) ) continue; - const implied = await implicator.check({ - actor, - permission, - recurse: this.check.bind(this), - }); - if ( implied ) { - return a.stop(implied); - } - } - }, - async function try_user_to_user_permissions (a) { - const { actor, permission_options } = a.values(); - const db = a.iget('db'); - - let sql_perm = permission_options.map((perm) => - `\`permission\` = ?`).join(' OR '); - - if ( permission_options.length > 1 ) { - sql_perm = '(' + sql_perm + ')'; - } - - // SELECT permission - const rows = await db.read( - 'SELECT * FROM `user_to_user_permissions` ' + - 'WHERE `holder_user_id` = ? AND ' + - sql_perm, - [ - actor.type.user.id, - ...permission_options, - ] - ); - - // Return the first matching permission where the - // issuer also has the permission granted - for ( const row of rows ) { - const issuer_actor = new Actor({ - type: new UserActorType({ - user: await get_user({ id: row.issuer_user_id }), - }), - }); - - // const issuer_perm = await this.check(issuer_actor, row.permission); - const issuer_perm = await a.icall('check', issuer_actor, row.permission); - - if ( ! issuer_perm ) continue; - - return a.stop(row.extra); - } - }, - async function try_user_to_group_permissions (a) { - const { actor, permission_options } = a.values(); - const db = a.iget('db'); - - let sql_perm = permission_options.map((perm) => - `p.permission = ?`).join(' OR '); - - if ( permission_options.length > 1 ) { - sql_perm = '(' + sql_perm + ')'; - } - const rows = await db.read( - 'SELECT p.permission, p.user_id, p.extra FROM `user_to_group_permissions` p ' + - 'JOIN `jct_user_group` ug ON p.group_id = ug.group_id ' + - 'WHERE ug.user_id = ? AND ' + sql_perm, - [ - actor.type.user.id, - ...permission_options, - ] - ); - - for ( const row of rows ) { - const issuer_actor = new Actor({ - type: new UserActorType({ - user: await get_user({ id: row.user_id }), - }), - }); - - const issuer_perm = await a.icall('check', issuer_actor, row.permission); - - if ( ! issuer_perm ) continue; - - return a.stop(row.extra); - } - } -]);