netlify-cli 12.8.0 → 12.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "12.8.0",
3
+ "version": "12.9.1",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "12.8.0",
9
+ "version": "12.9.1",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -82,7 +82,7 @@
82
82
  "netlify-headers-parser": "^7.1.1",
83
83
  "netlify-onegraph-internal": "0.10.1",
84
84
  "netlify-redirect-parser": "^14.1.1",
85
- "netlify-redirector": "^0.3.1",
85
+ "netlify-redirector": "^0.4.0",
86
86
  "node-fetch": "^2.6.0",
87
87
  "node-version-alias": "^1.0.1",
88
88
  "ora": "^5.0.0",
@@ -17610,9 +17610,9 @@
17610
17610
  }
17611
17611
  },
17612
17612
  "node_modules/netlify-redirector": {
17613
- "version": "0.3.1",
17614
- "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.3.1.tgz",
17615
- "integrity": "sha512-+8x07Ukx8vgKkGqTDq1GrkuCRR0DqheZ9fF5PXk6VbIChp9Qi8+psmwBV3hjocoyUvUGH7CIHLUk05aVwLN3wA=="
17613
+ "version": "0.4.0",
17614
+ "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.4.0.tgz",
17615
+ "integrity": "sha512-ssD+V9o2DD9VnilOYC+34i07IrlY8XDsh5mN+qLYA4MxCpdALKXFICcz1KzsHZabuIS5XsF1VP/HzDyx5ubJ2g=="
17616
17616
  },
17617
17617
  "node_modules/netlify/node_modules/node-fetch": {
17618
17618
  "version": "3.3.0",
@@ -37423,9 +37423,9 @@
37423
37423
  }
37424
37424
  },
37425
37425
  "netlify-redirector": {
37426
- "version": "0.3.1",
37427
- "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.3.1.tgz",
37428
- "integrity": "sha512-+8x07Ukx8vgKkGqTDq1GrkuCRR0DqheZ9fF5PXk6VbIChp9Qi8+psmwBV3hjocoyUvUGH7CIHLUk05aVwLN3wA=="
37426
+ "version": "0.4.0",
37427
+ "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.4.0.tgz",
37428
+ "integrity": "sha512-ssD+V9o2DD9VnilOYC+34i07IrlY8XDsh5mN+qLYA4MxCpdALKXFICcz1KzsHZabuIS5XsF1VP/HzDyx5ubJ2g=="
37429
37429
  },
37430
37430
  "next-tick": {
37431
37431
  "version": "1.1.0",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "12.8.0",
4
+ "version": "12.9.1",
5
5
  "author": "Netlify Inc.",
6
6
  "type": "module",
7
7
  "engines": {
@@ -147,7 +147,7 @@
147
147
  "netlify-headers-parser": "^7.1.1",
148
148
  "netlify-onegraph-internal": "0.10.1",
149
149
  "netlify-redirect-parser": "^14.1.1",
150
- "netlify-redirector": "^0.3.1",
150
+ "netlify-redirector": "^0.4.0",
151
151
  "node-fetch": "^2.6.0",
152
152
  "node-version-alias": "^1.0.1",
153
153
  "ora": "^5.0.0",
@@ -168,7 +168,7 @@ export const createHandler = function (options) {
168
168
  return
169
169
  }
170
170
 
171
- handleSynchronousFunction(error, result, request, response)
171
+ handleSynchronousFunction({ error, functionName: func.name, result, request, response })
172
172
  }
173
173
  }
174
174
  }
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  import { Buffer } from 'buffer'
3
3
 
4
- import { NETLIFYDEVERR } from '../../utils/command-helpers.mjs'
4
+ import { chalk, log, NETLIFYDEVERR } from '../../utils/command-helpers.mjs'
5
5
  import renderErrorTemplate from '../render-error-template.mjs'
6
6
 
7
7
  import { detectAwsSdkError } from './utils.mjs'
@@ -16,20 +16,35 @@ const addHeaders = (headers, response) => {
16
16
  })
