@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
187 lines (186 loc) • 22 kB
JavaScript
import playerToggleOperatorEvent from "../events/player/PlayerToggleOperatorEvent.es.js";
import { withCwd } from "../utils/cwd.es.js";
import fs from "node:fs";
import { parseJSON5 } from "confbox";
import { PlayerNotFoundError } from "@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 (!fs.existsSync(withCwd(PERMISSION_FILE_NAME))) {
this.server.getLogger().warn(`Failed to load permissions list!`);
fs.writeFileSync(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 = parseJSON5((await fs.promises.readFile(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 (!fs.existsSync(withCwd(OPS_FILE_NAME))) {
this.server.getLogger().warn(`Failed to load operators list!`);
fs.writeFileSync(withCwd(OPS_FILE_NAME), "[]");
}
parseJSON5((await fs.promises.readFile(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 PlayerNotFoundError(username);
const event = new playerToggleOperatorEvent(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 fs.promises.writeFile(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
export { PermissionManager };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVybWlzc2lvbk1hbmFnZXIuZXMuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Blcm1pc3Npb24vUGVybWlzc2lvbk1hbmFnZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMnO1xuXG5pbXBvcnQgeyBwYXJzZUpTT041IH0gZnJvbSAnY29uZmJveCc7XG5cbmltcG9ydCB7IFBsYXllck5vdEZvdW5kRXJyb3IgfSBmcm9tICdAanNwcmlzbWFyaW5lL2Vycm9ycyc7XG5pbXBvcnQgdHlwZSB7IFBsYXllciwgU2VydmVyLCBTZXJ2aWNlIH0gZnJvbSAnLi4vJztcbmltcG9ydCB7IHdpdGhDd2QgfSBmcm9tICcuLi8nO1xuaW1wb3J0IHBsYXllclRvZ2dsZU9wZXJhdG9yRXZlbnQgZnJvbSAnLi4vZXZlbnRzL3BsYXllci9QbGF5ZXJUb2dnbGVPcGVyYXRvckV2ZW50JztcblxuaW50ZXJmYWNlIE9wVHlwZSB7XG4gICAgbmFtZTogc3RyaW5nO1xufVxuXG5jb25zdCBQRVJNSVNTSU9OX0ZJTEVfTkFNRSA9ICdwZXJtaXNzaW9ucy5qc29uJztcbmNvbnN0IE9QU19GSUxFX05BTUUgPSAnb3BzLmpzb24nO1xuXG4vKipcbiAqIFBlcm1pc3Npb24gbWFuYWdlci5cbiAqL1xuZXhwb3J0IGNsYXNzIFBlcm1pc3Npb25NYW5hZ2VyIGltcGxlbWVudHMgU2VydmljZSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IG9wczogU2V0PHN0cmluZz4gPSBuZXcgU2V0KCk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBwZXJtaXNzaW9uczogTWFwPHN0cmluZywgc3RyaW5nW10+ID0gbmV3IE1hcCgpO1xuICAgIHByaXZhdGUgZGVmYXVsdFBlcm1pc3Npb25zOiBzdHJpbmdbXSA9IFtdO1xuICAgIHByaXZhdGUgZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYSBuZXcgcGVybWlzc2lvbiBtYW5hZ2VyLlxuICAgICAqIEBwYXJhbSB7U2VydmVyfSBzZXJ2ZXIgLSBUaGUgc2VydmVyIGluc3RhbmNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihzZXJ2ZXI6IFNlcnZlcikge1xuICAgICAgICB0aGlzLnNlcnZlciA9IHNlcnZlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGUgdGhlIG1hbmFnZXIgYW5kIGxvYWQgYWxsIHBlcm1pc3Npb25zLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBtYW5hZ2VyIGlzIGVuYWJsZWQuXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBlbmFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMucGFyc2VPcHMoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5wYXJzZVBlcm1pc3Npb25zKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2lnbmlmaWVzIHRoYXQgdGhlIG1hbmFnZXIgaXMgYmVpbmcgZGlzYWJsZWQgYW5kIGFsbCBwZXJtaXNzaW9ucyBzaG91bGQgYmUgdW5sb2FkZWQuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG1hbmFnZXIgaXMgZGlzYWJsZWQuXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBkaXNhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLm9wcy5jbGVhcigpO1xuICAgICAgICB0aGlzLnBlcm1pc3Npb25zLmNsZWFyKCk7XG4gICAgICAgIHRoaXMuZGVmYXVsdFBlcm1pc3Npb25zID0gW107XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBkZWZhdWx0IHBlcm1pc3Npb25zLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gVGhlIGRlZmF1bHQgcGVybWlzc2lvbnMuXG4gICAgICovXG4gICAgcHVibGljIGdldERlZmF1bHRQZXJtaXNzaW9ucygpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlZmF1bHRQZXJtaXNzaW9ucztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYSBwbGF5ZXIncyBwZXJtaXNzaW9ucy5cbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gcGxheWVyIC0gVGhlIHBsYXllciB0byBnZXQgcGVybWlzc2lvbnMgZm9yLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZ1tdPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcGxheWVyJ3MgcGVybWlzc2lvbnMuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGdldFBlcm1pc3Npb25zKHBsYXllcjogUGxheWVyKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgLi4udGhpcy5kZWZhdWx0UGVybWlzc2lvbnMsXG4gICAgICAgICAgICAuLi4odGhpcy5wZXJtaXNzaW9ucy5nZXQocGxheWVyLmdldE5hbWUoKSkgPz8gW10pLFxuICAgICAgICAgICAgLi4uKHBsYXllci5pc09wKCkgPyB0aGlzLmRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zIDogW10pXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IGEgcGxheWVyJ3MgcGVybWlzc2lvbnMuXG4gICAgICpcbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFRoaXMgd2lsbCBub3QgYmUgc2F2ZWQgdG8gdGhlIHBlcm1pc3Npb25zLmpzb24gZmlsZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UGxheWVyfSBwbGF5ZXIgLSBUaGUgcGxheWVyIHRvIHNldCBwZXJtaXNzaW9ucyBmb3IuXG4gICAgICogQHBhcmFtIHtzdHJpbmdbXX0gW3Blcm1pc3Npb25zPVtdXSAtIFRoZSBwZXJtaXNzaW9ucyB0byBzZXQuXG4gICAgICovXG4gICAgcHVibGljIHNldFBlcm1pc3Npb25zKHBsYXllcjogUGxheWVyLCBwZXJtaXNzaW9uczogc3RyaW5nW10gPSBbXSkge1xuICAgICAgICB0aGlzLnBlcm1pc3Npb25zLnNldChwbGF5ZXIuZ2V0TmFtZSgpLCBwZXJtaXNzaW9ucyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwYXJzZVBlcm1pc3Npb25zKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHdpdGhDd2QoUEVSTUlTU0lPTl9GSUxFX05BTUUpKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLndhcm4oYEZhaWxlZCB0byBsb2FkIHBlcm1pc3Npb25zIGxpc3QhYCk7XG4gICAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgICAgICAgLy8gRklYTUU6IFRoaXMgb3ZlcndyaXRlcyBjb21tZW50cyBpbiB0aGUgZmlsZS5cbiAgICAgICAgICAgICAgICAgICAgd2l0aEN3ZChQRVJNSVNTSU9OX0ZJTEVfTkFNRSksXG4gICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRQZXJtaXNzaW9uczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWluZWNyYWZ0LmNvbW1hbmQuaGVscCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtaW5lY3JhZnQuY29tbWFuZC5saXN0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21pbmVjcmFmdC5jb21tYW5kLm1lJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2pzcHJpc21hcmluZS5jb21tYW5kLnBsdWdpbnMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnanNwcmlzbWFyaW5lLmNvbW1hbmQudmVyc2lvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdqc3ByaXNtYXJpbmUuY29tbWFuZC50cHMnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9uczogWycqJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiAnZmlsZmF0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb25zOiBbJyonXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICA0XG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBwZXJtaXNzaW9uc09iamVjdDogUGFydGlhbDx7XG4gICAgICAgICAgICAgICAgZGVmYXVsdFBlcm1pc3Npb25zOiBzdHJpbmdbXTtcbiAgICAgICAgICAgICAgICBkZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9uczogc3RyaW5nW107XG4gICAgICAgICAgICAgICAgcGxheWVyczogQXJyYXk8e1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb25zOiBzdHJpbmdbXTtcbiAgICAgICAgICAgICAgICB9PjtcbiAgICAgICAgICAgIH0+ID0gcGFyc2VKU09ONSgoYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUod2l0aEN3ZChQRVJNSVNTSU9OX0ZJTEVfTkFNRSkpKS50b1N0cmluZygpKTtcblxuICAgICAgICAgICAgdGhpcy5kZWZhdWx0UGVybWlzc2lvbnMgPSBwZXJtaXNzaW9uc09iamVjdC5kZWZhdWx0UGVybWlzc2lvbnMgfHwgW107XG4gICAgICAgICAgICB0aGlzLmRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zID0gcGVybWlzc2lvbnNPYmplY3QuZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnMgfHwgWycqJ107XG4gICAgICAgICAgICBwZXJtaXNzaW9uc09iamVjdC5wbGF5ZXJzPy5tYXAoKHBsYXllcikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnBlcm1pc3Npb25zLnNldChwbGF5ZXIubmFtZSwgcGxheWVyLnBlcm1pc3Npb25zLmxlbmd0aCA8PSAwID8gW10gOiBwbGF5ZXIucGVybWlzc2lvbnMpXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICR7UEVSTUlTU0lPTl9GSUxFX05BTUV9IGZpbGUuYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHBhcnNlT3BzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHdpdGhDd2QoT1BTX0ZJTEVfTkFNRSkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgRmFpbGVkIHRvIGxvYWQgb3BlcmF0b3JzIGxpc3QhYCk7XG4gICAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyh3aXRoQ3dkKE9QU19GSUxFX05BTUUpLCAnW10nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IG9wczogT3BUeXBlW10gPSBwYXJzZUpTT041KChhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZSh3aXRoQ3dkKE9QU19GSUxFX05BTUUpKSkudG9TdHJpbmcoKSk7XG5cbiAgICAgICAgICAgIG9wcy5tYXAoKG9wKSA9PiB0aGlzLm9wcy5hZGQob3AubmFtZSkpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICR7T1BTX0ZJTEVfTkFNRX0gZmlsZS5gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBhIHBsYXllciBhcyBhbiBvcGVyYXRvci5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VybmFtZSAtIFRoZSBwbGF5ZXIgdG8gc2V0IGFzIGFuIG9wZXJhdG9yLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gb3AgLSBXaGV0aGVyIHRoZSBwbGF5ZXIgc2hvdWxkIGJlIGFuIG9wZXJhdG9yLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIG9wZXJhdGlvbiB3YXMgc3VjY2Vzc2Z1bC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2V0T3AodXNlcm5hbWU6IHN0cmluZywgb3A6IGJvb2xlYW4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gdGhpcy5zZXJ2ZXIuZ2V0U2Vzc2lvbk1hbmFnZXIoKS5nZXRQbGF5ZXJCeUV4YWN0TmFtZSh1c2VybmFtZSk7IC8vIFRPRE86IGJ5IG5hbWUgbm90IGV4YWN0XG4gICAgICAgIGlmICghdGFyZ2V0KSB0aHJvdyBuZXcgUGxheWVyTm90Rm91bmRFcnJvcih1c2VybmFtZSk7XG4gICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IHBsYXllclRvZ2dsZU9wZXJhdG9yRXZlbnQodGFyZ2V0LCBvcCk7XG4gICAgICAgIHRoaXMuc2VydmVyLnBvc3QoWydwbGF5ZXJUb2dnbGVPcGVyYXRvcicsIGV2ZW50XSk7XG4gICAgICAgIGlmIChldmVudC5pc0NhbmNlbGxlZCgpKSByZXR1cm4gZmFsc2U7XG5cbiAgICAgICAgYXdhaXQgdGFyZ2V0LmdldE5ldHdvcmtTZXNzaW9uKCkuc2VuZEF2YWlsYWJsZUNvbW1hbmRzKCk7XG5cbiAgICAgICAgaWYgKG9wKSB0aGlzLm9wcy5hZGQodXNlcm5hbWUpO1xuICAgICAgICBlbHNlIHRoaXMub3BzLmRlbGV0ZSh1c2VybmFtZSk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGZzLnByb21pc2VzLndyaXRlRmlsZShcbiAgICAgICAgICAgICAgICAvLyBGSVhNRTogVGhpcyBvdmVyd3JpdGVzIGNvbW1lbnRzIGluIHRoZSBmaWxlLlxuICAgICAgICAgICAgICAgIHdpdGhDd2QoT1BTX0ZJTEVfTkFNRSksXG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgIEFycmF5LmZyb20odGhpcy5vcHMudmFsdWVzKCkpLm1hcCgobmFtZSkgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXZlbDogNFxuICAgICAgICAgICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgICAgIDRcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBhd2FpdCB0YXJnZXQuc2VuZFNldHRpbmdzKCk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBhIHBsYXllciBpcyBhbiBvcGVyYXRvci5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VybmFtZSAtIFRoZSBwbGF5ZXIgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHBsYXllciBpcyBhbiBvcGVyYXRvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgaXNPcCh1c2VybmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wcy5oYXModXNlcm5hbWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIGEgcGxheWVyIGNhbiBleGVjdXRlIGEgY29tbWFuZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UGxheWVyfSBleGVjdXRlciAtIFRoZSBwbGF5ZXIgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge29iamVjdH0gQW4gb2JqZWN0IHdpdGggYW4gZXhlY3V0ZSBtZXRob2QgdGhhdCB0YWtlcyBhIHBlcm1pc3Npb24gc3RyaW5nIGFuZCByZXR1cm5zIHdoZXRoZXIgdGhlIHBsYXllciBjYW4gZXhlY3V0ZSB0aGUgY29tbWFuZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgY2FuKGV4ZWN1dGVyPzogUGxheWVyKSB7XG4gICAgICAgIGNvbnN0IGV4ZWN1dGUgPSAocGVybWlzc2lvbj86IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgaWYgKCFleGVjdXRlcikgdGhyb3cgbmV3IEVycm9yKGBFeGVjdXRlciBjYW4ndCBiZSB1bmRlZmluZWQgb3IgbnVsbGApO1xuXG4gICAgICAgICAgICBpZiAoIXBlcm1pc3Npb24pIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmlzQ29uc29sZSgpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5pc09wKCkpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmdldFBlcm1pc3Npb25zKCkuaW5jbHVkZXMocGVybWlzc2lvbikpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmdldFBlcm1pc3Npb25zKCkuaW5jbHVkZXMoJyonKSkgcmV0dXJuIHRydWU7XG5cbiAgICAgICAgICAgIGNvbnN0IHNwbGl0ID0gcGVybWlzc2lvbi5zcGxpdCgnLicpO1xuICAgICAgICAgICAgbGV0IHNjb3BlID0gJyc7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGFjdGlvbiBvZiBzcGxpdCkge1xuICAgICAgICAgICAgICAgIGlmIChzY29wZSkgc2NvcGUgPSBgJHtzY29wZX0uJHthY3Rpb259YDtcbiAgICAgICAgICAgICAgICBlbHNlIHNjb3BlID0gYWN0aW9uO1xuXG4gICAgICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmdldFBlcm1pc3Npb25zKCkuaW5jbHVkZXMoc2NvcGUpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICBpZiAoZXhlY3V0ZXIuZ2V0UGVybWlzc2lvbnMoKS5pbmNsdWRlcyhgJHtzY29wZX0uKmApKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBleGVjdXRlLFxuICAgICAgICAgICAgbm90OiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgZXhlY3V0ZTogKHBlcm1pc3Npb24/OiBzdHJpbmcpID0+ICFleGVjdXRlKHBlcm1pc3Npb24pXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAg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