From e45fe466eec54c8eab17a7c0b881832d2017542f Mon Sep 17 00:00:00 2001 From: steve-p-com Date: Sun, 1 May 2016 10:02:01 +0100 Subject: [PATCH] Remove optional dependencies that are not truly cross-platform --- lib/file-locking.js | 152 +++++++++++++++++++++++++ lib/local-fs.js | 94 +++------------- lib/local-storage.js | 19 +++- lib/plugin-loader.js | 16 +-- lib/plugins/htpasswd/crypt3.js | 56 ++++++++++ lib/plugins/htpasswd/index.js | 138 +++++++++++++++++++++++ lib/plugins/htpasswd/utils.js | 65 +++++++++++ npm-shrinkwrap.json | 199 +++++++-------------------------- package.json | 13 +-- 9 files changed, 496 insertions(+), 256 deletions(-) create mode 100644 lib/file-locking.js create mode 100644 lib/plugins/htpasswd/crypt3.js create mode 100644 lib/plugins/htpasswd/index.js create mode 100644 lib/plugins/htpasswd/utils.js diff --git a/lib/file-locking.js b/lib/file-locking.js new file mode 100644 index 000000000..7b19e2e25 --- /dev/null +++ b/lib/file-locking.js @@ -0,0 +1,152 @@ +/** + * file-locking.js - file system locking (replaces fs-ext) + */ + +var async = require('async'), + locker = require('lockfile'), + fs = require('fs'), + path = require('path') + +// locks a file by creating a lock file +function lockFile(name, next) { + var lockFileName = name + '.lock', + lockOpts = { + wait: 1000, // time (ms) to wait when checking for stale locks + pollPeriod: 100, // how often (ms) to re-check stale locks + + stale: 5 * 60 * 1000, // locks are considered stale after 5 minutes + + retries: 100, // number of times to attempt to create a lock + retryWait: 100 // time (ms) between tries + } + + async.series({ + + statdir: function (callback) { + // test to see if the directory exists + fs.stat(path.dirname(name), function (err, stats) { + if (err) { + callback(err) + } else if (!stats.isDirectory()) { + callback(new Error(path.dirname(name) + ' is not a directory')) + } else { + callback(null) + } + }) + }, + + statfile: function (callback) { + // test to see if the file to lock exists + fs.stat(name, function (err, stats) { + if (err) { + callback(err) + } else if (!stats.isFile()) { + callback(new Error(path.dirname(name) + ' is not a file')) + } else { + callback(null) + } + }); + }, + + lockfile: function (callback) { + // try to lock the file + locker.lock(lockFileName, lockOpts, callback) + } + + }, function (err) { + if (err) { + // lock failed + return next(err) + } + + // lock succeeded + return next(null); + }) + +} + +// unlocks file by removing existing lock file +function unlockFile(name, next) { + var lockFileName = name + '.lock' + + locker.unlock(lockFileName, function (err) { + if (err) { + return next(err) + } + + return next(null) + }) +} + +/** + * reads a local file, which involves + * optionally taking a lock + * reading the file contents + * optionally parsing JSON contents + */ +function readFile(name, options, next) { + if (typeof options === 'function' && next === null) { + next = options; + options = {} + } + + options = options || {} + options.lock = options.lock || false + options.parse = options.parse || false + + function lock(callback) { + if (!options.lock) { + return callback(null) + } + + lockFile(name, function (err) { + if (err) { + return callback(err) + } + return callback(null) + }) + } + + function read(callback) { + fs.readFile(name, 'utf8', function (err, contents) { + if (err) { + return callback(err) + } + + callback(null, contents) + + }) + } + + function parseJSON(contents, callback) { + if (!options.parse) { + return callback(null, contents) + } + + try { + contents = JSON.parse(contents) + return callback(null, contents) + } catch (err) { + return callback(err) + } + } + + async.waterfall([ + lock, + read, + parseJSON + ], + + function (err, result) { + if (err) { + return next(err) + } else { + return next(null, result) + } + }) +} + +exports.lockFile = lockFile; +exports.unlockFile = unlockFile; + +exports.readFile = readFile; diff --git a/lib/local-fs.js b/lib/local-fs.js index db85b0006..8d7a66719 100644 --- a/lib/local-fs.js +++ b/lib/local-fs.js @@ -10,15 +10,7 @@ function FSError(code) { return err } -try { - var fsExt = require('fs-ext') -} catch (e) { - fsExt = { - flock: function() { - arguments[arguments.length-1]() - } - } -} +var locker = require('./file-locking') function tempFile(str) { return str + '.tmp' + String(Math.random()).substr(2) @@ -134,7 +126,7 @@ function read_stream(name, stream, callback) { }) }) - var stream = MyStreams.ReadTarballStream() + stream = MyStreams.ReadTarballStream() stream.abort = function() { rstream.close() } @@ -159,64 +151,6 @@ function read(name, callback) { fs.readFile(name, callback) } -// open and flock with exponential backoff -function open_flock(name, opmod, flmod, tries, backoff, cb) { - fs.open(name, opmod, function(err, fd) { - if (err) return cb(err, fd) - - fsExt.flock(fd, flmod, function(err) { - if (err) { - if (!tries) { - fs.close(fd, function() { - cb(err) - }) - } else { - fs.close(fd, function() { - setTimeout(function() { - open_flock(name, opmod, flmod, tries-1, backoff*2, cb) - }, backoff) - }) - } - } else { - cb(null, fd) - } - }) - }) -} - -// this function neither unlocks file nor closes it -// it'll have to be done manually later -function lock_and_read(name, _callback) { - open_flock(name, 'r', 'exnb', 4, 10, function(err, fd) { - function callback(err) { - if (err && fd) { - fs.close(fd, function(err2) { - _callback(err) - }) - } else { - _callback.apply(null, arguments) - } - } - - if (err) return callback(err, fd) - - fs.fstat(fd, function(err, st) { - if (err) return callback(err, fd) - - var buffer = Buffer(st.size) - if (st.size === 0) return onRead(null, 0, buffer) - fs.read(fd, buffer, 0, st.size, null, onRead) - - function onRead(err, bytesRead, buffer) { - if (err) return callback(err, fd) - if (bytesRead != st.size) return callback(Error('st.size != bytesRead'), fd) - - callback(null, fd, buffer) - } - }) - }) -} - module.exports.read = read module.exports.read_json = function(name, cb) { @@ -233,22 +167,24 @@ module.exports.read_json = function(name, cb) { }) } -module.exports.lock_and_read = lock_and_read +module.exports.lock_and_read = function(name, cb) { + locker.readFile(name, {lock: true}, function(err, res) { + if (err) return cb(err) + return cb(null, res) + }) +} module.exports.lock_and_read_json = function(name, cb) { - lock_and_read(name, function(err, fd, res) { - if (err) return cb(err, fd) - - var args = [] - try { - args = [ null, fd, JSON.parse(res.toString('utf8')) ] - } catch(err) { - args = [ err, fd ] - } - cb.apply(null, args) + locker.readFile(name, {lock: true, parse: true}, function(err, res) { + if (err) return cb(err) + return cb(null, res); }) } +module.exports.unlock_file = function (name, cb) { + locker.unlockFile(name, cb) +} + module.exports.create = create module.exports.create_json = function(name, value, cb) { diff --git a/lib/local-storage.js b/lib/local-storage.js index e73bad50d..b5544d5e4 100644 --- a/lib/local-storage.js +++ b/lib/local-storage.js @@ -543,19 +543,26 @@ Storage.prototype.update_package = function(name, updateFn, _callback) { var self = this var storage = self.storage(name) if (!storage) return _callback( Error[404]('no such package available') ) - storage.lock_and_read_json(info_file, function(err, fd, json) { - function callback() { + storage.lock_and_read_json(info_file, function(err, json) { + var locked = false + + // callback that cleans up lock first + function callback(err) { var _args = arguments - if (fd) { - fs.close(fd, function(err) { - if (err) return _callback(err) - _callback.apply(null, _args) + if (locked) { + storage.unlock_file(info_file, function () { + // ignore any error from the unlock + _callback.apply(err, _args) }) } else { _callback.apply(null, _args) } } + if (!err) { + locked = true + } + if (err) { if (err.code === 'EAGAIN') { return callback( Error[503]('resource temporarily unavailable') ) diff --git a/lib/plugin-loader.js b/lib/plugin-loader.js index 793b5351f..dac03c5f7 100644 --- a/lib/plugin-loader.js +++ b/lib/plugin-loader.js @@ -15,23 +15,25 @@ function load_plugins(config, plugin_configs, params, sanity_check) { var plugins = Object.keys(plugin_configs || {}).map(function(p) { var plugin + // try local plugins first + plugin = try_load(Path.resolve('./lib/plugins', p)) + // npm package - if (plugin == null && p.match(/^[^\.\/]/)) { + if (plugin === null && p.match(/^[^\.\/]/)) { plugin = try_load('sinopia-' + p) } - if (plugin == null) { + if (plugin === null) { plugin = try_load(p) } // relative to config path - if (plugin == null && p.match(/^\.\.?($|\/)/)) { + if (plugin === null && p.match(/^\.\.?($|\/)/)) { plugin = try_load(Path.resolve(Path.dirname(config.self_path), p)) } - if (plugin == null) { - throw Error('"' + p + '" plugin not found\n' - + 'try "npm install sinopia-' + p + '"') + if (plugin === null) { + throw Error('"' + p + '" plugin not found\ntry "npm install sinopia-' + p + '"') } if (typeof(plugin) !== 'function') @@ -39,7 +41,7 @@ function load_plugins(config, plugin_configs, params, sanity_check) { plugin = plugin(plugin_configs[p], params) - if (plugin == null || !sanity_check(plugin)) + if (plugin === null || !sanity_check(plugin)) throw Error('"' + p + '" doesn\'t look like a valid plugin') return plugin diff --git a/lib/plugins/htpasswd/crypt3.js b/lib/plugins/htpasswd/crypt3.js new file mode 100644 index 000000000..d992bcc79 --- /dev/null +++ b/lib/plugins/htpasswd/crypt3.js @@ -0,0 +1,56 @@ +/** Node.js Crypt(3) Library + + Inspired by (and intended to be compatible with) sendanor/crypt3 + + see https://github.com/sendanor/node-crypt3 + + The key difference is the removal of the dependency on the unix crypt(3) function + which is not platform independent, and requires compilation. Instead, a pure + javascript version is used. + +*/ + +var crypt = require('unix-crypt-td-js'), + crypto = require('crypto'); + +function createSalt(type) { + type = type || 'sha512'; + + switch (type) { + + case 'md5': + return '$1$' + crypto.randomBytes(10).toString('base64'); + + case 'blowfish': + return '$2a$' + crypto.randomBytes(10).toString('base64'); + + case 'sha256': + return '$5$' + crypto.randomBytes(10).toString('base64'); + + case 'sha512': + return '$6$' + crypto.randomBytes(10).toString('base64'); + + default: + throw new TypeError('Unknown salt type at crypt3.createSalt: ' + type); + } + +} + +function crypt3(key, salt) { + salt = salt || createSalt(); + return crypt(key, salt); +} + +/** Crypt(3) password and data encryption. + * @param {string} key user's typed password + * @param {string} salt Optional salt, for example SHA-512 use "$6$salt$". + * @returns {string} A generated hash in format $id$salt$encrypted + * @see https://en.wikipedia.org/wiki/Crypt_(C) + */ +module.exports = crypt3; + +/** Create salt + * @param {string} type The type of salt: md5, blowfish (only some linux distros), sha256 or sha512. Default is sha512. + * @returns {string} Generated salt string + */ +module.exports.createSalt = createSalt; diff --git a/lib/plugins/htpasswd/index.js b/lib/plugins/htpasswd/index.js new file mode 100644 index 000000000..f978a6d0c --- /dev/null +++ b/lib/plugins/htpasswd/index.js @@ -0,0 +1,138 @@ +var fs = require('fs') +var Path = require('path') +var utils = require('./utils') + +module.exports = HTPasswd + +function HTPasswd(config, stuff) { + var self = Object.create(HTPasswd.prototype) + self._users = {} + + // config for this module + self._config = config + + // sinopia logger + self._logger = stuff.logger + + // sinopia main config object + self._sinopia_config = stuff.config + + // all this "sinopia_config" stuff is for b/w compatibility only + self._maxusers = self._config.max_users + if (!self._maxusers) self._maxusers = self._sinopia_config.max_users + // set maxusers to Infinity if not specified + if (!self._maxusers) self._maxusers = Infinity + + self._last_time = null + var file = self._config.file + if (!file) file = self._sinopia_config.users_file + if (!file) throw new Error('should specify "file" in config') + self._path = Path.resolve(Path.dirname(self._sinopia_config.self_path), file) + return self +} + +HTPasswd.prototype.authenticate = function (user, password, cb) { + var self = this + self._reload(function (err) { + if (err) return cb(err.code === 'ENOENT' ? null : err) + if (!self._users[user]) return cb(null, false) + if (!utils.verify_password(user, password, self._users[user])) return cb(null, false) + + // authentication succeeded! + // return all usergroups this user has access to; + // (this particular package has no concept of usergroups, so just return user herself) + return cb(null, [user]) + }) +} + +// hopefully race-condition-free way to add users: +// 1. lock file for writing (other processes can still read) +// 2. reload .htpasswd +// 3. write new data into .htpasswd.tmp +// 4. move .htpasswd.tmp to .htpasswd +// 5. reload .htpasswd +// 6. unlock file +HTPasswd.prototype.adduser = function (user, password, real_cb) { + var self = this + + function sanity_check() { + var err = null + if (self._users[user]) { + err = Error('this user already exists') + } else if (Object.keys(self._users).length >= self._maxusers) { + err = Error('maximum amount of users reached') + } + if (err) err.status = 403 + return err + } + + // preliminary checks, just to ensure that file won't be reloaded if it's not needed + var s_err = sanity_check() + if (s_err) return real_cb(s_err, false) + + utils.lock_and_read(self._path, function (err, res) { + var locked = false + + // callback that cleans up lock first + function cb(err) { + if (locked) { + utils.unlock_file(self._path, function () { + // ignore any error from the unlock + real_cb(err, !err) + }) + } else { + real_cb(err, !err) + } + } + + if (!err) { + locked = true + } + + // ignore ENOENT errors, we'll just create .htpasswd in that case + if (err && err.code !== 'ENOENT') return cb(err) + + var body = (res || '').toString('utf8') + self._users = utils.parse_htpasswd(body) + + // real checks, to prevent race conditions + var s_err = sanity_check() + if (s_err) return cb(s_err) + + try { + console.log('body = utils.add_user_to_htpasswd(body, user, password)') + console.log(user, password) + body = utils.add_user_to_htpasswd(body, user, password) + } catch (err) { + return cb(err) + } + fs.writeFile(self._path, body, function (err) { + if (err) return cb(err) + self._reload(function () { + cb(null, true) + }) + }) + }) +} + +HTPasswd.prototype._reload = function (_callback) { + var self = this + + fs.stat(self._path, function (err, stats) { + if (err) return _callback(err) + + if (self._last_time === stats.mtime) return _callback() + self._last_time = stats.mtime + + fs.readFile(self._path, 'utf8', function (err, buffer) { + if (err) return _callback(err) + + self._users = utils.parse_htpasswd(buffer) + + _callback() + + }); + + }); + +} diff --git a/lib/plugins/htpasswd/utils.js b/lib/plugins/htpasswd/utils.js new file mode 100644 index 000000000..229662f9f --- /dev/null +++ b/lib/plugins/htpasswd/utils.js @@ -0,0 +1,65 @@ +var crypto = require('crypto') +var crypt3 = require('./crypt3') +var locker = require('../../file-locking') + +// this function neither unlocks file nor closes it +// it'll have to be done manually later +function lock_and_read(name, cb) { + locker.readFile(name, {lock: true}, function (err, res) { + if (err) { + return cb(err) + } + return cb(null, res) + }) +} + +// close and unlock file +function unlock_file(name, cb) { + locker.unlockFile(name, cb) +} + +function parse_htpasswd(input) { + var result = {} + input.split('\n').forEach(function(line) { + var args = line.split(':', 3) + if (args.length > 1) result[args[0]] = args[1] + }) + return result +} + +function verify_password(user, passwd, hash) { + if (hash.indexOf('{PLAIN}') === 0) { + return passwd === hash.substr(7) + } else if (hash.indexOf('{SHA}') === 0) { + return crypto.createHash('sha1').update(passwd, 'binary').digest('base64') === hash.substr(5) + } else if (crypt3) { + return crypt3(passwd, hash) === hash + } else { + return false + } +} + +function add_user_to_htpasswd(body, user, passwd) { + if (user !== encodeURIComponent(user)) { + var err = Error('username should not contain non-uri-safe characters') + err.status = 409 + throw err + } + + if (crypt3) { + passwd = crypt3(passwd) + } else { + passwd = '{SHA}' + crypto.createHash('sha1').update(passwd, 'binary').digest('base64') + } + var comment = 'autocreated ' + (new Date()).toJSON() + + var newline = user + ':' + passwd + ':' + comment + '\n' + if (body.length && body[body.length-1] !== '\n') newline = '\n' + newline + return body + newline +} + +module.exports.parse_htpasswd = parse_htpasswd +module.exports.verify_password = verify_password +module.exports.add_user_to_htpasswd = add_user_to_htpasswd +module.exports.lock_and_read = lock_and_read +module.exports.unlock_file = unlock_file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 8f8755ed8..80cc010ce 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -65,7 +65,7 @@ }, "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.13 <0.5.0", + "from": "iconv-lite@0.4.13", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" }, "on-finished": { @@ -139,9 +139,9 @@ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", "dependencies": { "nan": { - "version": "2.2.1", + "version": "2.3.2", "from": "nan@>=2.0.8 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.2.tgz" } } }, @@ -316,18 +316,6 @@ } } }, - "crypt3": { - "version": "0.2.0", - "from": "crypt3@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/crypt3/-/crypt3-0.2.0.tgz", - "dependencies": { - "nan": { - "version": "2.2.1", - "from": "nan@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz" - } - } - }, "es6-shim": { "version": "0.35.0", "from": "es6-shim@>=0.35.0 <0.36.0", @@ -546,7 +534,7 @@ }, "mime-types": { "version": "2.1.10", - "from": "mime-types@>=2.1.10 <2.2.0", + "from": "mime-types@>=2.1.6 <2.2.0", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz", "dependencies": { "mime-db": { @@ -570,18 +558,6 @@ } } }, - "fs-ext": { - "version": "0.5.0", - "from": "fs-ext@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/fs-ext/-/fs-ext-0.5.0.tgz", - "dependencies": { - "nan": { - "version": "2.2.1", - "from": "nan@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz" - } - } - }, "handlebars": { "version": "4.0.5", "from": "handlebars@>=4.0.5 <5.0.0", @@ -632,9 +608,9 @@ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" }, "source-map": { - "version": "0.5.3", + "version": "0.5.5", "from": "source-map@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz" + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.5.tgz" }, "uglify-to-browserify": { "version": "1.0.2", @@ -691,9 +667,9 @@ } }, "lazy-cache": { - "version": "1.0.3", + "version": "1.0.4", "from": "lazy-cache@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" } } }, @@ -807,6 +783,11 @@ } } }, + "lockfile": { + "version": "1.0.1", + "from": "lockfile@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.1.tgz" + }, "lunr": { "version": "0.7.0", "from": "lunr@>=0.7.0 <0.8.0", @@ -854,9 +835,9 @@ "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.0.tgz" }, "readable-stream": { - "version": "2.1.0", - "from": "readable-stream@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.0.tgz", + "version": "2.1.2", + "from": "readable-stream@>=2.1.2 <3.0.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.2.tgz", "dependencies": { "core-util-is": { "version": "1.0.2", @@ -868,64 +849,6 @@ "from": "inherits@>=2.0.1 <2.1.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, - "inline-process-browser": { - "version": "2.0.1", - "from": "inline-process-browser@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/inline-process-browser/-/inline-process-browser-2.0.1.tgz", - "dependencies": { - "falafel": { - "version": "1.2.0", - "from": "falafel@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz", - "dependencies": { - "acorn": { - "version": "1.2.2", - "from": "acorn@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" - }, - "foreach": { - "version": "2.0.5", - "from": "foreach@>=2.0.5 <3.0.0", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "object-keys": { - "version": "1.0.9", - "from": "object-keys@>=1.0.6 <2.0.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.9.tgz" - } - } - }, - "through2": { - "version": "0.6.5", - "from": "through2@>=0.6.5 <0.7.0", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.33-1 <1.1.0-0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - } - } - }, - "xtend": { - "version": "4.0.1", - "from": "xtend@>=4.0.0 <4.1.0-0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } - } - } - } - }, "isarray": { "version": "1.0.0", "from": "isarray@>=1.0.0 <1.1.0", @@ -941,45 +864,6 @@ "from": "string_decoder@>=0.10.0 <0.11.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, - "unreachable-branch-transform": { - "version": "0.5.1", - "from": "unreachable-branch-transform@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/unreachable-branch-transform/-/unreachable-branch-transform-0.5.1.tgz", - "dependencies": { - "esmangle-evaluator": { - "version": "1.0.0", - "from": "esmangle-evaluator@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/esmangle-evaluator/-/esmangle-evaluator-1.0.0.tgz" - }, - "recast": { - "version": "0.11.5", - "from": "recast@>=0.11.4 <0.12.0", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.5.tgz", - "dependencies": { - "ast-types": { - "version": "0.8.16", - "from": "ast-types@0.8.16", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.16.tgz" - }, - "esprima": { - "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" - }, - "private": { - "version": "0.1.6", - "from": "private@>=0.1.5 <0.2.0", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz" - }, - "source-map": { - "version": "0.5.3", - "from": "source-map@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz" - } - } - } - } - }, "util-deprecate": { "version": "1.0.2", "from": "util-deprecate@>=1.0.1 <1.1.0", @@ -1015,9 +899,9 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz" }, "linkify-it": { - "version": "1.2.0", + "version": "1.2.1", "from": "linkify-it@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.1.tgz" }, "mdurl": { "version": "1.0.1", @@ -1372,26 +1256,29 @@ } }, "sshpk": { - "version": "1.7.4", + "version": "1.8.3", "from": "sshpk@>=1.7.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.4.tgz", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", "dependencies": { "asn1": { "version": "0.2.3", "from": "asn1@>=0.2.3 <0.3.0", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" }, + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + }, "dashdash": { - "version": "1.13.0", - "from": "dashdash@>=1.10.1 <2.0.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.0.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } + "version": "1.13.1", + "from": "dashdash@>=1.12.0 <2.0.0", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.1.tgz" + }, + "getpass": { + "version": "0.1.6", + "from": "getpass@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz" }, "jsbn": { "version": "0.1.0", @@ -1399,9 +1286,9 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" }, "tweetnacl": { - "version": "0.14.3", - "from": "tweetnacl@>=0.13.0 <1.0.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz" + "version": "0.13.3", + "from": "tweetnacl@>=0.13.0 <0.14.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" }, "jodid25519": { "version": "1.0.2", @@ -1410,7 +1297,7 @@ }, "ecc-jsbn": { "version": "0.1.1", - "from": "ecc-jsbn@>=0.0.1 <1.0.0", + "from": "ecc-jsbn@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" } } @@ -1434,7 +1321,7 @@ }, "mime-types": { "version": "2.1.10", - "from": "mime-types@>=2.1.10 <2.2.0", + "from": "mime-types@>=2.1.7 <2.2.0", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz", "dependencies": { "mime-db": { @@ -1481,15 +1368,15 @@ "from": "semver@>=5.1.0 <6.0.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz" }, - "sinopia-htpasswd": { - "version": "0.4.5", - "from": "sinopia-htpasswd@>=0.4.5 <0.5.0", - "resolved": "https://registry.npmjs.org/sinopia-htpasswd/-/sinopia-htpasswd-0.4.5.tgz" - }, "symbol": { "version": "0.2.1", "from": "symbol@>=0.2.1 <0.3.0", "resolved": "https://registry.npmjs.org/symbol/-/symbol-0.2.1.tgz" + }, + "unix-crypt-td-js": { + "version": "1.0.0", + "from": "unix-crypt-td-js@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.0.0.tgz" } } } diff --git a/package.json b/package.json index e58f68cf7..28445458d 100644 --- a/package.json +++ b/package.json @@ -29,26 +29,23 @@ "http-errors": "^1.4.0", "jju": "^1.3.0", "js-yaml": "^3.6.0", + "lockfile": "^1.0.1", "lunr": "^0.7.0", "minimatch": "^3.0.0", "mkdirp": "^0.5.1", "pkginfo": "^0.4.0", - "readable-stream": "^2.1.0", + "readable-stream": "^2.1.2", "render-readme": "^1.3.1", "request": "^2.72.0", "semver": "^5.1.0", - "sinopia-htpasswd": "^0.4.5", - "symbol": "^0.2.1" - }, - "optionalDependencies": { - "fs-ext": "^0.5.0", - "crypt3": "^0.2.0" + "symbol": "^0.2.1", + "unix-crypt-td-js": "^1.0.0" }, "devDependencies": { "rimraf": "^2.5.2", "bluebird": "^3.3.5", "mocha": "^2.4.5", - "eslint": "^2.8.0", + "eslint": "^2.9.0", "browserify": "^13.0.0", "browserify-handlebars": "^1.0.0", "grunt": "^1.0.1",