mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Block Certain Env Keys That Are Used Internally (#6260)
Closes: #6244 This will block the following keys: ``` NODE_.+ __.+ ``` There doesn't seem to be a way to simulate a failed build or else I'd add tests for it.
This commit is contained in:
parent
d2ef34429c
commit
1e5d0908d0
9
errors/env-key-not-allowed.md
Normal file
9
errors/env-key-not-allowed.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# The key "<your key>" under "env" in next.config.js is not allowed.
|
||||||
|
|
||||||
|
#### Why This Error Occurred
|
||||||
|
|
||||||
|
Next.js configures internal variables for replacement itself. These start with `__` or `NODE_`, for this reason they are not allowed as values for `env` in `next.config.js`
|
||||||
|
|
||||||
|
#### Possible Ways to Fix It
|
||||||
|
|
||||||
|
Rename the specified key so that it does not start with `__` or `NODE_`.
|
|
@ -4,6 +4,7 @@ import {CONFIG_FILE} from 'next-server/constants'
|
||||||
const targets = ['server', 'serverless']
|
const targets = ['server', 'serverless']
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
|
env: [],
|
||||||
webpack: null,
|
webpack: null,
|
||||||
webpackDevMiddleware: null,
|
webpackDevMiddleware: null,
|
||||||
poweredByHeader: true,
|
poweredByHeader: true,
|
||||||
|
|
|
@ -249,7 +249,7 @@ export default class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.nextConfig.poweredByHeader) {
|
if (this.nextConfig.poweredByHeader) {
|
||||||
res.setHeader('X-Powered-By', 'Next.js ' + process.env.NEXT_VERSION)
|
res.setHeader('X-Powered-By', 'Next.js ' + process.env.__NEXT_VERSION)
|
||||||
}
|
}
|
||||||
return this.sendHTML(req, res, html)
|
return this.sendHTML(req, res, html)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ try {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update file's data
|
// update file's data
|
||||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
file.data = Buffer.from(result.outputText.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ const args = arg({
|
||||||
// Version is inlined into the file using taskr build pipeline
|
// Version is inlined into the file using taskr build pipeline
|
||||||
if (args['--version']) {
|
if (args['--version']) {
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
console.log(`Next.js v${process.env.NEXT_VERSION}`)
|
console.log(`Next.js v${process.env.__NEXT_VERSION}`)
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,18 +291,20 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
||||||
dev && new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive
|
dev && new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive
|
||||||
!dev && new webpack.HashedModuleIdsPlugin(),
|
!dev && new webpack.HashedModuleIdsPlugin(),
|
||||||
// Removes server/client code by minifier
|
// Removes server/client code by minifier
|
||||||
new webpack.DefinePlugin(Object.assign(
|
new webpack.DefinePlugin({
|
||||||
{},
|
...(Object.keys(config.env).reduce((acc, key) => {
|
||||||
config.env ? Object.keys(config.env)
|
if (/^(?:NODE_.+)|(?:__.+)$/i.test(key)) {
|
||||||
.reduce((acc, key) => ({
|
throw new Error(`The key "${key}" under "env" in next.config.js is not allowed. https://err.sh/zeit/next.js/env-key-not-allowed`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
...acc,
|
...acc,
|
||||||
...{ [`process.env.${key}`]: JSON.stringify(config.env[key]) }
|
[`process.env.${key}`]: JSON.stringify(config.env[key])
|
||||||
}), {}) : {},
|
}
|
||||||
{
|
}, {})),
|
||||||
'process.crossOrigin': JSON.stringify(config.crossOrigin),
|
'process.crossOrigin': JSON.stringify(config.crossOrigin),
|
||||||
'process.browser': JSON.stringify(!isServer)
|
'process.browser': JSON.stringify(!isServer)
|
||||||
}
|
}),
|
||||||
)),
|
|
||||||
// This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
|
// This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
|
||||||
!isServer && dev && new webpack.DefinePlugin({
|
!isServer && dev && new webpack.DefinePlugin({
|
||||||
'process.env.__NEXT_DIST_DIR': JSON.stringify(distDir)
|
'process.env.__NEXT_DIST_DIR': JSON.stringify(distDir)
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default async ({ assetPrefix }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
ws = new WebSocket(`${wsProtocol}://${hostname}:${process.env.NEXT_WS_PORT}${process.env.NEXT_WS_PROXY_PATH}`)
|
ws = new WebSocket(`${wsProtocol}://${hostname}:${process.env.__NEXT_WS_PORT}${process.env.__NEXT_WS_PROXY_PATH}`)
|
||||||
ws.onopen = () => resolve()
|
ws.onopen = () => resolve()
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
|
|
@ -167,8 +167,8 @@ export default class HotReloader {
|
||||||
addWsConfig (configs) {
|
addWsConfig (configs) {
|
||||||
const { websocketProxyPath, websocketProxyPort } = this.config.onDemandEntries
|
const { websocketProxyPath, websocketProxyPort } = this.config.onDemandEntries
|
||||||
const opts = {
|
const opts = {
|
||||||
'process.env.NEXT_WS_PORT': websocketProxyPort || this.wsPort,
|
'process.env.__NEXT_WS_PORT': websocketProxyPort || this.wsPort,
|
||||||
'process.env.NEXT_WS_PROXY_PATH': JSON.stringify(websocketProxyPath)
|
'process.env.__NEXT_WS_PROXY_PATH': JSON.stringify(websocketProxyPath)
|
||||||
}
|
}
|
||||||
configs[0].plugins.push(new webpack.DefinePlugin(opts))
|
configs[0].plugins.push(new webpack.DefinePlugin(opts))
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ try {
|
||||||
if (file.base === 'next-dev.js') result.outputText = result.outputText.replace('// REPLACE_NOOP_IMPORT', `import('./noop');`)
|
if (file.base === 'next-dev.js') result.outputText = result.outputText.replace('// REPLACE_NOOP_IMPORT', `import('./noop');`)
|
||||||
|
|
||||||
// update file's data
|
// update file's data
|
||||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
file.data = Buffer.from(result.outputText.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -2,11 +2,19 @@ const withCSS = require('@zeit/next-css')
|
||||||
const withSass = require('@zeit/next-sass')
|
const withSass = require('@zeit/next-sass')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
module.exports = withCSS(withSass({
|
module.exports = withCSS(withSass({
|
||||||
|
env: {
|
||||||
|
...(process.env.ENABLE_ENV_FAIL_UNDERSCORE ? {
|
||||||
|
'__NEXT_MY_VAR': 'test'
|
||||||
|
} : {}),
|
||||||
|
...(process.env.ENABLE_ENV_FAIL_NODE ? {
|
||||||
|
'NODE_ENV': 'abc'
|
||||||
|
} : {})
|
||||||
|
},
|
||||||
onDemandEntries: {
|
onDemandEntries: {
|
||||||
// Make sure entries are not getting disposed.
|
// Make sure entries are not getting disposed.
|
||||||
maxInactiveAge: 1000 * 60 * 60
|
maxInactiveAge: 1000 * 60 * 60
|
||||||
},
|
},
|
||||||
webpack (config, {buildId}) {
|
webpack (config) {
|
||||||
// When next-css is `npm link`ed we have to solve loaders from the project root
|
// When next-css is `npm link`ed we have to solve loaders from the project root
|
||||||
const nextLocation = path.join(require.resolve('next/package.json'), '../')
|
const nextLocation = path.join(require.resolve('next/package.json'), '../')
|
||||||
const nextCssNodeModulesLocation = path.join(
|
const nextCssNodeModulesLocation = path.join(
|
||||||
|
|
|
@ -5,18 +5,20 @@ import {
|
||||||
nextServer,
|
nextServer,
|
||||||
nextBuild,
|
nextBuild,
|
||||||
startApp,
|
startApp,
|
||||||
stopApp
|
stopApp,
|
||||||
|
runNextCommand
|
||||||
} from 'next-test-utils'
|
} from 'next-test-utils'
|
||||||
import webdriver from 'next-webdriver'
|
import webdriver from 'next-webdriver'
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||||
|
|
||||||
|
const appDir = join(__dirname, '../')
|
||||||
|
|
||||||
let appPort
|
let appPort
|
||||||
let server
|
let server
|
||||||
|
|
||||||
describe('Production Config Usage', () => {
|
describe('Production Config Usage', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const appDir = join(__dirname, '../')
|
|
||||||
await nextBuild(appDir)
|
await nextBuild(appDir)
|
||||||
const app = nextServer({
|
const app = nextServer({
|
||||||
dir: join(__dirname, '../'),
|
dir: join(__dirname, '../'),
|
||||||
|
@ -37,6 +39,34 @@ describe('Production Config Usage', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('env', () => {
|
||||||
|
it('should fail with __ in env key', async () => {
|
||||||
|
const result = await runNextCommand(['build', appDir], {spawnOptions: {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
ENABLE_ENV_FAIL_UNDERSCORE: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stdout: true,
|
||||||
|
stderr: true})
|
||||||
|
|
||||||
|
expect(result.stderr).toMatch(/The key "__NEXT_MY_VAR" under/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail with NODE_ in env key', async () => {
|
||||||
|
const result = await runNextCommand(['build', appDir], {spawnOptions: {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
ENABLE_ENV_FAIL_NODE: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stdout: true,
|
||||||
|
stderr: true})
|
||||||
|
|
||||||
|
expect(result.stderr).toMatch(/The key "NODE_ENV" under/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('with generateBuildId', () => {
|
describe('with generateBuildId', () => {
|
||||||
it('should add the custom buildid', async () => {
|
it('should add the custom buildid', async () => {
|
||||||
const browser = await webdriver(appPort, '/')
|
const browser = await webdriver(appPort, '/')
|
||||||
|
|
|
@ -69,7 +69,14 @@ export function runNextCommand (argv, options = {}) {
|
||||||
const cwd = path.dirname(require.resolve('next/package'))
|
const cwd = path.dirname(require.resolve('next/package'))
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(`Running command "next ${argv.join(' ')}"`)
|
console.log(`Running command "next ${argv.join(' ')}"`)
|
||||||
const instance = spawn('node', ['dist/bin/next', ...argv], { cwd, stdio: options.stdout ? ['ignore', 'pipe', 'ignore'] : 'inherit' })
|
const instance = spawn('node', ['dist/bin/next', ...argv], { ...options.spawnOptions, cwd, stdio: ['ignore', 'pipe', 'pipe'] })
|
||||||
|
|
||||||
|
let stderrOutput = ''
|
||||||
|
if (options.stderr) {
|
||||||
|
instance.stderr.on('data', function (chunk) {
|
||||||
|
stderrOutput += chunk
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let stdoutOutput = ''
|
let stdoutOutput = ''
|
||||||
if (options.stdout) {
|
if (options.stdout) {
|
||||||
|
@ -80,11 +87,14 @@ export function runNextCommand (argv, options = {}) {
|
||||||
|
|
||||||
instance.on('close', () => {
|
instance.on('close', () => {
|
||||||
resolve({
|
resolve({
|
||||||
stdout: stdoutOutput
|
stdout: stdoutOutput,
|
||||||
|
stderr: stderrOutput
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
instance.on('error', (err) => {
|
instance.on('error', (err) => {
|
||||||
|
err.stdout = stdoutOutput
|
||||||
|
err.stderr = stderrOutput
|
||||||
reject(err)
|
reject(err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue