mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 06:55:45 +01:00
added security features from terser
This commit is contained in:
@@ -16,7 +16,8 @@
|
|||||||
"@vitejs/plugin-react": "^4.3.3",
|
"@vitejs/plugin-react": "^4.3.3",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^6.0.7",
|
"vite": "^6.0.7",
|
||||||
"esbuild": "^0.21.0"
|
"esbuild": "^0.21.0",
|
||||||
|
"terser": "5.44.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -2,43 +2,166 @@ import { defineConfig, loadEnv } from 'vite'
|
|||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// Security-focused Vite configuration
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
// Load env file based on `mode` in the current directory
|
const isProduction = mode === 'production'
|
||||||
|
const isDevelopment = mode === 'development'
|
||||||
|
|
||||||
|
// Load environment variables securely
|
||||||
const env = loadEnv(mode, process.cwd(), '')
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
|
|
||||||
// Only expose specific environment variables to the client
|
// Strictly defined client-safe environment variables
|
||||||
const clientEnv = {
|
const clientEnv = {
|
||||||
NODE_ENV: mode,
|
NODE_ENV: mode,
|
||||||
ENABLE_PRO: env.ENABLE_PRO || 'false',
|
ENABLE_PRO: env.ENABLE_PRO || 'false',
|
||||||
VITE_APP_TITLE: env.VITE_APP_TITLE || 'Shift Planning App',
|
VITE_APP_TITLE: env.VITE_APP_TITLE || 'Shift Planning App',
|
||||||
// Add other client-safe variables here
|
VITE_API_URL: isProduction ? '/api' : 'http://localhost:3002/api',
|
||||||
|
// Explicitly define only what's needed - no dynamic env variables
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugins: [react()],
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
port: 3003,
|
port: 3003,
|
||||||
host: true,
|
host: true,
|
||||||
open: mode === 'development',
|
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: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:3002',
|
target: 'http://localhost:3002',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
|
// Additional proxy security
|
||||||
|
configure: (proxy, _options) => {
|
||||||
|
proxy.on('error', (err, _req, _res) => {
|
||||||
|
console.log('proxy error', err)
|
||||||
|
})
|
||||||
|
proxy.on('proxyReq', (proxyReq, req, _res) => {
|
||||||
|
console.log('Sending Request to the Target:', req.method, req.url)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Security: disable HMR in non-dev environments
|
||||||
|
hmr: isDevelopment
|
||||||
|
},
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
sourcemap: mode === 'development',
|
// Security: No source maps in production
|
||||||
minify: mode === 'production' ? 'terser' : false,
|
sourcemap: isDevelopment ? 'inline' : false,
|
||||||
terserOptions: mode === 'production' ? {
|
// Generate deterministic hashes for better caching and security
|
||||||
|
assetsDir: 'assets',
|
||||||
|
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: {
|
||||||
|
vendor: ['react', 'react-dom'],
|
||||||
|
router: ['react-router-dom'],
|
||||||
|
utils: ['lodash', 'date-fns']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Minification with security-focused settings
|
||||||
|
minify: isProduction ? 'terser' : false,
|
||||||
|
terserOptions: isProduction ? {
|
||||||
compress: {
|
compress: {
|
||||||
drop_console: true,
|
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,
|
||||||
|
unused: true,
|
||||||
|
joins: true,
|
||||||
|
if_return: true,
|
||||||
|
comparisons: true,
|
||||||
|
loops: true,
|
||||||
|
hoist_funs: true,
|
||||||
|
hoist_vars: true,
|
||||||
|
reduce_vars: 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
|
||||||
|
}
|
||||||
} : undefined,
|
} : 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: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve(__dirname, './src'),
|
'@': resolve(__dirname, './src'),
|
||||||
@@ -51,10 +174,31 @@ export default defineConfig(({ mode }) => {
|
|||||||
'@/design': resolve(__dirname, './src/design')
|
'@/design': resolve(__dirname, './src/design')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// ✅ SICHER: Nur explizit definierte Variablen
|
|
||||||
|
// ✅ SICHER: Strict environment variable control
|
||||||
define: Object.keys(clientEnv).reduce((acc, key) => {
|
define: Object.keys(clientEnv).reduce((acc, key) => {
|
||||||
acc[`process.env.${key}`] = JSON.stringify(clientEnv[key])
|
acc[`import.meta.env.${key}`] = JSON.stringify(clientEnv[key])
|
||||||
return acc
|
return acc
|
||||||
}, {} as Record<string, string>)
|
}, {} 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]'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user