fix: validate HTTP dates IPv6 URLs and parser errors
CSS quality / css-quality (push) Has been cancelled

This commit is contained in:
hectorzhao
2026-09-14 15:15:58 +08:00
parent 92b112cc6e
commit a420d61b23
16 changed files with 403 additions and 58 deletions
+55 -1
View File
@@ -1,5 +1,5 @@
import { createHash, createHmac } from 'node:crypto';
import { HttpException } from '@nestjs/common';
import { BadRequestException, HttpException } from '@nestjs/common';
import type { LookupFunction } from 'node:net';
/** Keep the validated address pinned while honoring Node's all-address lookup contract. */
@@ -10,6 +10,60 @@ export function pinnedWebhookLookup(address: string, family: number): LookupFunc
};
}
/** Validate calendar components before Date can normalize an impossible day. */
export function parseOpenApiDate(value: string): Date {
const parts = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?(Z|[+-]\d{2}:\d{2}))?$/.exec(
value,
);
if (parts) {
const year = Number(parts[1]);
const month = Number(parts[2]);
const day = Number(parts[3]);
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const zone = parts[8];
const validZone = !zone || zone === 'Z' || (Number(zone.slice(1, 3)) < 24 && Number(zone.slice(4)) < 60);
const date = new Date(value);
if (
month >= 1 &&
month <= 12 &&
day >= 1 &&
day <= days[month - 1] &&
Number(parts[4] ?? 0) < 24 &&
Number(parts[5] ?? 0) < 60 &&
Number(parts[6] ?? 0) < 60 &&
validZone &&
Number.isFinite(date.getTime())
)
return date;
}
throw new BadRequestException({ code: 'TIME_RANGE_INVALID', message: '时间必须为有效的ISO8601日期或带时区时间' });
}
export type OpenApiProblemResponse = {
setHeader(name: string, value: string): void;
status(code: number): { type(value: string): { send(body: unknown): void } };
};
export function sendOpenApiProblem(
response: OpenApiProblemResponse,
requestId: string,
failure: { status: number; code: string; message: string },
) {
response.setHeader('X-Request-Id', requestId);
response
.status(failure.status)
.type('application/problem+json')
.send({
type: `https://cmpp-platform.local/problems/${failure.code.toLowerCase()}`,
title: failure.status >= 500 ? 'Internal Server Error' : 'Request failed',
status: failure.status,
code: failure.code,
detail: failure.message,
requestId,
});
}
/** v1 compatibility: an absent parsed body hashes as {}, never try alternate hashes. */
export function openApiBodyHash(rawBody: Buffer | undefined, body: unknown) {
return createHash('sha256')