47 lines
1.9 KiB
JavaScript
47 lines
1.9 KiB
JavaScript
export function evaluateSecurityAlertPolicy(result, profile, now = new Date()) {
|
|
if (!result?.notify) return { send: false, reason: 'agent_declined' };
|
|
if (!profile) return { send: true, reason: 'no_profile' };
|
|
|
|
const priority = ['routine', 'priority', 'flash'].includes(result.priority) ? result.priority : 'routine';
|
|
const preference = profile.alertPreference || 'important';
|
|
if (preference === 'critical_only' && priority !== 'flash') {
|
|
return { send: false, reason: 'critical_only' };
|
|
}
|
|
if (preference === 'important' && priority === 'routine') {
|
|
return { send: false, reason: 'routine_suppressed' };
|
|
}
|
|
if (priority !== 'flash' && isWithinQuietHours(profile.quietHours, profile.timezone, now)) {
|
|
return { send: false, reason: 'quiet_hours' };
|
|
}
|
|
return { send: true, reason: 'allowed' };
|
|
}
|
|
|
|
export function isWithinQuietHours(value, timezone, now = new Date()) {
|
|
const match = String(value || '').match(/^([01]\d|2[0-3]):([0-5]\d)-([01]\d|2[0-3]):([0-5]\d)$/);
|
|
if (!match) return false;
|
|
const localMinutes = minutesInTimezone(now, timezone);
|
|
if (localMinutes == null) return false;
|
|
const start = Number(match[1]) * 60 + Number(match[2]);
|
|
const end = Number(match[3]) * 60 + Number(match[4]);
|
|
if (start === end) return true;
|
|
return start < end
|
|
? localMinutes >= start && localMinutes < end
|
|
: localMinutes >= start || localMinutes < end;
|
|
}
|
|
|
|
function minutesInTimezone(date, timezone) {
|
|
try {
|
|
const parts = new Intl.DateTimeFormat('en-GB', {
|
|
timeZone: timezone || 'UTC',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hourCycle: 'h23',
|
|
}).formatToParts(date);
|
|
const hour = Number(parts.find(part => part.type === 'hour')?.value);
|
|
const minute = Number(parts.find(part => part.type === 'minute')?.value);
|
|
return Number.isFinite(hour) && Number.isFinite(minute) ? hour * 60 + minute : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|