fix: prevent removing project by mistake due to build or generate paths (#3869)

This commit is contained in:
Pim 2018-09-14 09:06:44 +02:00 committed by Pooya Parsa
parent 40ad691f60
commit 226b90d4ae
5 changed files with 116 additions and 6 deletions

View File

@ -15,7 +15,7 @@ export default class Generator {
// Set variables
this.staticRoutes = path.resolve(this.options.srcDir, this.options.dir.static)
this.srcBuiltPath = path.resolve(this.options.buildDir, 'dist', 'client')
this.distPath = path.resolve(this.options.rootDir, this.options.generate.dir)
this.distPath = this.options.generate.dir
this.distNuxtPath = path.join(
this.distPath,
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath

View File

@ -3,11 +3,14 @@ import fs from 'fs'
import _ from 'lodash'
import consola from 'consola'
import { isPureObject, isUrl } from '../common/utils'
import { isPureObject, isUrl, guardDir } from '../common/utils'
import modes from './modes'
import defaults from './nuxt.config'
// hasValue utility
const hasValue = v => typeof v === 'string' && v
const Options = {}
export default Options
@ -40,8 +43,8 @@ Options.from = function (_options) {
options.extensions = [options.extensions]
}
const hasValue = v => typeof v === 'string' && v
options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
// Resolve rootDir
options.rootDir = hasValue(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
// Apply defaults by ${buildDir}/dist/build.config.js
// TODO: Unsafe operation.
@ -54,12 +57,39 @@ Options.from = function (_options) {
// Apply defaults
_.defaultsDeep(options, defaults)
// Resolve dirs
options.srcDir = hasValue(options.srcDir)
// Check srcDir and generate.dir excistence
const hasSrcDir = hasValue(options.srcDir)
const hasGenerateDir = hasValue(options.generate.dir)
// Resolve srcDir
options.srcDir = hasSrcDir
? path.resolve(options.rootDir, options.srcDir)
: options.rootDir
// Resolve buildDir
options.buildDir = path.resolve(options.rootDir, options.buildDir)
// Protect rootDir against buildDir
guardDir(options, 'rootDir', 'buildDir')
if (hasGenerateDir) {
// Resolve generate.dir
options.generate.dir = path.resolve(options.rootDir, options.generate.dir)
// Protect rootDir against buildDir
guardDir(options, 'rootDir', 'generate.dir')
}
if (hasSrcDir) {
// Protect srcDir against buildDir
guardDir(options, 'srcDir', 'buildDir')
if (hasGenerateDir) {
// Protect srcDir against generate.dir
guardDir(options, 'srcDir', 'generate.dir')
}
}
// Populate modulesDir
options.modulesDir = []
.concat(options.modulesDir)

View File

@ -1,5 +1,6 @@
import path from 'path'
import _ from 'lodash'
import consola from 'consola'
export const encodeHtml = function encodeHtml(str) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;')
@ -326,3 +327,25 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
})
return cleanChildrenRoutes(routes)
}
// Guard dir1 from dir2 which can be indiscriminately removed
export const guardDir = function guardDir(options, key1, key2) {
const dir1 = _.get(options, key1, false)
const dir2 = _.get(options, key2, false)
if (
dir1 &&
dir2 &&
(
dir1 === dir2 ||
(
dir1.startsWith(dir2) &&
!path.basename(dir1).startsWith(path.basename(dir2))
)
)
) {
const errorMessage = `options.${key2} cannot be a parent of or same as ${key1}`
consola.fatal(errorMessage)
throw new Error(errorMessage)
}
}

View File

@ -17,4 +17,14 @@ describe('basic fail generate', () => {
expect(e.message).toBe('Not today!')
})
})
test('Fail when generate.dir equals rootDir', async () => {
const options = await loadFixture('basic', {
generate: { dir: '../basic' }
})
expect(() => {
new Nuxt(options) /* eslint-disable-line no-new */
}).toThrow(/options.generate.dir cannot be/)
})
})

View File

@ -236,6 +236,53 @@ describe('utils', () => {
.toBe(Utils.wp(`loader1!loader2!..${path.sep}baz`))
})
})
describe('guardDir', () => {
test('Parent dir is guarded', () => {
expect(() => {
Utils.guardDir({
dir1: '/root/parent',
dir2: '/root'
}, 'dir1', 'dir2')
}).toThrow()
})
test('Same dir is guarded', () => {
expect(() => {
Utils.guardDir({
dir1: '/root/parent',
dir2: '/root/parent'
}, 'dir1', 'dir2')
}).toThrow()
})
test('Same level dir is not guarded', () => {
expect(() => {
Utils.guardDir({
dir1: '/root/parent-next',
dir2: '/root/parent'
}, 'dir1', 'dir2')
}).not.toThrow()
})
test('Same level dir is not guarded 2', () => {
expect(() => {
Utils.guardDir({
dir1: '/root/parent',
dir2: '/root/parent-next'
}, 'dir1', 'dir2')
}).not.toThrow()
})
test('Child dir is not guarded', () => {
expect(() => {
Utils.guardDir({
dir1: '/root/parent',
dir2: '/root/parent/child'
}, 'dir1', 'dir2')
}).not.toThrow()
})
})
})
test('createRoutes should allow snake case routes', () => {