Express CSP Nonce med TypeScript
Jag har ett Express-projekt i TypeScript och jag försökte lägga till en CSP Nonce med Helmet.
app.use(helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
}
}));
Men när jag startar programmet får jag följande fel:
./index.ts:820
return new TSError(diagnosticText, diagnosticCodes);
^
TSError: ⨯ Unable to compile TypeScript:
src/app.ts:17:59 - error TS2339: Property 'locals' does not exist on type 'ServerResponse'.
17 scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
~~~~~~
at createTSError (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:820:12)
at reportTSError (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:824:19)
at getOutput (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:1014:36)
at Object.compile (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:1322:43)
at Module.m._compile (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:1454:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Object.require.extensions.<computed> [as .ts] (/home/frdiolin/WebstormProjects/Calender2.0/node_modules/ts-node/src/index.ts:1458:12)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
diagnosticCodes: [ 2339 ]
}
När jag försökte starta samma kod i JS fungerar det bra. Vad går fel?
Svar #1
Kort sagt: kasta res till en Express Response. Se kodexemplet nedan.
Detta är ett fel enbart i TypeScript. res.locals är en Express-funktion, men Helmet är utformat för att fungera utan Express, så res.locals ingår inte i Helmets typer. Med andra ord, res känner inte till en .locals-egenskap eftersom Helmet inte förutsätter att den finns.
Du kan fixa detta genom att tala om för TypeScript att detta är ett Express-svarobjekt. Använd res as Response.
Här är ett exempel:
import express, { Response } from "express";
// ...
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
scriptSrc: [
"'self'",
// The `res as Response` is what you need.
(_req, res) => `'nonce-${(res as Response).locals.cspNonce}'`,
],
},
})
);
