diff --git a/lib/config.js b/lib/config.js index e9add9e..c0be31e 100644 --- a/lib/config.js +++ b/lib/config.js @@ -50,6 +50,14 @@ function Config(config) { } } + if (!self.npm_client_version) { + self.npm_client_version = "*" + } + + if (!self.sentry_dsn) { + self.sentry_dsn = process.env.SENTRY_DSN; + } + var users = {all:true, anonymous:true, 'undefined':true, owner:true, none:true} var check_user_or_uplink = function(arg) { diff --git a/lib/index-api.js b/lib/index-api.js index f91b624..352173e 100644 --- a/lib/index-api.js +++ b/lib/index-api.js @@ -4,6 +4,7 @@ var expressJson5 = require('express-json5') var Error = require('http-errors') var Path = require('path') var Middleware = require('./middleware') +var Semver = require('semver'); var Utils = require('./utils') var expect_json = Middleware.expect_json var match = Middleware.match @@ -22,6 +23,7 @@ module.exports = function(config, auth, storage) { app.param('tag', validate_name) app.param('version', validate_name) app.param('revision', validate_name) + app.param('token', validate_name) // these can't be safely put into express url for some reason app.param('_rev', match(/^-rev$/)) @@ -165,6 +167,11 @@ module.exports = function(config, auth, storage) { var token = (req.body.name && req.body.password) ? auth.aes_encrypt(req.body.name + ':' + req.body.password).toString('base64') : undefined + + if (!Semver.satisfies(req.header('version'), config.npm_client_version) && config.npm_client_version !== '*') { + return next( Error[422]('Your npm version is not accepted. Required: "' + config.npm_client_version + '" Received: "' + req.header('version') + '"') ) + } + if (req.remote_user.name != null) { res.status(201) return next({ @@ -202,6 +209,13 @@ module.exports = function(config, auth, storage) { } }) + app.delete('/-/user/token/:token', function(req, res, next) { + res.status(200) + next({ + ok: 'Logged out', + }) + }) + function tag_package_version(req, res, next) { if (typeof(req.body) !== 'string') return next('route') diff --git a/lib/index.js b/lib/index.js index 20dcfb7..1ebbac5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,7 @@ var express = require('express') var Error = require('http-errors') var compression = require('compression') +var raven = require('raven') var Auth = require('./auth') var Logger = require('./logger') var Config = require('./config') @@ -16,13 +17,20 @@ module.exports = function(config_hash) { var storage = Storage(config) var auth = Auth(config) var app = express() + var ravenClient = config.sentry_dsn ? new raven.Client(config.sentry_dsn) : null + if (ravenClient) { + ravenClient.patchGlobal() + } // run in production mode by default, just in case // it shouldn't make any difference anyway app.set('env', process.env.NODE_ENV || 'production') function error_reporting_middleware(req, res, next) { res.report_error = res.report_error || function(err) { + if (ravenClient) { + raven.middleware.express.errorHandler(ravenClient)(err, req, res, next) + } if (err.status && err.status >= 400 && err.status < 600) { if (!res.headersSent) { res.status(err.status) diff --git a/package.yaml b/package.yaml index 346232f..2b2b15e 100644 --- a/package.yaml +++ b/package.yaml @@ -41,6 +41,7 @@ dependencies: jju: '1.x' JSONStream: '1.x' + raven: '>=0.10.0' mkdirp: '>=0.3.5 <1.0.0-0' sinopia-htpasswd: '>= 0.4.3' http-errors: '>=1.2.0' diff --git a/test/functional/index.js b/test/functional/index.js index c424eaa..201a3d4 100644 --- a/test/functional/index.js +++ b/test/functional/index.js @@ -59,6 +59,7 @@ describe('Func', function() { require('./scoped')() require('./security')() require('./adduser')() + require('./logout')() require('./addtag')() require('./plugins')() diff --git a/test/functional/lib/server.js b/test/functional/lib/server.js index 3e33a9f..e2b733c 100644 --- a/test/functional/lib/server.js +++ b/test/functional/lib/server.js @@ -43,6 +43,13 @@ Server.prototype.auth = function(user, pass) { }) } +Server.prototype.logout = function(token) { + return this.request({ + uri: '/-/user/token/'+encodeURIComponent(token), + method: 'DELETE' + }) +} + Server.prototype.get_package = function(name) { return this.request({ uri: '/'+encodeURIComponent(name), diff --git a/test/functional/logout.js b/test/functional/logout.js new file mode 100644 index 0000000..3729e70 --- /dev/null +++ b/test/functional/logout.js @@ -0,0 +1,11 @@ +module.exports = function() { + var server = process.server + + describe('logout', function() { + it('should log out', function () { + return server.logout('some-token') + .status(200) + .body_ok(/Logged out/) + }) + }) +}