qwen_2.5_model / src /modules /webhook /dto /is-header-map.validator.ts
Muhammad Noman
Deploy OpenWA to Hugging Face Spaces
46252cd
Raw
History Blame Contribute Delete
1.87 kB
import { registerDecorator, ValidationOptions } from 'class-validator';
const HEADER_NAME = /^[A-Za-z0-9-]+$/;
const MAX_HEADERS = 50;
const MAX_VALUE_LENGTH = 1024;
/** Reject C0 control chars + DEL — notably CR/LF, the header-injection vector. */
function hasControlChar(s: string): boolean {
for (let i = 0; i < s.length; i++) {
const c = s.charCodeAt(i);
if (c < 0x20 || c === 0x7f) return true;
}
return false;
}
/**
* Validate operator-supplied webhook custom headers as a flat map of valid header names to string
* values: rejects non-object shapes, invalid header names, non-string or control-character values
* (CR/LF header injection), and over-large maps (≤50 entries, value ≤1024 chars). Reserved-name
* stripping still happens at delivery time (sanitizeCustomHeaders); this is the input-side guard.
*/
export function IsHeaderMap(options?: ValidationOptions) {
return function (target: object, propertyName: string): void {
registerDecorator({
name: 'isHeaderMap',
target: target.constructor,
propertyName,
options,
validator: {
validate(value: unknown): boolean {
if (value === undefined || value === null) return true; // @IsOptional handles absence
if (typeof value !== 'object' || Array.isArray(value)) return false;
const entries = Object.entries(value as Record<string, unknown>);
if (entries.length > MAX_HEADERS) return false;
return entries.every(
([k, v]) =>
HEADER_NAME.test(k) && typeof v === 'string' && v.length <= MAX_VALUE_LENGTH && !hasControlChar(v),
);
},
defaultMessage(): string {
return 'headers must be a flat map of valid header names to string values (no control characters, max 50 entries, value max 1024 chars)';
},
},
});
};
}