Browse Source

move from role check

avoid authStore.userData?.role === roles.ADMIN
pull/1660/head
Bernd Storath 6 months ago
parent
commit
190cfcfb8a
  1. 7
      src/app/components/ui/UserMenu.vue
  2. 2
      src/app/middleware/auth.global.ts
  3. 1
      src/server/api/session.get.ts
  4. 32
      src/shared/utils/permissions.ts

7
src/app/components/ui/UserMenu.vue

@ -37,7 +37,12 @@
Account
</NuxtLink>
</DropdownMenuItem>
<DropdownMenuItem v-if="authStore.userData?.role === roles.ADMIN">
<DropdownMenuItem
v-if="
authStore.userData &&
hasPermissions(authStore.userData, 'admin', 'any')
"
>
<NuxtLink
to="/admin"
class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"

2
src/app/middleware/auth.global.ts

@ -21,7 +21,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
// 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');
}
}

1
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,

32
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<UserType, 'id' | 'role'>
| (Pick<UserType, 'id'> & { role: BrandedNumber });
type PermissionCheck<Key extends keyof Permissions> =
| 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<Resource extends keyof Permissions>(
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;

Loading…
Cancel
Save