Files
sass-mohfarawati/lib/contact-protection.ts
T

133 lines
3.4 KiB
TypeScript

export const CONTACT_PROTECTION_SETTINGS_KEY = "contact_protection_settings";
export const CONTACT_RATE_LIMIT_KEY_PREFIX = "contact_rate_limit";
export type ContactProtectionSettings = {
turnstile: {
enabled: boolean;
siteKey: string;
secretKey: string;
};
rateLimit: {
enabled: boolean;
maxRequests: number;
windowMinutes: number;
};
};
export type ContactProtectionFormValues = {
turnstile: {
enabled: boolean;
siteKey: string;
secretKey: string;
hasSecretKey: boolean;
};
rateLimit: {
enabled: boolean;
maxRequests: number;
windowMinutes: number;
};
};
export type PublicContactProtectionSettings = {
turnstile: {
enabled: boolean;
siteKey: string;
};
rateLimit: {
enabled: boolean;
};
};
export function buildDefaultContactProtectionSettings(): ContactProtectionSettings {
return {
turnstile: {
enabled: false,
siteKey: "",
secretKey: "",
},
rateLimit: {
enabled: true,
maxRequests: 5,
windowMinutes: 10,
},
};
}
function parsePositiveInt(value: unknown, fallback: number) {
const parsed =
typeof value === "number"
? value
: typeof value === "string"
? Number.parseInt(value, 10)
: fallback;
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
}
export function parseContactProtectionValue(
rawValue: string | null | undefined,
): ContactProtectionSettings {
const defaults = buildDefaultContactProtectionSettings();
if (!rawValue) {
return defaults;
}
try {
const parsed = JSON.parse(rawValue) as Record<string, unknown>;
const turnstile = parsed.turnstile && typeof parsed.turnstile === "object"
? (parsed.turnstile as Record<string, unknown>)
: {};
const rateLimit = parsed.rateLimit && typeof parsed.rateLimit === "object"
? (parsed.rateLimit as Record<string, unknown>)
: {};
return {
turnstile: {
enabled: Boolean(turnstile.enabled),
siteKey: typeof turnstile.siteKey === "string" ? turnstile.siteKey.trim() : "",
secretKey: typeof turnstile.secretKey === "string" ? turnstile.secretKey : "",
},
rateLimit: {
enabled: rateLimit.enabled === undefined ? defaults.rateLimit.enabled : Boolean(rateLimit.enabled),
maxRequests: parsePositiveInt(rateLimit.maxRequests, defaults.rateLimit.maxRequests),
windowMinutes: parsePositiveInt(rateLimit.windowMinutes, defaults.rateLimit.windowMinutes),
},
};
} catch {
return defaults;
}
}
export function toContactProtectionFormValues(
settings: ContactProtectionSettings,
): ContactProtectionFormValues {
return {
turnstile: {
enabled: settings.turnstile.enabled,
siteKey: settings.turnstile.siteKey,
secretKey: "",
hasSecretKey: Boolean(settings.turnstile.secretKey),
},
rateLimit: {
enabled: settings.rateLimit.enabled,
maxRequests: settings.rateLimit.maxRequests,
windowMinutes: settings.rateLimit.windowMinutes,
},
};
}
export function toPublicContactProtectionSettings(
settings: ContactProtectionSettings,
): PublicContactProtectionSettings {
return {
turnstile: {
enabled: settings.turnstile.enabled && Boolean(settings.turnstile.siteKey),
siteKey: settings.turnstile.siteKey,
},
rateLimit: {
enabled: settings.rateLimit.enabled,
},
};
}