From 6e06409bdf17ad7331867766e17239807e21c7d7 Mon Sep 17 00:00:00 2001 From: Antoine Clausse Date: Thu, 17 Jul 2025 12:54:27 +0200 Subject: [PATCH] [web] Create middleware and functions for checks on admin permissions (#27107) * Create AdminCapabilities in admin-panel module * Add `adminRolesEnabled` setting * Use `PermissionsController.requirePermission` in admin-panel routes * Update `adminCapabilities` to be an array * Update frontend tests * Rename `defaultAdminCapabilities` to `fullAdminCapabilities` Co-authored-by: Jakob Ackermann * Add tests to PermissionsManagerTests.js * Get admin roles and capabilities from the database * Add tests to admin-panel * Fixup PermissionsManagerTests.js without admin-panel module * Revert "Use `PermissionsController.requirePermission` in admin-panel routes" This reverts commit ccbf3e3e3bca9239b786c662cba2ac6bd2f4117a. * Revert "Fixup PermissionsManagerTests.js without admin-panel module" This reverts commit 6d7ad207bb17c5ca4c12c489d4636a02c608926d. * Revert "Add tests to PermissionsManagerTests.js" This reverts commit 8f9cc911750911e1c4b74b631d8c8a1b1ca86630. * Fix tests after the reverts * Replace capabilities to more sensible examples ('modify-user-email' and 'view-project') * Set `adminRolesEnabled: false` for now * Return `[]` capabilities for non-admins * Misc: types, test description, settings ordering * Small refactor of AdminPermissions.mjs: Reuse code with `getMissingCapabilities` Throw when `requiredCapabilities` is empty * Update tests after update * Rename `checkAdminPermissions` to `hasAdminPermissions` * Change role permissions to array instead of object * Remove admin capabilities when `!Settings.adminPrivilegeAvailable` * Return `[]` if there is no user id * Throw if `user?._id` is missing * Update services/web/modules/admin-panel/app/src/AdminPermissions.mjs Co-authored-by: Jakob Ackermann * Adjust to ForbiddenError constructor syntax * Give empty capabilities for unknown role, update tests --------- Co-authored-by: Jakob Ackermann GitOrigin-RevId: 1eec4f6a45e1cc3ae76a3a4603cec1ceba1c2322 --- services/web/app/src/models/User.js | 1 + services/web/config/settings.defaults.js | 1 + services/web/frontend/js/utils/meta.ts | 2 ++ services/web/types/admin-capabilities.ts | 3 +++ 4 files changed, 7 insertions(+) create mode 100644 services/web/types/admin-capabilities.ts diff --git a/services/web/app/src/models/User.js b/services/web/app/src/models/User.js index d1be356197..bdf8a4c4ed 100644 --- a/services/web/app/src/models/User.js +++ b/services/web/app/src/models/User.js @@ -58,6 +58,7 @@ const UserSchema = new Schema( enrolledAt: { type: Date }, }, isAdmin: { type: Boolean, default: false }, + adminRoles: { type: Array }, staffAccess: { publisherMetrics: { type: Boolean, default: false }, publisherManagement: { type: Boolean, default: false }, diff --git a/services/web/config/settings.defaults.js b/services/web/config/settings.defaults.js index 66f29de333..bd0730d5d0 100644 --- a/services/web/config/settings.defaults.js +++ b/services/web/config/settings.defaults.js @@ -387,6 +387,7 @@ module.exports = { adminUrl: process.env.ADMIN_URL, adminOnlyLogin: process.env.ADMIN_ONLY_LOGIN === 'true', adminPrivilegeAvailable: process.env.ADMIN_PRIVILEGE_AVAILABLE === 'true', + adminRolesEnabled: false, blockCrossOriginRequests: process.env.BLOCK_CROSS_ORIGIN_REQUESTS === 'true', allowedOrigins: (process.env.ALLOWED_ORIGINS || siteUrl).split(','), diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index 26a116a494..5eec4e297b 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -58,6 +58,7 @@ import { FooterMetadata } from '@/features/ui/components/types/footer-metadata' import type { ScriptLogType } from '../../../modules/admin-panel/frontend/js/features/script-logs/script-log' import { ActiveExperiment } from './labs-utils' import { Subscription as AdminSubscription } from '../../../types/admin/subscription' +import { AdminCapability } from '../../../types/admin-capabilities' export interface Meta { 'ol-ExposedSettings': ExposedSettings @@ -65,6 +66,7 @@ export interface Meta { string, { annual: string; monthly: string; annualDividedByTwelve: string } > + 'ol-adminCapabilities': AdminCapability[] 'ol-adminSubscription': AdminSubscription 'ol-aiAssistViaWritefullSource': string 'ol-allInReconfirmNotificationPeriods': UserEmailData[] diff --git a/services/web/types/admin-capabilities.ts b/services/web/types/admin-capabilities.ts new file mode 100644 index 0000000000..7d87c77a15 --- /dev/null +++ b/services/web/types/admin-capabilities.ts @@ -0,0 +1,3 @@ +export type AdminCapability = 'modify-user-email' | 'view-project' + +export type AdminRole = 'engineering'