UNPKG

am-i-allowed

Version:

A generic, very powerful yet very friendly, 0 dependencies, agnostic, permissions/access-control/authorization library

88 lines (72 loc) 3.19 kB
import {GROUP_ROLE_PREFIX, IActor, IPrivilegeManaged, Operation, PermissionChecker} from "./types"; import {PrivilegeManager} from "./am-i-allowed"; /** * This is the standardPermissionChecker logic. First, explicit role assignments are checked, then group related, which means, * if user and entity groups intersect, then either the default group permissions are used or the entities GroupMember role is used, * then the default type's user permissions and entities "User" role, and the same with visitor ("Visitor" role, etc). * @param privilegeManager * @param actor * @param operation * @param entity * @param specialContext */ export const standardPermissionChecker: PermissionChecker = async (privilegeManager: PrivilegeManager, actor: IActor, operation: Operation, entity: IPrivilegeManaged, specialContext?: any): Promise<boolean> => { const operations = privilegeManager.operationTree.expandOperation(operation); const metaData = await privilegeManager.findMetaData(entity) const entityRoles = await privilegeManager.getRolesForActor(actor, entity) const isVisitor = !actor.id const isAUser = !isVisitor const actorGroups = await getGroups(actor?.groups) const entityGroups = await getGroups(entity.permissionGroupIds) const commonGroups = actorGroups.filter(g => entityGroups.includes(g)) || [] const isGroupMember = commonGroups?.length > 0 if (!metaData.groupMembershipMandatory || isGroupMember) for (let op of operations) { if (isAllowed(op)) return true } if (entity.permissionSuper) { return privilegeManager.isAllowed(actor, operation, await entity.permissionSuper(), specialContext) } return false function isAllowed(op: Operation): boolean { for (let role of entityRoles) if (role.operations.has(op)) return true for (let group of commonGroups) { const groupMemberRole = metaData.roles[GROUP_ROLE_PREFIX + group] if (groupMemberRole?.operations.has(op)) return true } for (let group of actorGroups) { if (metaData.groupPermissions[group]?.has(op)) return true } if (isGroupMember) if (metaData.defaultGroupMemberPermissions.has(op) || entityRoles['GroupMember']?.operations.has(op)) return true if (isAUser) if (metaData.defaultUserPermissions.has(op) || entityRoles['User']?.operations.has(op)) return true if (isVisitor) { if (metaData.defaultVisitorPermissions.has(op) || entityRoles['Visitor']?.operations.has(op)) return true } return false } } export type GroupList = string[] export type GroupSpecifier = string | (() => string) | GroupList | (() => Promise<GroupList>) async function getGroups(groups: GroupSpecifier): Promise<GroupList> { let g: any = groups if (typeof groups === 'function') { g = groups() if (g.then) g = await g } if (!g) return [] if (typeof g == 'string') return [g] return g }