UNPKG

@softvisio/core

Version:
139 lines (114 loc) 4.68 kB
import Component from "#lib/app/api/component"; import GlobPatterns from "#lib/glob/patterns"; import { isKebabCase, validatePath } from "#lib/naming-conventions"; import sql from "#lib/sql"; const STATIC_PERMISSIONS = new Set( [ "guests", "users", "root", "telegram-bot-users" ] ); export default class extends Component { #resolvers = {}; // static get staticPermissions () { return STATIC_PERMISSIONS; } // properties get resolvers () { return this.#resolvers; } // protected async _init () { const types = {}; for ( const [ type, typeSpec ] of Object.entries( this.app.acl.config.types ) ) { types[ type ] = { type, "roles": {}, "notifications": {}, }; for ( const [ role, roleSpec ] of Object.entries( typeSpec.roles ) ) { types[ type ].roles[ role ] = { role, ...roleSpec, }; } if ( typeSpec.notifications ) { for ( const [ notification, notificationSpec ] of Object.entries( typeSpec.notifications ) ) { types[ type ].notifications[ notification ] = { notification, ...notificationSpec, }; } } } const allPermissions = new Set(); // check api schema permissions, create permissions index { for ( const method of Object.values( this.api.schema.methods ) ) { if ( !method.permission ) continue; // static permission if ( STATIC_PERMISSIONS.has( method.permission ) ) continue; // validate permission name const [ namespace, name ] = method.permission.split( ":" ); if ( !validatePath( namespace, { "absolute": false, "folder": false, "format": "kebab-case", } ) || !isKebabCase( name ) ) { return result( [ 500, `Permission "${ method.permission }" is invalid` ] ); } allPermissions.add( method.permission ); } } // acl types { for ( const type of Object.values( types ) ) { // roles for ( const role of Object.values( type.roles ) ) { const resolvedPermissions = new Set(), globPatterns = new GlobPatterns().add( role.permissions ); // resolve role permissions for ( const schemaPermission of allPermissions ) { if ( globPatterns.test( schemaPermission ) ) { resolvedPermissions.add( schemaPermission ); } } role.permissions = [ ...resolvedPermissions ]; } // notifications if ( type.notifications ) { for ( const notification of Object.values( type.notifications ) ) { if ( !notification.roles ) continue; // check notification roles for ( const role of notification.roles ) { if ( !type.roles[ role ] ) { return result( [ 400, `ACL notification ${ notification.notification } role ${ role } is not defined` ] ); } } } } } } // acl resolvers { for ( const [ aclResolver, query ] of Object.entries( this.api.schema.aclResolvers ) ) { this.#resolvers[ aclResolver ] = query ? sql( query ).prepare() : null; } } // check api methods acl object types { for ( const method of Object.values( this.api.schema.methods ) ) { if ( !method.aclResolvers ) continue; for ( const aclResolver of method.aclResolvers ) { if ( !( aclResolver in this.#resolvers ) ) { return result( [ 500, `ACL object type "${ aclResolver }" is not registered` ] ); } } } } const res = await this.app.acl.updateTypes( types ); if ( !res.ok ) return res; return result( 200 ); } }