17
17
  }
18
18
 
19
- export const handleSynchronousFunction = function (err, result, request, response) {
20
- if (err) {
21
- return handleErr(err, request, response)
19
+ export const handleSynchronousFunction = function ({
20
+ error: invocationError,
21
+ functionName,
22
+ request,
23
+ response,
24
+ result,
25
+ }) {
26
+ if (invocationError) {
27
+ return handleErr(invocationError, request, response)
22
28
  }
23
29
 
24
30
  const { error } = validateLambdaResponse(result)
25
31
  if (error) {
26
- console.log(`${NETLIFYDEVERR} ${error}`)
32
+ log(`${NETLIFYDEVERR} ${error}`)
27
33
  return handleErr(error, request, response)
28
34
  }
29
35
 
30
36
  response.statusCode = result.statusCode
31
- addHeaders(result.headers, response)
32
- addHeaders(result.multiValueHeaders, response)
37
+
38
+ try {
39
+ addHeaders(result.headers, response)
40
+ addHeaders(result.multiValueHeaders, response)
41
+ } catch (headersError) {
42
+ formatError(headersError)
43
+
44
+ log(`${NETLIFYDEVERR} Failed to set header in function ${chalk.yellow(functionName)}: ${headersError.message}`)
45
+
46
+ return handleErr(headersError, request, response)
47
+ }
33
48
 
34
49
  if (result.body) {
35
50
  response.write(result.isBase64Encoded ? Buffer.from(result.body, 'base64') : result.body)
@@ -37,6 +52,12 @@ export const handleSynchronousFunction = function (err, result, request, respons
37
52
  response.end()
38
53
  }
39
54
 
55
+ const formatError = (err) => {
56
+ err.errorType = err.code
57
+ err.errorMessage = err.message
58
+ err.stackTrace = err.trace
59
+ }
60
+
40
61
  const formatLambdaLocalError = (err, acceptsHtml) =>
41
62
  acceptsHtml
42
63
  ? JSON.stringify({
@@ -29,10 +29,11 @@ import {
29
29
  import { fileExistsAsync, isFileAsync } from '../lib/fs.mjs'
30
30
  import renderErrorTemplate from '../lib/render-error-template.mjs'
31
31
 
32
- import { NETLIFYDEVLOG, NETLIFYDEVWARN } from './command-helpers.mjs'
32
+ import { NETLIFYDEVLOG, NETLIFYDEVWARN, log, chalk } from './command-helpers.mjs'
33
33
  import createStreamPromise from './create-stream-promise.mjs'
34
34
  import { headersForPath, parseHeaders } from './headers.mjs'
35
35
  import { createRewriter, onChanges } from './rules-proxy.mjs'
36
+ import { signRedirect } from './sign-redirect.mjs'
36
37
 
37
38
  const decompress = util.promisify(zlib.gunzip)
38
39
  const shouldGenerateETag = Symbol('Internal: response should generate ETag')
@@ -143,7 +144,7 @@ const alternativePathsFor = function (url) {
143
144
  return paths
144
145
  }
145
146
 
146
- const serveRedirect = async function ({ match, options, proxy, req, res }) {
147
+ const serveRedirect = async function ({ env, match, options, proxy, req, res, siteInfo }) {
147
148
  if (!match) return proxy.web(req, res, options)
148
149
 
149
150
  options = options || req.proxyOptions || {}
@@ -155,6 +156,24 @@ const serveRedirect = async function ({ match, options, proxy, req, res }) {
155
156
  })
156
157
  }
157
158
 
159
+ if (match.signingSecret) {
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
+ }
175
+ }
176
+
158
177
  if (isFunction(options.functionsPort, req.url)) {
159
178
  return proxy.web(req, res, { target: options.functionsServer })
160
179
  }
@@ -306,7 +325,7 @@ const reqToURL = function (req, pathname) {
306
325
 
307
326
  const MILLISEC_TO_SEC = 1e3
308
327
 
309
- const initializeProxy = async function ({ configPath, distDir, host, port, projectDir }) {
328
+ const initializeProxy = async function ({ configPath, distDir, env, host, port, projectDir, siteInfo }) {
310
329
  const proxy = httpProxy.createProxyServer({
311
330
  selfHandleResponse: true,
312
331
  target: {
@@ -370,13 +389,21 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
370
389
  return proxy.web(req, res, req.proxyOptions)
371
390
  }
372
391
  if (req.proxyOptions && req.proxyOptions.match) {
373
- return serveRedirect({ req, res, proxy: handlers, match: req.proxyOptions.match, options: req.proxyOptions })
392
+ return serveRedirect({
393
+ req,
394
+ res,
395
+ proxy: handlers,
396
+ match: req.proxyOptions.match,
397
+ options: req.proxyOptions,
398
+ siteInfo,
399
+ env,
400
+ })
374
401
  }
375
402
  }
376
403
 
377
404
  if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
378
405
  req.url = proxyRes.headers.location
379
- return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions })
406
+ return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions, siteInfo, env })
380
407
  }
381
408
 
382
409
  const responseData = []
@@ -472,7 +499,11 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
472
499
  return handlers
473
500
  }
474
501
 
475
- const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings }, req, res) => {
502
+ const onRequest = async (
503
+ { addonsUrls, edgeFunctionsProxy, env, functionsServer, proxy, rewriter, settings, siteInfo },
504
+ req,
505
+ res,
506
+ ) => {
476
507
  req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method)
477
508
  ? null
478
509
  : await createStreamPromise(req, BYTES_LIMIT)
@@ -509,7 +540,7 @@ const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, prox
509
540
  // We don't want to generate an ETag for 3xx redirects.
510
541
  req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400
511
542
 
512
- return serveRedirect({ req, res, proxy, match, options })
543
+ return serveRedirect({ req, res, proxy, match, options, siteInfo, env })
513
544
  }
514
545
 
515
546
  // The request will be served by the framework server, which means we want to
@@ -565,11 +596,13 @@ export const startProxy = async function ({
565
596
  state,
566
597
  })
567
598
  const proxy = await initializeProxy({
599
+ env,
568
600
  host: settings.frameworkHost,
569
601
  port: settings.frameworkPort,
570
602
  distDir: settings.dist,
571
603
  projectDir,
572
604
  configPath,
605
+ siteInfo,
573
606
  })
574
607
 
575
608
  const rewriter = await createRewriter({
@@ -588,6 +621,8 @@ export const startProxy = async function ({
588
621
  addonsUrls,
589
622
  functionsServer,
590
623
  edgeFunctionsProxy,
624
+ siteInfo,
625
+ env,
591
626
  })
592
627
  const primaryServer = settings.https
593
628
  ? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)
@@ -36,6 +36,7 @@ const normalizeRedirect = function ({
36
36
  conditions: { country, language, role, ...conditions },
37
37
  from,
38
38
  query,
39
+ signed,
39
40
  ...redirect
40
41
  }) {
41
42
  return {
@@ -48,5 +49,10 @@ const normalizeRedirect = function ({
48
49
  ...(country && { Country: country }),
49
50
  ...(language && { Language: language }),
50
51
  },
52
+ ...(signed && {
53
+ sign: {
54
+ jwt_secret: signed,
55
+ },
56
+ }),
51
57
  }
52
58
  }
@@ -0,0 +1,16 @@
1
+ import jwt from 'jsonwebtoken'
2
+
3
+ // https://docs.netlify.com/routing/redirects/rewrites-proxies/#signed-proxy-redirects
4
+ export const signRedirect = ({ deployContext, secret, siteID, siteURL }) => {
5
+ const claims = {
6
+ deploy_context: deployContext,
7
+ netlify_id: siteID,
8
+ site_url: siteURL,
9
+ }
10
+ const options = {
11
+ expiresIn: '5 minutes',
12
+ issuer: 'netlify',
13
+ }
14
+
15
+ return jwt.sign(claims, secret, options)
16
+ }