syncova-policies/lib/policy-input.ts
Weapie 265ca8ac38
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 5m15s
Improve accessibility and access controls; verify production and database recovery
2026-09-14 11:44:41 +02:00

27 lines
1.5 KiB
TypeScript

import { DEFAULTED_FIELDS } from './policy-defaults'
import type { DefaultedField } from './policy-defaults'
const OPTIONAL_FIELDS = ['processingPurposes', 'legalBasis', 'legitimateInterests',
'storageDuration', 'dataSource', 'dataCategories'] as const
const REQUIRED_FIELDS = ['title', 'processingDescription', 'recipients'] as const
export type PolicyInput = Record<typeof REQUIRED_FIELDS[number], string> &
Partial<Record<DefaultedField | typeof OPTIONAL_FIELDS[number], string | null>> & { isPublic?: boolean }
/** Validate untrusted request values before callers use string operations. */
export function parsePolicyInput(value: unknown): PolicyInput | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) return null
const input = value as Record<string, unknown>
if (input.isPublic !== undefined && typeof input.isPublic !== 'boolean') return null
const fields = [...REQUIRED_FIELDS, ...OPTIONAL_FIELDS, ...DEFAULTED_FIELDS]
for (const field of fields) {
const text = input[field]
if (text !== undefined && text !== null && (typeof text !== 'string' || text.length > 100000)) return null
}
const text = (key: string) => typeof input[key] === 'string' ? input[key].trim() : ''
return {
...Object.fromEntries([...OPTIONAL_FIELDS, ...DEFAULTED_FIELDS].map(key => [key, text(key) || null])),
title: text('title'), processingDescription: text('processingDescription'), recipients: text('recipients'),
...(input.isPublic === undefined ? {} : { isPublic: input.isPublic as boolean }),
}
}