Fix jwt-token

This commit is contained in:
2025-09-19 08:14:41 +02:00
parent f98fd04191
commit 3f1b50871a
5 changed files with 343 additions and 113 deletions

272
server/utils/i18n.js Normal file
View File

@@ -0,0 +1,272 @@
/**
* Internationalization utility for backend error messages and system messages
*/
const SUPPORTED_LANGUAGES = ['en', 'sv'];
const DEFAULT_LANGUAGE = 'en';
// Error message translations
const ERROR_MESSAGES = {
en: {
// Authentication errors
TOKEN_EXPIRED: 'Your session has expired. Please log in again.',
INVALID_TOKEN: 'Invalid authentication token. Please log in again.',
TOKEN_NOT_ACTIVE: 'Authentication token is not yet active.',
USER_NOT_FOUND: 'User account not found. Please contact support.',
ACCOUNT_DEACTIVATED: 'Your account has been deactivated. Please contact support.',
AUTH_REQUIRED: 'Authentication is required to access this resource.',
NO_TOKEN: 'No authentication token provided.',
// Authorization errors
INSUFFICIENT_PERMISSIONS: 'Access denied. This action requires {requiredRoles} permissions, but you have {userRole} permissions.',
PERMISSION_DENIED: 'You do not have permission to perform this action.',
INSUFFICIENT_MANAGEMENT_PRIVILEGES: 'Insufficient management privileges to access this resource.',
// Management errors
AUTHENTICATION_REQUIRED: 'Management authentication required.',
INSUFFICIENT_PRIVILEGES: 'Insufficient management privileges.',
INVALID_MANAGEMENT_CREDENTIALS: 'Invalid management credentials.',
MANAGEMENT_AUTH_ERROR: 'Management authentication error.',
// Tenant management
TENANT_NOT_FOUND: 'Tenant not found.',
TENANT_CREATION_FAILED: 'Failed to create tenant.',
TENANT_UPDATE_FAILED: 'Failed to update tenant.',
TENANT_DELETE_FAILED: 'Failed to delete tenant.',
TENANT_SLUG_EXISTS: 'Tenant slug already exists.',
DOMAIN_EXISTS: 'Domain already exists for another tenant.',
CANNOT_DELETE_DEFAULT: 'Cannot delete default tenant.',
NAME_SLUG_REQUIRED: 'Name and slug are required.',
TENANT_CREATED: 'Tenant created successfully.',
TENANT_UPDATED: 'Tenant updated successfully.',
TENANT_DELETED: 'Tenant deleted successfully.',
FETCH_TENANTS_FAILED: 'Failed to fetch tenants.',
FETCH_TENANT_FAILED: 'Failed to fetch tenant.',
// System errors
SYSTEM_INFO_FAILED: 'Failed to fetch system information.',
DOCKER_ACCESS_ERROR: 'This could mean Docker is not running, no containers are active, or the monitoring system needs Docker access.',
MANAGEMENT_AUTH_REQUIRED: 'Management authentication is required to access this resource.',
INVALID_MANAGEMENT_TOKEN: 'Invalid management authentication token.',
// General errors
AUTHENTICATION_FAILED: 'Authentication failed. Please try again.',
ACCESS_DENIED: 'Access denied.',
VALIDATION_ERROR: 'Validation error occurred.',
INTERNAL_ERROR: 'An internal error occurred. Please try again later.'
},
sv: {
// Authentication errors
TOKEN_EXPIRED: 'Din session har löpt ut. Vänligen logga in igen.',
INVALID_TOKEN: 'Ogiltig autentiseringstoken. Vänligen logga in igen.',
TOKEN_NOT_ACTIVE: 'Autentiseringstoken är inte aktiv ännu.',
USER_NOT_FOUND: 'Användarkonto hittades inte. Vänligen kontakta support.',
ACCOUNT_DEACTIVATED: 'Ditt konto har inaktiverats. Vänligen kontakta support.',
AUTH_REQUIRED: 'Autentisering krävs för att komma åt denna resurs.',
NO_TOKEN: 'Ingen autentiseringstoken tillhandahållen.',
// Authorization errors
INSUFFICIENT_PERMISSIONS: 'Åtkomst nekad. Denna åtgärd kräver {requiredRoles} behörigheter, men du har {userRole} behörigheter.',
PERMISSION_DENIED: 'Du har inte behörighet att utföra denna åtgärd.',
INSUFFICIENT_MANAGEMENT_PRIVILEGES: 'Otillräckliga förvaltningsprivilegier för att komma åt denna resurs.',
// Management errors
MANAGEMENT_AUTH_REQUIRED: 'Förvaltningsautentisering krävs för att komma åt denna resurs.',
INVALID_MANAGEMENT_TOKEN: 'Ogiltig förvaltningsautentiseringstoken.',
AUTHENTICATION_REQUIRED: 'Förvaltningsautentisering krävs.',
INSUFFICIENT_PRIVILEGES: 'Otillräckliga förvaltningsprivilegier.',
INVALID_MANAGEMENT_CREDENTIALS: 'Ogiltiga förvaltningsuppgifter.',
MANAGEMENT_AUTH_ERROR: 'Förvaltningsautentiseringsfel.',
// Tenant management
TENANT_NOT_FOUND: 'Hyresgäst hittades inte.',
TENANT_CREATION_FAILED: 'Misslyckades att skapa hyresgäst.',
TENANT_UPDATE_FAILED: 'Misslyckades att uppdatera hyresgäst.',
TENANT_DELETE_FAILED: 'Misslyckades att ta bort hyresgäst.',
TENANT_SLUG_EXISTS: 'Hyresgästslug finns redan.',
DOMAIN_EXISTS: 'Domän finns redan för en annan hyresgäst.',
CANNOT_DELETE_DEFAULT: 'Kan inte ta bort standardhyresgäst.',
NAME_SLUG_REQUIRED: 'Namn och slug krävs.',
TENANT_CREATED: 'Hyresgäst skapad framgångsrikt.',
TENANT_UPDATED: 'Hyresgäst uppdaterad framgångsrikt.',
TENANT_DELETED: 'Hyresgäst borttagen framgångsrikt.',
FETCH_TENANTS_FAILED: 'Misslyckades att hämta hyresgäster.',
FETCH_TENANT_FAILED: 'Misslyckades att hämta hyresgäst.',
// System errors
SYSTEM_INFO_FAILED: 'Misslyckades att hämta systeminformation.',
DOCKER_ACCESS_ERROR: 'Detta kan betyda att Docker inte körs, inga behållare är aktiva eller att övervakningssystemet behöver Docker-åtkomst.',
// General errors
AUTHENTICATION_FAILED: 'Autentisering misslyckades. Vänligen försök igen.',
ACCESS_DENIED: 'Åtkomst nekad.',
VALIDATION_ERROR: 'Valideringsfel inträffade.',
INTERNAL_ERROR: 'Ett internt fel inträffade. Vänligen försök igen senare.'
}
};
// System message translations (for alerts, notifications, etc.)
const SYSTEM_MESSAGES = {
en: {
// Alert messages
CRITICAL_THREAT_DETECTED: 'CRITICAL THREAT: {droneType} DETECTED - IMMEDIATE RESPONSE REQUIRED',
HIGH_THREAT_DETECTED: 'HIGH THREAT: {droneType} detected at {distance}m',
MEDIUM_THREAT_DETECTED: 'MEDIUM THREAT: {droneType} detected in vicinity',
LOW_THREAT_DETECTED: 'LOW THREAT: {droneType} detected at distance',
MONITORING_DETECTED: 'MONITORING: {droneType} detected at long range',
MILITARY_THREAT_ENHANCED: 'MILITARY THREAT: {droneType} DETECTED - ENHANCED RESPONSE REQUIRED',
// Device messages
DEVICE_OFFLINE: 'Device {deviceName} is offline',
DEVICE_ONLINE: 'Device {deviceName} is back online',
HEARTBEAT_RECEIVED: 'Heartbeat received from {deviceName}',
// General system messages
OPERATION_SUCCESSFUL: 'Operation completed successfully',
OPERATION_FAILED: 'Operation failed',
DATA_SAVED: 'Data saved successfully',
DATA_DELETED: 'Data deleted successfully'
},
sv: {
// Alert messages
CRITICAL_THREAT_DETECTED: 'KRITISKT HOT: {droneType} UPPTÄCKT - OMEDELBAR RESPONS KRÄVS',
HIGH_THREAT_DETECTED: 'HÖGT HOT: {droneType} upptäckt på {distance}m',
MEDIUM_THREAT_DETECTED: 'MEDELHÖGT HOT: {droneType} upptäckt i närheten',
LOW_THREAT_DETECTED: 'LÅGT HOT: {droneType} upptäckt på avstånd',
MONITORING_DETECTED: 'ÖVERVAKNING: {droneType} upptäckt på långt avstånd',
MILITARY_THREAT_ENHANCED: 'MILITÄRT HOT: {droneType} UPPTÄCKT - FÖRSTÄRKT RESPONS KRÄVS',
// Device messages
DEVICE_OFFLINE: 'Enhet {deviceName} är offline',
DEVICE_ONLINE: 'Enhet {deviceName} är online igen',
HEARTBEAT_RECEIVED: 'Heartbeat mottagen från {deviceName}',
// General system messages
OPERATION_SUCCESSFUL: 'Operationen slutfördes framgångsrikt',
OPERATION_FAILED: 'Operationen misslyckades',
DATA_SAVED: 'Data sparad framgångsrikt',
DATA_DELETED: 'Data raderad framgångsrikt'
}
};
// Drone type translations
const DRONE_TYPES = {
en: {
0: 'Unknown Drone',
1: 'DJI Mavic',
2: 'Orlan',
3: 'Racing Drone',
4: 'DJI Phantom',
5: 'Zala Lancet',
6: 'Eleron',
7: 'Commercial Drone',
8: 'Professional Drone'
},
sv: {
0: 'Okänd Drönare',
1: 'DJI Mavic',
2: 'Orlan',
3: 'Racing Drönare',
4: 'DJI Phantom',
5: 'Zala Lancet',
6: 'Eleron',
7: 'Kommersiell Drönare',
8: 'Professionell Drönare'
}
};
/**
* Get user's preferred language from request headers
*/
function getLanguageFromRequest(req) {
// Check for explicit language header
const explicitLang = req.headers['accept-language-override'] || req.headers['x-language'];
if (explicitLang && SUPPORTED_LANGUAGES.includes(explicitLang)) {
return explicitLang;
}
// Parse Accept-Language header
const acceptLanguage = req.headers['accept-language'];
if (acceptLanguage) {
const languages = acceptLanguage
.split(',')
.map(lang => lang.split(';')[0].trim().toLowerCase())
.map(lang => lang.split('-')[0]); // Get just the language part (sv from sv-SE)
for (const lang of languages) {
if (SUPPORTED_LANGUAGES.includes(lang)) {
return lang;
}
}
}
return DEFAULT_LANGUAGE;
}
/**
* Get localized error message
*/
function getErrorMessage(messageKey, language = DEFAULT_LANGUAGE, params = {}) {
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
let message = ERROR_MESSAGES[lang]?.[messageKey] || ERROR_MESSAGES[DEFAULT_LANGUAGE]?.[messageKey] || messageKey;
// Replace parameters in message
Object.keys(params).forEach(key => {
message = message.replace(new RegExp(`{${key}}`, 'g'), params[key]);
});
return message;
}
/**
* Get localized system message
*/
function getSystemMessage(messageKey, language = DEFAULT_LANGUAGE, params = {}) {
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
let message = SYSTEM_MESSAGES[lang]?.[messageKey] || SYSTEM_MESSAGES[DEFAULT_LANGUAGE]?.[messageKey] || messageKey;
// Replace parameters in message
Object.keys(params).forEach(key => {
message = message.replace(new RegExp(`{${key}}`, 'g'), params[key]);
});
return message;
}
/**
* Get localized drone type name
*/
function getDroneTypeName(droneType, language = DEFAULT_LANGUAGE) {
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
return DRONE_TYPES[lang]?.[droneType] || DRONE_TYPES[DEFAULT_LANGUAGE]?.[droneType] || 'Unknown';
}
/**
* Create localized error response
*/
function createErrorResponse(req, status, errorCode, params = {}) {
const language = getLanguageFromRequest(req);
const message = getErrorMessage(errorCode, language, params);
return {
status,
json: {
success: false,
message,
error: errorCode,
errorCode,
language,
...params
}
};
}
module.exports = {
getLanguageFromRequest,
getErrorMessage,
getSystemMessage,
getDroneTypeName,
createErrorResponse,
SUPPORTED_LANGUAGES,
DEFAULT_LANGUAGE
};