diff --git a/package.json b/package.json index 2186e0ff..3edec6b7 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,6 @@ "promise-nodify": "^1.0.2", "random-uuid-v4": "0.0.6", "raw-body": "^2.2.0", - "sanitize-filename": "^1.6.1", "serve-favicon": "~2.3.2", "tail": "^1.2.1", "uuid": "^3.0.1", diff --git a/packages/node_modules/express-pouchdb/lib/clean-filename.js b/packages/node_modules/express-pouchdb/lib/clean-filename.js deleted file mode 100644 index 8a216a85..00000000 --- a/packages/node_modules/express-pouchdb/lib/clean-filename.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var sanitize = require('sanitize-filename'); - -function cleanFilename(name) { - // some windows reserved names like 'con' and 'prn' - // return an empty string here, so just wrap them in - // double underscores so it's at least something - return sanitize(name) || sanitize('__' + name + '__'); -} - -module.exports = cleanFilename; \ No newline at end of file diff --git a/packages/node_modules/express-pouchdb/lib/index.js b/packages/node_modules/express-pouchdb/lib/index.js index 551027ae..93298100 100644 --- a/packages/node_modules/express-pouchdb/lib/index.js +++ b/packages/node_modules/express-pouchdb/lib/index.js @@ -62,6 +62,10 @@ modes.fullCouchDB = [ 'validation' ].concat(modes.minimumForPouchDB); + +var internalPaths = [] +var regexFindDbNameInPath = /\/([^/?]*)/ + function toObject(array) { var result = {}; array.forEach(function (item) { @@ -185,6 +189,30 @@ module.exports = function (startPouchDB, opts) { next(); }); + app.use(function (req, res, next) { + var regexFindDbNameInPath = /\/([^/?]*)/ + var dbName = decodeURIComponent(req.url.match(regexFindDbNameInPath)[1]) + + if (!dbName) { + return next(); + } + + // allow internal routes starting with _ like /_all_dbs + if (dbName[0] === '_' && internalPaths.indexOf(dbName) !== -1) { + return next() + } + + // allow valid dbName + if (/^[a-z][a-z0-9_$()+/-]*$/.test(dbName)) { + return next() + } + + utils.sendJSON(res, 400, { + error: 'illegal_database_name', + reason: "Name: '" + dbName + "'. Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter." + }); + }); + // load all modular files [ // order matters in this list! @@ -247,6 +275,15 @@ module.exports = function (startPouchDB, opts) { ); } + // check for internal routes GET /_all_dbs + app._router.stack.forEach(function (stack) { + if (!stack.route) return; + + if (stack.route.path[1] === '_') { + internalPaths.push(stack.route.path.match(regexFindDbNameInPath)[1]); + } + }); + if (startPouchDB) { app.setPouchDB(startPouchDB); } diff --git a/packages/node_modules/express-pouchdb/lib/routes/db.js b/packages/node_modules/express-pouchdb/lib/routes/db.js index 60a9eb6b..c4421266 100644 --- a/packages/node_modules/express-pouchdb/lib/routes/db.js +++ b/packages/node_modules/express-pouchdb/lib/routes/db.js @@ -5,13 +5,12 @@ var startTime = new Date().getTime(), wrappers = require('pouchdb-wrappers'), mkdirp = require('mkdirp'), pathResolve = require('path').resolve, - cleanFilename = require('../clean-filename'), deleteDB = require('../create-or-delete-dbs').deleteDB; module.exports = function (app) { // Create a database. app.put('/:db', utils.jsonParser, function (req, res) { - var name = cleanFilename(req.params.db); + var name = req.params.db; req.PouchDB.allDbs(function (err, dbs) { if (err) { @@ -75,7 +74,7 @@ module.exports = function (app) { }); } - var dbName = cleanFilename(req.params.db); + var dbName = req.params.db; deleteDB(req.PouchDB, dbName, utils.makeOpts(req)).then(function () { utils.sendJSON(res, 200, {ok: true}); }, function (err) { diff --git a/packages/node_modules/express-pouchdb/lib/routes/rewrite.js b/packages/node_modules/express-pouchdb/lib/routes/rewrite.js index c39bbe03..470bf206 100644 --- a/packages/node_modules/express-pouchdb/lib/routes/rewrite.js +++ b/packages/node_modules/express-pouchdb/lib/routes/rewrite.js @@ -2,7 +2,6 @@ var utils = require('../utils'); var REGEX = /\/([^\/]*)\/_design\/([^\/]*)\/_rewrite\/([^?]*)/; -var cleanFilename = require('../clean-filename'); module.exports = function (app) { utils.requires(app, 'routes/db'); @@ -32,7 +31,7 @@ module.exports = function (app) { }); } - var dbName = cleanFilename(decodeURIComponent(match[1])); + var dbName = decodeURIComponent(match[1]); utils.setDBOnReq(dbName, app.dbWrapper, req, res, function () { var query = match[2] + "/" + match[3]; var opts = utils.expressReqToCouchDBReq(req); diff --git a/packages/node_modules/express-pouchdb/lib/utils.js b/packages/node_modules/express-pouchdb/lib/utils.js index e46b3265..db773164 100644 --- a/packages/node_modules/express-pouchdb/lib/utils.js +++ b/packages/node_modules/express-pouchdb/lib/utils.js @@ -4,7 +4,6 @@ var pathResolve = require('path').resolve; var rawBody = require('raw-body'); var Promise = require('pouchdb-promise'); var mkdirp = require('mkdirp'); -var cleanFilename = require('./clean-filename'); var getOrCreateDB = require('./create-or-delete-dbs').getOrCreateDB; //shared middleware @@ -64,7 +63,6 @@ exports.makeOpts = function (req, startOpts) { }; exports.setDBOnReq = function (dbName, dbWrapper, req, res, next) { - dbName = cleanFilename(dbName); req.PouchDB.allDbs(function (err, dbs) { if (err) { return exports.sendError(res, err); diff --git a/tests/express-pouchdb/test.js b/tests/express-pouchdb/test.js index f018b040..6779ce8c 100644 --- a/tests/express-pouchdb/test.js +++ b/tests/express-pouchdb/test.js @@ -260,6 +260,42 @@ describe('redirects', function () { }); }); +describe('invalid databases (#213)', function () { + it('GET /_invalid should return 400 Bad Request', function (done) { + request(coreApp) + .get('/_invalid') + .expect(400) + .expect(function (res) { + var error = JSON.parse(res.text); + if (error.error !== 'illegal_database_name') { + return 'should return "illegal_database_name" error'; + } + if (!/Name: '_invalid'/.test(error.reasons)) { + return 'should return "reason"'; + } + }) + .end(done); + }); + + it('GET /_internal should not return 400 Bad Request', function (done) { + // router handler is never called because it’s already handled by the + // `GET /:db` handler which returns a 404, as no `_internal` db exists + coreApp.get('/_internal', function () {}); + + request(coreApp) + .get('/_internal') + .expect(404) + .end(done); + }); + + it('GET /user%2Fabc4567 should not return 400 Bad Request', function (done) { + request(coreApp) + .get('/user%2Fabc4567') + .expect(404) + .end(done); + }); +}); + function assertException(func, re) { var e; try {