mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
Merge pull request #18 from steve-p-com/master
Remove platform specific deps. Introduce bundled-in plugins.
This commit is contained in:
commit
06980e0cc1
9 changed files with 496 additions and 256 deletions
152
lib/file-locking.js
Normal file
152
lib/file-locking.js
Normal file
|
@ -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;
|
|
@ -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) {
|
||||
|
|
|
@ -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') )
|
||||
|
|
|
@ -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
|
||||
|
|
56
lib/plugins/htpasswd/crypt3.js
Normal file
56
lib/plugins/htpasswd/crypt3.js
Normal file
|
@ -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;
|
138
lib/plugins/htpasswd/index.js
Normal file
138
lib/plugins/htpasswd/index.js
Normal file
|
@ -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()
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
65
lib/plugins/htpasswd/utils.js
Normal file
65
lib/plugins/htpasswd/utils.js
Normal file
|
@ -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
|
199
npm-shrinkwrap.json
generated
199
npm-shrinkwrap.json
generated
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
package.json
13
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",
|
||||
|
|
Loading…
Reference in a new issue