diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 00000000..56af04ea --- /dev/null +++ b/dump.rdb @@ -0,0 +1 @@ +REDIS0006ÿܳCðZÜòV \ No newline at end of file diff --git a/src/cli/core/config/config.js b/src/cli/core/config/config.js index ffa7be56..49c5a0b2 100755 --- a/src/cli/core/config/config.js +++ b/src/cli/core/config/config.js @@ -108,10 +108,14 @@ result.set = (json) => { } result.save = (json) => { - extend(true, result, json) + // extend(true, result, json) - var confPath = path.join(result.root,'abe.json') - fse.writeJsonSync(confPath, json, { space: 2, encoding: 'utf-8' }) + if (result.localConfigExist()){ + // var abeJson = fse.readJsonSync(path.join(result.root,'abe.json')) + // extend(true, abeJson, json) + var confPath = path.join(result.root,'abe.json') + fse.writeJsonSync(confPath, json, { space: 2, encoding: 'utf-8' }) + } } result.getConfigByWebsite = () => { diff --git a/src/cli/users/operations.js b/src/cli/users/operations.js index bcd533f0..2144ee22 100644 --- a/src/cli/users/operations.js +++ b/src/cli/users/operations.js @@ -29,7 +29,7 @@ export function add(newUser) { newUser.password = User.utils.encryptPassword(10, newUser.password) bdd.push(newUser) - User.manager.instance.save(bdd) + User.manager.instance.update(bdd) return { success:1, @@ -46,7 +46,7 @@ export function deactivate(id) { bdd[i].actif = 0 } } - User.manager.instance.save(bdd) + User.manager.instance.update(bdd) return bdd } @@ -59,7 +59,7 @@ export function activate(id) { bdd[i].actif = 1 } } - User.manager.instance.save(bdd) + User.manager.instance.update(bdd) return bdd } @@ -74,7 +74,7 @@ export function remove(id) { } } bdd = newBdd - User.manager.instance.save(bdd) + User.manager.instance.update(bdd) return bdd } @@ -100,7 +100,7 @@ export function update(data) { }) } } - bdd = User.manager.instance.save(bdd) + bdd = User.manager.instance.update(bdd) return { success:1, @@ -123,7 +123,7 @@ export function updatePassword(data, password) { } } - bdd = User.manager.instance.save(bdd) + bdd = User.manager.instance.update(bdd) return { success:1, diff --git a/src/cli/users/utils.js b/src/cli/users/utils.js index b40460ba..762f18eb 100644 --- a/src/cli/users/utils.js +++ b/src/cli/users/utils.js @@ -1,3 +1,5 @@ +import redis from 'redis' +import Limiter from 'ratelimiter' import owasp from 'owasp-password-strength-test' import bcrypt from 'bcrypt-nodejs' import Cookies from 'cookies' @@ -190,7 +192,22 @@ export function getTokenFromCookies(req, res) { return cookies.get('x-access-token') } +export function isAbeRestrictedUrl(currentRoute) { + if( currentRoute.indexOf('/abe/users/forgot') > -1 + || currentRoute.indexOf('/abe/users/login') > -1 + || currentRoute.indexOf('/abe/users/reset') > -1 + || !/^\/abe/.test(currentRoute)) { + return false + } + + return true +} + export function isUserAllowedOnRoute(workflow, currentRoute) { + if( currentRoute.indexOf('/abe/users/forgot') > -1 || currentRoute.indexOf('/abe/users/login') > -1 || !/^\/abe/.test(currentRoute)) { + return true + } + var isAllowed = false if (currentRoute.indexOf('abe/') === -1) { @@ -252,4 +269,41 @@ export function getUserWorkflow(status, role) { flows = [addFlow("draft", "draft", "submit"), addFlow("publish", "publish", "submit")] } return flows +} + +export function loginLimitTry(username) { + var p = new Promise((resolve) => { + var isNexted = false + try { + var limiterConfig = config.users.limiter + + var client = redis.createClient() + client.on('error', function() { + if (!isNexted) { + isNexted = true + resolve() + } + }) + + var limit = new Limiter({ + id: username, + db: client, + duration: limiterConfig.duration, + max: limiterConfig.max + }) + + limit.get(function(err, limit) { + if (err) { + resolve() + }else { + resolve(limit) + } + }) + }catch(e) { + console.log('loginLimitTry', e) + resolve() + } + }) + + return p } \ No newline at end of file diff --git a/src/server/app.js b/src/server/app.js index dd39a9fb..40398db3 100755 --- a/src/server/app.js +++ b/src/server/app.js @@ -105,16 +105,6 @@ app.use(function (req, res, next) { res.locals.nonce = uuid.v4() next() }) -app.use(function (req, res, next) { - if(typeof req.query.logs !== 'undefined' && req.query.logs !== null - && req.query.logs === 'true') { - config.logs = true - }else if(typeof req.query.logs !== 'undefined' && req.query.logs !== null - && req.query.logs === 'false') { - config.logs = false - } - next() -}) if(config.security === true){ app.use(helmet()) diff --git a/src/server/middlewares/isAuthorized.js b/src/server/middlewares/isAuthorized.js index 86016951..b51713b0 100644 --- a/src/server/middlewares/isAuthorized.js +++ b/src/server/middlewares/isAuthorized.js @@ -6,7 +6,7 @@ import { var middleware = function(req, res, next) { if (!config.users.enable) { if (req.url.indexOf('/abe/users/login') > -1) { - res.redirect('/abe') + res.redirect('/abe/editor') return }else { next() @@ -14,18 +14,23 @@ var middleware = function(req, res, next) { } } - if( req.url.indexOf('/abe/users/forgot') > -1 || req.url.indexOf('/abe/users/login') > -1 || !/^\/abe/.test(req.url)) { - next() - return + var decoded = User.utils.decodeUser(req, res) + var user = User.utils.findSync(decoded.iss) + res.user = user + + if(!User.utils.isAbeRestrictedUrl(req.url)) { + // if (user != null && req.url.indexOf('/abe/users/login') > -1 && req.method === 'GET' ) { + // res.redirect('/abe/editor') + // return + // }else { + next() + return + // } } var isHtml = /text\/html/.test(req.get('accept')) ? true : false - var decoded = User.utils.decodeUser(req, res) - var user = User.utils.findSync(decoded.iss) - if (user != null && User.utils.isUserAllowedOnRoute(user.role.workflow, req.url)) { - res.user = user next() }else { if(isHtml) { diff --git a/src/server/middlewares/login.js b/src/server/middlewares/login.js index 9884eda8..534bfc6e 100644 --- a/src/server/middlewares/login.js +++ b/src/server/middlewares/login.js @@ -1,58 +1,10 @@ -import redis from 'redis' -import Limiter from 'ratelimiter' - import { config + ,User } from '../../cli' var middleware = function(req, res, next) { - var isNexted = false - if( req.url === '/abe/users/login' && req.method === 'POST' ) { - try { - var username = req.body.username - var limiterConfig = config.users.limiter - - var client = redis.createClient() - client.on('error', function() { - if (!isNexted) { - isNexted = true - next() - } - }) - - var limit = new Limiter({ - id: username, - db: client, - duration: limiterConfig.duration, - max: limiterConfig.max - }) - - limit.get(function(err, limit) { - if (err) return next(err) - - try { - res.set('X-RateLimit-Limit', limit.total) - res.set('X-RateLimit-Remaining', limit.remaining - 1) - res.set('X-RateLimit-Reset', limit.reset) - - // all good - console.log('remaining ', limit.remaining - 1, limit.total, username) - if (limit.remaining) return next() - - // not good - var after = limit.reset - (Date.now() / 1000) | 0 - res.set('Retry-After', after) - res.send(429, 'Rate limit exceeded') - } catch(e) { - console.log('e', e) - next() - } - }) - } catch(e) { - console.log('e', e) - next() - } - }else if( req.url.indexOf('/abe/') > -1) { + if( req.url.indexOf('/abe/') > -1) { var send = res.send var token = req.csrfToken() res.send = function (string) { diff --git a/src/server/public/scripts/modules/EditorJson.js b/src/server/public/scripts/modules/EditorJson.js index e5df0ee5..259b95c9 100755 --- a/src/server/public/scripts/modules/EditorJson.js +++ b/src/server/public/scripts/modules/EditorJson.js @@ -68,12 +68,12 @@ export default class Json { alert(jsonRes.error) return } - // if(typeof jsonRes.reject !== 'undefined' && jsonRes.reject !== null) { - // location.reload() - // return - // } - this.data = jsonRes.json - location.reload() + if (jsonRes.success == 1) { + this.data = jsonRes.json + location.reload() + }else { + alert(jsonRes.message) + } } catch(e){ alert('The following error happened : \n' + e + '\n if it persist, reload your web page tab.') diff --git a/src/server/public/scripts/modules/EditorSave.js b/src/server/public/scripts/modules/EditorSave.js index 3c51e901..9cc803ff 100755 --- a/src/server/public/scripts/modules/EditorSave.js +++ b/src/server/public/scripts/modules/EditorSave.js @@ -122,8 +122,8 @@ export default class EditorSave { target.classList.remove('done') target.removeAttribute('disabled') - this._abeDisplayStatus.innerHTML = result.json.abe_meta.status if(result.success === 1) { + this._abeDisplayStatus.innerHTML = result.json.abe_meta.status window.json = result.json } var formWrapper = document.querySelector('#abeForm') diff --git a/src/server/public/scripts/modules/UserList.js b/src/server/public/scripts/modules/UserList.js index a94f2826..660d502e 100644 --- a/src/server/public/scripts/modules/UserList.js +++ b/src/server/public/scripts/modules/UserList.js @@ -39,7 +39,9 @@ var usersList = { 'info': false, 'columns': columns }) + } + if ($('#filtered-list-url').size() > 0) { this._handleFormUserRoleSubmit = this._formUserRoleSubmit.bind(this) this._formUserRole = document.querySelector('[data-user-role]') @@ -93,15 +95,19 @@ var usersList = { var inputs = this._formUserRole.querySelectorAll('input[type=checkbox]') var data = {} Array.prototype.forEach.call(inputs, (input) => { - var name = input.getAttribute('name') - if (data[name] == null) { - data[name] = [] + if (!input.disabled) { + var name = input.getAttribute('name') + if (data[name] == null) { + data[name] = [] + } + if (input.checked) { + data[name].push(input.getAttribute('value')) + } } - data[name].push(input.getAttribute('value')) }) var toSave = qs.stringify(data) - + this._ajax( { url: '/abe/list-url/save', diff --git a/src/server/routes/get-list-url.js b/src/server/routes/get-list-url.js index 431ce2bd..90b2b7d1 100644 --- a/src/server/routes/get-list-url.js +++ b/src/server/routes/get-list-url.js @@ -17,7 +17,7 @@ var route = function(router, req, res, next) { urls.push({ url: route.route.path, method: Object.keys(route.route.methods)[0].toUpperCase(), - regex: '^\\' + route.route.path.replace(/\*$/, '') + '.*?' + regex: route.route.path.replace(/\*$/, '') + '.*' }) }) diff --git a/src/server/routes/post-list-url-save.js b/src/server/routes/post-list-url-save.js index 3b7eed11..fff8d0ea 100644 --- a/src/server/routes/post-list-url-save.js +++ b/src/server/routes/post-list-url-save.js @@ -10,11 +10,22 @@ import { var route = function(req, res, next) { var authorizations = req.body - delete authorizations.admin - config.user - console.log('* * * * * * * * * * * * * * * * * * * * * * * * * * * * *') - console.log('authorizations', authorizations) + let json = config.getLocalConfig() + + Array.prototype.forEach.call(Object.keys(authorizations), (key) => { + if (key != "admin") { + json.users.routes[key] = authorizations[key] + } + }) + + config.save(json) + + res.set('Content-Type', 'application/json') + res.send(JSON.stringify({ + success: 1, + message: 'config saved' + })) } export default route \ No newline at end of file diff --git a/src/server/routes/users/post/login.js b/src/server/routes/users/post/login.js index 179bf03b..b6bb82f3 100755 --- a/src/server/routes/users/post/login.js +++ b/src/server/routes/users/post/login.js @@ -36,35 +36,46 @@ passport.deserializeUser(function(id, done) { }) var route = function(req, res, next) { - passport.authenticate( - 'local', - { session: false}, - function(err, user, info) { - var secret = config.users.secret - if (err) { return next(err) } - - if (!user) { - req.flash('info', info.message) + User.utils.loginLimitTry(req.body.username) + .then((limit) => { + if (limit != null) { + // all good + if (!limit.remaining) { + req.flash('info', 'Rate limit exceeded') return res.redirect('/abe/users/login') - // return res.status(401).json({ error: info }); } - var expires = moment().add(7, 'days').valueOf() - var token = jwt.encode({ - iss: user.id, - exp: expires, - username: user.username, - name: user.name, - email: user.email, - role: user.role - }, secret) + } + + passport.authenticate( + 'local', + { session: false}, + function(err, user, info) { + var secret = config.users.secret + if (err) { return next(err) } - var cookies = new Cookies( req, res, { - secure: config.cookie.secure - }) - cookies.set( 'x-access-token', token ) + if (!user) { + req.flash('info', info.message) + return res.redirect('/abe/users/login') + // return res.status(401).json({ error: info }); + } + var expires = moment().add(7, 'days').valueOf() + var token = jwt.encode({ + iss: user.id, + exp: expires, + username: user.username, + name: user.name, + email: user.email, + role: user.role + }, secret) - res.redirect('/abe/editor/') - })(req, res, next) + var cookies = new Cookies( req, res, { + secure: config.cookie.secure + }) + cookies.set( 'x-access-token', token ) + + res.redirect('/abe/editor/') + })(req, res, next) + }) } export default route \ No newline at end of file diff --git a/src/server/views/list-url.html b/src/server/views/list-url.html index f78b27f4..b8f8e504 100644 --- a/src/server/views/list-url.html +++ b/src/server/views/list-url.html @@ -15,14 +15,17 @@
  • Url list
  • -
    - - + +
    + +
    +
    +
    +
    - {{#each @root.roles}} {{/each}} @@ -33,17 +36,18 @@ - {{#each @root.roles}} - {{#isAuthorized ../url this.workflow}} - + - {{/isAuthorized}} + {{#isAuthorized ../url this.workflow}} + + {{else}} + + {{/isAuthorized}} + {{/ifCond}} + {{/each}} {{/each}} diff --git a/src/server/views/partials/toolbar.html b/src/server/views/partials/toolbar.html index dc0edac7..eadc701a 100755 --- a/src/server/views/partials/toolbar.html +++ b/src/server/views/partials/toolbar.html @@ -1,5 +1,5 @@ {{#each @root.workflows}} - {{#isAuthorized this.status this.url}} + {{#isAuthorized this.url @root.user.role.workflow}} + {{else}} {{/isAuthorized}} {{/each}} \ No newline at end of file
    method linkregex{{this.name}}
    {{method}} {{url}}{{regex}} - - + {{#ifCond this.workflow "admin"}} + {{else}} - - -