From 190cfcfb8adfaaac6ee2a689bd31d923c835ad0b Mon Sep 17 00:00:00 2001 From: Bernd Storath <999999bst@gmail.com> Date: Tue, 11 Feb 2025 12:02:42 +0100 Subject: [PATCH] move from role check avoid authStore.userData?.role === roles.ADMIN --- src/app/components/ui/UserMenu.vue | 7 ++++++- src/app/middleware/auth.global.ts | 2 +- src/server/api/session.get.ts | 1 + src/shared/utils/permissions.ts | 32 ++++++++++++++++++++++++------ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/app/components/ui/UserMenu.vue b/src/app/components/ui/UserMenu.vue index 31547319..77542d53 100644 --- a/src/app/components/ui/UserMenu.vue +++ b/src/app/components/ui/UserMenu.vue @@ -37,7 +37,12 @@ Account - + { // Check for admin access if (to.path.startsWith('/admin')) { - if (userData.role !== roles.ADMIN) { + if (userData && hasPermissions(userData, 'admin', 'any')) { return abortNavigation('Not allowed to access Admin Panel'); } } diff --git a/src/server/api/session.get.ts b/src/server/api/session.get.ts index 6623c86f..e86b6845 100644 --- a/src/server/api/session.get.ts +++ b/src/server/api/session.get.ts @@ -16,6 +16,7 @@ export default defineEventHandler(async (event) => { } return { + id: user.id, role: user.role, username: user.username, name: user.name, diff --git a/src/shared/utils/permissions.ts b/src/shared/utils/permissions.ts index 83d26d61..912b5ac1 100644 --- a/src/shared/utils/permissions.ts +++ b/src/shared/utils/permissions.ts @@ -1,7 +1,11 @@ import type { ClientType } from '#db/repositories/client/types'; import type { UserType } from '#db/repositories/user/types'; -export type Role = number & { readonly __role: unique symbol }; +type BrandedRole = { + readonly __role: unique symbol; +}; + +export type Role = number & BrandedRole; export const roles = { ADMIN: 1 as Role, @@ -26,9 +30,24 @@ function roleToKey(role: Role) { return roleKey as Roles; } +// TODO: https://github.com/nitrojs/nitro/issues/2758#issuecomment-2650531472 + +type BrandedNumber = { + toString: unknown; + toFixed: unknown; + toExponential: unknown; + toPrecision: unknown; + valueOf: unknown; + toLocaleString: unknown; +} & BrandedRole; + +type SharedUserType = + | Pick + | (Pick & { role: BrandedNumber }); + type PermissionCheck = | boolean - | ((user: UserType, data: Permissions[Key]['dataType']) => boolean); + | ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean); type RolesWithPermissions = { [R in Roles]: { @@ -87,14 +106,15 @@ export const ROLES = { } as const satisfies RolesWithPermissions; export function hasPermissions( - user: UserType, + user: SharedUserType, resource: Resource, action: Permissions[Resource]['action'], data?: Permissions[Resource]['dataType'] ) { - const permission = (ROLES as RolesWithPermissions)[roleToKey(user.role)][ - resource - ][action]; + const permission = (ROLES as RolesWithPermissions)[ + // TODO: remove typecast + roleToKey(user.role as Role) + ][resource][action]; if (typeof permission === 'boolean') { return permission;