From c1416161c2664073ccf13b127a75d00035f1accd Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Wed, 29 Jul 2026 09:11:42 +0200 Subject: [PATCH] hotfix: ProtectedRoute allows access for system_admin + empty permissions + /kein-zugriff route + NoAccessPage --- .../src/components/common/ProtectedRoute.tsx | 14 ++++++++++++ frontend/src/pages/NoAccessPage.tsx | 22 +++++++++++++++++++ frontend/src/routes/index.tsx | 5 +++++ 3 files changed, 41 insertions(+) create mode 100644 frontend/src/pages/NoAccessPage.tsx diff --git a/frontend/src/components/common/ProtectedRoute.tsx b/frontend/src/components/common/ProtectedRoute.tsx index 0016ed9..c8afa17 100644 --- a/frontend/src/components/common/ProtectedRoute.tsx +++ b/frontend/src/components/common/ProtectedRoute.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Navigate } from 'react-router-dom'; import { usePermission } from '@/hooks/usePermission'; +import { useAuthStore } from '@/store/authStore'; interface ProtectedRouteProps { permission: string; @@ -9,6 +10,19 @@ interface ProtectedRouteProps { export function ProtectedRoute({ permission, children }: ProtectedRouteProps) { const { hasPermission } = usePermission(); + const user = useAuthStore((state) => state.user); + + // If user is system admin, always allow + if (user?.is_system_admin) { + return <>{children}; + } + + // If permissions array is empty or not loaded yet, allow access + // (better to show page and let backend 403 handle it than block everything) + const perms = user?.permissions || []; + if (perms.length === 0) { + return <>{children}; + } if (!hasPermission(permission)) { return ; diff --git a/frontend/src/pages/NoAccessPage.tsx b/frontend/src/pages/NoAccessPage.tsx new file mode 100644 index 0000000..e457b32 --- /dev/null +++ b/frontend/src/pages/NoAccessPage.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { ShieldX } from 'lucide-react'; + +export default function NoAccessPage() { + return ( +
+ +

Kein Zugriff

+

+ Sie haben keine Berechtigung, auf diese Seite zuzugreifen. + Bitte wenden Sie sich an einen Administrator, falls Sie Zugriff benötigen. +

+ + Zum Dashboard + +
+ ); +} diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 267ab02..67cacbb 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -64,6 +64,7 @@ const ActivityTimelinePage = React.lazy(() => import('@/pages/ActivityTimeline') const SettingsWebhooksPage = React.lazy(() => import('@/pages/SettingsWebhooks').then(m => ({ default: m.SettingsWebhooksPage }))); const SettingsBackupPage = React.lazy(() => import('@/pages/SettingsBackup').then(m => ({ default: m.SettingsBackupPage }))); const SettingsRechtePage = React.lazy(() => import('@/pages/SettingsRechte').then(m => ({ default: m.SettingsRechtePage }))); +const NoAccessPage = React.lazy(() => import('@/pages/NoAccessPage').then(m => ({ default: m.NoAccessPage }))); /** Centered spinner fallback for lazy-loaded routes */ function PageLoader() { @@ -120,6 +121,10 @@ const router = createBrowserRouter([ path: '/guest/contacts', element: , }, + { + path: '/kein-zugriff', + element: {withSuspense()}, + }, { element: (