129 lines
3.5 KiB
JavaScript
129 lines
3.5 KiB
JavaScript
const foodsharingClient = require('./foodsharingClient');
|
||
const sessionStore = require('./sessionStore');
|
||
const notificationService = require('./notificationService');
|
||
|
||
const ADMIN_SESSION_ERROR_COOLDOWN_MS = 6 * 60 * 60 * 1000;
|
||
const adminSessionErrorCooldowns = new Map();
|
||
|
||
function shouldNotifyAdminSessionError(key) {
|
||
if (!key) {
|
||
return false;
|
||
}
|
||
const now = Date.now();
|
||
const lastNotified = adminSessionErrorCooldowns.get(key) || 0;
|
||
if (now - lastNotified < ADMIN_SESSION_ERROR_COOLDOWN_MS) {
|
||
return false;
|
||
}
|
||
adminSessionErrorCooldowns.set(key, now);
|
||
return true;
|
||
}
|
||
|
||
function isUnauthorizedError(error) {
|
||
const status = error?.response?.status;
|
||
return status === 401 || status === 403;
|
||
}
|
||
|
||
function isCsrfError(error) {
|
||
const status = error?.response?.status;
|
||
if (status !== 400) {
|
||
return false;
|
||
}
|
||
const data = error?.response?.data;
|
||
const message =
|
||
typeof data === 'string'
|
||
? data
|
||
: typeof data?.message === 'string'
|
||
? data.message
|
||
: '';
|
||
return message.toLowerCase().includes('csrf');
|
||
}
|
||
|
||
async function refreshSession(session, { label } = {}) {
|
||
if (!session?.credentials?.email || !session?.credentials?.password) {
|
||
console.warn(
|
||
`[SESSION] Session ${session?.id || 'unbekannt'} kann nicht erneuert werden – keine Zugangsdaten gespeichert.`
|
||
);
|
||
return false;
|
||
}
|
||
try {
|
||
const refreshed = await foodsharingClient.login(
|
||
session.credentials.email,
|
||
session.credentials.password
|
||
);
|
||
sessionStore.update(session.id, {
|
||
cookieHeader: refreshed.cookieHeader,
|
||
csrfToken: refreshed.csrfToken,
|
||
profile: {
|
||
...session.profile,
|
||
...refreshed.profile
|
||
}
|
||
});
|
||
console.log(
|
||
`[SESSION] Session ${session.id} wurde erfolgreich erneuert${label ? ` (${label})` : ''}.`
|
||
);
|
||
return true;
|
||
} catch (error) {
|
||
console.error(
|
||
`[SESSION] Session ${session?.id || 'unbekannt'} konnte nicht erneuert werden${label ? ` (${label})` : ''}:`,
|
||
error.message
|
||
);
|
||
const profileId = session?.profile?.id ? String(session.profile.id) : null;
|
||
const notifyKey = profileId || session?.id || null;
|
||
if (shouldNotifyAdminSessionError(notifyKey)) {
|
||
try {
|
||
await notificationService.sendAdminSessionErrorNotification({
|
||
profileId,
|
||
profileEmail: session?.credentials?.email || session?.profile?.email,
|
||
profileName: session?.profile?.name,
|
||
sessionId: session?.id,
|
||
error: error?.message,
|
||
label
|
||
});
|
||
} catch (notifyError) {
|
||
console.error('[NOTIFY] Admin-Session-Fehler konnte nicht gemeldet werden:', notifyError.message);
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
async function ensureSession(session) {
|
||
if (!session?.profile?.id) {
|
||
return false;
|
||
}
|
||
if (!session.cookieHeader) {
|
||
return refreshSession(session, { label: 'missing-cookie' });
|
||
}
|
||
return true;
|
||
}
|
||
|
||
async function withSessionRetry(session, action, { label } = {}) {
|
||
if (!session) {
|
||
throw new Error('Session fehlt');
|
||
}
|
||
if (!session.cookieHeader && session.credentials) {
|
||
const refreshed = await refreshSession(session, { label });
|
||
if (!refreshed) {
|
||
throw new Error('Session konnte nicht erneuert werden');
|
||
}
|
||
}
|
||
try {
|
||
return await action();
|
||
} catch (error) {
|
||
if (!isUnauthorizedError(error) && !isCsrfError(error)) {
|
||
throw error;
|
||
}
|
||
const refreshed = await refreshSession(session, { label });
|
||
if (!refreshed) {
|
||
throw error;
|
||
}
|
||
return action();
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
ensureSession,
|
||
refreshSession,
|
||
withSessionRetry
|
||
};
|