mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 06:55:45 +01:00
Compare commits
3 Commits
v1.0.3
...
1231c8362f
| Author | SHA1 | Date | |
|---|---|---|---|
| 1231c8362f | |||
| 663eb61352 | |||
| 23f1dd7aa0 |
@@ -22,6 +22,8 @@ const app = express();
|
||||
const PORT = 3002;
|
||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
app.set('trust proxy', true);
|
||||
|
||||
// Security configuration
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.info('Checking for JWT_SECRET');
|
||||
@@ -34,14 +36,20 @@ if (process.env.NODE_ENV === 'production') {
|
||||
|
||||
// Security headers
|
||||
app.use(helmet({
|
||||
contentSecurityPolicy: isDevelopment ? false : {
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", "'unsafe-inline'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||
imgSrc: ["'self'", "data:", "https:"],
|
||||
connectSrc: ["'self'"],
|
||||
fontSrc: ["'self'"],
|
||||
objectSrc: ["'none'"],
|
||||
mediaSrc: ["'self'"],
|
||||
frameSrc: ["'none'"],
|
||||
},
|
||||
},
|
||||
hsts: false,
|
||||
crossOriginEmbedderPolicy: false
|
||||
}));
|
||||
|
||||
|
||||
@@ -9,41 +9,42 @@ generate_secret() {
|
||||
tr -dc 'A-Za-z0-9!@#$%^&*()_+-=' < /dev/urandom | head -c $length
|
||||
}
|
||||
|
||||
# Prüfe ob .env existiert, falls nicht erstelle sie
|
||||
# Prüfe ob .env existiert
|
||||
if [ ! -f /app/.env ]; then
|
||||
echo "📝 Erstelle .env Datei..."
|
||||
|
||||
# Generiere automatisch ein sicheres JWT Secret falls nicht gesetzt
|
||||
# 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 generiertes JWT Secret wurde erstellt"
|
||||
echo "🔑 Automatisch sicheres JWT Secret generiert"
|
||||
else
|
||||
echo "🔑 Verwende vorhandenes JWT Secret aus Umgebungsvariable"
|
||||
fi
|
||||
|
||||
# Erstelle .env aus Template
|
||||
# Erstelle .env aus Template mit envsubst
|
||||
envsubst < /app/.env.template > /app/.env
|
||||
echo "✅ .env Datei erstellt"
|
||||
|
||||
# Logge die ersten Zeilen (ohne Secrets)
|
||||
echo "✅ .env Datei erstellt mit folgenden Einstellungen:"
|
||||
head -n 5 /app/.env
|
||||
else
|
||||
echo "ℹ️ .env Datei existiert bereits"
|
||||
|
||||
# Validiere bestehende .env Datei
|
||||
if ! grep -q "JWT_SECRET=" /app/.env; then
|
||||
echo "❌ Fehler: JWT_SECRET nicht in .env gefunden"
|
||||
exit 1
|
||||
# Wenn .env existiert, aber JWT_SECRET Umgebungsvariable gesetzt ist, aktualisiere sie
|
||||
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
|
||||
|
||||
# Sicherheitsüberprüfungen
|
||||
if grep -q "your-secret-key" /app/.env; then
|
||||
echo "❌ FEHLER: Standard JWT Secret in .env gefunden - bitte ändern!"
|
||||
# Validiere dass JWT_SECERT nicht der Standardwert ist
|
||||
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
|
||||
chown -R schichtplaner:nodejs /app
|
||||
|
||||
echo "🔧 Starte Anwendung..."
|
||||
exec "$@"
|
||||
@@ -1,4 +1,4 @@
|
||||
// frontend/src/pages/Features/Features.tsx
|
||||
// frontend/src/components/Layou/FooterLinks/Features/Features.tsx
|
||||
import React from 'react';
|
||||
|
||||
const Features: React.FC = () => {
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
.createButton {
|
||||
padding: 10px 20px;
|
||||
background-color: #2ecc71;
|
||||
background-color: #51258f;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
@@ -116,7 +116,7 @@
|
||||
}
|
||||
|
||||
.createButton:hover {
|
||||
background-color: #27ae60;
|
||||
background-color: #51258f;
|
||||
}
|
||||
|
||||
.createButton:disabled {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
// vite.config.ts
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { resolve } from 'path'
|
||||
|
||||
// Security-focused Vite configuration
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isProduction = mode === 'production'
|
||||
const isDevelopment = mode === 'development'
|
||||
|
||||
// Load environment variables securely
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
|
||||
// Strictly defined client-safe environment variables
|
||||
// 🆕 WICHTIG: Relative Pfade für Production
|
||||
const clientEnv = {
|
||||
NODE_ENV: mode,
|
||||
ENABLE_PRO: env.ENABLE_PRO || 'false',
|
||||
@@ -19,146 +18,40 @@ export default defineConfig(({ mode }) => {
|
||||
}
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
react({
|
||||
// React specific security settings
|
||||
jsxRuntime: 'automatic',
|
||||
babel: {
|
||||
plugins: [
|
||||
// Remove console in production
|
||||
isProduction && ['babel-plugin-transform-remove-console', { exclude: ['error', 'warn'] }]
|
||||
].filter(Boolean)
|
||||
}
|
||||
})
|
||||
],
|
||||
plugins: [react()],
|
||||
|
||||
server: {
|
||||
port: 3003,
|
||||
host: true,
|
||||
open: isDevelopment,
|
||||
// Security headers for dev server
|
||||
headers: {
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'X-Frame-Options': 'DENY',
|
||||
'X-XSS-Protection': '1; mode=block',
|
||||
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||
'Permissions-Policy': 'camera=(), microphone=(), location=()'
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3002',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
}
|
||||
},
|
||||
// Security: disable HMR in non-dev environments
|
||||
hmr: isDevelopment
|
||||
}
|
||||
},
|
||||
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
// Security: No source maps in production
|
||||
sourcemap: isDevelopment ? 'inline' : false,
|
||||
// Generate deterministic hashes for better caching and security
|
||||
assetsDir: 'assets',
|
||||
sourcemap: isDevelopment,
|
||||
base: isProduction ? '/' : '/',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// Security: Use content hashes for cache busting and integrity
|
||||
chunkFileNames: 'assets/[name]-[hash].js',
|
||||
entryFileNames: 'assets/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[name]-[hash].[ext]',
|
||||
// Security: Manual chunks to separate vendor code
|
||||
manualChunks: (id) => {
|
||||
if (id.includes('node_modules')) {
|
||||
if (id.includes('react') || id.includes('react-dom')) {
|
||||
return 'vendor-react'
|
||||
}
|
||||
if (id.includes('react-router-dom')) {
|
||||
return 'vendor-router'
|
||||
}
|
||||
return 'vendor'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Minification with security-focused settings
|
||||
minify: isProduction ? 'terser' : false,
|
||||
terserOptions: isProduction ? {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
// Security: Remove potentially sensitive code
|
||||
pure_funcs: [
|
||||
'console.log',
|
||||
'console.info',
|
||||
'console.debug',
|
||||
'console.warn',
|
||||
'console.trace',
|
||||
'console.table',
|
||||
'debugger'
|
||||
],
|
||||
dead_code: true,
|
||||
if_return: true,
|
||||
comparisons: true,
|
||||
loops: true,
|
||||
hoist_funs: true,
|
||||
hoist_vars: true,
|
||||
reduce_vars: true,
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
sequences: true,
|
||||
unused: true
|
||||
},
|
||||
mangle: {
|
||||
// Security: Obfuscate code
|
||||
toplevel: true,
|
||||
keep_classnames: false,
|
||||
keep_fnames: false,
|
||||
reserved: [
|
||||
'React',
|
||||
'ReactDOM',
|
||||
'useState',
|
||||
'useEffect',
|
||||
'useContext',
|
||||
'createElement'
|
||||
]
|
||||
},
|
||||
format: {
|
||||
comments: false,
|
||||
beautify: false,
|
||||
// Security: ASCII only to prevent encoding attacks
|
||||
ascii_only: true
|
||||
pure_funcs: ['console.log', 'console.debug', 'console.info']
|
||||
}
|
||||
} : undefined,
|
||||
// Security: Report bundle size issues
|
||||
reportCompressedSize: true,
|
||||
chunkSizeWarningLimit: 1000,
|
||||
// Security: Don't expose source paths
|
||||
assetsInlineLimit: 4096
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 3004,
|
||||
headers: {
|
||||
// Security headers for preview server
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'X-Frame-Options': 'DENY',
|
||||
'X-XSS-Protection': '1; mode=block',
|
||||
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
|
||||
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||
'Content-Security-Policy': `
|
||||
default-src 'self';
|
||||
script-src 'self' 'unsafe-inline';
|
||||
style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: https:;
|
||||
font-src 'self';
|
||||
connect-src 'self';
|
||||
base-uri 'self';
|
||||
form-action 'self';
|
||||
frame-ancestors 'none';
|
||||
`.replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
},
|
||||
|
||||
resolve: {
|
||||
@@ -174,30 +67,9 @@ export default defineConfig(({ mode }) => {
|
||||
}
|
||||
},
|
||||
|
||||
// ✅ SICHER: Strict environment variable control
|
||||
define: Object.keys(clientEnv).reduce((acc, key) => {
|
||||
acc[`import.meta.env.${key}`] = JSON.stringify(clientEnv[key])
|
||||
return acc
|
||||
}, {} as Record<string, string>),
|
||||
|
||||
// Security: Clear build directory
|
||||
emptyOutDir: true,
|
||||
|
||||
// Security: Optimize dependencies
|
||||
optimizeDeps: {
|
||||
include: ['react', 'react-dom', 'react-router-dom'],
|
||||
exclude: ['@vitejs/plugin-react']
|
||||
},
|
||||
|
||||
// Security: CSS configuration
|
||||
css: {
|
||||
devSourcemap: isDevelopment,
|
||||
modules: {
|
||||
localsConvention: 'camelCase',
|
||||
generateScopedName: isProduction
|
||||
? '[hash:base64:8]'
|
||||
: '[name]__[local]--[hash:base64:5]'
|
||||
}
|
||||
}
|
||||
}, {} as Record<string, string>)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user