From 9defe0746fbbf8dbea537ea842f4de260f329896 Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Thu, 26 Apr 2018 15:39:21 +0200 Subject: [PATCH] Implemented authorisation checks and logout --- lib/api/admin.js | 40 ++++++++++++++++++++++++------ lib/api/token.js | 3 +-- lib/authtokens.js | 4 ++- lib/repository/user.js | 39 ++++++++++++++++++++++++++--- public/src/locale/en.js | 1 + public/src/locale/nl.js | 1 + public/src/route/admin/Menu.vue | 34 ++++++++++++++++++++++++- public/src/route/admin/Uploads.vue | 1 - public/src/shared.js | 26 +++++++++++++++++-- 9 files changed, 130 insertions(+), 19 deletions(-) diff --git a/lib/api/admin.js b/lib/api/admin.js index b469417..36210d4 100644 --- a/lib/api/admin.js +++ b/lib/api/admin.js @@ -2,9 +2,10 @@ const config = require('../../config'); const express = require('Express'); const asyncHandler = require('express-async-handler'); const jwt = require('jsonwebtoken'); +const AuthTokens = require('../authtokens'); -async function checkAuthorization(req, res, onVerified) +async function checkAuthorization(req, res, repository, onVerified) { if (!req.headers.authorization || req.headers.authorization.split(' ')[0] !== 'Bearer') { @@ -24,7 +25,16 @@ async function checkAuthorization(req, res, onVerified) } if (decoded.userId) - await onVerified(decoded); + { + var user = await repository.users.getUser(decoded.userId); + if (user === null || !user.active) + { + res.sendStatus(403); + return; + } + else + await onVerified(user); + } else res.sendStatus(400); } @@ -42,12 +52,26 @@ module.exports = (repository) => { var router = express.Router(); + + router.get('/whoami', asyncHandler(async (req, res) => + { + await checkAuthorization(req, res, repository, async (user) => + { + res.send({ + userId: user.userId, + username: user.username, + auth: user.auth + }); + }); + })); + + router.get('/codes', asyncHandler(async (req, res) => { - await checkAuthorization(req, res, async (decoded) => + await checkAuthorization(req, res, repository, async (user) => { - var codes = await repository.codes.getCodes(decoded.userId); - var usernames = await repository.users.getUsernames(); + var codes = await repository.codes.getCodes(user.hasAuth(AuthTokens.ViewAllCodes) ? null : user.userId); + var usernames = await repository.users.getUserNames(); codes.forEach((item) => { @@ -61,10 +85,10 @@ module.exports = (repository) => router.get('/uploads', asyncHandler(async (req, res) => { - await checkAuthorization(req, res, async (decoded) => + await checkAuthorization(req, res, repository, async (user) => { - var files = await repository.uploads.getUploads(decoded.userId); - var usernames = await repository.users.getUsernames(); + var files = await repository.uploads.getUploads(user.hasAuth(AuthTokens.ViewAllUploads) ? null : user.userId); + var usernames = await repository.users.getUserNames(); files.forEach((item) => { diff --git a/lib/api/token.js b/lib/api/token.js index 65ed5e6..0c13a7d 100644 --- a/lib/api/token.js +++ b/lib/api/token.js @@ -47,8 +47,7 @@ module.exports = (repository) => if (user !== null) { jwt.sign({ - userId: user.id, - auth: user.auth + userId: user.id }, config.jwtSecret, (err, token) => { if (err) diff --git a/lib/authtokens.js b/lib/authtokens.js index 3df0234..9aacc6a 100644 --- a/lib/authtokens.js +++ b/lib/authtokens.js @@ -1,5 +1,7 @@ const AuthTokens = { - ManageUsers: 'manageUsers' + ManageUsers: 'manageUsers', + ViewAllUploads: 'viewAllUploads', + ViewAllCodes: 'viewAllCodes' } var all = []; diff --git a/lib/repository/user.js b/lib/repository/user.js index 2f68397..09bf4a9 100644 --- a/lib/repository/user.js +++ b/lib/repository/user.js @@ -10,6 +10,7 @@ class User self.id = values.id || values._id || null; self.username = values.username || null; + self.name = values.name || null; self.password = values.password || null; self.email = values.email || null; self.auth = values.auth || []; @@ -25,6 +26,8 @@ class User hasAuth(token) { + var self = this; + return self.auth.includes(token); } } @@ -58,6 +61,7 @@ class UserRepository { self.addUser(new User({ username: 'admin', + name: 'Administrator', password: 'changeme', auth: AuthTokens.all })) @@ -103,6 +107,32 @@ class UserRepository } + getUser(userId) + { + var self = this; + + return new Promise((resolve, reject) => + { + self.store.findOne({ _id: userId }, (err, doc) => + { + if (err) + { + reject(err); + return; + } + + if (doc == null) + { + resolve(false); + return; + } + + resolve(new User(doc)); + }); + }); + } + + addUser(user) { var self = this; @@ -119,6 +149,7 @@ class UserRepository self.store.insert({ username: user.username, + name: user.name, email: user.email, hashedPassword: hash, created: user.created, @@ -140,7 +171,7 @@ class UserRepository } - getUsernames() + getUserNames() { var self = this; @@ -154,13 +185,13 @@ class UserRepository return; } - var usernames = {}; + var userNames = {}; docs.forEach((dbUser) => { - usernames[dbUser._id] = dbUser.username + userNames[dbUser._id] = dbUser.name }); - resolve(usernames); + resolve(userNames); }); }); } diff --git a/public/src/locale/en.js b/public/src/locale/en.js index 7c26b8d..4bc8fb8 100644 --- a/public/src/locale/en.js +++ b/public/src/locale/en.js @@ -24,6 +24,7 @@ export default { admin: { loading: 'Loading…', empty: 'No data', + logout: 'Logout', login: { usernamePlaceholder: 'Username or e-mail address', diff --git a/public/src/locale/nl.js b/public/src/locale/nl.js index a29a068..9fef1c1 100644 --- a/public/src/locale/nl.js +++ b/public/src/locale/nl.js @@ -24,6 +24,7 @@ export default { admin: { loading: 'Bezig met laden…', empty: 'Geen gegevens', + logout: 'Uitloggen', login: { usernamePlaceholder: 'Gebruikersnaam of e-mail adres', diff --git a/public/src/route/admin/Menu.vue b/public/src/route/admin/Menu.vue index bfd2d72..275b05e 100644 --- a/public/src/route/admin/Menu.vue +++ b/public/src/route/admin/Menu.vue @@ -5,7 +5,11 @@ @@ -13,6 +17,8 @@ @@ -47,6 +69,11 @@ export default { background-color: black; + .pure-menu-horizontal .pure-menu-list + { + width: 100%; + } + .pure-menu-link { color: white; @@ -64,5 +91,10 @@ export default { background-color: #228dd4; } } + + .right + { + float: right; + } } \ No newline at end of file diff --git a/public/src/route/admin/Uploads.vue b/public/src/route/admin/Uploads.vue index 8322f0a..9cca2dc 100644 --- a/public/src/route/admin/Uploads.vue +++ b/public/src/route/admin/Uploads.vue @@ -92,7 +92,6 @@ export default { if (parts.length > 0) ext = parts.pop(); - console.log(ext); return '/images/fileicons/32px/' + ext + '.png'; } } diff --git a/public/src/shared.js b/public/src/shared.js index 20aa07b..055a91b 100644 --- a/public/src/shared.js +++ b/public/src/shared.js @@ -1,10 +1,13 @@ import Vue from 'vue'; import Cookies from 'js-cookie'; +import axios from 'axios'; + export default new Vue({ data() { return { - token: null + token: null, + user: [] } }, @@ -20,7 +23,26 @@ export default new Vue({ watch: { token(newValue) { - Cookies.set('token', newValue); + var self = this; + + if (newValue !== null) + { + Cookies.set('token', newValue); + + axios.get('/admin/whoami', { + headers: { + Authorization: 'Bearer ' + self.token + }}) + .then((response) => + { + self.user = response.data; + }); + } + else + { + Cookies.remove('token'); + self.user = null; + } } } }); \ No newline at end of file