UNPKG

very-express

Version:

based on json schema and openapi, generate Express RestApi server with mongoDb

66 lines (53 loc) 2.32 kB
// {{headerComment}} import { Request, Response, NextFunction } from "express"; import { VexResErr } from "../_types/vex"; import joinWhitelistRegistry from "./JoinWhitelistRegistry.gen"; /** * Validates join paths against the centralized whitelist registry. * * The registry maps documentName → { relationName → relatedDocumentName } * and is generated at build time by VeryExpress from schema FK metadata. * * Nested paths like "user.userContact" on Package are validated hop-by-hop: * 1. check "user" in Package's map → next doc = "User" * 2. check "userContact" in User's map → ok */ class JoinWhitelistMiddleware { middleware(documentName: string) { return (req: Request, res: Response, next: NextFunction): void => { const join = this.extractJoin(req); if (!join || join.length === 0) { return next(); } for (const joinPath of join) { this.validateJoinPath(joinPath, documentName); } next(); }; } private validateJoinPath(joinPath: string, rootDocumentName: string): void { const segments = joinPath.split("."); let currentDoc = rootDocumentName; const visited = new Set<string>(); for (const segment of segments) { if (visited.has(currentDoc)) { throw new VexResErr(403, undefined, `Circular join detected: "${joinPath}" revisits "${currentDoc}"`); } visited.add(currentDoc); const relations = joinWhitelistRegistry[currentDoc]; if (!relations || !(segment in relations)) { throw new VexResErr(403, undefined, `Join "${segment}" is not allowed on "${currentDoc}"`); } currentDoc = relations[segment]; } } private extractJoin(req: Request): string[] | undefined { // getList sends join inside POST body; get sends it as query param const bodyJoin = (req.body as { join?: string[] })?.join; const queryJoin = req.query?.join; if (bodyJoin) return bodyJoin; if (!queryJoin) return undefined; return Array.isArray(queryJoin) ? (queryJoin as string[]) : [queryJoin as string]; } } export default new JoinWhitelistMiddleware();