UNPKG

integreat

Version:
126 lines 4.52 kB
import { arrayIncludes, ensureArray, ensureArrayOrUndefined, } from '../../utils/array.js'; import { isRootIdent } from '../../utils/is.js'; const authorizedByIntegreat = Symbol('authorizedByIntegreat'); export const isAuthorizedAction = (action) => action.meta && action.meta[authorizedByIntegreat]; export const setAuthorizedMark = (action, isAuthorized = true) => ({ ...action, meta: { ...action.meta, [authorizedByIntegreat]: isAuthorized }, }); function authorizeByAllow(allow, hasIdent = false) { switch (allow) { case undefined: case 'all': return undefined; case 'auth': return hasIdent ? undefined : 'NO_IDENT'; default: return 'ALLOW_NONE'; } } const hasFromFields = (access) => typeof access.identFromField === 'string' || typeof access.roleFromField === 'string'; const authMethods = [ 'allow', 'ident', 'role', 'identFromField', 'roleFromField', ]; const isAuthMethod = (method) => authMethods.includes(method); const hasAuthMethod = (access) => Object.keys(access).filter(isAuthMethod).length > 0; const createRequiredError = (items, itemName) => `Authentication was refused, ${itemName}${items.length > 1 ? 's' : ''} required: ${items.map((item) => `'${item}'`).join(', ')}`; function authorizeByFromField(type, ident) { if (ident) { return undefined; } else { return { reason: 'NO_IDENT', error: `Authentication was refused for type '${type}'`, }; } } export function validateRoleOrIdent(required, present) { const rolesArr = ensureArray(required); return (rolesArr.length > 0 && arrayIncludes(rolesArr, ensureArrayOrUndefined(present))); } export function authorizeByRoleOrIdent(access, ident) { if ((!access.role && !access.ident) || validateRoleOrIdent(access.role, ident?.roles) || validateRoleOrIdent(access.ident, ident?.id)) { return undefined; } else { return access.ident ? { reason: 'WRONG_IDENT', error: createRequiredError(ensureArray(access.ident), 'ident'), } : { reason: 'MISSING_ROLE', error: createRequiredError(ensureArray(access.role), 'role'), }; } } function authorizeByOneSchema(ident, schema, type, actionType, requireAuth) { if (!schema) { return { reason: 'NO_SCHEMA', error: `Authentication was refused for type '${type}'`, }; } const access = schema.accessForAction(actionType); if (requireAuth && !hasAuthMethod(access)) { return { reason: 'ACCESS_METHOD_REQUIRED', error: `Authentication was refused for type '${type}'`, }; } const allowReason = authorizeByAllow(access.allow, !!ident?.id); if (allowReason) { return { reason: allowReason, error: `Authentication was refused for type '${type}'`, }; } if (hasFromFields(access)) { return authorizeByFromField(type, ident); } return authorizeByRoleOrIdent(access, ident); } function authorizeBySchema(ident, schemas, actionTypes, action, requireAuth) { for (const actionType of actionTypes) { const error = authorizeByOneSchema(ident, schemas.get(actionType), actionType, action, requireAuth); if (error) { return error; } } return { reason: undefined, error: undefined }; } export default (schemas, requireAuth) => function authorizeAction(action) { const { payload: { type }, response: { status } = {}, meta: { ident } = {}, } = action; if (typeof status === 'string' && status !== 'ok') { return setAuthorizedMark(action, false); } if (!isRootIdent(ident)) { const types = ensureArray(type); if (types.length > 0) { const { reason, error } = authorizeBySchema(ident, schemas, types, action.type, requireAuth); if (reason || error) { return setAuthorizedMark({ ...action, response: { ...action.response, status: 'noaccess', error, reason, origin: 'auth:action', }, }, false); } } } return setAuthorizedMark(action); }; //# sourceMappingURL=authAction.js.map