1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-02-21 07:29:37 +01:00

use http-errors package instead of custom stuff

This commit is contained in:
Alex Kocharin 2014-09-10 21:55:26 +04:00
parent dbb588f031
commit a5cd498f92
11 changed files with 79 additions and 252 deletions

@ -1,6 +1,6 @@
var Path = require('path')
, crypto = require('crypto')
, UError = require('./error').UserError
, Error = require('http-errors')
, Logger = require('./logger')
, assert = require('assert')
@ -65,10 +65,8 @@ function Auth(config) {
},
adduser: function(user, password, cb) {
if (config.users && config.users[user]) return cb(new UError({
status: 403,
message: 'this user already exists',
}))
if (config.users && config.users[user])
return cb(Error[403]('this user already exists'))
return cb()
},
@ -76,17 +74,11 @@ function Auth(config) {
this.plugins.push({
authenticate: function(user, password, cb) {
return cb(new UError({
status: 403,
message: 'bad username/password, access denied',
}))
return cb(Error[403]('bad username/password, access denied'))
},
adduser: function(user, password, cb) {
return cb(new UError({
status: 409,
message: 'registration is disabled',
}))
return cb(Error[409]('registration is disabled'))
},
})
}

@ -2,7 +2,7 @@ var assert = require('assert')
, crypto = require('crypto')
, Path = require('path')
, minimatch = require('minimatch')
, UError = require('./error').UserError
, Error = require('http-errors')
, LocalList = require('./local-list')
, utils = require('./utils')

@ -1,62 +0,0 @@
var util = require('util')
, utils = require('./utils')
function parse_error_params(params, status, message) {
if (typeof(params) === 'string') {
return {
message: params,
status: status,
}
} else if (typeof(params) === 'number') {
return {
message: message,
status: params,
}
} else if (utils.is_object(params)) {
if (params.message == null) params.message = message
if (params.status == null) params.status = status
return params
} else {
return {
message: message,
status: status,
}
}
}
/*
* Errors caused by malfunctioned code
*/
var AppError = function(params, constr) {
Error.captureStackTrace(this, constr || this)
params = parse_error_params(params, 500, 'Internal server error')
this.message = params.message
this.status = params.status
}
util.inherits(AppError, Error)
AppError.prototype.name = 'Application Error'
/*
* Errors caused by wrong request
*/
var UserError = function(params, constr) {
params = parse_error_params(params, 404, 'The requested resource was not found')
this.message = params.message
this.status = params.status
}
util.inherits(UserError, Error)
UserError.prototype.name = 'User Error'
/*
* Mimic filesystem errors
*/
var FSError = function(code) {
this.code = code
}
util.inherits(UserError, Error)
UserError.prototype.name = 'FS Error'
module.exports.AppError = AppError
module.exports.UserError = UserError
module.exports.FSError = FSError

