kindergarten
Version:
Kindergarten is a JavaScript library which helps programmers to achieve modular security using sandbox pattern
294 lines (220 loc) • 8.31 kB
JavaScript
;
exports.__esModule = true;
exports.default = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _each = require('lodash/each');
var _each2 = _interopRequireDefault(_each);
var _filter = require('lodash/filter');
var _filter2 = _interopRequireDefault(_filter);
var _forIn = require('lodash/forIn');
var _forIn2 = _interopRequireDefault(_forIn);
var _isFunction = require('lodash/isFunction');
var _isFunction2 = _interopRequireDefault(_isFunction);
var _isString = require('lodash/isString');
var _isString2 = _interopRequireDefault(_isString);
var _isEmpty = require('lodash/isEmpty');
var _isEmpty2 = _interopRequireDefault(_isEmpty);
var _some = require('lodash/some');
var _some2 = _interopRequireDefault(_some);
var _Rule = require('../Rule');
var _Rule2 = _interopRequireDefault(_Rule);
var _isRule = require('../utils/isRule');
var _isRule2 = _interopRequireDefault(_isRule);
var _errors = require('../errors');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var HeadGoverness = function () {
/**
* Creates a new instance of the HeadGoverness
*/
function HeadGoverness() {
_classCallCheck(this, HeadGoverness);
this.rules = [];
}
/**
* Throws an error if child is not allowed to do some action
*/
_createClass(HeadGoverness, [{
key: 'guard',
value: function guard(action) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var target = args[0];
if (this.isAllowed.apply(this, [action].concat(args))) {
return target;
}
throw new _errors.AccessDenied('Child is not allowed to ' + action + ' ' + ((0, _isString2.default)(target) ? target : 'the target') + '.');
}
/**
* Watch over some child action. By default we only execute it, but custom
* governesses can override it to do some custom stuff like calling `guard()`
* or something else (see. `StrictGoverness` class).
*/
}, {
key: 'governed',
value: function governed(callback) {
var args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var callingContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
return callback.apply(callingContext, args);
}
/**
* Returns true if child is allowed to perform some action
*/
}, {
key: 'isAllowed',
value: function isAllowed(action) {
var _this = this;
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
if (this.isGuarded()) {
var _ret = function () {
var allowRules = [];
var strictDisallowRules = [];
(0, _each2.default)(_this.getRules(action), function (rule) {
var verificationResult = rule.verify.apply(rule, args);
if ((0, _isRule2.default)(rule)) {
// Is there any rule explicitly allowing the child to do that?
if (rule.type.isPositive && verificationResult) {
allowRules.push(rule);
}
// Is there any rule strictly disallowing the child to do that?
if (!verificationResult && rule.definition.isStrict) {
strictDisallowRules.push(rule);
}
}
});
if ((0, _isEmpty2.default)(allowRules) || !(0, _isEmpty2.default)(strictDisallowRules)) {
return {
v: false
};
}
}();
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
}
return true;
}
/**
* Returns false if child is allowed to perform some action
*/
}, {
key: 'isNotAllowed',
value: function isNotAllowed() {
return !this.isAllowed.apply(this, arguments);
}
/**
* The getter of unguarded property. If governess is ungarded, then no errors will be
* thrown when guard() method is called.
*/
}, {
key: 'getRules',
value: function getRules(type) {
return type ? (0, _filter2.default)(this.rules, function (rule) {
return rule.type.type === type;
}) : this.rules;
}
}, {
key: 'learnRules',
value: function learnRules(perimeter) {
var _this2 = this;
var governObj = perimeter.govern || {};
var keys = 0;
(0, _forIn2.default)(governObj, function (val, key) {
if (governObj.hasOwnProperty(key)) {
var ruleDef = governObj[key];
// function rules must be called in context of perimeter to have access
// to `this.child`
if ((0, _isFunction2.default)(ruleDef)) {
ruleDef.ruleContext = ruleDef.ruleContext || perimeter;
}
var rule = new _Rule2.default(key, ruleDef);
rule._perimeter = perimeter;
if (!_this2.hasRule(perimeter, rule)) {
_this2.addRule(rule);
keys++;
}
}
});
return keys;
}
}, {
key: 'addRule',
value: function addRule() {
var _this3 = this;
var counter = 0;
for (var _len3 = arguments.length, rules = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
rules[_key3] = arguments[_key3];
}
(0, _each2.default)(rules, function (rule) {
if (!(0, _isRule2.default)(rule)) {
throw new _errors.ArgumentError('Governess cannot learn the rule. Does it inherit from Rule class?');
}
++counter;
_this3.rules.push(rule);
});
return counter;
}
/**
* Return true if governess already has a given rule from perimeter.
*/
}, {
key: 'hasRule',
value: function hasRule(perimeter, rule) {
return (0, _some2.default)(this.rules, function (r) {
return r.type.raw === rule.type.raw && r._perimeter === perimeter;
});
}
/**
* The governess is empty when no rules have been defined
*/
}, {
key: 'hasAnyRules',
value: function hasAnyRules() {
return !(0, _isEmpty2.default)(this.rules);
}
/**
* Perform some stuff unguarded
*/
}, {
key: 'doUnguarded',
value: function doUnguarded(callback, context) {
var returnValue = void 0;
context = context || null;
if ((0, _isFunction2.default)(callback)) {
var before = this.unguarded;
this.unguarded = true;
returnValue = callback.apply(context);
this.unguarded = before;
}
return returnValue;
}
}, {
key: 'isUnguarded',
value: function isUnguarded() {
return this.unguarded;
}
}, {
key: 'isGuarded',
value: function isGuarded() {
return !this.isUnguarded();
}
}, {
key: 'unguarded',
get: function get() {
return !!this._unguarded;
}
/**
* The setter of unguarded property. If governess is ungarded, then no errors will be
* thrown when guard() method is called.
*/
,
set: function set(value) {
this._unguarded = !!value;
return value;
}
}]);
return HeadGoverness;
}();
exports.default = HeadGoverness;