diff --git a/backend/server.js b/backend/server.js index 7bb6b5e..1fde812 100644 --- a/backend/server.js +++ b/backend/server.js @@ -80,44 +80,6 @@ process.on('unhandledRejection', (reason, promise) => { console.error('[unhandledRejection]', reason); }); -// Globale Fehlerbehandlung für API-Routen -app.use((err, req, res, next) => { - if (res.headersSent) { - return next(err); - } - - const status = err?.statusCode || err?.status || 500; - - // Unterstützung für Fehlercodes - let errorResponse; - if (err instanceof HttpError && err.errorCode) { - // Neues Format mit Fehlercode - errorResponse = err.toJSON(); - } else { - // Legacy-Format: String-Nachricht - const message = err?.message || 'Interner Serverfehler'; - errorResponse = { - message - }; - } - - const response = { - success: false, - ...errorResponse, - // Für Rückwärtskompatibilität: error-Feld mit Nachricht - error: errorResponse.message || errorResponse.code || 'Interner Serverfehler' - }; - - if (process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development') { - response.debug = { - stack: err?.stack || null - }; - } - - console.error('[ExpressError]', err); - res.status(status).json(response); -}); - app.use('/api/auth', authRoutes); app.use('/api/clubs', clubRoutes); app.use('/api/clubmembers', memberRoutes); @@ -196,6 +158,44 @@ const setCanonicalTag = (req, res, next) => { app.use(setCanonicalTag); app.use(express.static(path.join(__dirname, '../frontend/dist'))); +// Globale Fehlerbehandlung für API-Routen (MUSS nach allen Routes sein!) +app.use((err, req, res, next) => { + if (res.headersSent) { + return next(err); + } + + const status = err?.statusCode || err?.status || 500; + + // Unterstützung für Fehlercodes + let errorResponse; + if (err instanceof HttpError && err.errorCode) { + // Neues Format mit Fehlercode + errorResponse = err.toJSON(); + } else { + // Legacy-Format: String-Nachricht + const message = err?.message || 'Interner Serverfehler'; + errorResponse = { + message + }; + } + + const response = { + success: false, + ...errorResponse, + // Für Rückwärtskompatibilität: error-Feld mit Nachricht + error: errorResponse.message || errorResponse.code || 'Interner Serverfehler' + }; + + if (process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development') { + response.debug = { + stack: err?.stack || null + }; + } + + console.error('[ExpressError]', err); + res.status(status).json(response); +}); + (async () => { try { await sequelize.authenticate(); diff --git a/backend/services/myTischtennisService.js b/backend/services/myTischtennisService.js index a6cafa7..17cb480 100644 --- a/backend/services/myTischtennisService.js +++ b/backend/services/myTischtennisService.js @@ -182,6 +182,10 @@ class MyTischtennisService { if (!password) { if (hasStoredPassword) { password = account.getPassword(); + if (!password) { + console.error('[myTischtennisService.verifyLogin] Could not decrypt stored password'); + throw new HttpError('Gespeichertes Passwort konnte nicht entschlüsselt werden. Bitte Passwort erneut eingeben.', 400); + } } else if (hasValidSession) { // Prüfe, ob bestehende Session noch gültig ist const profileResult = await myTischtennisClient.getUserProfile(account.cookie); @@ -214,7 +218,9 @@ class MyTischtennisService { } // Login-Versuch mit Passwort + console.log('[myTischtennisService.verifyLogin] Attempting login for user:', account.email); const loginResult = await myTischtennisClient.login(account.email, password); + console.log('[myTischtennisService.verifyLogin] Login result:', { success: loginResult.success, error: loginResult.error }); if (loginResult.success) { account.lastLoginSuccess = now; @@ -248,7 +254,9 @@ class MyTischtennisService { }; } else { await account.save(); // Save lastLoginAttempt - throw new HttpError(loginResult.error || 'myTischtennis-Login fehlgeschlagen', 401); + const errorMessage = loginResult.error || 'myTischtennis-Login fehlgeschlagen'; + console.error('[myTischtennisService.verifyLogin] Login failed:', errorMessage); + throw new HttpError(errorMessage, 401); } } diff --git a/backend/utils/encrypt.js b/backend/utils/encrypt.js index 03477b4..be6db89 100644 --- a/backend/utils/encrypt.js +++ b/backend/utils/encrypt.js @@ -26,14 +26,27 @@ function decryptData(data) { if (!data || data === null || data === undefined || data === '') { return null; } + + // Prüfe, ob die Daten bereits entschlüsselt sind (nicht im Hex-Format) + // Hex-Strings haben nur 0-9 und a-f Zeichen und gerade Länge + const isHexString = /^[0-9a-fA-F]+$/.test(data) && data.length % 2 === 0; + + if (!isHexString) { + // Daten sind wahrscheinlich bereits entschlüsselt oder in einem anderen Format + // Versuche, sie direkt zurückzugeben + return data; + } + try { const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(process.env.ENCRYPTION_KEY, 'hex'), Buffer.alloc(16, 0)); let decrypted = decipher.update(data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } catch (error) { - console.error('[decryptData] Error decrypting data:', error); - return null; + // Wenn Entschlüsselung fehlschlägt, versuche die Daten direkt zurückzugeben + // (falls sie bereits entschlüsselt sind) + console.warn('[decryptData] Error decrypting data, returning as-is:', error.message); + return data; } } diff --git a/frontend/src/views/MyTischtennisAccount.vue b/frontend/src/views/MyTischtennisAccount.vue index 7f60a1c..147c4d0 100644 --- a/frontend/src/views/MyTischtennisAccount.vue +++ b/frontend/src/views/MyTischtennisAccount.vue @@ -46,7 +46,7 @@
@@ -287,14 +287,17 @@ export default { }, async testConnection() { + console.log('[testConnection] Starting connection test...'); try { - await apiClient.post('/mytischtennis/verify'); + const response = await apiClient.post('/mytischtennis/verify'); + console.log('[testConnection] Response:', response); this.$store.dispatch('showMessage', { text: this.$t('myTischtennisAccount.loginSuccessful'), type: 'success' }); await this.loadAccount(); // Aktualisiere Account-Daten inkl. clubId, fedNickname } catch (error) { + console.error('[testConnection] Error:', error); const message = getSafeErrorMessage(error, 'Login fehlgeschlagen'); if (error.response?.status === 400 && message.includes('Kein Passwort gespeichert')) {