From 78413535532e91a603144c00e93cd33a6bd27ce4 Mon Sep 17 00:00:00 2001 From: Andrew Aladjev Date: Mon, 18 Jul 2016 20:43:56 +0300 Subject: [PATCH 1/3] fixing sample web app --- sample/app/guid.js | 9 ++++++- sample/app/validate.js | 10 +++---- sample/pouchdb.js | 54 ++++++++++++++++---------------------- sample/routes/replicate.js | 1 + sample/routes/validate.js | 5 ++-- sample/server.js | 42 ++++++++++++++++++++++------- sample/views/validate.ejs | 3 ++- 7 files changed, 73 insertions(+), 51 deletions(-) diff --git a/sample/app/guid.js b/sample/app/guid.js index d0b21e4..361c271 100644 --- a/sample/app/guid.js +++ b/sample/app/guid.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = function guid() { +function guid() { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) @@ -9,3 +9,10 @@ module.exports = function guid() { return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } + +if (typeof module != 'undefined') { + module.exports = guid; +} +if (typeof angular != 'undefined') { + angular.module('myApp').constant('$guid', guid); +} diff --git a/sample/app/validate.js b/sample/app/validate.js index 70459e4..c5ec404 100644 --- a/sample/app/validate.js +++ b/sample/app/validate.js @@ -1,6 +1,6 @@ var myApp = angular.module('myApp', []); -myApp.controller('ValidateController', ['$scope', '$http', function ($scope, $http) { +myApp.controller('ValidateController', ['$scope', '$http', '$guid', function ($scope, $http, $guid) { $scope.greeting = 'Welcome to SALTI!'; $scope.errors = 'no errors'; $scope.messages = 'no messages'; @@ -26,10 +26,8 @@ myApp.controller('ValidateController', ['$scope', '$http', function ($scope, $ht }); } + function genDoc(){ + return JSON.stringify({ _id: $guid(), 'type': 'foobar' }) + } }]); - -function genDoc(){ - return JSON.stringify({ _id: guid(), "type": "foobar" }) -} - diff --git a/sample/pouchdb.js b/sample/pouchdb.js index d55316e..78bb53b 100644 --- a/sample/pouchdb.js +++ b/sample/pouchdb.js @@ -1,35 +1,25 @@ "use strict"; module.exports = [{ - "path": "/_validate", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }, - { - "path": "/foobarrepl", - "roles": [{ - "role": "public", - "verbs": ["GET", "POST", "PUT"] - }] - }, - { - "path": "/foobarrepl/_local", - "roles": [{ - "role": "public", - "verbs": ["GET", "POST", "PUT"] - }] - }, { - "path": "/_session", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, { - "path": "/_all_dbs", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }]; + 'role': 'public', + 'paths': [{ + 'path': '/_validate', + 'verbs': ['GET', 'PUT', 'POST'] + },{ + 'path': '/foobarrepl', + 'verbs': ['GET', 'POST', 'PUT'] + },{ + 'path': '/foobarrepl/_local', + 'verbs': ['GET', 'POST', 'PUT'] + },{ + 'path': '/_session', + 'verbs': ['GET'] + },{ + 'path': '/_all_dbs', + 'verbs': ['GET', 'PUT', 'POST'] + },{ + 'path': '/_utils', + 'verbs': ['GET'] + } + ] +}]; diff --git a/sample/routes/replicate.js b/sample/routes/replicate.js index 6c5f536..356b26b 100644 --- a/sample/routes/replicate.js +++ b/sample/routes/replicate.js @@ -2,6 +2,7 @@ var express = require('express'); var router = express.Router(); var debug = require('debug')('thalisalti:replicate'); var http = require('http'); +var guid = require('../app/guid'); var pouchDBBase = require('pouchdb'); var PouchDB = pouchDBBase.defaults({ prefix: './db/' }); diff --git a/sample/routes/validate.js b/sample/routes/validate.js index 117ecd1..2e17ba2 100644 --- a/sample/routes/validate.js +++ b/sample/routes/validate.js @@ -8,7 +8,7 @@ var pbsetup = PouchDB.defaults({ prefix: './db/' }); var pouchDbOptions = { ajax : { agentOptions:{ rejectUnauthorized: false - } + } }}; @@ -36,8 +36,9 @@ router.post('/', function (req, res, next) { } var remoteDB = new PouchDB('http://localhost:3001/_validate', pouchDbOptions) - + debugger remoteDB.put(theDoc, function (err, response) { + console.trace(); if (err) { debug(err); diff --git a/sample/server.js b/sample/server.js index 785c753..8820813 100644 --- a/sample/server.js +++ b/sample/server.js @@ -2,20 +2,26 @@ 'use strict'; var express = require('express'), + https = require('https'), http = require('http'), + fs = require('fs'), app = express(), PouchDB = require('pouchdb'), router = express.Router(), debug = require('debug')('thalisalti:express'); - -//this is our sample UI site on port http://localhost:3000 +//this is our sample UI site on port https://localhost:3000 // the 2 express apps: var webApp = require('./app'); var webAppPort = normalizePort(process.env.PORT || '3000'); +var serverCommonOptions = { + key: loadPEM('key'), + cert: loadPEM('key-cert') +}; + webApp.set('port', webAppPort); -var webServer = http.createServer(webApp); +var webServer = https.createServer(serverCommonOptions, webApp); webServer.listen(webAppPort, function () { debug('webServer is listening on port %s', webAppPort); }); @@ -33,8 +39,15 @@ var opts = { var acllib = require('../lib/index'); var acl = require('./pouchdb'); +//mocker.. +router.all('*', function(req, res, next) { + req.connection.pskRole = 'public'; + next(); +}); //Norml middleware usage.. -router.all('*', acllib(acl)); +router.all('*', acllib('db', acl, function (thaliId) { + debug('thaliId %s', thaliId); +})); var pouchApp = require('express-pouchdb')(pbsetup, opts); @@ -44,6 +57,17 @@ app.use('/', router); app.listen(pouchPort); +// various utility functions... + +// cert/pem loaders +function filenamePEM(n) { + return require('path').join('./', n + '.pem'); +} + +function loadPEM(n) { + return fs.readFileSync(filenamePEM(n)); +} + function normalizePort(val) { var port = parseInt(val, 10); @@ -65,18 +89,18 @@ function onError(error, parent) { throw error; } - // var bind = typeof port === 'string' - // ? 'Pipe ' + port - // : 'Port ' + port; + var bind = typeof error.port === 'string' + ? 'Pipe ' + error.port + : 'Port ' + error.port; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - console.error('port requires elevated privileges'); + console.error(bind + ' requires elevated privileges'); process.exit(1); break; case 'EADDRINUSE': - console.error('port is already in use'); + console.error(bind + ' is already in use'); process.exit(1); break; default: diff --git a/sample/views/validate.ejs b/sample/views/validate.ejs index effb3d1..4a2c4bb 100644 --- a/sample/views/validate.ejs +++ b/sample/views/validate.ejs @@ -41,6 +41,7 @@ + - \ No newline at end of file + From e20e201419c7876f49158518b1540a35af470954 Mon Sep 17 00:00:00 2001 From: Andrew Aladjev Date: Wed, 20 Jul 2016 15:09:10 +0300 Subject: [PATCH 2/3] fixed acl schema, added strip trailing slash function and its test, fixed sample, removed acl-example.js --- .gitignore | 1 + lib/acl-schema.json | 26 ++++---- lib/index.js | 74 +++++++++++++-------- package.json | 1 + sample/acl-example.js | 68 ++++++++++---------- sample/db/.gitkeep | 0 sample/fauxton.js | 91 -------------------------- sample/pouchdb.js | 99 ++++++++++++++++++++++------ sample/routes/replicate.js | 2 +- sample/routes/validate.js | 31 ++++----- sample/views/replicate.ejs | 4 +- test/test-trailing-slash.js | 124 ++++++++++++++++++++++++++++++++++++ 12 files changed, 321 insertions(+), 200 deletions(-) create mode 100644 sample/db/.gitkeep delete mode 100644 sample/fauxton.js create mode 100644 test/test-trailing-slash.js diff --git a/.gitignore b/.gitignore index 2675515..6daafc5 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ browse.VC.db # pouchdb db/* sample/db/* +!sample/db/.gitkeep diff --git a/lib/acl-schema.json b/lib/acl-schema.json index e402caf..2a33f58 100644 --- a/lib/acl-schema.json +++ b/lib/acl-schema.json @@ -3,30 +3,32 @@ "id": "/", "type": "array", "items": { - "id": "1", + "id": "items", "type": "object", "properties": { - "path": { - "id": "path", - "type": "string" + "role": { + "id": "role", + "type": "string", + "default": "public" }, - "roles": { - "id": "roles", + "paths": { + "id": "paths", "type": "array", "items": { - "id": "1", + "id": "items", "type": "object", "properties": { - "role": { - "id": "role", - "type": "string" + "path": { + "id": "path", + "type": "string", + "default": "/" }, "verbs": { "id": "verbs", "type": "array", "items": { - "id": "0", - "type": "string" + "type": "string", + "default": "GET" } } } diff --git a/lib/index.js b/lib/index.js index 7bca607..724ef1d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,7 @@ /*jshint -W121 */ 'use strict'; var assert = require('assert'); +var objectAssign = require('object-assign'); var debug = require('debug')('thalisalti:acl'); var fast = require('./indexOf'); @@ -8,9 +9,23 @@ var fast = require('./indexOf'); var NOTFOUND = -1; var IDTOKEN = '{:id}'; +var defaults = { + stripTrailingSlash: true +}; + + +function stripTrailingSlash(path) { + // single slash '/' is a valid path, it should be ignored + var lastIndex = path.length - 1; + if (lastIndex > 0 && path[lastIndex] === '/') { + debug('ignoring trailing slash for %s', path); + return path.substring(0, lastIndex); + } + return path; +} /** Gets the req object, collection of paths, and path to validate */ -function lookupPathVerb(req, paths, lookupPath) { +function lookupPathVerb(req, paths, path, lookupPath) { var pathExists = fast.indexOf(paths, lookupPath, 'path'); if (NOTFOUND === pathExists) { @@ -21,7 +36,7 @@ function lookupPathVerb(req, paths, lookupPath) { var verbExists = fast.indexOf(verbs, req.method); if (NOTFOUND === verbExists) { - debug('verb and path not found: req.Path: %s lookupPath: %s', req.path, lookupPath); + debug('verb and path not found: req.Path: %s lookupPath: %s', path, lookupPath); return false; } @@ -50,7 +65,7 @@ if (!String.prototype.startsWith) { -module.exports = function(dbname, inAcl, callback) { +module.exports = function(dbname, inAcl, callback, options) { if (!dbname || typeof dbname !== 'string') { throw new Error('invalid configuration - missing dbname'); @@ -59,13 +74,15 @@ module.exports = function(dbname, inAcl, callback) { if (!inAcl || !(inAcl instanceof Array)) { throw new Error('invalid configuration - inAcl is not an array'); } - + if(!callback || typeof callback !== 'function'){ throw new Error('invalid configuration - callback is NOT a function'); } + options = objectAssign({}, defaults, options); + var thaliPrefix = '/' + dbname + '/_local/thali_'; - + var acl = JSON.parse(JSON.stringify(inAcl).replace(/{:db}/g, dbname)); //path.role.verb @@ -75,8 +92,13 @@ module.exports = function(dbname, inAcl, callback) { var okPathVerb = false; debug('method: %s url: %s path: %s', req.method, req.url, req.path); + var path = req.path; + if (options.stripTrailingSlash) { + path = stripTrailingSlash(req.path); + } + if (!req.connection.pskRole) { - debug('unauthorized0: no role: %s ', req.path); + debug('unauthorized0: no role: %s ', path); return res.status(401).send(msg401); } @@ -86,14 +108,14 @@ module.exports = function(dbname, inAcl, callback) { var roleExists = fast.indexOf(acl, pskRole, 'role'); if (NOTFOUND === roleExists) { - debug('unauthorized1: %s : %s', pskRole, req.path); + debug('unauthorized1: %s : %s', pskRole, path); return res.status(401).send(msg401); } var paths = acl[roleExists].paths; //here we're doing a strict simple RAW path lookup on ACLs - var rawExists = fast.indexOf(paths, req.path, 'path'); + var rawExists = fast.indexOf(paths, path, 'path'); if (NOTFOUND !== rawExists) { //verbs are just an array of strings @@ -101,7 +123,7 @@ module.exports = function(dbname, inAcl, callback) { var verbExists = fast.indexOf(verbs, req.method); if (NOTFOUND === verbExists) { - debug('unauthorized3: %s : %s', pskRole, req.path); + debug('unauthorized3: %s : %s', pskRole, path); return res.status(401).send(msg401); } else { @@ -112,21 +134,21 @@ module.exports = function(dbname, inAcl, callback) { else { //this section deals with /db/id, /db/_local/id, and /db/id/attachment stuff. - var pathParts = req.path.split('/'); + var pathParts = path.split('/'); if (pathParts[0] !== '') { //sanity check.. the first element should always be empty. - debug('unauthorized4.0: %s : %s', pskRole, req.path); + debug('unauthorized4.0: %s : %s', pskRole, path); return res.status(401).send(msg401); } - var lookupPath = req.path.substring(0, req.path.lastIndexOf('/') + 1) + IDTOKEN; + var lookupPath = path.substring(0, path.lastIndexOf('/') + 1) + IDTOKEN; if (pathParts.length === 3) { //we have just a path and ID //do a search on /db/id and bail if NO GOOD - if (!lookupPathVerb(req, paths, lookupPath)) { - debug('unauthorized4.1: req.Path: %s req.path: %s', req.path, lookupPath); + if (!lookupPathVerb(req, paths, path, lookupPath)) { + debug('unauthorized4.1: req.Path: %s req.path: %s', path, lookupPath); return res.status(401).send(msg401); } else { @@ -138,19 +160,19 @@ module.exports = function(dbname, inAcl, callback) { //is this a /thali_ one? //TODO: - var isThaliPrefix = req.path.startsWith(thaliPrefix); - if (isThaliPrefix && ! lookupPathVerb(req, paths, thaliPrefix + IDTOKEN)){ - debug('unauthorized4.thaliPrefix: req.Path: %s path: %s', req.path, thaliPrefix); - return res.status(401).send(msg401); + var isThaliPrefix = path.startsWith(thaliPrefix); + if (isThaliPrefix && ! lookupPathVerb(req, paths, path, thaliPrefix + IDTOKEN)){ + debug('unauthorized4.thaliPrefix: req.Path: %s path: %s', path, thaliPrefix); + return res.status(401).send(msg401); } - - if (isThaliPrefix && !getThaliId(req.path, dbname, callback)) { - debug('unauthorized4.thaliCallback: req.Path: %s path: %s', req.path, thaliPrefix); + + if (isThaliPrefix && !getThaliId(path, dbname, callback)) { + debug('unauthorized4.thaliCallback: req.Path: %s path: %s', path, thaliPrefix); return res.status(401).send(msg401); } - if (!lookupPathVerb(req, paths, lookupPath)) { - debug('unauthorized4.2: req.Path: %s req.path: %s', req.path, lookupPath); + if (!lookupPathVerb(req, paths, path, lookupPath)) { + debug('unauthorized4.2: req.Path: %s req.path: %s', path, lookupPath); return res.status(401).send(msg401); } else { @@ -161,8 +183,8 @@ module.exports = function(dbname, inAcl, callback) { else if (pathParts.length === 4 && pathParts[3] === 'attachment') { var attachmentPath = '/' + pathParts[1] + '/' + IDTOKEN + '/attachment'; - if (!lookupPathVerb(req, paths, attachmentPath)) { - debug('unauthorized4.3: req.Path: %s req.path: %s', req.path, attachmentPath); + if (!lookupPathVerb(req, paths, path, attachmentPath)) { + debug('unauthorized4.3: req.Path: %s req.path: %s', path, attachmentPath); return res.status(401).send(msg401); } else { @@ -170,7 +192,7 @@ module.exports = function(dbname, inAcl, callback) { } } else { - debug('unauthorized5: %s : %s', pskRole, req.path); + debug('unauthorized5: %s : %s', pskRole, path); return res.status(401).send(msg401); } } diff --git a/package.json b/package.json index 6de3ba4..36f1293 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "homepage": "https://github.com/thaliproject/salti#readme", "dependencies": { + "object-assign": "^4.1.0", "debug": "^2.2.0" }, "devDependencies": { diff --git a/sample/acl-example.js b/sample/acl-example.js index f413e87..31d4172 100644 --- a/sample/acl-example.js +++ b/sample/acl-example.js @@ -2,36 +2,40 @@ //go here with the schema and build away... //http://jeremydorn.com/json-editor/ -//http://bit.ly/1Qs3l66 -//ideally - 1 less check if path has a trailing /.. -// ie. /foo/ is faster than /bar - -module.exports = [{ - "path": "/", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }, { - "role": "user", - "verbs": ["GET"] - }] -}, { - "path": "/foo/", - "roles": [{ - "role": "public", - "verbs": ["GET", "POST"] - }, { - "role": "user", - "verbs": ["GET", "PUR", "POST"] - }] -}, { - "path": "/bar", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }, { - "role": "user", - "verbs": ["GET"] - }] -}]; +module.exports = [ + { + 'role': 'public', + 'paths': [ + { + 'path': '/', + 'verbs': ['GET'] + }, + { + 'path': '/foo', + 'verbs': ['GET', 'POST'] + }, + { + 'path': '/bar', + 'verbs': ['GET'] + } + ] + }, + { + 'role': 'user', + 'paths': [ + { + 'path': '/', + 'verbs': ['GET'] + }, + { + 'path': '/foo', + 'verbs': ['GET', 'PUT', 'POST'] + }, + { + 'path': '/bar', + 'verbs': ['GET'] + } + ] + } +]; diff --git a/sample/db/.gitkeep b/sample/db/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sample/fauxton.js b/sample/fauxton.js deleted file mode 100644 index 6585b5b..0000000 --- a/sample/fauxton.js +++ /dev/null @@ -1,91 +0,0 @@ -"use strict"; - -module.exports = [{ - "path": "/_utils", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }, { - "role": "user", - "verbs": ["GET"] - }] -}, - { - "path": "/db", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, - { - "path": "/_utils/css", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, - { - "path": "/_utils/js", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, { - "path": "/_utils/img", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, { - "path": "/_session", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, { - "path": "/_utils/fonts", - "roles": [{ - "role": "public", - "verbs": ["GET"] - }] - }, { - "path": "/foobardb", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }, { - "path": "/_all_dbs", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }, { - "path": "/_utils/js/zeroclipboard", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }, - { - "path": "/_uuids", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }, - { - "path": "/favicon.ico", - "roles": [{ - "role": "public", - "verbs": ["GET", "PUT", "POST"] - }] - }]; - - -///_uuids - -///_all_dbs -// /_utils/js/zeroclipboard/Z -//db_utils -//db/css/ diff --git a/sample/pouchdb.js b/sample/pouchdb.js index 78bb53b..6c669fa 100644 --- a/sample/pouchdb.js +++ b/sample/pouchdb.js @@ -1,25 +1,86 @@ "use strict"; module.exports = [{ - 'role': 'public', - 'paths': [{ - 'path': '/_validate', - 'verbs': ['GET', 'PUT', 'POST'] - },{ - 'path': '/foobarrepl', - 'verbs': ['GET', 'POST', 'PUT'] - },{ - 'path': '/foobarrepl/_local', - 'verbs': ['GET', 'POST', 'PUT'] - },{ - 'path': '/_session', - 'verbs': ['GET'] - },{ - 'path': '/_all_dbs', - 'verbs': ['GET', 'PUT', 'POST'] - },{ - 'path': '/_utils', - 'verbs': ['GET'] + "role": "public", + "paths": [ + { + "path": "/_validate", + "verbs": ["GET"] + }, + { + "path": "/_validate/_bulk_docs", + "verbs": ["POST"] + }, + { + "path": "/_validate/_all_docs", + "verbs": ["GET"] + }, + + { + "path": "/foobarrepl", + "verbs": ["GET"] + }, + { + "path": "/foobarrepl/_local/{:id}", + "verbs": ["GET"] + }, + { + "path": "/foobarrepl/_bulk_docs", + "verbs": ["POST"] + }, + { + "path": "/foobarrepl/_revs_diff", + "verbs": ["POST"] + }, + { + "path": "/foobarrepl/_all_docs", + "verbs": ["GET"] + }, + + { + "path": "/foobar", + "verbs": ["GET"] + }, + { + "path": "/foobar/_all_docs", + "verbs": ["GET"] + }, + + { + "path": "/_utils", + "verbs": ["GET"] + }, + { + "path": "/_utils/css/index-6688cd4426ead40b085270f8cb007530.css", + "verbs": ["GET"] + }, + { + "path": "/_utils/js/require-34a7e370ea98389d118cc328682c0939.js", + "verbs": ["GET"] + }, + { + "path": "/_utils/img/pouchdb-site.png", + "verbs": ["GET"] + }, + { + "path": "/_utils/fonts/fontawesome-webfont.woff", + "verbs": ["GET"] + }, + { + "path": "/_utils/fonts/fauxtonicon.woff", + "verbs": ["GET"] + }, + { + "path": "/favicon.ico", + "verbs": ["GET"] + }, + { + "path": "/_all_dbs", + "verbs": ["GET"] + }, + { + "path": "/_session", + "verbs": ["GET"] } ] }]; diff --git a/sample/routes/replicate.js b/sample/routes/replicate.js index 356b26b..e4d9468 100644 --- a/sample/routes/replicate.js +++ b/sample/routes/replicate.js @@ -20,7 +20,7 @@ router.post('/', function (req, res, next) { var pouchDbOptions = { ajax : { agentOptions:{ rejectUnauthorized: false - } + } }}; var remoteDB = new PouchDB('http://localhost:3001/foobarrepl', pouchDbOptions) diff --git a/sample/routes/validate.js b/sample/routes/validate.js index 2e17ba2..051dc5f 100644 --- a/sample/routes/validate.js +++ b/sample/routes/validate.js @@ -5,10 +5,10 @@ var router = express.Router(); var PouchDB = require('pouchdb'); var pbsetup = PouchDB.defaults({ prefix: './db/' }); -var pouchDbOptions = { ajax : { - agentOptions:{ - rejectUnauthorized: false - } +var pouchDbOptions = { ajax: { + agentOptions: { + rejectUnauthorized: false + } }}; @@ -22,31 +22,28 @@ router.post('/', function (req, res, next) { debug('invalid request on post - missing doc'); return res.status(400).send ({ error: 'invalid request - missing doc'}); } - + if (! req.body.secret) { debug('no secret provided - continuing...'); } - + var theDoc = JSON.parse (req.body.doc); - + debug('PUT a newdoc: ' + JSON.stringify(theDoc)); - + pouchDbOptions.ajax.headers = { 'User-Agent': 'request' - } - - var remoteDB = new PouchDB('http://localhost:3001/_validate', pouchDbOptions) - debugger + }; + + var remoteDB = new PouchDB('http://localhost:3001/_validate', pouchDbOptions); remoteDB.put(theDoc, function (err, response) { - console.trace(); if (err) { debug(err); - - return res.status(500).send( { error: err, message: 'failed to put new doc' }); + return res.status(500).send({ error: err, message: 'failed to put new doc' }); } - return res.status(200).send( response ); + return res.status(200).send(response); }); -}) +}); module.exports = router; diff --git a/sample/views/replicate.ejs b/sample/views/replicate.ejs index 7af808f..6969d77 100644 --- a/sample/views/replicate.ejs +++ b/sample/views/replicate.ejs @@ -6,7 +6,7 @@

Replication

-
View Fauxton Utils
+
View Fauxton Utils
Click the below to start an on-demand replication...
@@ -21,4 +21,4 @@
- \ No newline at end of file + diff --git a/test/test-trailing-slash.js b/test/test-trailing-slash.js new file mode 100644 index 0000000..d2e524f --- /dev/null +++ b/test/test-trailing-slash.js @@ -0,0 +1,124 @@ +'use strict'; + +var request = require('supertest'), + express = require('express'), + fspath = require('path'), + colors = require('colors'), + assert = require('assert'); + +var lib = require(fspath.join(__dirname, '../lib/index')); + +function genericHandlers(router) { + var handlers = require('./handlers2'); + router.get('*', handlers.get); + return router; +} + +var acl = [{ + 'role': 'user', + 'paths': [ + { + 'path': '/', + 'verbs': ['GET'] + }, + { + 'path': '/foo', + 'verbs': ['GET'] + }, + { + 'path': '/bar/', + 'verbs': ['GET'] + } + ] +}]; + +describe('test-trailing-slash.js - should let all through', function() { + describe('strip trailing slash - true', function() { + var app, router; + app = express(); + router = express.Router(); + + before(function() { + router.all('*', function(req, res, next) { + req.connection.pskRole = 'user'; + next(); + }) + router.all('*', lib('foobar', acl, function(){}, { stripTrailingSlash: true })); + app.use('/', genericHandlers(router)); + }) + it('/ should be 200', function(done) { + request(app) + .get('/') + .expect(200, done); + }) + it('/\/ should be 200', function(done) { + request(app) + .get('/\/') + .expect(200, done); + }) + it('/foo should be 200', function(done) { + request(app) + .get('/foo') + .expect(200, done); + }) + it('/foo/ should be 200', function(done) { + request(app) + .get('/foo/') + .expect(200, done); + }) + it('/bar should be 401', function(done) { + request(app) + .get('/bar') + .expect(401, done); + }) + it('/bar/ should be 401', function(done) { + request(app) + .get('/bar/') + .expect(401, done); + }) + }); + describe('strip trailing slash - false', function() { + var app, router; + app = express(); + router = express.Router(); + + before(function() { + router.all('*', function(req, res, next) { + req.connection.pskRole = 'user'; + next(); + }) + router.all('*', lib('foobar', acl, function(){}, { stripTrailingSlash: false })); + app.use('/', genericHandlers(router)); + }) + it('/ should be 200', function(done) { + request(app) + .get('/') + .expect(200, done); + }) + it('/\/ should be 401', function(done) { + request(app) + .get('/\/') + .expect(401, done); + }) + it('/foo should be 200', function(done) { + request(app) + .get('/foo') + .expect(200, done); + }) + it('/foo/ should be 401', function(done) { + request(app) + .get('/foo/') + .expect(401, done); + }) + it('/bar should be 401', function(done) { + request(app) + .get('/bar') + .expect(401, done); + }) + it('/bar/ should be 200', function(done) { + request(app) + .get('/bar/') + .expect(200, done); + }) + }); +}); From 8bcfb3fc4fd2fe04c7e03aeff99f4396ba3f1fa9 Mon Sep 17 00:00:00 2001 From: Andrew Aladjev Date: Thu, 21 Jul 2016 12:51:40 +0300 Subject: [PATCH 3/3] removed key, added auto creating db folder, added test for urlencoded slash --- .gitignore | 1 - sample/db/.gitkeep | 0 sample/pouchdb.js | 20 ++++++++++---------- sample/server.js | 27 ++++++++------------------- test/test-trailing-slash.js | 30 ++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 30 deletions(-) delete mode 100644 sample/db/.gitkeep diff --git a/.gitignore b/.gitignore index 6daafc5..2675515 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,3 @@ browse.VC.db # pouchdb db/* sample/db/* -!sample/db/.gitkeep diff --git a/sample/db/.gitkeep b/sample/db/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/sample/pouchdb.js b/sample/pouchdb.js index 6c669fa..e5401e4 100644 --- a/sample/pouchdb.js +++ b/sample/pouchdb.js @@ -5,45 +5,45 @@ module.exports = [{ "paths": [ { "path": "/_validate", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/_validate/_bulk_docs", - "verbs": ["POST"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/_validate/_all_docs", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobarrepl", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobarrepl/_local/{:id}", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobarrepl/_bulk_docs", - "verbs": ["POST"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobarrepl/_revs_diff", - "verbs": ["POST"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobarrepl/_all_docs", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobar", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { "path": "/foobar/_all_docs", - "verbs": ["GET"] + "verbs": ["GET", "POST", "PUT"] }, { diff --git a/sample/server.js b/sample/server.js index 8820813..543c6b6 100644 --- a/sample/server.js +++ b/sample/server.js @@ -2,7 +2,6 @@ 'use strict'; var express = require('express'), - https = require('https'), http = require('http'), fs = require('fs'), app = express(), @@ -10,24 +9,23 @@ var express = require('express'), router = express.Router(), debug = require('debug')('thalisalti:express'); -//this is our sample UI site on port https://localhost:3000 +//this is our sample UI site on port http://localhost:3000 // the 2 express apps: var webApp = require('./app'); var webAppPort = normalizePort(process.env.PORT || '3000'); -var serverCommonOptions = { - key: loadPEM('key'), - cert: loadPEM('key-cert') -}; - webApp.set('port', webAppPort); -var webServer = https.createServer(serverCommonOptions, webApp); +var webServer = http.createServer(webApp); webServer.listen(webAppPort, function () { debug('webServer is listening on port %s', webAppPort); }); webServer.on('error', onError); -var pbsetup = PouchDB.defaults({ prefix: './db/' }); +var pouchDBName = 'db'; +if (! fs.existsSync('./' + pouchDBName)){ + fs.mkdirSync('./' + pouchDBName); +} +var pbsetup = PouchDB.defaults({ prefix: './' + pouchDBName + '/' }); var pouchPort = normalizePort(process.env.PORT2 || '3001'); var opts = { @@ -45,7 +43,7 @@ router.all('*', function(req, res, next) { next(); }); //Norml middleware usage.. -router.all('*', acllib('db', acl, function (thaliId) { +router.all('*', acllib(pouchDBName, acl, function (thaliId) { debug('thaliId %s', thaliId); })); @@ -59,15 +57,6 @@ app.listen(pouchPort); // various utility functions... -// cert/pem loaders -function filenamePEM(n) { - return require('path').join('./', n + '.pem'); -} - -function loadPEM(n) { - return fs.readFileSync(filenamePEM(n)); -} - function normalizePort(val) { var port = parseInt(val, 10); diff --git a/test/test-trailing-slash.js b/test/test-trailing-slash.js index d2e524f..0c06297 100644 --- a/test/test-trailing-slash.js +++ b/test/test-trailing-slash.js @@ -56,6 +56,11 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/\/') .expect(200, done); }) + it('/%2F should be 401', function(done) { + request(app) + .get('/%2F') + .expect(401, done); + }) it('/foo should be 200', function(done) { request(app) .get('/foo') @@ -66,6 +71,11 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/foo/') .expect(200, done); }) + it('/foo%2F should be 401', function(done) { + request(app) + .get('/foo%2F') + .expect(401, done); + }) it('/bar should be 401', function(done) { request(app) .get('/bar') @@ -76,6 +86,11 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/bar/') .expect(401, done); }) + it('/bar%2F should be 401', function(done) { + request(app) + .get('/bar%2F') + .expect(401, done); + }) }); describe('strip trailing slash - false', function() { var app, router; @@ -100,6 +115,11 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/\/') .expect(401, done); }) + it('/%2F should be 401', function(done) { + request(app) + .get('/%2F') + .expect(401, done); + }) it('/foo should be 200', function(done) { request(app) .get('/foo') @@ -110,6 +130,11 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/foo/') .expect(401, done); }) + it('/foo%2F should be 401', function(done) { + request(app) + .get('/foo%2F') + .expect(401, done); + }) it('/bar should be 401', function(done) { request(app) .get('/bar') @@ -120,5 +145,10 @@ describe('test-trailing-slash.js - should let all through', function() { .get('/bar/') .expect(200, done); }) + it('/bar%2F should be 401', function(done) { + request(app) + .get('/bar%2F') + .expect(401, done); + }) }); });