49 lines
1.2 KiB
TypeScript
49 lines
1.2 KiB
TypeScript
import {
|
|
Injectable,
|
|
NestInterceptor,
|
|
ExecutionContext,
|
|
CallHandler,
|
|
} from "@nestjs/common";
|
|
import { Observable } from "rxjs";
|
|
|
|
/**
|
|
* Strips HTML/script tags from all string values in the request body.
|
|
* Applied globally to prevent stored XSS via API inputs.
|
|
*/
|
|
@Injectable()
|
|
export class SanitizeInterceptor implements NestInterceptor {
|
|
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
|
const request = context.switchToHttp().getRequest();
|
|
|
|
if (request.body && typeof request.body === "object") {
|
|
request.body = this.sanitize(request.body);
|
|
}
|
|
|
|
return next.handle();
|
|
}
|
|
|
|
private sanitize(value: unknown): unknown {
|
|
if (typeof value === "string") {
|
|
return this.stripTags(value);
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
return value.map((item) => this.sanitize(item));
|
|
}
|
|
|
|
if (value !== null && typeof value === "object") {
|
|
const sanitized: Record<string, unknown> = {};
|
|
for (const [key, val] of Object.entries(value)) {
|
|
sanitized[key] = this.sanitize(val);
|
|
}
|
|
return sanitized;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
private stripTags(input: string): string {
|
|
return input.replace(/<[^>]*>/g, "");
|
|
}
|
|
}
|