From c85379e4ff982319fc6762eab8cf4c8750dcfb22 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Sat, 25 Apr 2026 23:34:57 -0600 Subject: [PATCH] feat(auth): enforce edit restrictions on demo-restricted accounts --- client/src/components/AppHeader.vue | 13 +- client/src/components/SelectionActionBar.vue | 174 ++++++++++++---- .../__tests__/SelectionActionBar.spec.ts | 171 ++++++++++++++++ client/src/features/admin/UserFormDrawer.vue | 4 + .../__tests__/usePermissions.spec.ts | 49 +++++ .../auth/composables/usePermissions.ts | 9 +- .../src/features/author/views/AuthorsView.vue | 8 +- .../book-dock/components/BookDockToolbar.vue | 15 +- .../__tests__/BookDockToolbar.spec.ts | 187 ++++++++++++++++++ .../src/features/settings/AccountSettings.vue | 67 +++++-- .../src/features/settings/SettingsHeader.vue | 8 +- .../features/tools/components/ToolsHeader.vue | 2 +- client/src/router/index.ts | 11 ++ client/src/views/BookDockView.vue | 3 + packages/types/src/permissions.ts | 2 + .../decorators/common-decorators.test.ts | 8 + .../decorators/forbid-permission.decorator.ts | 12 ++ .../common/guards/permission.guard.test.ts | 75 ++++++- server/src/common/guards/permission.guard.ts | 11 +- .../services/permission.service.test.ts | 4 + .../src/common/services/permission.service.ts | 4 + .../src/modules/auth/auth.controller.test.ts | 30 +++ server/src/modules/auth/auth.controller.ts | 6 +- .../authors/authors.controller.test.ts | 10 + .../src/modules/authors/authors.controller.ts | 2 + .../book-dock/book-dock.controller.test.ts | 10 + .../modules/book-dock/book-dock.controller.ts | 2 + .../src/modules/book/book.controller.test.ts | 35 ++++ server/src/modules/book/book.controller.ts | 9 + .../notification.controller.test.ts | 8 + .../notification/notification.controller.ts | 2 + .../notification/notification.gateway.test.ts | 63 ++++++ .../notification/notification.gateway.ts | 3 + .../src/modules/user/user.controller.test.ts | 29 +++ server/src/modules/user/user.controller.ts | 4 + server/test/guard-mechanics.e2e-spec.ts | 42 +++- 36 files changed, 1010 insertions(+), 82 deletions(-) create mode 100644 client/src/components/__tests__/SelectionActionBar.spec.ts create mode 100644 client/src/features/auth/composables/__tests__/usePermissions.spec.ts create mode 100644 client/src/features/book-dock/components/__tests__/BookDockToolbar.spec.ts create mode 100644 server/src/common/decorators/forbid-permission.decorator.ts create mode 100644 server/src/modules/notification/notification.gateway.test.ts diff --git a/client/src/components/AppHeader.vue b/client/src/components/AppHeader.vue index 5534dfa8c..fc282bedc 100644 --- a/client/src/components/AppHeader.vue +++ b/client/src/components/AppHeader.vue @@ -41,7 +41,7 @@ const router = useRouter() const route = useRoute() const { user, logout } = useAuth() const { open: openChangePassword } = useChangePasswordDialog() -const { hasPermission } = usePermissions() +const { hasPermission, isDemoRestrictedAccount } = usePermissions() const { onLibraryUploadCompleted } = useLibraryUploadEvents() const { summary: bookDockSummary, fetchSummary: fetchBookDockSummary, subscribe: subscribeBookDockSummary } = useBookDockSummary() const { subscribe: subscribeNotifications } = useNotifications() @@ -51,7 +51,10 @@ const isBookDockActive = computed(() => route.name === 'book-dock') const isStatisticsActive = computed(() => route.name === 'statistics') const iconRadiusClass = computed(() => (themeStore.radius === 'sharp' ? 'rounded-none' : 'rounded-full')) -const canChangePassword = computed(() => user.value?.provisioningMethod !== 'oidc' && user.value?.provisioningMethod !== 'shared') +const canChangePassword = computed( + () => !isDemoRestrictedAccount.value && user.value?.provisioningMethod !== 'oidc' && user.value?.provisioningMethod !== 'shared', +) +const canAccessNotifications = computed(() => hasPermission('notification_access') && !isDemoRestrictedAccount.value) function navigateToBookDock() { router.push({ name: 'book-dock' }) @@ -156,7 +159,7 @@ onMounted(() => { fetchBookDockSummary() subscribeBookDockSummary() } - if (hasPermission('notification_access')) { + if (canAccessNotifications.value) { subscribeNotifications() } }) @@ -442,7 +445,7 @@ function formatBadgeClass(fmt: string): string {
+ Demo-restricted account: editing profile, password, avatar, and linked identities is disabled. +