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 = () => {
-

Zertifikate für {selectedFqdn.fqdn}

+

+ Zertifikate für {selectedFqdn?.fqdn || 'Unbekannter FQDN'} +

- {certificates.map((cert, index) => ( -
-
-
-
- - #{certificates.length - index} - -

CA-Zertifikat-ID: {cert.certificateId}

-
-
-

- 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 ( +

+
+
+
+ + #{certificates.length - index} -

- {cert.providerId && ( -

- Provider:{' '} - {cert.providerId} +

CA-Zertifikat-ID: {certCertificateId}

+
+
+

+ Interne UID:{' '} + {certId}

- )} + {certCreatedAt && !isNaN(certCreatedAt.getTime()) && ( +

+ Erstellt:{' '} + {certCreatedAt.toLocaleString('de-DE')} +

+ )} +

+ Status:{' '} + + {certStatus} + +

+ {certProviderId && ( +

+ Provider:{' '} + {certProviderId} +

+ )} +
+
- + {certPEM && ( +
+
Zertifikat (PEM):
+
+                              {certPEM}
+                            
+
+ )}
- {cert.certificatePEM && ( -
-
Zertifikat (PEM):
-
-                            {cert.certificatePEM}
-                          
-
- )} -
- ))} + ) + })}
)}
diff --git a/frontend/src/pages/Spaces.jsx b/frontend/src/pages/Spaces.jsx index 8997112..1734c37 100644 --- a/frontend/src/pages/Spaces.jsx +++ b/frontend/src/pages/Spaces.jsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../hooks/usePermissions' +import { usePermissions } from '../contexts/PermissionsContext' const Spaces = () => { const navigate = useNavigate() diff --git a/frontend/src/pages/Users.jsx b/frontend/src/pages/Users.jsx index dd5d106..69218e0 100644 --- a/frontend/src/pages/Users.jsx +++ b/frontend/src/pages/Users.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 Users = () => { const { authFetch } = useAuth()