mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
Folder routes only looked at the requested name, so `shot.png -> ../secret.bin` and `notes.txt -> ../history` were served (registration answers 400 for both), and a FIFO or device behind a supported name parked a worker on an open that never returned. After resolving, the target's extension must be supported and it must be a regular file (locally fs.stat, remotely the probe kind). A 101..255-character file name answered 404 "Route not found": Fastify caps a path parameter at 100 characters. The server now sets routerOptions.maxParamLength (MAX_ROUTE_PARAM_LENGTH, shared with the route test harness) and a wiring guard pins it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
/**
|
|
* Shared utilities for route testing.
|
|
*
|
|
* Creates minimal Fastify instances with just the route module under test
|
|
* and a mock context. Uses app.inject() for HTTP testing without real ports.
|
|
*/
|
|
import Fastify, { type FastifyInstance } from 'fastify';
|
|
import fastifyCookie from '@fastify/cookie';
|
|
import { createMockRouteContext, type MockRouteContext } from '../mocks/index.js';
|
|
import { installRouteErrorHandler } from '../../src/web/route-error-handler.js';
|
|
import { MAX_ROUTE_PARAM_LENGTH } from '../../src/web/route-helpers.js';
|
|
|
|
export interface RouteTestHarness {
|
|
app: FastifyInstance;
|
|
ctx: MockRouteContext;
|
|
}
|
|
|
|
/**
|
|
* Creates a Fastify instance with a route module registered against a mock context.
|
|
*
|
|
* @param registerFn - The route registration function (e.g., registerSessionRoutes).
|
|
* Uses `any` for ctx parameter because route functions expect typed port intersections
|
|
* that MockRouteContext satisfies structurally but not nominally.
|
|
* @param ctxOptions - Optional overrides for the mock context. `authUser` stands
|
|
* in for what the auth middleware would attach in multi-user mode; without it
|
|
* `getAuthUser()` falls back to a synthetic admin, which passes every
|
|
* ownership check and would make a scoping test pass vacuously.
|
|
*/
|
|
export async function createRouteTestHarness(
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
registerFn: (app: FastifyInstance, ctx: any) => void,
|
|
ctxOptions?: { sessionId?: string; authUser?: { username: string; role: 'admin' | 'user' } }
|
|
): Promise<RouteTestHarness> {
|
|
const app = Fastify({ logger: false, routerOptions: { maxParamLength: MAX_ROUTE_PARAM_LENGTH } });
|
|
|
|
// Register cookie plugin — some routes access req.cookies
|
|
await app.register(fastifyCookie);
|
|
|
|
if (ctxOptions?.authUser) {
|
|
const authUser = ctxOptions.authUser;
|
|
app.addHook('onRequest', async (req) => {
|
|
(req as unknown as { authUser: typeof authUser }).authUser = authUser;
|
|
});
|
|
}
|
|
|
|
const ctx = createMockRouteContext(ctxOptions);
|
|
|
|
registerFn(app, ctx);
|
|
// Mirror production: structured errors thrown by route helpers (findSessionOrFail,
|
|
// parseBody) are rendered to {success:false} bodies at the right status.
|
|
installRouteErrorHandler(app);
|
|
await app.ready();
|
|
|
|
return { app, ctx };
|
|
}
|