From 0db0caf422716143f1c440137f2cd1736424d9be Mon Sep 17 00:00:00 2001 From: Jack Foltz Date: Wed, 25 Jul 2018 21:34:16 -0400 Subject: [PATCH] Add ping api route and test for valid session --- app/routes/auth.js | 17 ++++++----- app/util/requireAuth.js | 18 ++++++++---- app/util/wrap.js | 3 ++ test/api.js | 75 +++++++++++++++++++++++++++++++++---------------- test/testUtil.js | 29 +++++++++---------- 5 files changed, 89 insertions(+), 53 deletions(-) create mode 100644 app/util/wrap.js diff --git a/app/routes/auth.js b/app/routes/auth.js index cfc9b98..042365b 100644 --- a/app/routes/auth.js +++ b/app/routes/auth.js @@ -8,13 +8,8 @@ const passport = require('passport'); const canonicalizeRequest = require('../util/canonicalize').canonicalizeRequest; const requireAuth = require('../util/requireAuth').requireAuth; +const wrap = require('../util/wrap.js').wrap; -// Wraps an async middleware to catch promise rejection -function asyncMiddleware(fn) { - return (req, res, next) => { - Promise.resolve(fn(req, res, next)).catch(next); - } -} // Wraps passport.authenticate to return a promise function authenticate(req, res, next) { @@ -65,7 +60,7 @@ async function validateInvite(code) { } -router.post('/register', canonicalizeRequest, asyncMiddleware(async (req, res, next) => { +router.post('/register', canonicalizeRequest, wrap(async (req, res, next) => { // Validate the invite and username const [inviteStatus, usernameStatus] = await Promise.all([ @@ -93,7 +88,7 @@ router.post('/register', canonicalizeRequest, asyncMiddleware(async (req, res, n res.status(200).json({'message': 'Registration successful.'}); })); -router.post('/login', canonicalizeRequest, asyncMiddleware(async (req, res, next) => { +router.post('/login', canonicalizeRequest, wrap(async (req, res, next) => { // Authenticate const user = await authenticate(req, res, next); if (!user) @@ -113,7 +108,11 @@ router.get('/logout', function (req, res) { res.status(200).json({'message': 'Logged out.'}); }); -router.get('/session', requireAuth, (req, res, next) => { +router.get('/ping', requireAuth(), (req, res, next) => { + res.status(200).json({'message': 'pong'}); +}); + +router.get('/session', requireAuth(), (req, res, next) => { res.status(200).json({ username: req.session.passport.username, canonicalname: req.session.passport.canonicalname, diff --git a/app/util/requireAuth.js b/app/util/requireAuth.js index feffe2f..38dc150 100644 --- a/app/util/requireAuth.js +++ b/app/util/requireAuth.js @@ -1,7 +1,15 @@ -exports.requireAuth = - (req, res, next) => { - if (req.isAuthenticated()) +const Key = require('../models/Key.js'); +const wrap = require('./wrap.js').wrap; + +const verifyScope = (scope, requiredScope) => scope.indexOf(requiredScope) !== -1; +const getKeyScope = async apikey => (await Key.findOne({key: apikey})).scope; + +exports.requireAuth = scope => + wrap(async (req, res, next) => { + if (req.isAuthenticated() && (scope ? verifyScope(req.session.passport.scope, scope) : true)) + next(); + else if (req.body.apikey && (scope ? verifyScope(getKeyScope(req.body.apikey), scope) : true)) next(); else - res.status(401).json({'message:': 'Unauthorized.'}); - }; \ No newline at end of file + res.status(401).json({'message': 'Unauthorized.'}); + }); \ No newline at end of file diff --git a/app/util/wrap.js b/app/util/wrap.js new file mode 100644 index 0000000..f4dfb5a --- /dev/null +++ b/app/util/wrap.js @@ -0,0 +1,3 @@ +// Wraps an async middleware function to catch promise rejection +exports.wrap = fn => + (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); \ No newline at end of file diff --git a/test/api.js b/test/api.js index a10cf77..980a880 100644 --- a/test/api.js +++ b/test/api.js @@ -3,6 +3,10 @@ process.env.NODE_ENV = 'test'; const app = require('../server'); const server = app.server; +const chai = require('chai'); +chai.use(require('chai-http')); +const should = chai.should(); + const User = require('../app/models/User.js'); const Invite = require('../app/models/Invite.js'); const Upload = require('../app/models/Upload.js'); @@ -123,17 +127,25 @@ describe('Users', function() { describe('/POST login', () => { async function verifySuccessfulLogin(credentials) { - const res = await util.login(credentials); + const agent = chai.request.agent(server); + + const res = await util.login(credentials, agent); res.should.have.status(200); - res.body.should.be.a('object'); - res.body.should.have.property('message').eql('Logged in.'); + res.body.should.have.property('message').equal('Logged in.'); + res.should.have.cookie('session.id'); + + const ping = await util.ping(agent); + ping.should.have.status(200); + ping.body.should.have.property('message').equal('pong'); + + agent.close(); } async function verifyFailedLogin(credentials) { const res = await util.login(credentials); res.should.have.status(401); res.body.should.be.a('object'); - res.body.should.have.property('message').eql('Unauthorized.'); + res.body.should.have.property('message').equal('Unauthorized.'); } describe('0 Valid Request', () => { @@ -159,32 +171,47 @@ describe('Users', function() { }); }); -/*describe('Uploads', function() { - describe('/POST upload', function() { - it('SHOULD accept logged in valid upload', function(done) { - util.verifySuccessfulUpload({ - username: 'TestUser2', - password: 'TestPassword' - }, done); +/*describe('Uploads', () => { + describe('/POST upload', () => { + + + describe('0 Valid Request', () => { + it('SHOULD accept logged in valid upload', function(done) { + util.verifySuccessfulUpload({ + username: 'TestUser2', + password: 'TestPassword' + }, done); + }); }); - it('SHOULD NOT accept unauthenticated valid upload', function(done) { - util.verifyFailedAuthUpload(done); + describe('1 Invalid Authentication', () => { + it('SHOULD NOT accept unauthenticated request', function(done) { + util.verifyFailedAuthUpload(done); + }); }); - it('SHOULD NOT accept invalid permission, valid upload', function(done) { - util.verifyFailedPermissionUpload({ - username: 'TestUser1', - password: 'TestPassword' - }, done); + describe('2 Invalid Permission', () => { + it('SHOULD NOT accept without file.upload permission', function(done) { + util.verifyFailedPermissionUpload({ + username: 'TestUser1', + password: 'TestPassword' + }, done); + }); }); - it('SHOULD NOT accept invalid size upload', function(done) { - util.verifyFailedSizeUpload({ - username: 'TestUser2', - password: 'TestPassword' - }, done); - }) + describe('3 Invalid File', () => { + it('SHOULD NOT accept invalid size', function(done) { + util.verifyFailedSizeUpload({ + username: 'TestUser2', + password: 'TestPassword' + }, done); + }) + }); + + + + + }); });*/ diff --git a/test/testUtil.js b/test/testUtil.js index 6819164..72a3892 100644 --- a/test/testUtil.js +++ b/test/testUtil.js @@ -1,22 +1,15 @@ process.env.NODE_ENV = 'test'; -const User = require('../app/models/User.js'); -const Invite = require('../app/models/Invite.js'); -const Upload = require('../app/models/Upload.js'); - -const chai = require('chai'); -const http = require('chai-http'); -chai.use(http); -const should = chai.should(); - const app = require('../server'); const server = app.server; -//TODO: REMOVE -const async = require('async'); - -const canonicalize = require("../app/util/canonicalize").canonicalize; +const chai = require('chai'); +chai.use(require('chai-http')); +const should = chai.should(); +const User = require('../app/models/User.js'); +const Invite = require('../app/models/Invite.js'); +const Upload = require('../app/models/Upload.js'); //---------------- DATABASE UTIL ----------------// @@ -29,10 +22,11 @@ exports.clearDatabase = async () => //---------------- API ROUTES ----------------// -exports.login = async (credentials) => - chai.request(server) +exports.login = async (credentials, agent) => { + return (agent ? agent : chai.request(server)) .post('/api/auth/login') .send(credentials); +}; exports.createInvite = async (invite) => { if (!invite.code) invite.code = 'code'; @@ -51,6 +45,11 @@ exports.registerUser = async (user) => { .send(user); }; +exports.ping = async (agent) => + (agent ? agent : chai.request(server)) + .get('/api/auth/ping') + .send(); + //---------------- TEST ENTRY CREATION ----------------// exports.createTestInvite = async () =>