homeio
PublikFork dari doctor-io/homeio
save-policies.ts
import {
SYSTEM_SECURITY_BAN_DURATION_MAX,
SYSTEM_SECURITY_BAN_DURATION_MIN,
SYSTEM_SECURITY_MAX_RETRIES_MAX,
SYSTEM_SECURITY_MAX_RETRIES_MIN,
} from "@/lib/shared/contracts/system";
import type {
BackupSettingsDraft,
GeneralPreferencesDraft,
NotificationSettingsDraft,
SecuritySettingsDraft,
SettingsBackend,
} from "@/modules/settings/components/panel/types";
export function normalizeHostnameDraft(hostname: string) {
return hostname.trim().toLowerCase().replace(/\s+/g, "");
}
export function isValidHostname(hostname: string) {
return /^[a-z0-9][a-z0-9.-]{0,62}$/.test(hostname || "homeio");
}
export function parseSecurityDraft(draft: SecuritySettingsDraft) {
return {
maxRetries: Number.parseInt(draft.fail2banMaxRetries, 10),
banDuration: Number.parseInt(draft.fail2banBanDurationSeconds, 10),
};
}
export function areSecurityNumbersValid(draft: SecuritySettingsDraft) {
const { maxRetries, banDuration } = parseSecurityDraft(draft);
return (
Number.isInteger(maxRetries) &&
maxRetries >= SYSTEM_SECURITY_MAX_RETRIES_MIN &&
maxRetries <= SYSTEM_SECURITY_MAX_RETRIES_MAX &&
Number.isInteger(banDuration) &&
banDuration >= SYSTEM_SECURITY_BAN_DURATION_MIN &&
banDuration <= SYSTEM_SECURITY_BAN_DURATION_MAX
);
}
export function getGeneralSaveTitle(args: {
draft: GeneralPreferencesDraft;
data: SettingsBackend["generalPreferences"];
}) {
const normalizedHostname = normalizeHostnameDraft(args.draft.hostname);
if (!isValidHostname(normalizedHostname)) {
return "Hostname is invalid";
}
if (args.data.isSaving) {
return "Saving general preferences";
}
return undefined;
}
export function isBackupTimeValid(time: string) {
return /^\d{2}:\d{2}$/.test(time);
}
export function parseBackupRetentionCount(draft: BackupSettingsDraft) {
return Number.parseInt(draft.retentionCount, 10);
}
export function isBackupRetentionCountValid(retentionCount: number) {
return (
Number.isInteger(retentionCount) &&
retentionCount >= 1 &&
retentionCount <= 365
);
}
export function getBackupSaveTitle(args: {
draft: BackupSettingsDraft;
data: SettingsBackend["backup"]["settings"];
}) {
const retentionCount = parseBackupRetentionCount(args.draft);
if (!isBackupTimeValid(args.draft.time)) {
return "Backup time must use HH:MM";
}
if (!isBackupRetentionCountValid(retentionCount)) {
return "Retention count must be between 1 and 365";
}
if (args.data.isSaving) {
return "Saving backup settings";
}
return undefined;
}
export function parseNotificationThresholds(draft: NotificationSettingsDraft) {
return {
cpu: Number.parseInt(draft.cpuAlertThresholdPercent, 10),
memory: Number.parseInt(draft.memoryAlertThresholdPercent, 10),
disk: Number.parseInt(draft.diskAlertThresholdPercent, 10),
temperature: Number.parseInt(draft.temperatureAlertThresholdCelsius, 10),
};
}
export function areNotificationThresholdsValid(draft: NotificationSettingsDraft) {
const thresholds = parseNotificationThresholds(draft);
return (
Number.isInteger(thresholds.cpu) &&
thresholds.cpu >= 1 &&
thresholds.cpu <= 100 &&
Number.isInteger(thresholds.memory) &&
thresholds.memory >= 1 &&
thresholds.memory <= 100 &&
Number.isInteger(thresholds.disk) &&
thresholds.disk >= 1 &&
thresholds.disk <= 100 &&
Number.isInteger(thresholds.temperature) &&
thresholds.temperature >= 1 &&
thresholds.temperature <= 150
);
}
export function getNotificationsSaveTitle(draft: NotificationSettingsDraft) {
if (!areNotificationThresholdsValid(draft)) {
return "Notification thresholds must use valid numeric ranges";
}
return undefined;
}
export function getSecuritySaveTitle(args: {
draft: SecuritySettingsDraft;
data: SettingsBackend["security"];
}) {
const { maxRetries, banDuration } = parseSecurityDraft(args.draft);
if (args.data.unavailable) {
return args.data.error ?? "Security settings unavailable";
}
if (
!Number.isInteger(maxRetries) ||
maxRetries < SYSTEM_SECURITY_MAX_RETRIES_MIN ||
maxRetries > SYSTEM_SECURITY_MAX_RETRIES_MAX
) {
return `Max retries must be between ${SYSTEM_SECURITY_MAX_RETRIES_MIN} and ${SYSTEM_SECURITY_MAX_RETRIES_MAX}`;
}
if (
!Number.isInteger(banDuration) ||
banDuration < SYSTEM_SECURITY_BAN_DURATION_MIN ||
banDuration > SYSTEM_SECURITY_BAN_DURATION_MAX
) {
return `Ban duration must be between ${SYSTEM_SECURITY_BAN_DURATION_MIN} and ${SYSTEM_SECURITY_BAN_DURATION_MAX} seconds`;
}
if (args.data.isSaving) {
return "Saving security settings";
}
return undefined;
}