UNPKG

rpcchannel

Version:

Easy RPC with permission controls

265 lines (212 loc) 21.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.RequirePermissions = RequirePermissions; exports.SetCanCallFunc = SetCanCallFunc; exports.AutoFunctionAccessController = exports.RequiresPermissions = exports.CanCallFunction = exports.FunctionLookupAccessController = exports.LegacyAccessController = exports.ChainedAccessController = exports.FunctionAccessController = exports.DenyAccessController = exports.AllowAccessController = exports.OptAccessPolicy = exports.AccessPolicy = void 0; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _addrmap = require("./addrmap"); var _utils = require("./utils"); function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } var AccessPolicy = { ALLOW: true, DENY: false }; exports.AccessPolicy = AccessPolicy; var OptAccessPolicy = Object.assign({ NONE: null }, AccessPolicy); exports.OptAccessPolicy = OptAccessPolicy; /** * Always allows access. */ var AllowAccessController = /*#__PURE__*/function () { function AllowAccessController() { (0, _classCallCheck2["default"])(this, AllowAccessController); } (0, _createClass2["default"])(AllowAccessController, [{ key: "can", value: function can() { return AccessPolicy.ALLOW; } }]); return AllowAccessController; }(); /** * Always denies access. */ exports.AllowAccessController = AllowAccessController; var DenyAccessController = /*#__PURE__*/function () { function DenyAccessController() { (0, _classCallCheck2["default"])(this, DenyAccessController); } (0, _createClass2["default"])(DenyAccessController, [{ key: "can", value: function can() { return AccessPolicy.DENY; } }]); return DenyAccessController; }(); /** * Controls access based on a single function */ exports.DenyAccessController = DenyAccessController; var FunctionAccessController = function FunctionAccessController(can) { (0, _classCallCheck2["default"])(this, FunctionAccessController); this.can = can; }; /** * Gives higher `AccessController`s in the chain priority. */ exports.FunctionAccessController = FunctionAccessController; var ChainedAccessController = /*#__PURE__*/function () { function ChainedAccessController() { var default_ap = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : OptAccessPolicy.NONE; (0, _classCallCheck2["default"])(this, ChainedAccessController); (0, _defineProperty2["default"])(this, "access_chain", []); this.default_ap = default_ap; } (0, _createClass2["default"])(ChainedAccessController, [{ key: "can", value: function can(addr, opts) { var val; this.access_chain.some(function (ctrl) { return (0, _utils.isDefined)(val = ctrl.can(addr, opts)); }); return (0, _utils.isDefined)(val) ? val : this.default_ap; } }]); return ChainedAccessController; }(); /** * The old type of access control based on an address-to-policy map. */ exports.ChainedAccessController = ChainedAccessController; var LegacyAccessController = /*#__PURE__*/function () { function LegacyAccessController() { (0, _classCallCheck2["default"])(this, LegacyAccessController); (0, _defineProperty2["default"])(this, "map", new _addrmap.AddressMap()); } (0, _createClass2["default"])(LegacyAccessController, [{ key: "can", value: function can(to) { return this.map.get(to); } }]); return LegacyAccessController; }(); /** * Lookup a function to determine access on a per-address basis */ exports.LegacyAccessController = LegacyAccessController; var FunctionLookupAccessController = /*#__PURE__*/function () { function FunctionLookupAccessController() { (0, _classCallCheck2["default"])(this, FunctionLookupAccessController); (0, _defineProperty2["default"])(this, "map", new _addrmap.AddressMap()); } (0, _createClass2["default"])(FunctionLookupAccessController, [{ key: "can", value: function can(to, opts) { var func = this.map.get(to); return func && func(to, opts) || OptAccessPolicy.NONE; } }]); return FunctionLookupAccessController; }(); exports.FunctionLookupAccessController = FunctionLookupAccessController; var CanCallFunction = Symbol('CanCall'); exports.CanCallFunction = CanCallFunction; var RequiresPermissions = Symbol('RequiresPermissions'); exports.RequiresPermissions = RequiresPermissions; /** * First, this `AccessController` will check the `RequiresPermissions` property * on the target function. If any of these are missing from the member `perms` * set, then access is denied. Otherwise, if `CanCallFunction` is defined, then * its result is returned. The `CanCallFunction` may also require permissions. */ var AutoFunctionAccessController = /*#__PURE__*/function () { function AutoFunctionAccessController() { var perms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Set(); (0, _classCallCheck2["default"])(this, AutoFunctionAccessController); this.perms = perms; } (0, _createClass2["default"])(AutoFunctionAccessController, [{ key: "can", value: function can(to, opts) { var obj = opts.func && opts.func[RequiresPermissions]; if ((0, _typeof2["default"])(obj) === 'object' && typeof obj[Symbol.iterator] === 'function') { var _iterator = _createForOfIteratorHelper(obj), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var requirement = _step.value; if (!this.perms.has(requirement)) { return AccessPolicy.DENY; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } var func = opts.func && opts.func[CanCallFunction]; if (typeof func === 'function') { var requirements = new Set(); var result = func(to, Object.assign({ require: function require(s) { return requirements.add(s); }, perms: this.perms }, opts)); var _iterator2 = _createForOfIteratorHelper(requirements), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var _requirement = _step2.value; if (!this.perms.has(_requirement)) { return AccessPolicy.DENY; } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return (0, _utils.isDefined)(result) ? Boolean(result) : OptAccessPolicy.NONE; } return OptAccessPolicy.NONE; } }]); return AutoFunctionAccessController; }(); exports.AutoFunctionAccessController = AutoFunctionAccessController; function RequirePermissions(perms) { return function ( // eslint-disable-next-line target, propertyKey, descriptor) { var func = descriptor.value; if (typeof func !== 'function') { throw new TypeError('Cannot require permissions for non-function'); } func[RequiresPermissions] = perms; }; } function SetCanCallFunc(can) { return function ( // eslint-disable-next-line target, propertyKey, descriptor) { var func = descriptor.value; if (typeof func !== 'function') { throw new TypeError('Cannot set access controller func on non-function'); } func[CanCallFunction] = can; }; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9hY2Nlc3Njb250cm9sLnRzIl0sIm5hbWVzIjpbIkFjY2Vzc1BvbGljeSIsIkFMTE9XIiwiREVOWSIsIk9wdEFjY2Vzc1BvbGljeSIsIk9iamVjdCIsImFzc2lnbiIsIk5PTkUiLCJBbGxvd0FjY2Vzc0NvbnRyb2xsZXIiLCJEZW55QWNjZXNzQ29udHJvbGxlciIsIkZ1bmN0aW9uQWNjZXNzQ29udHJvbGxlciIsImNhbiIsIkNoYWluZWRBY2Nlc3NDb250cm9sbGVyIiwiZGVmYXVsdF9hcCIsImFkZHIiLCJvcHRzIiwidmFsIiwiYWNjZXNzX2NoYWluIiwic29tZSIsImN0cmwiLCJMZWdhY3lBY2Nlc3NDb250cm9sbGVyIiwiQWRkcmVzc01hcCIsInRvIiwibWFwIiwiZ2V0IiwiRnVuY3Rpb25Mb29rdXBBY2Nlc3NDb250cm9sbGVyIiwiZnVuYyIsIkNhbkNhbGxGdW5jdGlvbiIsIlN5bWJvbCIsIlJlcXVpcmVzUGVybWlzc2lvbnMiLCJBdXRvRnVuY3Rpb25BY2Nlc3NDb250cm9sbGVyIiwicGVybXMiLCJTZXQiLCJvYmoiLCJpdGVyYXRvciIsInJlcXVpcmVtZW50IiwiaGFzIiwicmVxdWlyZW1lbnRzIiwicmVzdWx0IiwicmVxdWlyZSIsInMiLCJhZGQiLCJCb29sZWFuIiwiUmVxdWlyZVBlcm1pc3Npb25zIiwidGFyZ2V0IiwicHJvcGVydHlLZXkiLCJkZXNjcmlwdG9yIiwidmFsdWUiLCJUeXBlRXJyb3IiLCJTZXRDYW5DYWxsRnVuYyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUVBOzs7Ozs7OztBQUlPLElBQU1BLFlBQVksR0FBRztBQUMxQkMsRUFBQUEsS0FBSyxFQUFFLElBRG1CO0FBRTFCQyxFQUFBQSxJQUFJLEVBQUU7QUFGb0IsQ0FBckI7O0FBS0EsSUFBTUMsZUFBZSxHQUFHQyxNQUFNLENBQUNDLE1BQVAsQ0FBYztBQUFFQyxFQUFBQSxJQUFJLEVBQUU7QUFBUixDQUFkLEVBQThCTixZQUE5QixD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QWdCLFVBQXBCLEVBQWdDO0FBQzlCLFlBQU0sSUFBSXNCLFNBQUosQ0FBYyxtREFBZCxDQUFOO0FBQ0Q7O0FBQ0R0QixJQUFBQSxJQUFJLENBQUNDLGVBQUQsQ0FBSixHQUF3QmhCLEdBQXhCO0FBQ0QsR0FYRDtBQVlEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTXVsdGlzdHJpbmdBZGRyZXNzLCBBZGRyZXNzTWFwIH0gZnJvbSAnLi9hZGRybWFwJ1xuaW1wb3J0IHsgU2VyaWFsaXphYmxlRGF0YSB9IGZyb20gJy4vc2VyaWFsaXplcidcbmltcG9ydCB7IGlzRGVmaW5lZCB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBScGNDaGFubmVsLCBScGNGdW5jdGlvbiB9IGZyb20gJy4vcmVnaXN0cnknXG5cbmV4cG9ydCB0eXBlIEFjY2Vzc1BvbGljeSA9IGJvb2xlYW5cbmV4cG9ydCBjb25zdCBBY2Nlc3NQb2xpY3kgPSB7XG4gIEFMTE9XOiB0cnVlLFxuICBERU5ZOiBmYWxzZVxufVxuZXhwb3J0IHR5cGUgT3B0QWNjZXNzUG9saWN5ID0gQWNjZXNzUG9saWN5IHwgdW5kZWZpbmVkIHwgbnVsbFxuZXhwb3J0IGNvbnN0IE9wdEFjY2Vzc1BvbGljeSA9IE9iamVjdC5hc3NpZ24oeyBOT05FOiBudWxsIH0sIEFjY2Vzc1BvbGljeSlcblxuZXhwb3J0IGludGVyZmFjZSBDYW5DYWxsT3B0cyB7XG4gIGFyZ3M6IFNlcmlhbGl6YWJsZURhdGFbXVxuICB3Yzogc3RyaW5nW11cbiAgY2hhbm5lbDogUnBjQ2hhbm5lbFxuICBmdW5jPzogUnBjRnVuY3Rpb25cbn1cblxuZXhwb3J0IHR5cGUgQWNjZXNzQ2FuRnVuY3Rpb24gPSAoXG4gIGFkZHI6IE11bHRpc3RyaW5nQWRkcmVzcyxcbiAgb3B0czogQ2FuQ2FsbE9wdHNcbikgPT4gT3B0QWNjZXNzUG9saWN5XG5cbi8qKlxuICogQ29udHJvbHMgYWNjZXNzIHRvIFJQQyBlbmRwb2ludHMgYmFzZWQgb24gYWRkcmVzcyBBTkQgYXJndW1lbnRzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFjY2Vzc0NvbnRyb2xsZXIge1xuICBjYW4oYWRkcjogTXVsdGlzdHJpbmdBZGRyZXNzLCBvcHRzOiBDYW5DYWxsT3B0cyk6IE9wdEFjY2Vzc1BvbGljeVxufVxuLyoqXG4gKiBBbHdheXMgYWxsb3dzIGFjY2Vzcy5cbiAqL1xuZXhwb3J0IGNsYXNzIEFsbG93QWNjZXNzQ29udHJvbGxlciBpbXBsZW1lbnRzIEFjY2Vzc0NvbnRyb2xsZXIge1xuICBjYW4oKTogQWNjZXNzUG9saWN5IHtcbiAgICByZXR1cm4gQWNjZXNzUG9saWN5LkFMTE9XXG4gIH1cbn1cbi8qKlxuICogQWx3YXlzIGRlbmllcyBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBEZW55QWNjZXNzQ29udHJvbGxlciBpbXBsZW1lbnRzIEFjY2Vzc0NvbnRyb2xsZXIge1xuICBjYW4oKTogQWNjZXNzUG9saWN5IHtcbiAgICByZXR1cm4gQWNjZXNzUG9saWN5LkRFTllcbiAgfVxufVxuLyoqXG4gKiBDb250cm9scyBhY2Nlc3MgYmFzZWQgb24gYSBzaW5nbGUgZnVuY3Rpb25cbiAqL1xuZXhwb3J0IGNsYXNzIEZ1bmN0aW9uQWNjZXNzQ29udHJvbGxlciBpbXBsZW1lbnRzIEFjY2Vzc0NvbnRyb2xsZXIge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgY2FuOiBBY2Nlc3NDYW5GdW5jdGlvbikge31cbn1cbi8qKlxuICogR2l2ZXMgaGlnaGVyIGBBY2Nlc3NDb250cm9sbGVyYHMgaW4gdGhlIGNoYWluIHByaW9yaXR5LlxuICovXG5leHBvcnQgY2xhc3MgQ2hhaW5lZEFjY2Vzc0NvbnRyb2xsZXIgaW1wbGVtZW50cyBBY2Nlc3NDb250cm9sbGVyIHtcbiAgcHVibGljIHJlYWRvbmx5IGFjY2Vzc19jaGFpbjogQWNjZXNzQ29udHJvbGxlcltdID0gW11cbiAgY29uc3RydWN0b3IocHVibGljIGRlZmF1bHRfYXA6IE9wdEFjY2Vzc1BvbGljeSA9IE9wdEFjY2Vzc1BvbGljeS5OT05FKSB7fVxuICBjYW4oYWRkcjogTXVsdGlzdHJpbmdBZGRyZXNzLCBvcHRzOiBDYW5DYWxsT3B0cyk6IE9wdEFjY2Vzc1BvbGljeSB7XG4gICAgbGV0IHZhbDogT3B0QWNjZXNzUG9saWN5XG4gICAgdGhpcy5hY2Nlc3NfY2hhaW4uc29tZSgoY3RybCkgPT4gaXNEZWZpbmVkKCh2YWwgPSBjdHJsLmNhbihhZGRyLCBvcHRzKSkpKVxuICAgIHJldHVybiBpc0RlZmluZWQodmFsKSA/IHZhbCA6IHRoaXMuZGVmYXVsdF9hcFxuICB9XG59XG4vKipcbiAqIFRoZSBvbGQgdHlwZSBvZiBhY2Nlc3MgY29udHJvbCBiYXNlZCBvbiBhbiBhZGRyZXNzLXRvLXBvbGljeSBtYXAuXG4gKi9cbmV4cG9ydCBjbGFzcyBMZWdhY3lBY2Nlc3NDb250cm9sbGVyIGltcGxlbWVudHMgQWNjZXNzQ29udHJvbGxlciB7XG4gIHB1YmxpYyByZWFkb25seSBtYXAgPSBuZXcgQWRkcmVzc01hcDxBY2Nlc3NQb2xpY3k+KClcbiAgY2FuKHRvOiBNdWx0aXN0cmluZ0FkZHJlc3MpOiBPcHRBY2Nlc3NQb2xpY3kge1xuICAgIHJldHVybiB0aGlzLm1hcC5nZXQodG8pXG4gIH1cbn1cbi8qKlxuICogTG9va3VwIGEgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGFjY2VzcyBvbiBhIHBlci1hZGRyZXNzIGJhc2lzXG4gKi9cbmV4cG9ydCBjbGFzcyBGdW5jdGlvbkxvb2t1cEFjY2Vzc0NvbnRyb2xsZXIgaW1wbGVtZW50cyBBY2Nlc3NDb250cm9sbGVyIHtcbiAgcHVibGljIHJlYWRvbmx5IG1hcCA9IG5ldyBBZGRyZXNzTWFwPEFjY2Vzc0NhbkZ1bmN0aW9uPigpXG4gIGNhbih0bzogTXVsdGlzdHJpbmdBZGRyZXNzLCBvcHRzOiBDYW5DYWxsT3B0cyk6IE9wdEFjY2Vzc1BvbGljeSB7XG4gICAgY29uc3QgZnVuYyA9IHRoaXMubWFwLmdldCh0bylcbiAgICByZXR1cm4gKGZ1bmMgJiYgZnVuYyh0bywgb3B0cykpIHx8IE9wdEFjY2Vzc1BvbGljeS5OT05FXG4gIH1cbn1cbmV4cG9ydCBjb25zdCBDYW5DYWxsRnVuY3Rpb24gPSBTeW1ib2woJ0NhbkNhbGwnKVxuZXhwb3J0IGNvbnN0IFJlcXVpcmVzUGVybWlzc2lvbnMgPSBTeW1ib2woJ1JlcXVpcmVzUGVybWlzc2lvbnMnKVxuZXhwb3J0IGludGVyZmFjZSBQZXJtaXNzaW9uZWRDYW5DYWxsT3B0cyBleHRlbmRzIENhbkNhbGxPcHRzIHtcbiAgcmVxdWlyZTogKHBlcm06IHN0cmluZykgPT4gdm9pZFxuICBwZXJtczogU2V0PHN0cmluZz5cbn1cbmV4cG9ydCB0eXBlIFBlcm1pc3Npb25lZEFjY2Vzc0NhbkZ1bmN0aW9uID0gKFxuICBhZGRyOiBNdWx0aXN0cmluZ0FkZHJlc3MsXG4gIG9wdHM6IFBlcm1pc3Npb25lZENhbkNhbGxPcHRzXG4pID0+IE9wdEFjY2Vzc1BvbGljeVxuLyoqXG4gKiBGaXJzdCwgdGhpcyBgQWNjZXNzQ29udHJvbGxlcmAgd2lsbCBjaGVjayB0aGUgYFJlcXVpcmVzUGVybWlzc2lvbnNgIHByb3BlcnR5XG4gKiBvbiB0aGUgdGFyZ2V0IGZ1bmN0aW9uLiBJZiBhbnkgb2YgdGhlc2UgYXJlIG1pc3NpbmcgZnJvbSB0aGUgbWVtYmVyIGBwZXJtc2BcbiAqIHNldCwgdGhlbiBhY2Nlc3MgaXMgZGVuaWVkLiBPdGhlcndpc2UsIGlmIGBDYW5DYWxsRnVuY3Rpb25gIGlzIGRlZmluZWQsIHRoZW5cbiAqIGl0cyByZXN1bHQgaXMgcmV0dXJuZWQuIFRoZSBgQ2FuQ2FsbEZ1bmN0aW9uYCBtYXkgYWxzbyByZXF1aXJlIHBlcm1pc3Npb25zLlxuICovXG5leHBvcnQgY2xhc3MgQXV0b0Z1bmN0aW9uQWNjZXNzQ29udHJvbGxlciBpbXBsZW1lbnRzIEFjY2Vzc0NvbnRyb2xsZXIge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcGVybXMgPSBuZXcgU2V0PHN0cmluZz4oKSkge31cbiAgY2FuKHRvOiBNdWx0aXN0cmluZ0FkZHJlc3MsIG9wdHM6IENhbkNhbGxPcHRzKTogT3B0QWNjZXNzUG9saWN5IHtcbiAgICBjb25zdCBvYmogPSBvcHRzLmZ1bmMgJiYgb3B0cy5mdW5jW1JlcXVpcmVzUGVybWlzc2lvbnNdXG4gICAgaWYgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnICYmIHR5cGVvZiBvYmpbU3ltYm9sLml0ZXJhdG9yXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgZm9yIChjb25zdCByZXF1aXJlbWVudCBvZiBvYmopIHtcbiAgICAgICAgaWYgKCF0aGlzLnBlcm1zLmhhcyhyZXF1aXJlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gQWNjZXNzUG9saWN5LkRFTllcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBmdW5jID0gb3B0cy5mdW5jICYmIG9wdHMuZnVuY1tDYW5DYWxsRnVuY3Rpb25dXG4gICAgaWYgKHR5cGVvZiBmdW5jID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBjb25zdCByZXF1aXJlbWVudHMgPSBuZXcgU2V0PHN0cmluZz4oKVxuICAgICAgY29uc3QgcmVzdWx0ID0gZnVuYyhcbiAgICAgICAgdG8sXG4gICAgICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAgeyByZXF1aXJlOiAoczogc3RyaW5nKSA9PiByZXF1aXJlbWVudHMuYWRkKHMpLCBwZXJtczogdGhpcy5wZXJtcyB9LFxuICAgICAgICAgIG9wdHNcbiAgICAgICAgKVxuICAgICAgKVxuICAgICAgZm9yIChjb25zdCByZXF1aXJlbWVudCBvZiByZXF1aXJlbWVudHMpIHtcbiAgICAgICAgaWYgKCF0aGlzLnBlcm1zLmhhcyhyZXF1aXJlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gQWNjZXNzUG9saWN5LkRFTllcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIGlzRGVmaW5lZChyZXN1bHQpID8gQm9vbGVhbihyZXN1bHQpIDogT3B0QWNjZXNzUG9saWN5Lk5PTkVcbiAgICB9XG4gICAgcmV0dXJuIE9wdEFjY2Vzc1BvbGljeS5OT05FXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFJlcXVpcmVQZXJtaXNzaW9ucyhwZXJtczogc3RyaW5nW10pIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvclxuICApOiB2b2lkIHtcbiAgICBjb25zdCBmdW5jID0gZGVzY3JpcHRvci52YWx1ZVxuICAgIGlmICh0eXBlb2YgZnVuYyAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQ2Fubm90IHJlcXVpcmUgcGVybWlzc2lvbnMgZm9yIG5vbi1mdW5jdGlvbicpXG4gICAgfVxuICAgIGZ1bmNbUmVxdWlyZXNQZXJtaXNzaW9uc10gPSBwZXJtc1xuICB9XG59XG5leHBvcnQgZnVuY3Rpb24gU2V0Q2FuQ2FsbEZ1bmMoY2FuOiBBY2Nlc3NDYW5GdW5jdGlvbikge1xuICByZXR1cm4gZnVuY3Rpb24gKFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgIHRhcmdldDogYW55LFxuICAgIHByb3BlcnR5S2V5OiBzdHJpbmcsXG4gICAgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IGZ1bmMgPSBkZXNjcmlwdG9yLnZhbHVlXG4gICAgaWYgKHR5cGVvZiBmdW5jICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3Qgc2V0IGFjY2VzcyBjb250cm9sbGVyIGZ1bmMgb24gbm9uLWZ1bmN0aW9uJylcbiAgICB9XG4gICAgZnVuY1tDYW5DYWxsRnVuY3Rpb25dID0gY2FuXG4gIH1cbn1cbiJdfQ==