diff --git a/backend/spaces.db-shm b/backend/spaces.db-shm index 83ea5fb..22d9bfb 100644 Binary files a/backend/spaces.db-shm and b/backend/spaces.db-shm differ diff --git a/backend/spaces.db-wal b/backend/spaces.db-wal index 31d02e7..8b30f99 100644 Binary files a/backend/spaces.db-wal and b/backend/spaces.db-wal differ diff --git a/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png b/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png new file mode 100644 index 0000000..aaf893a Binary files /dev/null and b/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png differ diff --git a/frontend/src/contexts/PermissionsContext.jsx b/frontend/src/contexts/PermissionsContext.jsx index 8ff1ee3..a59fbb8 100644 --- a/frontend/src/contexts/PermissionsContext.jsx +++ b/frontend/src/contexts/PermissionsContext.jsx @@ -35,21 +35,31 @@ export const PermissionsProvider = ({ children }) => { } const response = await authFetch('/api/user/permissions') if (response.ok && isMountedRef.current) { - const data = await response.json() - setPermissions({ - isAdmin: data.isAdmin || false, - hasFullAccess: data.hasFullAccess || false, - accessibleSpaces: data.accessibleSpaces || [], - canCreateSpace: data.permissions?.canCreateSpace || false, - canDeleteSpace: data.permissions?.canDeleteSpace || false, - canCreateFqdn: data.permissions?.canCreateFqdn || {}, - canDeleteFqdn: data.permissions?.canDeleteFqdn || {}, - canUploadCSR: data.permissions?.canUploadCSR || {}, - canSignCSR: data.permissions?.canSignCSR || {}, - }) + try { + const data = await response.json() + // Nur Permissions aktualisieren, wenn Daten erfolgreich geparst wurden + setPermissions({ + isAdmin: data.isAdmin || false, + hasFullAccess: data.hasFullAccess || false, + accessibleSpaces: Array.isArray(data.accessibleSpaces) ? data.accessibleSpaces : [], + canCreateSpace: data.permissions?.canCreateSpace || false, + canDeleteSpace: data.permissions?.canDeleteSpace || false, + canCreateFqdn: data.permissions?.canCreateFqdn || {}, + canDeleteFqdn: data.permissions?.canDeleteFqdn || {}, + canUploadCSR: data.permissions?.canUploadCSR || {}, + canSignCSR: data.permissions?.canSignCSR || {}, + }) + } catch (parseErr) { + console.error('Error parsing permissions response:', parseErr) + // Bei Parse-Fehler Permissions nicht zurücksetzen, nur loggen + } + } else if (response.status === 401 && isMountedRef.current) { + // Bei 401 Unauthorized werden Permissions zurückgesetzt (wird von AuthContext gehandelt) + console.log('Unauthorized - permissions will be cleared by auth context') } } catch (err) { console.error('Error fetching permissions:', err) + // Bei Netzwerkfehlern etc. Permissions nicht zurücksetzen } finally { if (isInitial && isMountedRef.current) { setLoading(false) diff --git a/frontend/src/hooks/usePermissions.js b/frontend/src/hooks/usePermissions.js deleted file mode 100644 index 24ea552..0000000 --- a/frontend/src/hooks/usePermissions.js +++ /dev/null @@ -1,3 +0,0 @@ -// Re-export from PermissionsContext for backward compatibility -export { usePermissions } from '../contexts/PermissionsContext' - diff --git a/frontend/src/pages/Permissions.jsx b/frontend/src/pages/Permissions.jsx index b7bec68..7fe3289 100644 --- a/frontend/src/pages/Permissions.jsx +++ b/frontend/src/pages/Permissions.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../hooks/usePermissions' +import { usePermissions } from '../contexts/PermissionsContext' const Permissions = () => { const { authFetch } = useAuth() diff --git a/frontend/src/pages/SpaceDetail.jsx b/frontend/src/pages/SpaceDetail.jsx index 0f28d2d..353c5b3 100644 --- a/frontend/src/pages/SpaceDetail.jsx +++ b/frontend/src/pages/SpaceDetail.jsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../hooks/usePermissions' +import { usePermissions } from '../contexts/PermissionsContext' const SpaceDetail = () => { const { id } = useParams() @@ -423,40 +423,64 @@ const SpaceDetail = () => { } const handleViewCertificates = async (fqdn) => { + if (!fqdn || !fqdn.id) { + console.error('Invalid FQDN provided to handleViewCertificates') + return + } + setSelectedFqdn(fqdn) setLoadingCertificates(true) setCertificates([]) + setShowCertificatesModal(true) // Öffne Modal sofort, auch wenn noch geladen wird try { const response = await authFetch(`/api/spaces/${id}/fqdns/${fqdn.id}/certificates`) + if (response.ok) { - const certs = await response.json() - setCertificates(certs) + try { + const certs = await response.json() + // Stelle sicher, dass certs ein Array ist + setCertificates(Array.isArray(certs) ? certs : []) + } catch (parseErr) { + console.error('Error parsing certificates response:', parseErr) + setCertificates([]) + } } else { - console.error('Fehler beim Laden der Zertifikate') + // Bei Fehler-Response (404, 403, etc.) setze leeres Array + console.error('Fehler beim Laden der Zertifikate:', response.status, response.statusText) + setCertificates([]) } } catch (err) { console.error('Error fetching certificates:', err) + setCertificates([]) } finally { setLoadingCertificates(false) - setShowCertificatesModal(true) } } const handleRefreshCertificate = async (cert) => { + if (!cert || !cert.id || !selectedFqdn || !selectedFqdn.id) { + console.error('Invalid certificate or FQDN for refresh') + return + } + setRefreshingCertificate(cert.id) try { const response = await authFetch(`/api/spaces/${id}/fqdns/${selectedFqdn.id}/certificates/${cert.id}/refresh`, { method: 'POST' }) if (response.ok) { - const result = await response.json() - // Aktualisiere Zertifikat in der Liste - setCertificates(prev => prev.map(c => - c.id === cert.id - ? { ...c, certificatePEM: result.certificatePEM } - : c - )) + try { + const result = await response.json() + // Aktualisiere Zertifikat in der Liste + setCertificates(prev => prev.map(c => + c.id === cert.id + ? { ...c, certificatePEM: result.certificatePEM } + : c + )) + } catch (parseErr) { + console.error('Error parsing refresh response:', parseErr) + } } } catch (err) { console.error('Error refreshing certificate:', err) @@ -1478,10 +1502,13 @@ const SpaceDetail = () => {
- Interne UID:{' '} - {cert.id} -
-- Erstellt:{' '} - {new Date(cert.createdAt).toLocaleString('de-DE')} -
-
- Status:{' '}
-
- {cert.status}
+ {certificates.map((cert, index) => {
+ // Sicherstellen, dass cert ein gültiges Objekt ist
+ if (!cert || !cert.id) {
+ return null
+ }
+
+ const certId = cert.id || 'unknown'
+ const certCertificateId = cert.certificateId || 'N/A'
+ const certCreatedAt = cert.createdAt ? new Date(cert.createdAt) : null
+ const certStatus = cert.status || 'unknown'
+ const certProviderId = cert.providerId
+ const certPEM = cert.certificatePEM
+
+ return (
+
- Provider:{' '}
- {cert.providerId}
+
+ Interne UID:{' '}
+ {certId}
+ Erstellt:{' '}
+ {certCreatedAt.toLocaleString('de-DE')}
+
+ Status:{' '}
+
+ {certStatus}
+
+
+ Provider:{' '}
+ {certProviderId}
+ CA-Zertifikat-ID: {certCertificateId}
+ Zertifikat (PEM):
+
+ {certPEM}
+
+ Zertifikat (PEM):
-
- {cert.certificatePEM}
-
-