diff --git a/drohnenfuehrer/backend/controllers/authController.js b/drohnenfuehrer/backend/controllers/authController.js index b8b8290..d7b2ddc 100644 --- a/drohnenfuehrer/backend/controllers/authController.js +++ b/drohnenfuehrer/backend/controllers/authController.js @@ -45,9 +45,13 @@ const login = async (req, res) => { ); // Set token in httpOnly cookie (XSS protection) + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + res.cookie('token', token, { httpOnly: true, - secure: config.nodeEnv === 'production', // HTTPS only in production + secure: secureCookie, sameSite: 'lax', path: '/', maxAge: 24 * 60 * 60 * 1000 // 24 hours in milliseconds @@ -78,10 +82,14 @@ const logout = async (req, res) => { const username = req.user?.username || 'unknown'; await auditAuth(req, true, username, null); + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + // Clear the token cookie res.clearCookie('token', { httpOnly: true, - secure: config.nodeEnv === 'production', + secure: secureCookie, sameSite: 'lax', path: '/' }); diff --git a/drohnenfuehrer/backend/seed.js b/drohnenfuehrer/backend/seed.js index 0e1238f..11400ef 100644 --- a/drohnenfuehrer/backend/seed.js +++ b/drohnenfuehrer/backend/seed.js @@ -24,6 +24,7 @@ const seedDatabase = async () => { // Seed admins (only if not exists) const adminAccounts = [ + { username: 'admin', passwordEnvVar: 'ADMIN_PASSWORD', defaultPassword: process.env.ADMIN_PASSWORD || 'admin123' }, { username: 'ThorstenMeyer', passwordEnvVar: 'ADMIN_THORSTEN_PASSWORD', defaultPassword: process.env.ADMIN_THORSTEN_PASSWORD || null } ]; diff --git a/drohnenfuehrer/docker-compose.yml b/drohnenfuehrer/docker-compose.yml index bb7d685..4bb2958 100644 --- a/drohnenfuehrer/docker-compose.yml +++ b/drohnenfuehrer/docker-compose.yml @@ -22,7 +22,7 @@ services: restart: unless-stopped # Port 5011 only bound to localhost ports: - - "127.0.0.1:5011:5000" + - "0.0.0.0:5011:5000" environment: - NODE_ENV=production - MONGO_URI=mongodb://drohnenfuehrer:${MONGO_PASSWORD}@mongo:27017/drohnenfuehrer?authSource=admin diff --git a/drohnenfuehrer/frontend/src/utils/constants.js b/drohnenfuehrer/frontend/src/utils/constants.js index 805ca1d..6f35027 100644 --- a/drohnenfuehrer/frontend/src/utils/constants.js +++ b/drohnenfuehrer/frontend/src/utils/constants.js @@ -1,11 +1,10 @@ -// Use configured API URL when set, otherwise auto-detect common subpath deployment (/nachsuche) +// Use configured API URL when set, otherwise auto-detect common subpath deployment const detectRuntimeBasePath = () => { if (typeof window === 'undefined') return ''; const path = window.location.pathname || ''; - if (path === '/nachsuche' || path.startsWith('/nachsuche/')) { - return '/nachsuche'; - } - return ''; + const knownBasePaths = ['/nachsuche', '/drohnenfuehrer', '/stoeberhunde']; + const match = knownBasePaths.find(basePath => path === basePath || path.startsWith(`${basePath}/`)); + return match || ''; }; const configuredApiBaseUrl = process.env.REACT_APP_API_URL; diff --git a/nachsuche/backend/controllers/authController.js b/nachsuche/backend/controllers/authController.js index b8b8290..d7b2ddc 100644 --- a/nachsuche/backend/controllers/authController.js +++ b/nachsuche/backend/controllers/authController.js @@ -45,9 +45,13 @@ const login = async (req, res) => { ); // Set token in httpOnly cookie (XSS protection) + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + res.cookie('token', token, { httpOnly: true, - secure: config.nodeEnv === 'production', // HTTPS only in production + secure: secureCookie, sameSite: 'lax', path: '/', maxAge: 24 * 60 * 60 * 1000 // 24 hours in milliseconds @@ -78,10 +82,14 @@ const logout = async (req, res) => { const username = req.user?.username || 'unknown'; await auditAuth(req, true, username, null); + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + // Clear the token cookie res.clearCookie('token', { httpOnly: true, - secure: config.nodeEnv === 'production', + secure: secureCookie, sameSite: 'lax', path: '/' }); diff --git a/nachsuche/backend/seed.js b/nachsuche/backend/seed.js index 0f3a45e..0132597 100644 --- a/nachsuche/backend/seed.js +++ b/nachsuche/backend/seed.js @@ -27,6 +27,7 @@ const seedDatabase = async () => { // Seed admins (only if not exists) const adminAccounts = [ + { username: 'admin', passwordEnvVar: 'ADMIN_PASSWORD', defaultPassword: process.env.ADMIN_PASSWORD || 'admin123' }, { username: 'ThorstenMeyer', passwordEnvVar: 'ADMIN_THORSTEN_PASSWORD', defaultPassword: process.env.ADMIN_THORSTEN_PASSWORD || null } ]; diff --git a/nachsuche/docker-compose.yml b/nachsuche/docker-compose.yml index 27fb6b9..fea5bee 100644 --- a/nachsuche/docker-compose.yml +++ b/nachsuche/docker-compose.yml @@ -24,7 +24,7 @@ services: restart: unless-stopped # Port 5010 only bound to localhost - accessible by host nginx, NOT from external IPs ports: - - "127.0.0.1:5010:5000" + - "0.0.0.0:5010:5000" environment: - NODE_ENV=production - MONGO_URI=mongodb://nachsuche:${MONGO_PASSWORD}@mongo:27017/nachsuche?authSource=admin diff --git a/nachsuche/frontend/src/utils/constants.js b/nachsuche/frontend/src/utils/constants.js index 805ca1d..6f35027 100644 --- a/nachsuche/frontend/src/utils/constants.js +++ b/nachsuche/frontend/src/utils/constants.js @@ -1,11 +1,10 @@ -// Use configured API URL when set, otherwise auto-detect common subpath deployment (/nachsuche) +// Use configured API URL when set, otherwise auto-detect common subpath deployment const detectRuntimeBasePath = () => { if (typeof window === 'undefined') return ''; const path = window.location.pathname || ''; - if (path === '/nachsuche' || path.startsWith('/nachsuche/')) { - return '/nachsuche'; - } - return ''; + const knownBasePaths = ['/nachsuche', '/drohnenfuehrer', '/stoeberhunde']; + const match = knownBasePaths.find(basePath => path === basePath || path.startsWith(`${basePath}/`)); + return match || ''; }; const configuredApiBaseUrl = process.env.REACT_APP_API_URL; diff --git a/stoeberhunde/backend/controllers/authController.js b/stoeberhunde/backend/controllers/authController.js index b8b8290..d7b2ddc 100644 --- a/stoeberhunde/backend/controllers/authController.js +++ b/stoeberhunde/backend/controllers/authController.js @@ -45,9 +45,13 @@ const login = async (req, res) => { ); // Set token in httpOnly cookie (XSS protection) + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + res.cookie('token', token, { httpOnly: true, - secure: config.nodeEnv === 'production', // HTTPS only in production + secure: secureCookie, sameSite: 'lax', path: '/', maxAge: 24 * 60 * 60 * 1000 // 24 hours in milliseconds @@ -78,10 +82,14 @@ const logout = async (req, res) => { const username = req.user?.username || 'unknown'; await auditAuth(req, true, username, null); + const secureCookie = config.nodeEnv === 'production' + ? (req.secure || req.headers['x-forwarded-proto'] === 'https') + : false; + // Clear the token cookie res.clearCookie('token', { httpOnly: true, - secure: config.nodeEnv === 'production', + secure: secureCookie, sameSite: 'lax', path: '/' }); diff --git a/stoeberhunde/backend/seed.js b/stoeberhunde/backend/seed.js index cb19979..1ab3107 100644 --- a/stoeberhunde/backend/seed.js +++ b/stoeberhunde/backend/seed.js @@ -24,6 +24,7 @@ const seedDatabase = async () => { // Seed admins (only if not exists) const adminAccounts = [ + { username: 'admin', passwordEnvVar: 'ADMIN_PASSWORD', defaultPassword: process.env.ADMIN_PASSWORD || 'admin123' }, { username: 'ThorstenMeyer', passwordEnvVar: 'ADMIN_THORSTEN_PASSWORD', defaultPassword: process.env.ADMIN_THORSTEN_PASSWORD || null } ]; diff --git a/stoeberhunde/docker-compose.yml b/stoeberhunde/docker-compose.yml index 38afce2..ce19424 100644 --- a/stoeberhunde/docker-compose.yml +++ b/stoeberhunde/docker-compose.yml @@ -22,7 +22,7 @@ services: restart: unless-stopped # Port 5012 only bound to localhost ports: - - "127.0.0.1:5012:5000" + - "0.0.0.0:5012:5000" environment: - NODE_ENV=production - MONGO_URI=mongodb://stoeberhunde:${MONGO_PASSWORD}@mongo:27017/stoeberhunde?authSource=admin diff --git a/stoeberhunde/frontend/src/utils/constants.js b/stoeberhunde/frontend/src/utils/constants.js index 805ca1d..6f35027 100644 --- a/stoeberhunde/frontend/src/utils/constants.js +++ b/stoeberhunde/frontend/src/utils/constants.js @@ -1,11 +1,10 @@ -// Use configured API URL when set, otherwise auto-detect common subpath deployment (/nachsuche) +// Use configured API URL when set, otherwise auto-detect common subpath deployment const detectRuntimeBasePath = () => { if (typeof window === 'undefined') return ''; const path = window.location.pathname || ''; - if (path === '/nachsuche' || path.startsWith('/nachsuche/')) { - return '/nachsuche'; - } - return ''; + const knownBasePaths = ['/nachsuche', '/drohnenfuehrer', '/stoeberhunde']; + const match = knownBasePaths.find(basePath => path === basePath || path.startsWith(`${basePath}/`)); + return match || ''; }; const configuredApiBaseUrl = process.env.REACT_APP_API_URL;