@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
191 lines (190 loc) • 22.7 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_runtime = require("../_virtual/_rolldown/runtime.cjs.cjs");
const require_events_player_PlayerToggleOperatorEvent = require("../events/player/PlayerToggleOperatorEvent.cjs.cjs");
const require_utils_cwd = require("../utils/cwd.cjs.cjs");
let node_fs = require("node:fs");
node_fs = require_runtime.__toESM(node_fs, 1);
let confbox = require("confbox");
let _jsprismarine_errors = require("@jsprismarine/errors");
//#region src/permission/PermissionManager.ts
var PERMISSION_FILE_NAME = "permissions.json";
var OPS_FILE_NAME = "ops.json";
/**
* Permission manager.
*/
var PermissionManager = class {
server;
ops = /* @__PURE__ */ new Set();
permissions = /* @__PURE__ */ new Map();
defaultPermissions = [];
defaultOperatorPermissions = [];
/**
* Create a new permission manager.
* @param {Server} server - The server instance.
*/
constructor(server) {
this.server = server;
}
/**
* Enable the manager and load all permissions.
* @returns {Promise<void>} A promise that resolves when the manager is enabled.
* @group Lifecycle
*/
async enable() {
await this.parseOps();
await this.parsePermissions();
}
/**
* Signifies that the manager is being disabled and all permissions should be unloaded.
* @returns {Promise<void>} A promise that resolves when the manager is disabled.
* @group Lifecycle
*/
async disable() {
this.ops.clear();
this.permissions.clear();
this.defaultPermissions = [];
}
/**
* Get the default permissions.
* @returns {string[]} The default permissions.
*/
getDefaultPermissions() {
return this.defaultPermissions;
}
/**
* Get a player's permissions.
* @param {Player} player - The player to get permissions for.
* @returns {Promise<string[]>} A promise that resolves with the player's permissions.
*/
async getPermissions(player) {
return [
...this.defaultPermissions,
...this.permissions.get(player.getName()) ?? [],
...player.isOp() ? this.defaultOperatorPermissions : []
];
}
/**
* Set a player's permissions.
*
* @remarks
* This will not be saved to the permissions.json file.
*
* @param {Player} player - The player to set permissions for.
* @param {string[]} [permissions=[]] - The permissions to set.
*/
setPermissions(player, permissions = []) {
this.permissions.set(player.getName(), permissions);
}
async parsePermissions() {
try {
if (!node_fs.default.existsSync(require_utils_cwd.withCwd(PERMISSION_FILE_NAME))) {
this.server.getLogger().warn(`Failed to load permissions list!`);
node_fs.default.writeFileSync(require_utils_cwd.withCwd(PERMISSION_FILE_NAME), JSON.stringify({
defaultPermissions: [
"minecraft.command.help",
"minecraft.command.list",
"minecraft.command.me",
"jsprismarine.command.plugins",
"jsprismarine.command.version",
"jsprismarine.command.tps"
],
defaultOperatorPermissions: ["*"],
players: [{
name: "filfat",
permissions: ["*"]
}]
}, null, 4));
}
const permissionsObject = (0, confbox.parseJSON5)((await node_fs.default.promises.readFile(require_utils_cwd.withCwd(PERMISSION_FILE_NAME))).toString());
this.defaultPermissions = permissionsObject.defaultPermissions || [];
this.defaultOperatorPermissions = permissionsObject.defaultOperatorPermissions || ["*"];
permissionsObject.players?.map((player) => this.permissions.set(player.name, player.permissions.length <= 0 ? [] : player.permissions));
} catch (error) {
this.server.getLogger().error(error);
throw new Error(`Invalid ${PERMISSION_FILE_NAME} file.`);
}
}
async parseOps() {
try {
if (!node_fs.default.existsSync(require_utils_cwd.withCwd(OPS_FILE_NAME))) {
this.server.getLogger().warn(`Failed to load operators list!`);
node_fs.default.writeFileSync(require_utils_cwd.withCwd(OPS_FILE_NAME), "[]");
}
(0, confbox.parseJSON5)((await node_fs.default.promises.readFile(require_utils_cwd.withCwd(OPS_FILE_NAME))).toString()).map((op) => this.ops.add(op.name));
} catch (error) {
this.server.getLogger().error(error);
throw new Error(`Invalid ${OPS_FILE_NAME} file.`);
}
}
/**
* Set a player as an operator.
*
* @param {string} username - The player to set as an operator.
* @param {boolean} op - Whether the player should be an operator.
* @returns {Promise<boolean>} A promise that resolves with a boolean indicating whether the operation was successful.
*/
async setOp(username, op) {
const target = this.server.getSessionManager().getPlayerByExactName(username);
if (!target) throw new _jsprismarine_errors.PlayerNotFoundError(username);
const event = new require_events_player_PlayerToggleOperatorEvent.default(target, op);
this.server.post(["playerToggleOperator", event]);
if (event.isCancelled()) return false;
await target.getNetworkSession().sendAvailableCommands();
if (op) this.ops.add(username);
else this.ops.delete(username);
try {
await node_fs.default.promises.writeFile(require_utils_cwd.withCwd(OPS_FILE_NAME), JSON.stringify(Array.from(this.ops.values()).map((name) => ({
name,
level: 4
})), null, 4));
await target.sendSettings();
return true;
} catch {
return false;
}
}
/**
* Check if a player is an operator.
*
* @param {string} username - The player to check.
* @returns {boolean} Whether the player is an operator.
*/
isOp(username) {
return this.ops.has(username);
}
/**
* Check if a player can execute a command.
*
* @param {Player} executer - The player to check.
* @returns {object} An object with an execute method that takes a permission string and returns whether the player can execute the command.
*/
can(executer) {
const execute = (permission) => {
if (!executer) throw new Error(`Executer can't be undefined or null`);
if (!permission) return true;
if (executer.isConsole()) return true;
if (executer.isOp()) return true;
if (executer.getPermissions().includes(permission)) return true;
if (executer.getPermissions().includes("*")) return true;
const split = permission.split(".");
let scope = "";
for (const action of split) {
if (scope) scope = `${scope}.${action}`;
else scope = action;
if (executer.getPermissions().includes(scope)) return true;
if (executer.getPermissions().includes(`${scope}.*`)) return true;
}
return false;
};
return {
execute,
not: () => {
return { execute: (permission) => !execute(permission) };
}
};
}
};
//#endregion
exports.PermissionManager = PermissionManager;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVybWlzc2lvbk1hbmFnZXIuY2pzLmNqcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi9zcmMvcGVybWlzc2lvbi9QZXJtaXNzaW9uTWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSAnbm9kZTpmcyc7XG5cbmltcG9ydCB7IHBhcnNlSlNPTjUgfSBmcm9tICdjb25mYm94JztcblxuaW1wb3J0IHsgUGxheWVyTm90Rm91bmRFcnJvciB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvZXJyb3JzJztcbmltcG9ydCB0eXBlIHsgUGxheWVyLCBTZXJ2ZXIsIFNlcnZpY2UgfSBmcm9tICcuLi8nO1xuaW1wb3J0IHsgd2l0aEN3ZCB9IGZyb20gJy4uLyc7XG5pbXBvcnQgcGxheWVyVG9nZ2xlT3BlcmF0b3JFdmVudCBmcm9tICcuLi9ldmVudHMvcGxheWVyL1BsYXllclRvZ2dsZU9wZXJhdG9yRXZlbnQnO1xuXG5pbnRlcmZhY2UgT3BUeXBlIHtcbiAgICBuYW1lOiBzdHJpbmc7XG59XG5cbmNvbnN0IFBFUk1JU1NJT05fRklMRV9OQU1FID0gJ3Blcm1pc3Npb25zLmpzb24nO1xuY29uc3QgT1BTX0ZJTEVfTkFNRSA9ICdvcHMuanNvbic7XG5cbi8qKlxuICogUGVybWlzc2lvbiBtYW5hZ2VyLlxuICovXG5leHBvcnQgY2xhc3MgUGVybWlzc2lvbk1hbmFnZXIgaW1wbGVtZW50cyBTZXJ2aWNlIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNlcnZlcjogU2VydmVyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgb3BzOiBTZXQ8c3RyaW5nPiA9IG5ldyBTZXQoKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBlcm1pc3Npb25zOiBNYXA8c3RyaW5nLCBzdHJpbmdbXT4gPSBuZXcgTWFwKCk7XG4gICAgcHJpdmF0ZSBkZWZhdWx0UGVybWlzc2lvbnM6IHN0cmluZ1tdID0gW107XG4gICAgcHJpdmF0ZSBkZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9uczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG5ldyBwZXJtaXNzaW9uIG1hbmFnZXIuXG4gICAgICogQHBhcmFtIHtTZXJ2ZXJ9IHNlcnZlciAtIFRoZSBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAgICovXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHNlcnZlcjogU2VydmVyKSB7XG4gICAgICAgIHRoaXMuc2VydmVyID0gc2VydmVyO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVuYWJsZSB0aGUgbWFuYWdlciBhbmQgbG9hZCBhbGwgcGVybWlzc2lvbnMuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG1hbmFnZXIgaXMgZW5hYmxlZC5cbiAgICAgKiBAZ3JvdXAgTGlmZWN5Y2xlXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGVuYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wYXJzZU9wcygpO1xuICAgICAgICBhd2FpdCB0aGlzLnBhcnNlUGVybWlzc2lvbnMoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTaWduaWZpZXMgdGhhdCB0aGUgbWFuYWdlciBpcyBiZWluZyBkaXNhYmxlZCBhbmQgYWxsIHBlcm1pc3Npb25zIHNob3VsZCBiZSB1bmxvYWRlZC5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgbWFuYWdlciBpcyBkaXNhYmxlZC5cbiAgICAgKiBAZ3JvdXAgTGlmZWN5Y2xlXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGRpc2FibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMub3BzLmNsZWFyKCk7XG4gICAgICAgIHRoaXMucGVybWlzc2lvbnMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5kZWZhdWx0UGVybWlzc2lvbnMgPSBbXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGRlZmF1bHQgcGVybWlzc2lvbnMuXG4gICAgICogQHJldHVybnMge3N0cmluZ1tdfSBUaGUgZGVmYXVsdCBwZXJtaXNzaW9ucy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0RGVmYXVsdFBlcm1pc3Npb25zKCk6IHN0cmluZ1tdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVmYXVsdFBlcm1pc3Npb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIHBsYXllcidzIHBlcm1pc3Npb25zLlxuICAgICAqIEBwYXJhbSB7UGxheWVyfSBwbGF5ZXIgLSBUaGUgcGxheWVyIHRvIGdldCBwZXJtaXNzaW9ucyBmb3IuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBwbGF5ZXIncyBwZXJtaXNzaW9ucy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZ2V0UGVybWlzc2lvbnMocGxheWVyOiBQbGF5ZXIpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAuLi50aGlzLmRlZmF1bHRQZXJtaXNzaW9ucyxcbiAgICAgICAgICAgIC4uLih0aGlzLnBlcm1pc3Npb25zLmdldChwbGF5ZXIuZ2V0TmFtZSgpKSA/PyBbXSksXG4gICAgICAgICAgICAuLi4ocGxheWVyLmlzT3AoKSA/IHRoaXMuZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnMgOiBbXSlcbiAgICAgICAgXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgYSBwbGF5ZXIncyBwZXJtaXNzaW9ucy5cbiAgICAgKlxuICAgICAqIEByZW1hcmtzXG4gICAgICogVGhpcyB3aWxsIG5vdCBiZSBzYXZlZCB0byB0aGUgcGVybWlzc2lvbnMuanNvbiBmaWxlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtQbGF5ZXJ9IHBsYXllciAtIFRoZSBwbGF5ZXIgdG8gc2V0IHBlcm1pc3Npb25zIGZvci5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBbcGVybWlzc2lvbnM9W11dIC0gVGhlIHBlcm1pc3Npb25zIHRvIHNldC5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0UGVybWlzc2lvbnMocGxheWVyOiBQbGF5ZXIsIHBlcm1pc3Npb25zOiBzdHJpbmdbXSA9IFtdKSB7XG4gICAgICAgIHRoaXMucGVybWlzc2lvbnMuc2V0KHBsYXllci5nZXROYW1lKCksIHBlcm1pc3Npb25zKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHBhcnNlUGVybWlzc2lvbnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMod2l0aEN3ZChQRVJNSVNTSU9OX0ZJTEVfTkFNRSkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgRmFpbGVkIHRvIGxvYWQgcGVybWlzc2lvbnMgbGlzdCFgKTtcbiAgICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKFxuICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRTogVGhpcyBvdmVyd3JpdGVzIGNvbW1lbnRzIGluIHRoZSBmaWxlLlxuICAgICAgICAgICAgICAgICAgICB3aXRoQ3dkKFBFUk1JU1NJT05fRklMRV9OQU1FKSxcbiAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFBlcm1pc3Npb25zOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtaW5lY3JhZnQuY29tbWFuZC5oZWxwJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21pbmVjcmFmdC5jb21tYW5kLmxpc3QnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWluZWNyYWZ0LmNvbW1hbmQubWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnanNwcmlzbWFyaW5lLmNvbW1hbmQucGx1Z2lucycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdqc3ByaXNtYXJpbmUuY29tbWFuZC52ZXJzaW9uJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2pzcHJpc21hcmluZS5jb21tYW5kLnRwcydcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zOiBbJyonXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF5ZXJzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6ICdmaWxmYXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVybWlzc2lvbnM6IFsnKiddXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIDRcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHBlcm1pc3Npb25zT2JqZWN0OiBQYXJ0aWFsPHtcbiAgICAgICAgICAgICAgICBkZWZhdWx0UGVybWlzc2lvbnM6IHN0cmluZ1tdO1xuICAgICAgICAgICAgICAgIGRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zOiBzdHJpbmdbXTtcbiAgICAgICAgICAgICAgICBwbGF5ZXJzOiBBcnJheTx7XG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgcGVybWlzc2lvbnM6IHN0cmluZ1tdO1xuICAgICAgICAgICAgICAgIH0+O1xuICAgICAgICAgICAgfT4gPSBwYXJzZUpTT041KChhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZSh3aXRoQ3dkKFBFUk1JU1NJT05fRklMRV9OQU1FKSkpLnRvU3RyaW5nKCkpO1xuXG4gICAgICAgICAgICB0aGlzLmRlZmF1bHRQZXJtaXNzaW9ucyA9IHBlcm1pc3Npb25zT2JqZWN0LmRlZmF1bHRQZXJtaXNzaW9ucyB8fCBbXTtcbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnMgPSBwZXJtaXNzaW9uc09iamVjdC5kZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9ucyB8fCBbJyonXTtcbiAgICAgICAgICAgIHBlcm1pc3Npb25zT2JqZWN0LnBsYXllcnM/Lm1hcCgocGxheWVyKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMucGVybWlzc2lvbnMuc2V0KHBsYXllci5uYW1lLCBwbGF5ZXIucGVybWlzc2lvbnMubGVuZ3RoIDw9IDAgPyBbXSA6IHBsYXllci5wZXJtaXNzaW9ucylcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgJHtQRVJNSVNTSU9OX0ZJTEVfTkFNRX0gZmlsZS5gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcGFyc2VPcHMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMod2l0aEN3ZChPUFNfRklMRV9OQU1FKSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS53YXJuKGBGYWlsZWQgdG8gbG9hZCBvcGVyYXRvcnMgbGlzdCFgKTtcbiAgICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHdpdGhDd2QoT1BTX0ZJTEVfTkFNRSksICdbXScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgb3BzOiBPcFR5cGVbXSA9IHBhcnNlSlNPTjUoKGF3YWl0IGZzLnByb21pc2VzLnJlYWRGaWxlKHdpdGhDd2QoT1BTX0ZJTEVfTkFNRSkpKS50b1N0cmluZygpKTtcblxuICAgICAgICAgICAgb3BzLm1hcCgob3ApID0+IHRoaXMub3BzLmFkZChvcC5uYW1lKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgJHtPUFNfRklMRV9OQU1FfSBmaWxlLmApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IGEgcGxheWVyIGFzIGFuIG9wZXJhdG9yLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJuYW1lIC0gVGhlIHBsYXllciB0byBzZXQgYXMgYW4gb3BlcmF0b3IuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBvcCAtIFdoZXRoZXIgdGhlIHBsYXllciBzaG91bGQgYmUgYW4gb3BlcmF0b3IuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggYSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgb3BlcmF0aW9uIHdhcyBzdWNjZXNzZnVsLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRPcCh1c2VybmFtZTogc3RyaW5nLCBvcDogYm9vbGVhbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSB0aGlzLnNlcnZlci5nZXRTZXNzaW9uTWFuYWdlcigpLmdldFBsYXllckJ5RXhhY3ROYW1lKHVzZXJuYW1lKTsgLy8gVE9ETzogYnkgbmFtZSBub3QgZXhhY3RcbiAgICAgICAgaWYgKCF0YXJnZXQpIHRocm93IG5ldyBQbGF5ZXJOb3RGb3VuZEVycm9yKHVzZXJuYW1lKTtcbiAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgcGxheWVyVG9nZ2xlT3BlcmF0b3JFdmVudCh0YXJnZXQsIG9wKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIucG9zdChbJ3BsYXllclRvZ2dsZU9wZXJhdG9yJywgZXZlbnRdKTtcbiAgICAgICAgaWYgKGV2ZW50LmlzQ2FuY2VsbGVkKCkpIHJldHVybiBmYWxzZTtcblxuICAgICAgICBhd2FpdCB0YXJnZXQuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kQXZhaWxhYmxlQ29tbWFuZHMoKTtcblxuICAgICAgICBpZiAob3ApIHRoaXMub3BzLmFkZCh1c2VybmFtZSk7XG4gICAgICAgIGVsc2UgdGhpcy5vcHMuZGVsZXRlKHVzZXJuYW1lKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMud3JpdGVGaWxlKFxuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBUaGlzIG92ZXJ3cml0ZXMgY29tbWVudHMgaW4gdGhlIGZpbGUuXG4gICAgICAgICAgICAgICAgd2l0aEN3ZChPUFNfRklMRV9OQU1FKSxcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgQXJyYXkuZnJvbSh0aGlzLm9wcy52YWx1ZXMoKSkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsOiA0XG4gICAgICAgICAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgNFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGF3YWl0IHRhcmdldC5zZW5kU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIGEgcGxheWVyIGlzIGFuIG9wZXJhdG9yLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJuYW1lIC0gVGhlIHBsYXllciB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgcGxheWVyIGlzIGFuIG9wZXJhdG9yLlxuICAgICAqL1xuICAgIHB1YmxpYyBpc09wKHVzZXJuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3BzLmhhcyh1c2VybmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgYSBwbGF5ZXIgY2FuIGV4ZWN1dGUgYSBjb21tYW5kLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtQbGF5ZXJ9IGV4ZWN1dGVyIC0gVGhlIHBsYXllciB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7b2JqZWN0fSBBbiBvYmplY3Qgd2l0aCBhbiBleGVjdXRlIG1ldGhvZCB0aGF0IHRha2VzIGEgcGVybWlzc2lvbiBzdHJpbmcgYW5kIHJldHVybnMgd2hldGhlciB0aGUgcGxheWVyIGNhbiBleGVjdXRlIHRoZSBjb21tYW5kLlxuICAgICAqL1xuICAgIHB1YmxpYyBjYW4oZXhlY3V0ZXI/OiBQbGF5ZXIpIHtcbiAgICAgICAgY29uc3QgZXhlY3V0ZSA9IChwZXJtaXNzaW9uPzogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBpZiAoIWV4ZWN1dGVyKSB0aHJvdyBuZXcgRXJyb3IoYEV4ZWN1dGVyIGNhbid0IGJlIHVuZGVmaW5lZCBvciBudWxsYCk7XG5cbiAgICAgICAgICAgIGlmICghcGVybWlzc2lvbikgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZXIuaXNDb25zb2xlKCkpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmlzT3AoKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZXIuZ2V0UGVybWlzc2lvbnMoKS5pbmNsdWRlcyhwZXJtaXNzaW9uKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZXIuZ2V0UGVybWlzc2lvbnMoKS5pbmNsdWRlcygnKicpKSByZXR1cm4gdHJ1ZTtcblxuICAgICAgICAgICAgY29uc3Qgc3BsaXQgPSBwZXJtaXNzaW9uLnNwbGl0KCcuJyk7XG4gICAgICAgICAgICBsZXQgc2NvcGUgPSAnJztcbiAgICAgICAgICAgIGZvciAoY29uc3QgYWN0aW9uIG9mIHNwbGl0KSB7XG4gICAgICAgICAgICAgICAgaWYgKHNjb3BlKSBzY29wZSA9IGAke3Njb3BlfS4ke2FjdGlvbn1gO1xuICAgICAgICAgICAgICAgIGVsc2Ugc2NvcGUgPSBhY3Rpb247XG5cbiAgICAgICAgICAgICAgICBpZiAoZXhlY3V0ZXIuZ2V0UGVybWlzc2lvbnMoKS5pbmNsdWRlcyhzY29wZSkpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKGAke3Njb3BlfS4qYCkpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGV4ZWN1dGUsXG4gICAgICAgICAgICBub3Q6ICgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBleGVjdXRlOiAocGVybWlzc2lvbj86IHN0cmluZykgPT4gIWV4ZWN1dGUocGVybWlzc2lvbilcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xu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