diff --git a/backend/src/server.ts b/backend/src/server.ts index bf07187..269b7b9 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -85,7 +85,7 @@ if (process.env.NODE_ENV === 'production') { const configureTrustProxy = (): string | string[] | boolean | number => { const trustedProxyIps = process.env.TRUSTED_PROXY_IPS; - const trustProxyEnabled = process.env.TRUST_PROXY_ENABLED !== 'false'; // Default true for production + const trustProxyEnabled = process.env.TRUST_PROXY_ENABLED !== 'false'; // If explicitly disabled if (!trustProxyEnabled) { @@ -106,21 +106,9 @@ const configureTrustProxy = (): string | string[] | boolean | number => { return trustedProxyIps.trim(); } - // Default behavior based on environment - if (process.env.NODE_ENV === 'production') { - console.log('πŸ”’ Trust proxy: Using production defaults (private networks)'); - return [ - 'loopback', - 'linklocal', - 'uniquelocal', - '10.0.0.0/8', - '172.16.0.0/12', - '192.168.0.0/16' - ]; - } else { - console.log('πŸ”’ Trust proxy: Development mode (disabled)'); - return false; - } + // Default behavior for reverse proxy setup + console.log('πŸ”’ Trust proxy: Using reverse proxy defaults (trust all)'); + return true; // Trust all proxies when behind nginx }; app.set('trust proxy', configureTrustProxy()); @@ -140,7 +128,11 @@ app.use(helmet({ frameSrc: ["'none'"], }, }, - hsts: false, + hsts: { + maxAge: 31536000, + includeSubDomains: true, + preload: true + }, // Enable HSTS for HTTPS crossOriginEmbedderPolicy: false })); diff --git a/docker-init.sh b/docker-init.sh index 65ea84a..020d71d 100644 --- a/docker-init.sh +++ b/docker-init.sh @@ -3,17 +3,15 @@ set -e echo "πŸš€ Container Initialisierung gestartet..." -# Funktion zum Generieren eines sicheren Secrets generate_secret() { length=$1 tr -dc 'A-Za-z0-9!@#$%^&*()_+-=' < /dev/urandom | head -c $length } -# PrΓΌfe ob .env existiert +# Create .env if it doesn't exist if [ ! -f /app/.env ]; then echo "πŸ“ Erstelle .env Datei..." - # Verwende vorhandenes JWT_SECRET oder generiere ein neues if [ -z "$JWT_SECRET" ] || [ "$JWT_SECRET" = "your-secret-key-please-change" ]; then export JWT_SECRET=$(generate_secret 64) echo "πŸ”‘ Automatisch sicheres JWT Secret generiert" @@ -21,30 +19,37 @@ if [ ! -f /app/.env ]; then echo "πŸ”‘ Verwende vorhandenes JWT Secret aus Umgebungsvariable" fi - # Erstelle .env aus Template mit envsubst - envsubst < /app/.env.template > /app/.env - echo "βœ… .env Datei erstellt" + # Create .env with all proxy settings + cat > /app/.env << EOF +NODE_ENV=production +JWT_SECRET=${JWT_SECRET} +TRUST_PROXY_ENABLED=${TRUST_PROXY_ENABLED:-true} +TRUSTED_PROXY_IPS=${TRUSTED_PROXY_IPS:-172.0.0.0/8,10.0.0.0/8,192.168.0.0/16} +HOSTNAME=${HOSTNAME:-localhost} +EOF + echo "βœ… .env Datei erstellt" else echo "ℹ️ .env Datei existiert bereits" - # Wenn .env existiert, aber JWT_SECRET Umgebungsvariable gesetzt ist, aktualisiere sie + # Update JWT_SECRET if provided if [ -n "$JWT_SECRET" ] && [ "$JWT_SECRET" != "your-secret-key-please-change" ]; then echo "πŸ”‘ Aktualisiere JWT Secret in .env Datei" - # Aktualisiere nur das JWT_SECRET in der .env Datei sed -i "s/^JWT_SECRET=.*/JWT_SECRET=$JWT_SECRET/" /app/.env fi fi -# Validiere dass JWT_SECERT nicht der Standardwert ist +# Validate JWT_SECRET if grep -q "JWT_SECRET=your-secret-key-please-change" /app/.env; then echo "❌ FEHLER: Standard JWT Secret in .env gefunden!" echo "❌ Bitte setzen Sie JWT_SECRET Umgebungsvariable" exit 1 fi -# Setze sichere Berechtigungen chmod 600 /app/.env +echo "πŸ”§ Proxy Configuration:" +echo " - TRUST_PROXY_ENABLED: ${TRUST_PROXY_ENABLED:-true}" +echo " - TRUSTED_PROXY_IPS: ${TRUSTED_PROXY_IPS:-172.0.0.0/8,10.0.0.0/8,192.168.0.0/16}" echo "πŸ”§ Starte Anwendung..." exec "$@" \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0793f5b..bd72e3b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -15,6 +15,7 @@ import EmployeeManagement from './pages/Employees/EmployeeManagement'; import Settings from './pages/Settings/Settings'; import Help from './pages/Help/Help'; import Setup from './pages/Setup/Setup'; +import ErrorBoundary from './components/ErrorBoundary/ErrorBoundary'; // Free Footer Link Pages (always available) import FAQ from './components/Layout/FooterLinks/FAQ/FAQ'; @@ -160,14 +161,16 @@ const AppContent: React.FC = () => { function App() { return ( - - - - - - - - + + + + + + + + + + ); } diff --git a/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx b/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx new file mode 100644 index 0000000..b9e2c51 --- /dev/null +++ b/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -0,0 +1,101 @@ +// src/components/ErrorBoundary/ErrorBoundary.tsx +import React from 'react'; + +interface Props { + children: React.ReactNode; + fallback?: React.ReactNode; +} + +interface State { + hasError: boolean; + error?: Error; +} + +class ErrorBoundary extends React.Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error: Error): State { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error('🚨 Application Error:', error); + console.error('πŸ“‹ Error Details:', errorInfo); + + // In production, send to your error reporting service + // logErrorToService(error, errorInfo); + } + + render() { + if (this.state.hasError) { + // You can render any custom fallback UI + return this.props.fallback || ( +
+
⚠️
+

Oops! Something went wrong

+

+ We encountered an unexpected error. Please try refreshing the page. +

+
+ + +
+ {process.env.NODE_ENV === 'development' && this.state.error && ( +
+ Error Details (Development) +
+                {this.state.error.stack}
+              
+
+ )} +
+ ); + } + + return this.props.children; + } +} + +export default ErrorBoundary; \ No newline at end of file