refactor(api): add granular permission enforcement on admin routes
- add optional `permission` field to route definitions with type validation in `define.js` - check `hasPermission()` in router after `requireAdmin()` and return 403 if denied - document `permission` and `skipRateLimit` optional fields in api README - load user permissions in `AdminPage.server.js` and pass them to client via `user` prop - use `user.permissions` in `RolesPage` and `UsersPage` to conditionally render actions - expose permission-gated API routes in `auth/api.js`
This commit is contained in:
+16
-16
@@ -12,7 +12,7 @@ import { updateUser, requestPasswordReset } from './auth.js';
|
||||
import { hashPassword, verifyPassword, generateId } from '../../core/users/password.js';
|
||||
import { createEmailChangeToken, verifyEmailChangeToken, applyEmailChange, sendEmailChangeConfirmEmail, sendEmailChangeOldNotifyEmail, sendEmailChangeNewNotifyEmail, sendPasswordChangedEmail, sendPasswordResetEmail, sendInvitationEmail } from './email.js';
|
||||
import { createAccountSetup } from '../../core/users/verifications.js';
|
||||
import { listRoles, getRoleById, createRole, updateRole, deleteRole, getUserRoles, assignUserRole, revokeUserRole, deleteUserSessions } from '@zen/core/users';
|
||||
import { listRoles, getRoleById, createRole, updateRole, deleteRole, getUserRoles, assignUserRole, revokeUserRole, deleteUserSessions, PERMISSIONS } from '@zen/core/users';
|
||||
import { uploadImage, deleteFile, generateUniqueFilename, getFileExtension, FILE_TYPE_PRESETS, FILE_SIZE_LIMITS, validateUpload } from '@zen/core/storage';
|
||||
import { getPublicBaseUrl } from '@zen/core/shared/config';
|
||||
|
||||
@@ -896,8 +896,8 @@ async function handleAdminCreateUser(request) {
|
||||
// parameterised paths (/users/:id) so they match first.
|
||||
|
||||
export const routes = defineApiRoutes([
|
||||
{ path: '/users', method: 'GET', handler: handleListUsers, auth: 'admin' },
|
||||
{ path: '/users', method: 'POST', handler: handleAdminCreateUser, auth: 'admin' },
|
||||
{ path: '/users', method: 'GET', handler: handleListUsers, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users', method: 'POST', handler: handleAdminCreateUser, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/profile', method: 'PUT', handler: handleUpdateProfile, auth: 'user' },
|
||||
{ path: '/users/profile/email', method: 'POST', handler: handleInitiateEmailChange, auth: 'user' },
|
||||
{ path: '/users/profile/password', method: 'POST', handler: handleChangeOwnPassword, auth: 'user' },
|
||||
@@ -907,17 +907,17 @@ export const routes = defineApiRoutes([
|
||||
{ path: '/users/profile/sessions', method: 'DELETE', handler: handleDeleteAllSessions, auth: 'user' },
|
||||
{ path: '/users/profile/sessions/:sessionId', method: 'DELETE', handler: handleDeleteSession, auth: 'user' },
|
||||
{ path: '/users/email/confirm', method: 'GET', handler: handleConfirmEmailChange, auth: 'user' },
|
||||
{ path: '/users/:id/roles', method: 'GET', handler: handleGetUserRoles, auth: 'admin' },
|
||||
{ path: '/users/:id/roles', method: 'POST', handler: handleAssignUserRole, auth: 'admin' },
|
||||
{ path: '/users/:id/roles/:roleId', method: 'DELETE', handler: handleRevokeUserRole, auth: 'admin' },
|
||||
{ path: '/users/:id', method: 'GET', handler: handleGetUserById, auth: 'admin' },
|
||||
{ path: '/users/:id', method: 'PUT', handler: handleUpdateUserById, auth: 'admin' },
|
||||
{ path: '/users/:id/email', method: 'PUT', handler: handleAdminUpdateUserEmail, auth: 'admin' },
|
||||
{ path: '/users/:id/password', method: 'PUT', handler: handleAdminSetUserPassword, auth: 'admin' },
|
||||
{ path: '/users/:id/send-password-reset', method: 'POST', handler: handleAdminSendPasswordReset, auth: 'admin' },
|
||||
{ path: '/roles', method: 'GET', handler: handleListRoles, auth: 'admin' },
|
||||
{ path: '/roles', method: 'POST', handler: handleCreateRole, auth: 'admin' },
|
||||
{ path: '/roles/:id', method: 'GET', handler: handleGetRole, auth: 'admin' },
|
||||
{ path: '/roles/:id', method: 'PUT', handler: handleUpdateRole, auth: 'admin' },
|
||||
{ path: '/roles/:id', method: 'DELETE', handler: handleDeleteRole, auth: 'admin' },
|
||||
{ path: '/users/:id/roles', method: 'GET', handler: handleGetUserRoles, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users/:id/roles', method: 'POST', handler: handleAssignUserRole, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/roles/:roleId', method: 'DELETE', handler: handleRevokeUserRole, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id', method: 'GET', handler: handleGetUserById, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users/:id', method: 'PUT', handler: handleUpdateUserById, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/email', method: 'PUT', handler: handleAdminUpdateUserEmail, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/password', method: 'PUT', handler: handleAdminSetUserPassword, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/send-password-reset', method: 'POST', handler: handleAdminSendPasswordReset, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/roles', method: 'GET', handler: handleListRoles, auth: 'admin', permission: PERMISSIONS.ROLES_VIEW },
|
||||
{ path: '/roles', method: 'POST', handler: handleCreateRole, auth: 'admin', permission: PERMISSIONS.ROLES_MANAGE },
|
||||
{ path: '/roles/:id', method: 'GET', handler: handleGetRole, auth: 'admin', permission: PERMISSIONS.ROLES_VIEW },
|
||||
{ path: '/roles/:id', method: 'PUT', handler: handleUpdateRole, auth: 'admin', permission: PERMISSIONS.ROLES_MANAGE },
|
||||
{ path: '/roles/:id', method: 'DELETE', handler: handleDeleteRole, auth: 'admin', permission: PERMISSIONS.ROLES_MANAGE },
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user