Skip to content

Commit f2255d0

Browse files
committed
Merge branch 'main' of github.com:AikidoSec/node-RASP into beta
* 'main' of github.com:AikidoSec/node-RASP: Cleanup Preserve original handler name for Ghost
2 parents 2ebf97f + 27ee22d commit f2255d0

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

library/sources/Express.test.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,18 @@ function getApp(userMiddleware = true) {
111111
next();
112112
});
113113

114-
// A middleware that is used as a route
115-
app.use("/api/*path", (req, res, next) => {
114+
function apiMiddleware(
115+
req: express.Request,
116+
res: express.Response,
117+
next: express.NextFunction
118+
) {
116119
const context = getContext();
117120

118121
res.send(context);
119-
});
122+
}
123+
124+
// A middleware that is used as a route
125+
app.use("/api/*path", apiMiddleware);
120126

121127
app.get("/", (req, res) => {
122128
const context = getContext();
@@ -519,3 +525,32 @@ t.test("it allows white-listed IP address", async () => {
519525
t.same(res.statusCode, 200);
520526
}
521527
});
528+
529+
t.test("it preserves original function name in Layer object", async () => {
530+
const app = getApp();
531+
532+
/**
533+
* Ghost uses the name of the original function to look up the site router (a middleware)
534+
* Before the fix, the name of the middleware was changed to `<anonymous>` by Zen
535+
*
536+
* _getSiteRouter(req) {
537+
* let siteRouter = null;
538+
*
539+
* req.app._router.stack.every((router) => {
540+
* if (router.name === 'SiteRouter') {
541+
* siteRouter = router;
542+
* return false;
543+
* }
544+
*
545+
* return true;
546+
* });
547+
*
548+
* return siteRouter;
549+
* }
550+
*/
551+
t.same(
552+
// @ts-expect-error stack is private
553+
app.router.stack.filter((stack) => stack.name === "apiMiddleware").length,
554+
1
555+
);
556+
});

library/sources/express/wrapRequestHandler.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,43 @@ import { runWithContext } from "../../agent/Context";
33
import { contextFromRequest } from "./contextFromRequest";
44

55
export function wrapRequestHandler(handler: RequestHandler): RequestHandler {
6-
return (req, res, next) => {
6+
const fn: RequestHandler = (req, res, next) => {
77
const context = contextFromRequest(req);
88

99
return runWithContext(context, () => {
1010
return handler(req, res, next);
1111
});
1212
};
13+
14+
if (handler.name) {
15+
preserveFunctionName(fn, handler.name);
16+
}
17+
18+
return fn;
19+
}
20+
21+
/**
22+
* Preserve the original function name
23+
* e.g. Ghost looks up a middleware function by name in the router stack
24+
*
25+
* Object.getOwnPropertyDescriptor(function myFunction() {}, "name")
26+
*
27+
* {
28+
* value: 'myFunction',
29+
* writable: false,
30+
* enumerable: false,
31+
* configurable: true
32+
* }
33+
*/
34+
function preserveFunctionName(wrappedFunction: Function, originalName: string) {
35+
try {
36+
Object.defineProperty(wrappedFunction, "name", {
37+
value: originalName,
38+
writable: false,
39+
enumerable: false,
40+
configurable: true,
41+
});
42+
} catch (e) {
43+
// Ignore
44+
}
1345
}

0 commit comments

Comments
 (0)