Added access rights feature + read access check

This commit is contained in:
NGPixel 2016-10-31 22:44:00 -04:00
parent 09b4d37f4c
commit a05560e9fc
9 changed files with 122 additions and 17 deletions

View File

@ -24,10 +24,14 @@
- [x] Images
- [ ] Files/Documents
- [x] Authentication
- [x] Local
- [x] Microsoft Account
- [x] Google ID
- [x] Facebook
- [x] Strategies
- [x] Local
- [x] Microsoft Account
- [x] Google ID
- [x] Facebook
- [x] Access Rights
- [x] View
- [ ] Edit / Create
- [x] Background Agent (git sync, cache purge, etc.)
- [x] Caching
- [x] Create Entry

File diff suppressed because one or more lines are too long

View File

@ -131,7 +131,13 @@ module.exports = function(passport, appconfig) {
provider: 'local',
email: appconfig.admin,
name: "Administrator",
password: pwd
password: pwd,
rights: [{
role: 'admin',
path: '/',
exact: false,
deny: false
}]
});
}).then(() => {
winston.info('[' + PROCNAME + '][AUTH] Administrator account created successfully!');

57
libs/rights.js Normal file
View File

@ -0,0 +1,57 @@
"use strict";
const _ = require('lodash');
/**
* Rights
*/
module.exports = {
check(req, role) {
let rt = [];
let p = _.chain(req.originalUrl).toLower().trim().value();
// Load User Rights
if(_.isArray(req.user.rights)) {
rt = req.user.rights;
}
// Is admin?
if(_.find(rt, { role: 'admin' })) {
return true;
}
// Check specific role on path
let filteredRights = _.filter(rt, (r) => {
if(r.role === role || (r.role === 'write' && role === 'read')) {
if((!r.exact && _.startsWith(p, r.path)) || (r.exact && p === r.path)) {
return true;
}
}
return false;
});
// Check for deny scenario
let isValid = false;
if(filteredRights.length > 1) {
isValid = !_.chain(filteredRights).sortBy((r) => {
return r.path.length + ((r.deny) ? 0.5 : 0);
}).last().get('deny').value();
} else if(filteredRights.length == 1 && filteredRights[0].deny === false) {
isValid = true;
}
// Deny by default
return isValid;
}
};

View File

@ -19,6 +19,12 @@ module.exports = (req, res, next) => {
return res.redirect('/login');
}
// Check permissions
if(!rights.check(req, 'read')) {
return res.render('error-forbidden');
}
// Set i18n locale
req.i18n.changeLanguage(req.user.lang);

View File

@ -36,7 +36,10 @@ var userSchema = modb.Schema({
},
rights: [{
type: String
role: String,
path: String,
exact: Boolean,
deny: Boolean
}]
},

View File

@ -37,7 +37,7 @@
"bluebird": "^3.4.6",
"body-parser": "^1.15.2",
"cheerio": "^0.22.0",
"child-process-promise": "^2.1.3",
"child-process-promise": "^2.2.0",
"chokidar": "^1.6.0",
"compression": "^1.6.2",
"connect-flash": "^0.1.1",
@ -46,8 +46,8 @@
"cron": "^1.1.1",
"express": "^4.14.0",
"express-brute": "^1.0.0",
"express-brute-mongoose": "0.0.6",
"express-session": "^1.14.1",
"express-brute-mongoose": "0.0.7",
"express-session": "^1.14.2",
"farmhash": "^1.2.1",
"file-type": "^3.8.0",
"filesize.js": "^1.0.2",
@ -58,7 +58,7 @@
"i18next-express-middleware": "^1.0.2",
"i18next-node-fs-backend": "^0.1.2",
"js-yaml": "^3.6.1",
"lodash": "^4.16.4",
"lodash": "^4.16.5",
"markdown-it": "^8.0.0",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^2.5.0",
@ -77,7 +77,7 @@
"passport-google-oauth20": "^1.0.0",
"passport-local": "^1.0.0",
"passport-windowslive": "^1.0.2",
"passport.socketio": "^3.6.2",
"passport.socketio": "^3.7.0",
"pug": "^2.0.0-beta6",
"read-chunk": "^2.0.0",
"remove-markdown": "^0.1.0",

View File

@ -28,6 +28,7 @@ global.git = require('./libs/git').init(appconfig, false);
global.lang = require('i18next');
global.mark = require('./libs/markdown');
global.upl = require('./libs/uploads').init(appconfig);
global.rights = require('./libs/rights');
// ----------------------------------------
// Load modules
@ -217,9 +218,6 @@ io.use(passportSocketIo.authorize({
accept();
},
fail: (data, message, error, accept) => {
if(error) {
throw new Error(message);
}
return accept(new Error(message));
}
}));

31
views/error-forbidden.pug Normal file
View File

@ -0,0 +1,31 @@
doctype html
html
head
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(charset='UTF-8')
meta(name='viewport', content='width=device-width, initial-scale=1')
meta(name='theme-color', content='#009688')
meta(name='msapplication-TileColor', content='#009688')
meta(name='msapplication-TileImage', content='/favicons/ms-icon-144x144.png')
title= appconfig.title
// Favicon
each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href='/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
link(rel='icon', type='image/png', sizes='192x192', href='/favicons/android-icon-192x192.png')
each favsize in [32, 96, 16]
link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
link(rel='manifest', href='/manifest.json')
// CSS
link(type='text/css', rel='stylesheet', href='/css/libs.css')
link(type='text/css', rel='stylesheet', href='/css/app.css')
body(class='server-error')
section.hero.is-danger.is-fullheight
.hero-body
.container
a(href='/'): img(src='/favicons/android-icon-96x96.png')
h1.title(style={ 'margin-top': '30px'}) Forbidden
h2.subtitle(style={ 'margin-bottom': '50px'}) Sorry, you don't have the necessary permissions to access this page.
a.button.is-dark.is-inverted(href='/') Go Home