/* global __appdir */ const path = require('path') var db = require(path.join(__appdir, 'lib', 'sequelize')) var groupHelper = require(path.join(__appdir, 'lib', 'grouphelper')) module.exports = { exportFunctions } function exportFunctions (req, res, next) { req.user.hasPermission = permissionName => hasPermission(req.user.id, permissionName) req.user.getAllowedGroups = permissionName => getAllowedGroups(req.user.id, permissionName) req.user.hasPermissionForGroup = (permissionName, groupId) => hasPermissionForGroup(req.user.id, permissionName, groupId) req.user.getAllowedClients = permissionName => getAllowedClients(req.user.id, permissionName) req.user.hasPermissionForClient = (permissionName, clientId) => hasPermissionForClient(req.user.id, permissionName, clientId) next() } async function isSuperadmin (userid) { var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': 'superadmin' }, include: [{ as: 'roles', model: db.role, include: ['permissions'] }] }) return user !== null } // Check if the user has given permission. async function hasPermission (userid, permissionName) { var superAdmin = await isSuperadmin(userid) if (superAdmin) return true var permission = permissionName.split('.') // Wildcards var user if (permission[1] === '*') { user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': { [db.Op.like]: permission[0] + '%' } }, include: [{ as: 'roles', model: db.role, include: ['permissions'] }] }) } else { user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions'] }] }) } return user !== null } // Get a list of GroupIDs the user has the given permission for. 0 means for all groups. async function getAllowedGroups (userid, permissionName) { var superAdmin = await isSuperadmin(userid) if (superAdmin) return [0] var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', 'groups'] }] }) // User doesn't have the permission if (user === null) return [] // User has permission, permission is not groupdependent else if (!user.roles[0].permissions[0].groupdependent) return [0] // User has permission, permission is groupdependent else { var result = [] for (let i = 0; i < user.roles.length; i++) { var whitelist = [] var blacklist = [] // Fill in white- and blacklist for (let j = 0; j < user.roles[i].groups.length; j++) { if (user.roles[i].groups[j].role_x_group.blacklist) { blacklist.push(user.roles[i].groups[j]) } else { whitelist.push(user.roles[i].groups[j]) } } // Get childs of whitelist groups, filtered by blacklist var whitelistChilds = await groupHelper.getAllChildren(whitelist, blacklist) result = result.concat(whitelist.map(x => x.id)) result = result.concat(whitelistChilds.subgroups.map(s => s.id)) } // Filter result for unique entries return result.filter(function (elem, pos, arr) { return arr.indexOf(elem) === pos }) } } // Check if the user has a given permission for a given group. async function hasPermissionForGroup (userid, permissionName, groupId) { var superAdmin = await isSuperadmin(userid) if (superAdmin) return true var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', 'groups'] }] }) // User doesn't have permission if (user === null) return false // User has permission, permission is not groupdependent else if (!user.roles[0].permissions[0].groupdependent) return true // User has permission, permission is groupdependent, check for group else { var result = false var whitelist = [] var blacklist = [] // Fill in white- and blacklist for (let i = 0; i < user.roles.length; i++) { for (let j = 0; j < user.roles[i].groups.length; j++) { if (user.roles[i].groups[j].role_x_group.blacklist) { blacklist.push(user.roles[i].groups[j].id) } else { whitelist.push(user.roles[i].groups[j].id) } } } // Shortcut if (blacklist.includes(groupId)) { return false } // Remember it was found, check if any parent is in the blacklist tho. if (whitelist.includes(groupId)) { result = true } // Check parents for white-/blacklist entries. result = await checkParents(groupId, whitelist, blacklist, result) return result } } // Get a list of ClientIDs the user has the given permission for. 0 means for all clients. async function getAllowedClients (userid, permissionName) { var superAdmin = await isSuperadmin(userid) if (superAdmin) return [0] var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', { as: 'groups', model: db.group, include: ['clients'] }] }] }) // User doesn't have the permission if (user === null) return [] // User has permission, permission is not groupdependent else if (!user.roles[0].permissions[0].groupdependent) return [0] // User has permission, permission is groupdependent else { var result = [] for (let i = 0; i < user.roles.length; i++) { var whitelist = [] var blacklist = [] // Fill in white- and blacklist for (let j = 0; j < user.roles[i].groups.length; j++) { if (user.roles[i].groups[j].role_x_group.blacklist) { blacklist.push(user.roles[i].groups[j]) } else { whitelist.push(user.roles[i].groups[j]) } } // Get childs of whitelist groups, filtered by blacklist var whitelistChilds = await groupHelper.getAllChildren(whitelist, blacklist) result = result.concat(whitelistChilds.clients.map(c => c.id)) } // Filter result for unique entries return result.filter(function (elem, pos, arr) { return arr.indexOf(elem) === pos }) } } // Check if the user has a given permission for a given client. async function hasPermissionForClient (userid, permissionName, clientId) { var superAdmin = await isSuperadmin(userid) if (superAdmin) return true var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', { as: 'groups', model: db.group, include: ['clients'] }] }] }) // User doesn't have permission if (user === null) return false // User has permission, permission is not groupdependent else if (!user.roles[0].permissions[0].groupdependent) return true // User has permission, permission is groupdependent, check for client else { var result = false var whitelist = [] var blacklist = [] // Fill in white- and blacklist for (let i = 0; i < user.roles.length; i++) { for (let j = 0; j < user.roles[i].groups.length; j++) { var clients = user.roles[i].groups[j].clients.map(c => c.id) if (user.roles[i].groups[j].role_x_group.blacklist) { // Shortcut if (clients.includes(clientId)) return false blacklist.push(user.roles[i].groups[j].id) } else { // Remember it was found, check if any parent is in the blacklist tho. if (clients.includes(clientId)) result = true whitelist.push(user.roles[i].groups[j].id) } } } // Get groups the client is assigned to var client = await db.client.findOne({ where: { id: clientId }, include: [{ as: 'groups', model: db.group }] }) var groupIds = client.groups.map(g => g.id) // Check parents for white-/blacklist entries. result = await checkParents(groupIds, whitelist, blacklist, result) return result } } // Check if parents of groupIds are in the whitelist / blacklist async function checkParents (groupIds, whitelist, blacklist, result) { // No whitelist means the group cant be in one if (whitelist.length === 0) return false // No blacklist means the result can't be changed once it's true if (blacklist.length === 0 && result) return true var parentIds = [] var groups = await db.group.findAll({ where: { id: groupIds }, include: ['parents'] }) for (let i = 0; i < groups.length; i++) { for (let j = 0; j < groups[i].parents.length; j++) { var id = groups[i].parents[j].id // blacklisted if (blacklist.includes(id)) return false // Remember, but a further parent can still be blacklisted, so continue. if (whitelist.includes(id)) result = true if (!parentIds.includes(id)) parentIds.push(id) } } // No further parents found, result is the result. if (parentIds.length === 0) return result // Check next layer of parents result = await checkParents(parentIds, whitelist, blacklist, result) return result }