//--------------------------------------------------------
//-- Node IoC - Security - Services - Gate
//--------------------------------------------------------
import __ from '@absolunet/private-registry';
import checksTypes from '../../support/mixins/checksTypes';
/**
* Gate service that allows to register policies and test those policies before executing command or anything that needs security checks.
*
* @memberof security.services
* @augments support.mixins.CheckTypes
* @hideconstructor
*/
class Gate extends checksTypes() {
/**
* Class dependencies: <code>['app']</code>.
*
* @type {Array<string>}
*/
static get dependencies() {
return (super.dependencies || []).concat(['app']);
}
/**
* @inheritdoc
* @private
*/
init() {
__(this).set('policies', {});
}
/**
* Determine if the user is authorized to get through the given gates.
*
* @param {string|Array<string>} gate - Gate to validate through registered policies.
* @returns {boolean} Indicates that the policies passed.
*/
can(gate) {
const gates = Array.isArray(gate) ? gate : [gate];
return gates.every((g) => {
const { parameters, policies } = this.resolve(g);
return policies.every((policy) => {
return this.handlePolicy(policy, parameters);
});
});
}
/**
* Register policy.
*
* @param {string} policy - The policy name.
* @param {Function} handler - The policy handler.
*/
policy(policy, handler) {
const policies = __(this).get('policies');
policies[policy] = policies[policy] || [];
policies[policy].push(handler);
}
/**
* Register policy class.
*
* @param {ioc.security.Policy} policy - The policy class.
*/
register(policy) {
const policyInstance = this.app.make(policy);
this.policy(policyInstance.name, (...parameters) => {
return policyInstance.passes(...parameters);
});
}
/**
* Resolve policy handlers by name.
*
* @param {string} gate - The gate to resolve.
* @returns {{name: string, parameters: Array<string>, policies: Array<Function|*>}} The resolved gate name, parametres and policies.
*/
resolve(gate) {
const name = this.getGateName(gate);
const parameters = this.getGateParameters(gate);
const policies = (__(this).get('policies')[name] || [])
.map((policy) => {
return this.getPolicyConcrete(policy);
});
return { name, parameters, policies };
}
/**
* Get the gate name, without arguments.
*
* @param {string} gate - The gate.
* @returns {string} The gate name.
*/
getGateName(gate) {
return gate.split(':')[0];
}
/**
* Get gate arguments from string call.
*
* @param {string} gate - The gate.
* @returns {Array<string>} The list of parameters.
*/
getGateParameters(gate) {
return (gate.split(':')[1] || '').split(',').filter(Boolean);
}
/**
* Get policy handler instance, either a closure or a policy class instance.
*
* @param {*} policy - The policy or policy class.
* @returns {Function|Policy} The policy callable function or class instance.
*/
getPolicyConcrete(policy) {
return this.isFunction(policy) ? policy : this.app.make(policy);
}
/**
* Execute policy handling, either from a closure or a class instance.
*
* @param {Function} policy - The policy callable function or class instance.
* @param {Array<string>} parameters - The list of parameters.
* @returns {boolean} Indicates if the given policy passes with the given parameters.
*/
handlePolicy(policy, parameters = []) {
return this.isFunction(policy) ? policy(...parameters) : policy.handle(...parameters);
}
}
export default Gate;