2013-07-02 20:49:24 -05:00
|
|
|
var crypto = require('crypto');
|
2013-06-07 20:16:28 -05:00
|
|
|
var utils = require('./utils');
|
2013-06-14 03:34:29 -05:00
|
|
|
var UError = require('./error').UserError;
|
2013-10-11 00:32:59 -05:00
|
|
|
var Logger = require('./logger');
|
2013-06-07 20:16:28 -05:00
|
|
|
|
|
|
|
module.exports.validate_name = function validate_name(req, res, next, value, name) {
|
|
|
|
if (utils.validate_name(req.params.package)) {
|
|
|
|
req.params.package = String(req.params.package);
|
|
|
|
next();
|
|
|
|
} else {
|
2013-06-14 03:34:29 -05:00
|
|
|
next(new UError({
|
2013-06-07 20:16:28 -05:00
|
|
|
status: 403,
|
|
|
|
msg: 'invalid package name',
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports.media = function media(expect) {
|
|
|
|
return function(req, res, next) {
|
|
|
|
if (req.headers['content-type'] !== expect) {
|
2013-06-14 03:34:29 -05:00
|
|
|
next(new UError({
|
2013-06-07 20:16:28 -05:00
|
|
|
status: 415,
|
2013-09-27 03:55:42 -05:00
|
|
|
msg: 'wrong content-type, expect: '+expect+', got: '+req.headers['content-type'],
|
2013-06-07 20:16:28 -05:00
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports.expect_json = function expect_json(req, res, next) {
|
2013-10-02 13:26:20 -05:00
|
|
|
if (typeof(req.body) !== 'object' || req.body === null) {
|
2013-06-07 20:16:28 -05:00
|
|
|
return next({
|
|
|
|
status: 400,
|
|
|
|
msg: 'can\'t parse incoming json',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports.basic_auth = function basic_auth(callback) {
|
|
|
|
return function(req, res, next) {
|
|
|
|
var authorization = req.headers.authorization;
|
|
|
|
|
|
|
|
if (req.user) return next();
|
2013-06-14 02:10:50 -05:00
|
|
|
if (authorization == null) {
|
2013-10-11 00:32:59 -05:00
|
|
|
req.user = req.remoteUser = undefined;
|
2013-06-14 02:10:50 -05:00
|
|
|
return next();
|
|
|
|
}
|
2013-06-07 20:16:28 -05:00
|
|
|
|
|
|
|
var parts = authorization.split(' ');
|
|
|
|
|
|
|
|
if (parts.length !== 2) return next({
|
|
|
|
status: 400,
|
|
|
|
msg: 'bad authorization header',
|
|
|
|
});
|
|
|
|
|
|
|
|
var scheme = parts[0]
|
|
|
|
, credentials = new Buffer(parts[1], 'base64').toString()
|
|
|
|
, index = credentials.indexOf(':');
|
|
|
|
|
|
|
|
if ('Basic' != scheme || index < 0) return next({
|
|
|
|
status: 400,
|
|
|
|
msg: 'bad authorization header',
|
|
|
|
});
|
|
|
|
|
|
|
|
var user = credentials.slice(0, index)
|
|
|
|
, pass = credentials.slice(index + 1);
|
|
|
|
|
|
|
|
if (callback(user, pass)) {
|
|
|
|
req.user = req.remoteUser = user;
|
|
|
|
next();
|
|
|
|
} else {
|
|
|
|
next({
|
|
|
|
status: 403,
|
|
|
|
msg: 'bad username/password, access denied',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-02 20:49:24 -05:00
|
|
|
// express doesn't do etags with requests <= 1024b
|
|
|
|
// we use md5 here, it works well on 1k+ bytes, but sucks with fewer data
|
|
|
|
// could improve performance using crc32 after benchmarks
|
|
|
|
function md5sum(data) {
|
|
|
|
return crypto.createHash('md5').update(data).digest('hex');
|
|
|
|
}
|
|
|
|
|
2013-10-11 00:32:59 -05:00
|
|
|
module.exports.log_and_etagify = function(req, res, next) {
|
|
|
|
// logger
|
|
|
|
req.log = Logger.logger.child({sub: 'in'});
|
|
|
|
req.log.info({req: req, ip: req.ip}, '@{ip} requested \'@{req.method} @{req.url}\'');
|
|
|
|
|
|
|
|
var bytesin = 0;
|
|
|
|
req.on('data', function(chunk){ bytesin += chunk.length });
|
|
|
|
|
2013-07-02 20:49:24 -05:00
|
|
|
var _send = res.send;
|
|
|
|
res.send = function(body) {
|
2013-10-11 00:32:59 -05:00
|
|
|
var error;
|
2013-07-02 20:49:24 -05:00
|
|
|
if (typeof(body) === 'string' || typeof(body) === 'object') {
|
|
|
|
res.header('Content-type', 'application/json');
|
|
|
|
|
2013-10-11 00:32:59 -05:00
|
|
|
if (typeof(body) === 'object' && body != null) {
|
|
|
|
if (body.error) {
|
|
|
|
error = body.error;
|
|
|
|
}
|
2013-07-02 20:49:24 -05:00
|
|
|
body = JSON.stringify(body, undefined, '\t');
|
|
|
|
}
|
|
|
|
|
|
|
|
res.header('ETag', '"' + md5sum(body) + '"');
|
|
|
|
} else {
|
|
|
|
// send(null), send(204), etc.
|
|
|
|
}
|
2013-10-11 00:32:59 -05:00
|
|
|
|
|
|
|
var msg = '@{status}, user: @{user}, req: \'@{request.method} @{request.url}\'';
|
|
|
|
if (error) {
|
|
|
|
msg += ', error: @{!error}';
|
|
|
|
} else {
|
|
|
|
msg += ', bytes: @{bytes.in}/@{bytes.out}';
|
|
|
|
}
|
|
|
|
req.log.warn({
|
|
|
|
request: {method: req.method, url: req.url},
|
|
|
|
level: 35, // http
|
|
|
|
user: req.user,
|
|
|
|
status: res.statusCode,
|
|
|
|
error: error,
|
|
|
|
bytes: {
|
|
|
|
in: bytesin,
|
|
|
|
out: body.length,
|
|
|
|
}
|
|
|
|
}, msg);
|
|
|
|
|
|
|
|
res.send = _send;
|
|
|
|
res.send(body);
|
2013-07-02 20:49:24 -05:00
|
|
|
};
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|