integreat
Version:
Node.js integration layer
126 lines • 4.52 kB
JavaScript
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