Project-Image-Uploader/frontend/src/Utils/hostDetection.js
matthias.lotz 712b8477b9 feat: Implement public/internal host separation
Backend:
- Add hostGate middleware for host-based API protection
- Extend rate limiter with publicUploadLimiter (20/hour)
- Add source_host and source_type to audit logs
- Database migration for audit log source tracking
- Unit tests for hostGate middleware (10/20 passing)

Frontend:
- Add hostDetection utility for runtime host detection
- Implement React code splitting with lazy loading
- Update App.js with ProtectedRoute component
- Customize 404 page for public vs internal hosts
- Update env-config.js for host configuration

Docker:
- Add environment variables to prod/dev docker-compose
- Configure ENABLE_HOST_RESTRICTION flags
- Set PUBLIC_HOST and INTERNAL_HOST variables

Infrastructure:
- Prepared for nginx-proxy-manager setup
- Trust proxy configuration (TRUST_PROXY_HOPS=1)

Note: Some unit tests still need adjustment for ENV handling
2025-11-25 20:26:59 +01:00

95 lines
2.7 KiB
JavaScript

/**
* Host Detection Utility
*
* Erkennt, ob App auf public oder internal Host läuft
* Basiert auf window.location.hostname + env-config
*
* @module Utils/hostDetection
*/
/**
* Hole Host-Konfiguration und Feature-Flags
* @returns {Object} Host-Config mit Feature-Flags
*/
export const getHostConfig = () => {
const hostname = window.location.hostname;
// Hole Hosts aus Runtime-Config (wird von env.sh beim Container-Start gesetzt)
const publicHost = window._env_?.PUBLIC_HOST || 'deinprojekt.hobbyhimmel.de';
const internalHost = window._env_?.INTERNAL_HOST || 'deinprojekt.lan.hobbyhimmel.de';
// Bestimme Host-Typ
const isPublic = hostname === publicHost;
const isInternal = hostname === internalHost || hostname === 'localhost' || hostname === '127.0.0.1';
// Feature Flags basierend auf Host
return {
hostname,
publicHost,
internalHost,
isPublic,
isInternal,
// Feature Flags
canAccessAdmin: isInternal,
canAccessSlideshow: isInternal,
canAccessGroups: isInternal,
canAccessModeration: isInternal,
canAccessReorder: isInternal,
canAccessBatchUpload: isInternal,
canAccessSocialMedia: isInternal,
canAccessMigration: isInternal,
// Immer erlaubt (public + internal)
canUpload: true,
canManageByUUID: true
};
};
/**
* Prüft, ob App auf public Host läuft
* @returns {boolean} True wenn public Host
*/
export const isPublicHost = () => {
return getHostConfig().isPublic;
};
/**
* Prüft, ob App auf internal Host läuft
* @returns {boolean} True wenn internal Host
*/
export const isInternalHost = () => {
return getHostConfig().isInternal;
};
/**
* Hole spezifisches Feature-Flag
* @param {string} featureName - Name des Features (z.B. 'canAccessAdmin')
* @returns {boolean} True wenn Feature erlaubt
*/
export const canAccessFeature = (featureName) => {
const config = getHostConfig();
return config[featureName] || false;
};
/**
* Debug-Funktion: Logge Host-Config in Console
* Nur in Development
*/
export const logHostConfig = () => {
if (process.env.NODE_ENV === 'development') {
const config = getHostConfig();
console.log('🔍 Host Configuration:', {
hostname: config.hostname,
isPublic: config.isPublic,
isInternal: config.isInternal,
features: {
admin: config.canAccessAdmin,
slideshow: config.canAccessSlideshow,
groups: config.canAccessGroups,
moderation: config.canAccessModeration
}
});
}
};