From cd86177d76641df9b08e5ea0ddf0f4d3a1fcca81 Mon Sep 17 00:00:00 2001 From: isaacs Date: Tue, 4 Jun 2019 14:01:56 -0700 Subject: [PATCH] Omit filenames containing asterisks Filenames containing * chars break windows and create incompatible archives in the npm registry. In the next major release, this should raise an error instead of silently omitting them, so that authors can be alerted. Fix #9 --- index.js | 13 +++++ test/star-names.js | 122 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 test/star-names.js diff --git a/index.js b/index.js index 811c4b3..dd7706a 100644 --- a/index.js +++ b/index.js @@ -51,6 +51,9 @@ const defaultRules = [ 'core.+([0-9])', ] +// There may be others, but :?|<> are handled by node-tar +const nameIsBadForWindows = file => /\*/.test(file) + // a decorator that applies our custom rules to an ignore walker const npmWalker = Class => class Walker extends Class { constructor (opt) { @@ -191,6 +194,16 @@ const npmWalker = Class => class Walker extends Class { then() } + // override parent stat function to completely skip any filenames + // that will break windows entirely. + // XXX(isaacs) Next major version should make this an error instead. + stat (entry, file, dir, then) { + if (nameIsBadForWindows(entry)) + then() + else + super.stat(entry, file, dir, then) + } + // override parent onstat function to nix all symlinks onstat (st, entry, file, dir, then) { if (st.isSymbolicLink()) diff --git a/test/star-names.js b/test/star-names.js new file mode 100644 index 0000000..59e8f92 --- /dev/null +++ b/test/star-names.js @@ -0,0 +1,122 @@ +'use strict' +const fs = require('fs') + +const readdir = fs.readdir +fs.readdir = (path, cb) => { + readdir(path, (er, entries) => { + if (er) + cb(er) + else + cb(null, entries.concat('made*of*stars')) + }) +} + +const readdirSync = fs.readdirSync +fs.readdirSync = path => readdirSync(path).concat('made*of*stars') + +const path = require('path') + +const mkdirp = require('mkdirp') +const rimraf = require('rimraf') +const t = require('tap') + +const pack = require('../') + +const pkg = path.join(__dirname, path.basename(__filename, '.js')) +t.teardown(_ => rimraf.sync(pkg)) + +const elfJS = ` +module.exports = elf => + console.log("i'm a elf") +` + +const json = { + 'name': 'test-package', + 'version': '3.1.4', + 'main': 'elf.js' +} + +const expect = [ + 'package.json', + 'elf.js', + 'deps/foo/config/config.gypi' +] + +t.test('setup', t => { + rimraf.sync(pkg) + mkdirp.sync(pkg) + fs.writeFileSync( + path.join(pkg, 'package.json'), + JSON.stringify(json, null, 2) + ) + + fs.writeFileSync( + path.join(pkg, 'elf.js'), + elfJS + ) + + fs.writeFileSync( + path.join(pkg, '.npmrc'), + 'packaged=false' + ) + + fs.writeFileSync( + path.join(pkg, '.npmignore'), + '.npmignore\ndummy\npackage.json' + ) + + fs.writeFileSync( + path.join(pkg, 'dummy'), + 'foo' + ) + + // empty dir should be ignored + mkdirp.sync(pkg + '/this/dir/is/empty/and/ignored') + + const buildDir = path.join(pkg, 'build') + mkdirp.sync(buildDir) + fs.writeFileSync( + path.join(buildDir, 'config.gypi'), + "i_wont_be_included='with any luck'" + ) + + const depscfg = path.join(pkg, 'deps/foo/config') + mkdirp.sync(depscfg) + fs.writeFileSync( + path.join(depscfg, 'config.gypi'), + "i_will_be_included='with any luck'" + ) + + fs.writeFileSync( + path.join(buildDir, 'npm-debug.log'), + '0 lol\n' + ) + + const gitDir = path.join(pkg, '.git') + mkdirp.sync(gitDir) + fs.writeFileSync( + path.join(gitDir, 'gitstub'), + "won't fool git, also won't be included" + ) + + const historyDir = path.join(pkg, 'node_modules/history') + mkdirp.sync(historyDir) + fs.writeFileSync( + path.join(historyDir, 'README.md'), + "please don't include me" + ) + + t.end() +}) + +t.test('follows npm package ignoring rules', function (t) { + const check = (files, t) => { + t.same(files, expect) + t.end() + } + + t.test('sync', t => check(pack.sync({ path: pkg }), t)) + t.test('async', t => pack({ path: pkg }).then(files => check(files, t))) + + t.end() +})