Skip to content

Commit 99305de

Browse files
fix: sign redirect with secret from env var (#5415)
1 parent 027efcf commit 99305de

File tree

2 files changed

+30
-15
lines changed

2 files changed

+30
-15
lines changed

src/utils/proxy.mjs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
import { fileExistsAsync, isFileAsync } from '../lib/fs.mjs'
3030
import renderErrorTemplate from '../lib/render-error-template.mjs'
3131

32-
import { NETLIFYDEVLOG, NETLIFYDEVWARN } from './command-helpers.mjs'
32+
import { NETLIFYDEVLOG, NETLIFYDEVWARN, log, chalk } from './command-helpers.mjs'
3333
import createStreamPromise from './create-stream-promise.mjs'
3434
import { headersForPath, parseHeaders } from './headers.mjs'
3535
import { createRewriter, onChanges } from './rules-proxy.mjs'
@@ -144,7 +144,7 @@ const alternativePathsFor = function (url) {
144144
return paths
145145
}
146146

147-
const serveRedirect = async function ({ match, options, proxy, req, res, siteInfo }) {
147+
const serveRedirect = async function ({ env, match, options, proxy, req, res, siteInfo }) {
148148
if (!match) return proxy.web(req, res, options)
149149

150150
options = options || req.proxyOptions || {}
@@ -157,12 +157,21 @@ const serveRedirect = async function ({ match, options, proxy, req, res, siteInf
157157
}
158158

159159
if (match.signingSecret) {
160-
req.headers['x-nf-sign'] = signRedirect({
161-
deployContext: 'dev',
162-
secret: match.signingSecret,
163-
siteID: siteInfo.id,
164-
siteURL: siteInfo.url,
165-
})
160+
const signingSecretVar = env[match.signingSecret]
161+
162+
if (signingSecretVar) {
163+
req.headers['x-nf-sign'] = signRedirect({
164+
deployContext: 'dev',
165+
secret: signingSecretVar.value,
166+
siteID: siteInfo.id,
167+
siteURL: siteInfo.url,
168+
})
169+
} else {
170+
log(
171+
NETLIFYDEVWARN,
172+
`Could not sign redirect because environment variable ${chalk.yellow(match.signingSecret)} is not set`,
173+
)
174+
}
166175
}
167176

168177
if (isFunction(options.functionsPort, req.url)) {
@@ -316,7 +325,7 @@ const reqToURL = function (req, pathname) {
316325

317326
const MILLISEC_TO_SEC = 1e3
318327

319-
const initializeProxy = async function ({ configPath, distDir, host, port, projectDir, siteInfo }) {
328+
const initializeProxy = async function ({ configPath, distDir, env, host, port, projectDir, siteInfo }) {
320329
const proxy = httpProxy.createProxyServer({
321330
selfHandleResponse: true,
322331
target: {
@@ -387,13 +396,14 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
387396
match: req.proxyOptions.match,
388397
options: req.proxyOptions,
389398
siteInfo,
399+
env,
390400
})
391401
}
392402
}
393403

394404
if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
395405
req.url = proxyRes.headers.location
396-
return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions, siteInfo })
406+
return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions, siteInfo, env })
397407
}
398408

399409
const responseData = []
@@ -490,7 +500,7 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
490500
}
491501

492502
const onRequest = async (
493-
{ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings, siteInfo },
503+
{ addonsUrls, edgeFunctionsProxy, env, functionsServer, proxy, rewriter, settings, siteInfo },
494504
req,
495505
res,
496506
) => {
@@ -530,7 +540,7 @@ const onRequest = async (
530540
// We don't want to generate an ETag for 3xx redirects.
531541
req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400
532542

533-
return serveRedirect({ req, res, proxy, match, options, siteInfo })
543+
return serveRedirect({ req, res, proxy, match, options, siteInfo, env })
534544
}
535545

536546
// The request will be served by the framework server, which means we want to
@@ -586,6 +596,7 @@ export const startProxy = async function ({
586596
state,
587597
})
588598
const proxy = await initializeProxy({
599+
env,
589600
host: settings.frameworkHost,
590601
port: settings.frameworkPort,
591602
distDir: settings.dist,
@@ -611,6 +622,7 @@ export const startProxy = async function ({
611622
functionsServer,
612623
edgeFunctionsProxy,
613624
siteInfo,
625+
env,
614626
})
615627
const primaryServer = settings.https
616628
? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)

tests/integration/0.command.dev.test.cjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ test('should rewrite requests to an external server', async (t) => {
203203

204204
test('should sign external redirects with the `x-nf-sign` header when a `signed` value is set', async (t) => {
205205
await withSiteBuilder('site-redirects-file-to-external', async (builder) => {
206-
const mockSigningKey = 'iamverysecret'
206+
const mockSigningSecret = 'iamverysecret'
207207
const externalServer = startExternalServer()
208208
const { port } = externalServer.address()
209209
const siteInfo = {
@@ -224,7 +224,10 @@ test('should sign external redirects with the `x-nf-sign` header when a `signed`
224224
await builder
225225
.withNetlifyToml({
226226
config: {
227-
redirects: [{ from: '/sign/*', to: `http://localhost:${port}/:splat`, signed: mockSigningKey, status: 200 }],
227+
build: { environment: { VAR_WITH_SIGNING_SECRET: mockSigningSecret } },
228+
redirects: [
229+
{ from: '/sign/*', to: `http://localhost:${port}/:splat`, signed: 'VAR_WITH_SIGNING_SECRET', status: 200 },
230+
],
228231
},
229232
})
230233
.buildAsync()
@@ -254,7 +257,7 @@ test('should sign external redirects with the `x-nf-sign` header when a `signed`
254257

255258
;[getResponse, postResponse].forEach((response) => {
256259
const signature = response.headers['x-nf-sign']
257-
const payload = jwt.verify(signature, mockSigningKey)
260+
const payload = jwt.verify(signature, mockSigningSecret)
258261

259262
t.is(payload.deploy_context, 'dev')
260263
t.is(payload.netlify_id, siteInfo.id)

0 commit comments

Comments
 (0)