@ -3,7 +3,7 @@ var express = require('express')
, utils = require('./utils')
, Storage = require('./storage')
, Config = require('./config')
, UError = require('./error').UserError
, Error = require('http-errors')
, Middleware = require('./middleware')
, Logger = require('./logger')
, Cats = require('./status-cats')
@ -39,15 +39,10 @@ module.exports = function(config_hash) {
} else {
var message = "can't "+action+" restricted package without auth, did you forget 'npm set always-auth true'?"
}
next(new UError({
status: 403,
message: message,
}))
next(Error[403](message))
} else {
next(new UError({
status: 403,
message: 'user '+req.remote_user.name+' not allowed to '+action+' it'
}))
next(Error[403]('user ' + req.remote_user.name
+ ' not allowed to ' + action + ' it'))
}
}
}
@ -144,10 +139,7 @@ module.exports = function(config_hash) {
}
}
return next(new UError({
status: 404,
message: 'version not found: ' + req.params.version
}))
return next(Error[404]('version not found: ' + req.params.version))
})
})
@ -205,20 +197,14 @@ module.exports = function(config_hash) {
})
} else {
if (typeof(req.body.name) !== 'string' || typeof(req.body.password) !== 'string') {
return next(new UError({
status: 400,
message: 'user/password is not found in request (npm issue?)',
}))
return next(Error[400]('user/password is not found in request (npm issue?)'))
}
auth.add_user(req.body.name, req.body.password, function(err) {
if (err) {
if (err.status < 500 && err.message === 'this user already exists') {
// with npm registering is the same as logging in
// so we replace message in case of conflict
return next(new UError({
status: 409,
message: 'bad username/password, access denied'
}))
return next(Error[409]('bad username/password, access denied'))
}
return next(err)
}
@ -251,20 +237,14 @@ module.exports = function(config_hash) {
var name = req.params.package
if (Object.keys(req.body).length == 1 && utils.is_object(req.body.users)) {
return next(new UError({
// 501 status is more meaningful, but npm doesn't show error message for 5xx
status: 404,
message: 'npm star|unstar calls are not implemented',
}))
// 501 status is more meaningful, but npm doesn't show error message for 5xx
return next(Error[404]('npm star|unstar calls are not implemented'))
}
try {
var metadata = utils.validate_metadata(req.body, name)
} catch(err) {
return next(new UError({
status: 422,
message: 'bad incoming package data',
}))
return next(Error[422]('bad incoming package data'))
}
if (req.params._rev) {
@ -298,10 +278,7 @@ module.exports = function(config_hash) {
// npm is doing something strange again
// if this happens in normal circumstances, report it as a bug
return next(new UError({
status: 400,
message: 'unsupported registry call',
}))
return next(Error[400]('unsupported registry call'))
}
if (err && err.status != 409) return next(err)

@ -2,7 +2,13 @@ var fs = require('fs')
, Path = require('path')
, mkdirp = require('mkdirp')
, mystreams = require('./streams')
, FSError = require('./error').FSError
, Error = require('http-errors')
function FSError(code) {
var err = Error(code)
err.code = code
return err
}
try {
var fsExt = require('fs-ext')
@ -44,7 +50,7 @@ function write_stream(name) {
})
fs.exists(name, function(exists) {
if (exists) return stream.emit('error', new FSError('EEXISTS'))
if (exists) return stream.emit('error', FSError('EEXISTS'))
var tmpname = name + '.tmp-'+String(Math.random()).replace(/^0\./, '')
, file = fs.createWriteStream(tmpname)
@ -114,14 +120,14 @@ function read_stream(name, stream, callback) {
function create(name, contents, callback) {
fs.exists(name, function(exists) {
if (exists) return callback(new FSError('EEXISTS'))
if (exists) return callback(FSError('EEXISTS'))
write(name, contents, callback)
})
}
function update(name, contents, callback) {
fs.exists(name, function(exists) {
if (!exists) return callback(new FSError('ENOENT'))
if (!exists) return callback(FSError('ENOENT'))
write(name, contents, callback)
})
}
@ -167,7 +173,7 @@ function lock_and_read(name, callback) {
var buffer = new Buffer(st.size)
fs.read(fd, buffer, 0, st.size, null, function(err, bytesRead, buffer) {
if (err) return callback(err)
if (bytesRead != st.size) return callback(new Error('st.size != bytesRead'), fd)
if (bytesRead != st.size) return callback(Error('st.size != bytesRead'), fd)
callback(null, fd, buffer)
})

@ -3,7 +3,7 @@ var fs = require('fs')
, crypto = require('crypto')
, assert = require('assert')
, fs_storage = require('./local-fs')
, UError = require('./error').UserError
, Error = require('http-errors')
, utils = require('./utils')
, mystreams = require('./streams')
, Logger = require('./logger')
@ -41,26 +41,17 @@ Storage.prototype._internal_error = function(err, file, message) {
this.logger.error( {err: err, file: file}
, message + ' @{file}: @{!err.message}'
)
return new UError({
status: 500,
message: 'internal server error'
})
return Error[500]()
}
Storage.prototype.add_package = function(name, info, callback) {
var self = this
var storage = this.storage(name)
if (!storage) return callback(new UError({
status: 404,
message: 'this package cannot be added'
}))
if (!storage) return callback(Error[404]('this package cannot be added'))
storage.create_json(info_file, get_boilerplate(name), function(err) {
if (err && err.code === 'EEXISTS') {
return callback(new UError({
status: 409,
message: 'this package is already present'
}))
return callback(Error[409]('this package is already present'))
}
var latest = info['dist-tags'].latest
@ -76,17 +67,12 @@ Storage.prototype.remove_package = function(name, callback) {
self.logger.info({name: name}, 'unpublishing @{name} (all)')
var storage = self.storage(name)
if (!storage) return callback(new UError({
status: 404,
message: 'no such package available',
}))
if (!storage) return callback(Error[404]('no such package available'))
storage.read_json(info_file, function(err, data) {
if (err) {
if (err.code === 'ENOENT') {
return callback(new UError({
status: 404,
message: 'no such package available',
}))
return callback(Error[404]('no such package available'))
} else {
return callback(err)
}
@ -222,10 +208,7 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback)
delete metadata.readme
if (data.versions[version] != null) {
return cb(new UError({
status: 409,
message: 'this version already present'
}))
return cb(Error[409]('this version already present'))
}
// if uploaded tarball has a different shasum, it's very likely that we have some kind of error
@ -234,10 +217,9 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback)
if (utils.is_object(data._attachments[tarball])) {
if (data._attachments[tarball].shasum != null && metadata.dist.shasum != null) {
if (data._attachments[tarball].shasum != metadata.dist.shasum) {
return cb(new UError({
status: 400,
message: 'shasum error, ' + data._attachments[tarball].shasum + ' != ' + metadata.dist.shasum,
}))
return cb(Error[400]('shasum error, '
+ data._attachments[tarball].shasum
+ ' != ' + metadata.dist.shasum))
}
}
@ -258,10 +240,7 @@ Storage.prototype.add_tags = function(name, tags, callback) {
self.update_package(name, function updater(data, cb) {
for (var t in tags) {
if (data.versions[tags[t]] == null) {
return cb(new UError({
status: 404,
message: "this version doesn't exist"
}))
return cb(Error[404]("this version doesn't exist"))
}
utils.tag_version(data, tags[t], t, self.config)
@ -280,10 +259,7 @@ Storage.prototype.change_package = function(name, metadata, revision, callback)
var self = this
if (!utils.is_object(metadata.versions) || !utils.is_object(metadata['dist-tags'])) {
return callback(new UError({
status: 422,
message: 'bad data',
}))
return callback(Error[422]('bad data'))
}
self.update_package(name, function updater(data, cb) {
@ -316,10 +292,7 @@ Storage.prototype.remove_tarball = function(name, filename, revision, callback)
delete data._attachments[filename]
cb()
} else {
cb(new UError({
status: 404,
message: 'no such file available',
}))
cb(Error[404]('no such file available'))
}
}, function(err) {
if (err) return callback(err)
@ -347,10 +320,7 @@ Storage.prototype.add_tarball = function(name, filename) {
var self = this
if (name === info_file || name === '__proto__') {
process.nextTick(function() {
stream.emit('error', new UError({
status: 403,
message: 'can\'t use this filename'
}))
stream.emit('error', Error[403]("can't use this filename"))
})
return stream
}
@ -358,10 +328,7 @@ Storage.prototype.add_tarball = function(name, filename) {
var storage = self.storage(name)
if (!storage) {
process.nextTick(function() {
stream.emit('error', new UError({
status: 404,
message: 'can\'t upload this package'
}))
stream.emit('error', Error[404]("can't upload this package"))
})
return stream
}
@ -370,10 +337,7 @@ Storage.prototype.add_tarball = function(name, filename) {
wstream.on('error', function(err) {
if (err.code === 'EEXISTS') {
stream.emit('error', new UError({
status: 409,
message: 'this tarball is already present'
}))
stream.emit('error', Error[409]('this tarball is already present'))
} else if (err.code === 'ENOENT') {
// check if package exists to throw an appropriate message
self.get_package(name, function(_err, res) {
@ -411,10 +375,7 @@ Storage.prototype.add_tarball = function(name, filename) {
}
stream.done = function() {
if (!length) {
stream.emit('error', new UError({
status: 422,
message: 'refusing to accept zero-length file'
}))
stream.emit('error', Error[422]('refusing to accept zero-length file'))
wstream.abort()
} else {
wstream.done()
@ -440,7 +401,6 @@ Storage.prototype.get_readme = function(name, version, callback) {
if (exists) {
returnReadme();
} else {
debugger
self.unpack_tarball(fileName, function(err) {
returnReadme();
});
@ -455,7 +415,7 @@ debugger
callback(data)
})
}
};
}
Storage.prototype.get_tarball = function(name, filename, callback) {
assert(utils.validate_name(filename))
@ -469,10 +429,7 @@ Storage.prototype.get_tarball = function(name, filename, callback) {
var storage = self.storage(name)
if (!storage) {
process.nextTick(function() {
stream.emit('error', new UError({
status: 404,
message: 'no such file available',
}))
stream.emit('error', Error[404]('no such file available'))
})
return stream
}
@ -480,10 +437,7 @@ Storage.prototype.get_tarball = function(name, filename, callback) {
var rstream = storage.read_stream(filename)
rstream.on('error', function(err) {
if (err && err.code === 'ENOENT') {
stream.emit('error', new UError({
status: 404,
message: 'no such file available',
}))
stream.emit('error', Error(404, 'no such file available'))
} else {
stream.emit('error', err)
}
@ -504,18 +458,12 @@ Storage.prototype.get_package = function(name, options, callback) {
var self = this
var storage = self.storage(name)
if (!storage) return callback(new UError({
status: 404,
message: 'no such package available'
}))
if (!storage) return callback(Error[404]('no such package available'))
storage.read_json(info_file, function(err, result) {
if (err) {
if (err.code === 'ENOENT') {
return callback(new UError({
status: 404,
message: 'no such package available'
}))
return callback(Error[404]('no such package available'))
} else {
return callback(self._internal_error(err, info_file, 'error reading'))
}
@ -575,10 +523,7 @@ Storage.prototype.get_recent_packages = function(startkey, callback) {
Storage.prototype.update_package = function(name, updateFn, _callback) {
var self = this
var storage = self.storage(name)
if (!storage) return _callback(new UError({
status: 404,
message: 'no such package available',
}))
if (!storage) return _callback(Error[404]('no such package available'))
storage.lock_and_read_json(info_file, function(err, fd, json) {
function callback() {
var _args = arguments
@ -594,15 +539,9 @@ Storage.prototype.update_package = function(name, updateFn, _callback) {
if (err) {
if (err.code === 'EAGAIN') {
return callback(new UError({
status: 503,
message: 'resource temporarily unavailable'
}))
return callback(Error[503]('resource temporarily unavailable'))
} else if (err.code === 'ENOENT') {
return callback(new UError({
status: 404,
message: 'no such package available',
}))
return callback(Error[404]('no such package available'))
} else {
return callback(err)
}

@ -1,4 +1,5 @@
var Logger = require('bunyan')
, Error = require('http-errors')
, Stream = require('stream')
, utils = require('./utils')
@ -49,7 +50,7 @@ module.exports.setup = function(logs) {
}
}
} else {
throw new Error('wrong target type for a log')
throw Error('wrong target type for a log')
}
if (target.level === 'http') target.level = 35

@ -1,6 +1,6 @@
var crypto = require('crypto')
, Error = require('http-errors')
, utils = require('./utils')
, UError = require('./error').UserError
, Logger = require('./logger')
module.exports.validate_name = function validate_name(req, res, next, value, name) {
@ -10,20 +10,15 @@ module.exports.validate_name = function validate_name(req, res, next, value, nam
} else if (utils.validate_name(value)) {
next()
} else {
next(new UError({
status: 403,
message: 'invalid ' + name,
}))
next(Error[403]('invalid ' + name))
}
}
module.exports.media = function media(expect) {
return function(req, res, next) {
if (req.headers['content-type'] !== expect) {
next(new UError({
status: 415,
message: 'wrong content-type, expect: '+expect+', got: '+req.headers['content-type'],
}))
next(Error[415]('wrong content-type, expect: ' + expect
+ ', got: '+req.headers['content-type']))
} else {
next()
}
@ -47,10 +42,7 @@ module.exports.anti_loop = function(config) {
for (var i=0; i<arr.length; i++) {
var m = arr[i].match(/\s*(\S+)\s+(\S+)/)
if (m && m[2] === config.server_id) {
return next(new UError({
status: 508,
message: 'loop detected',
}))
return next(Error[508]('loop detected'))
}
}
}

@ -1,6 +1,6 @@
var async = require('async')
, assert = require('assert')
, UError = require('./error').UserError
, Error = require('http-errors')
, Local = require('./local-storage')
, Proxy = require('./up-storage')
, mystreams = require('./streams')
@ -63,10 +63,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
if (err && err.status !== 404) return cb(err)
if (results) {
return cb(new UError({
status: 409,
message: 'this package is already present'
}))
return cb(Error[409]('this package is already present'))
}
cb()
@ -80,10 +77,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
// checking package
if (results) {
return cb(new UError({
status: 409,
message: 'this package is already present'
}))
return cb(Error[409]('this package is already present'))
}
for (var i=0; i<err_results.length; i++) {
@ -91,10 +85,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
// if uplink fails with a status other than 404, we report failure
if (err_results[i][0] != null) {
if (err_results[i][0].status !== 404) {
return cb(new UError({
status: 503,
message: 'one of the uplinks is down, refuse to publish'
}))
return cb(Error[503]('one of the uplinks is down, refuse to publish'))
}
}
}
@ -491,7 +482,7 @@ Storage.prototype._sync_package_with_uplinks = function(name, pkginfo, options,
if (err && err.status === 304)
pkginfo._uplinks[up.upname].fetched = Date.now()
if (err || !up_res) return cb(null, [err || new Error('no data')])
if (err || !up_res) return cb(null, [err || Error('no data')])
try {
utils.validate_metadata(up_res, name)
@ -527,10 +518,9 @@ Storage.prototype._sync_package_with_uplinks = function(name, pkginfo, options,
assert(!err && Array.isArray(uplink_errors))
if (!exists) {
return callback(new UError({
status: 404,
message: 'no such package available'
}), null, uplink_errors)
return callback( Error[404]('no such package available')
, null
, uplink_errors )
}
self.local.update_versions(name, pkginfo, function(err, pkginfo) {

@ -2,7 +2,7 @@ var URL = require('url')
, request = require('request')
, Stream = require('stream')
, zlib = require('zlib')
, UError = require('./error').UserError
, Error = require('http-errors')
, mystreams = require('./streams')
, Logger = require('./logger')
, utils = require('./utils')
@ -101,8 +101,8 @@ Storage.prototype.request = function(options, cb) {
if (!this.status_check()) {
var req = new Stream.Readable()
process.nextTick(function() {
if (typeof(cb) === 'function') cb(new Error('uplink is offline'))
req.emit('error', new Error('uplink is offline'))
if (typeof(cb) === 'function') cb(Error('uplink is offline'))
req.emit('error', Error('uplink is offline'))
})
// preventing 'Uncaught, unspecified "error" event'
req.on('error', function(){})
@ -265,14 +265,11 @@ Storage.prototype.get_package = function(name, options, callback) {
}, function(err, res, body) {
if (err) return callback(err)
if (res.statusCode === 404) {
return callback(new UError({
message: 'package doesn\'t exist on uplink',
status: 404,
}))
return callback(Error[404]("package doesn't exist on uplink"))
}
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
var error = new Error('bad status code: ' + res.statusCode)
error.status = res.statusCode
var error = Error('bad status code: ' + res.statusCode)
error.remoteStatus = res.statusCode
return callback(error)
}
callback(null, body, res.headers.etag)
@ -299,16 +296,10 @@ Storage.prototype.get_url = function(url) {
rstream.on('response', function(res) {
if (res.statusCode === 404) {
return stream.emit('error', new UError({
message: 'file doesn\'t exist on uplink',
status: 404,
}))
return stream.emit('error', Error[404]("file doesn't exist on uplink"))
}
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
return stream.emit('error', new UError({
message: 'bad uplink status code: ' + res.statusCode,
status: 500,
}))
return stream.emit('error', Error('bad uplink status code: ' + res.statusCode))
}
if (res.headers['content-length']) {
expected_length = res.headers['content-length']
@ -327,7 +318,7 @@ Storage.prototype.get_url = function(url) {
rstream.on('end', function(d) {
if (d) current_length += d.length
if (expected_length && current_length != expected_length)
stream.emit('error', new Error('content length mismatch'))
stream.emit('error', Error('content length mismatch'))
})
return stream
}

@ -28,6 +28,7 @@ dependencies:
cookies: '>=0.5.0 <1.0.0-0'
request: '>=2.31.0 <3.0.0-0'
async: '>=0.9.0 <1.0.0-0'
http-errors: '~1.2.0' # ferver
# 2.x and 3.x have the same interface
semver: '>=2.2.1 <4.0.0-0'