30118a2401
- Kettenbau mit Aussteller- und Signaturprüfung (checkIssued plus verify), Wurzel nur auf Wunsch - build-Route für Fullchain und Nur Kette (PEM), eigene JSON-Grenze 512 KiB mit 413 und Code tooLarge - Reiter Zusammenführen mit Kettenansicht, Hinweis bei fehlendem Zwischenzertifikat Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { PassThrough } from 'node:stream';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
CERT_BUILD_JSON_LIMIT,
|
|
CERT_BUILD_ROUTE,
|
|
certBuildBodyErrors,
|
|
certBuildJsonBody,
|
|
} from './cert-json-body';
|
|
import {
|
|
CERT_BASENAME_MAX,
|
|
CERT_PASSWORD_MAX,
|
|
CERT_PEM_MAX,
|
|
CERT_POOL_MAX,
|
|
} from './dto/cert-build.dto';
|
|
|
|
/** PEM-aehnlicher Text: eine Zeile je 64 Zeichen, genau `chars` Zeichen lang. */
|
|
function pemLike(chars: number): string {
|
|
let out = '';
|
|
while (out.length < chars) out += `${'A'.repeat(64)}\n`;
|
|
return out.slice(0, chars);
|
|
}
|
|
|
|
interface FakeReq extends PassThrough {
|
|
headers: Record<string, string>;
|
|
method: string;
|
|
body?: unknown;
|
|
}
|
|
|
|
function fakeRequest(raw: string): FakeReq {
|
|
const req = new PassThrough() as FakeReq;
|
|
req.headers = {
|
|
'content-type': 'application/json',
|
|
'content-length': String(Buffer.byteLength(raw)),
|
|
};
|
|
req.method = 'POST';
|
|
req.end(raw);
|
|
return req;
|
|
}
|
|
|
|
function runParser(raw: string): Promise<{ req: FakeReq; error: unknown }> {
|
|
const req = fakeRequest(raw);
|
|
return new Promise((resolve) => {
|
|
certBuildJsonBody(req as never, {} as never, (error?: unknown) => resolve({ req, error }));
|
|
});
|
|
}
|
|
|
|
function fakeResponse() {
|
|
const res = {
|
|
statusCode: 0,
|
|
payload: undefined as unknown,
|
|
status(code: number) {
|
|
res.statusCode = code;
|
|
return res;
|
|
},
|
|
json(body: unknown) {
|
|
res.payload = body;
|
|
return res;
|
|
},
|
|
};
|
|
return res;
|
|
}
|
|
|
|
describe('cert-json-body (D-26)', () => {
|
|
it('traegt den Namen certBuildJsonBody, nie jsonParser oder urlencodedParser', () => {
|
|
expect(certBuildJsonBody.name).toBe('certBuildJsonBody');
|
|
expect(CERT_BUILD_ROUTE).toBe('/modules/cert-manager/build');
|
|
expect(CERT_BUILD_JSON_LIMIT).toBe(512 * 1024);
|
|
});
|
|
|
|
it('die groesste Anfrage innerhalb der DTO-Grenzen bleibt unter dem Grenzwert und wird gelesen', async () => {
|
|
const body = {
|
|
content: 'fullchain',
|
|
certPem: pemLike(CERT_PEM_MAX),
|
|
poolPems: Array.from({ length: CERT_POOL_MAX }, () => pemLike(CERT_PEM_MAX)),
|
|
keyPem: pemLike(CERT_PEM_MAX),
|
|
csrPem: pemLike(CERT_PEM_MAX),
|
|
password: 'p'.repeat(CERT_PASSWORD_MAX),
|
|
baseName: 'b'.repeat(CERT_BASENAME_MAX),
|
|
};
|
|
const raw = JSON.stringify(body);
|
|
expect(Buffer.byteLength(raw)).toBeLessThan(CERT_BUILD_JSON_LIMIT);
|
|
const { req, error } = await runParser(raw);
|
|
expect(error).toBeUndefined();
|
|
expect((req.body as typeof body).poolPems).toHaveLength(CERT_POOL_MAX);
|
|
});
|
|
|
|
it('eine Anfrage ueber 512 KiB wird mit 413 und Code tooLarge beantwortet', async () => {
|
|
const { error } = await runParser(JSON.stringify({ content: 'x'.repeat(600 * 1024) }));
|
|
const res = fakeResponse();
|
|
const next = vi.fn();
|
|
certBuildBodyErrors(error, {} as never, res as never, next);
|
|
expect(res.statusCode).toBe(413);
|
|
expect(res.payload).toMatchObject({ code: 'tooLarge' });
|
|
expect(typeof (res.payload as { message: string }).message).toBe('string');
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('fehlerhaftes JSON ergibt 400 mit Code invalidInput', async () => {
|
|
const { error } = await runParser('{"content": ');
|
|
const res = fakeResponse();
|
|
const next = vi.fn();
|
|
certBuildBodyErrors(error, {} as never, res as never, next);
|
|
expect(res.statusCode).toBe(400);
|
|
expect(res.payload).toMatchObject({ code: 'invalidInput' });
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('jeden anderen Fehler reicht die Funktion unveraendert weiter', () => {
|
|
const other = new Error('boom');
|
|
const res = fakeResponse();
|
|
const next = vi.fn();
|
|
certBuildBodyErrors(other, {} as never, res as never, next);
|
|
expect(next).toHaveBeenCalledWith(other);
|
|
expect(res.statusCode).toBe(0);
|
|
});
|
|
});
|