UNPKG

kindergarten

Version:

Kindergarten is a JavaScript library which helps programmers to achieve modular security using sandbox pattern

294 lines (220 loc) 8.31 kB
'use strict'; 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;