48 lines
2.3 KiB
TypeScript
48 lines
2.3 KiB
TypeScript
import type BetterSqlite3 from "better-sqlite3";
|
|
|
|
const auditRefPattern = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,159}$/;
|
|
const safeStringPattern = /^[A-Za-z0-9_.:@-]{1,160}$/;
|
|
const forbiddenKeys = new Set([
|
|
"absolute_path", "api_key", "body", "code_hmac", "content", "credential", "email", "image",
|
|
"image_content", "password", "path", "prompt", "secret", "session_token", "verification_code", "whitelist",
|
|
]);
|
|
const forbiddenKeyFragments = ["content", "credential", "email", "image", "password", "path", "prompt", "secret", "token"];
|
|
|
|
function safeSummaryValue(value: unknown, depth: number): boolean {
|
|
if (depth > 3) return false;
|
|
if (value === null || typeof value === "boolean") return true;
|
|
if (typeof value === "number") return Number.isSafeInteger(value);
|
|
if (typeof value === "string") return safeStringPattern.test(value) && !value.includes("@");
|
|
if (Array.isArray(value)) return value.length <= 20 && value.every((entry) => safeSummaryValue(entry, depth + 1));
|
|
if (!value || typeof value !== "object") return false;
|
|
const entries = Object.entries(value);
|
|
return entries.length <= 32 && entries.every(([key, entry]) => (
|
|
auditRefPattern.test(key)
|
|
&& !forbiddenKeys.has(key.toLowerCase())
|
|
&& !forbiddenKeyFragments.some((fragment) => key.toLowerCase().includes(fragment))
|
|
&& safeSummaryValue(entry, depth + 1)
|
|
));
|
|
}
|
|
|
|
export function configureWorkerDatabase(database: BetterSqlite3.Database) {
|
|
database.pragma("journal_mode = WAL");
|
|
database.pragma("foreign_keys = ON");
|
|
database.pragma("synchronous = FULL");
|
|
database.pragma("busy_timeout = 5000");
|
|
database.function("dada_audit_ref_is_safe", { deterministic: true }, (value: unknown) => (
|
|
typeof value === "string" && auditRefPattern.test(value) ? 1 : 0
|
|
));
|
|
database.function("dada_audit_summary_is_safe", { deterministic: true }, (value: unknown) => {
|
|
if (typeof value !== "string" || Buffer.byteLength(value, "utf8") > 2_048) return 0;
|
|
try {
|
|
return safeSummaryValue(JSON.parse(value), 0) ? 1 : 0;
|
|
} catch {
|
|
return 0;
|
|
}
|
|
});
|
|
database.function("dada_allow_retention_purge", { deterministic: false }, () => 0);
|
|
database.function("dada_retention_purge_now", { deterministic: false }, () => 0);
|
|
database.function("dada_allow_privacy_purge", { deterministic: false }, () => 0);
|
|
database.function("dada_privacy_purge_subject", { deterministic: false }, () => "");
|
|
}
|