@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
307 lines (304 loc) • 30.7 kB
JavaScript
import fs from 'node:fs';
import { parseJSON5 } from 'confbox';
import { PlayerNotFoundError } from '@jsprismarine/errors';
import '@jsprismarine/jsbinaryutils';
import 'node:assert';
import { withCwd } from '../utils/cwd.es.js';
import '../block/BlockToolType.es.js';
import '@jsprismarine/bedrock-data';
import '@jsprismarine/nbt';
import 'zlib';
import '@jsprismarine/math';
import '@jsprismarine/minecraft';
import '../network/packet/AddActorPacket.es.js';
import '../network/packet/MoveActorAbsolutePacket.es.js';
import '../network/packet/RemoveActorPacket.es.js';
import 'node:crypto';
import '../network/packet/ActorFallPacket.es.js';
import '../network/packet/AddItemActorPacket.es.js';
import '../network/packet/AddPlayerPacket.es.js';
import '../network/packet/AnimatePacket.es.js';
import '../network/packet/AvailableActorIdentifiersPacket.es.js';
import '../network/packet/AvailableCommandsPacket.es.js';
import '../network/CompressionProvider.es.js';
import '../network/packet/NetworkSettingsPacket.es.js';
import '../network/packet/BiomeDefinitionListPacket.es.js';
import '../network/packet/ChangeDimensionPacket.es.js';
import '../network/packet/ChunkRadiusUpdatedPacket.es.js';
import '../network/packet/CommandRequestPacket.es.js';
import '../network/packet/ContainerClosePacket.es.js';
import '../network/packet/ContainerOpenPacket.es.js';
import '../network/packet/CreativeContentPacket.es.js';
import '../network/packet/DisconnectPacket.es.js';
import '../network/packet/EmoteListPacket.es.js';
import '../network/packet/InteractPacket.es.js';
import '../network/packet/InventoryContentPacket.es.js';
import '../network/packet/InventoryTransactionPacket.es.js';
import '../network/packet/ItemComponentPacket.es.js';
import '../network/packet/ItemStackRequestPacket.es.js';
import '../network/packet/ItemStackResponsePacket.es.js';
import '../network/packet/LevelChunkPacket.es.js';
import '../network/packet/LevelSoundEventPacket.es.js';
import '../network/packet/LoginPacket.es.js';
import '../network/packet/MobEquipmentPacket.es.js';
import '../network/packet/MovePlayerPacket.es.js';
import '../network/packet/NetworkChunkPublisherUpdatePacket.es.js';
import '../network/packet/OnScreenTextureAnimationPacket.es.js';
import '../network/packet/PacketViolationWarningPacket.es.js';
import '../network/packet/PlaySoundPacket.es.js';
import '../network/packet/PlayStatusPacket.es.js';
import '../network/packet/PlayerActionPacket.es.js';
import '../network/packet/PlayerListPacket.es.js';
import '../network/packet/PlayerSkinPacket.es.js';
import '../network/packet/RequestChunkRadiusPacket.es.js';
import '../network/packet/RequestNetworkSettingsPacket.es.js';
import '../network/packet/ResourcePackResponsePacket.es.js';
import '../network/packet/ResourcePackStackPacket.es.js';
import '../network/packet/ResourcePacksInfoPacket.es.js';
import '../network/packet/ServerSettingsRequestPacket.es.js';
import '../network/packet/SetActorDataPacket.es.js';
import '../network/packet/SetDefaultGametypePacket.es.js';
import '../network/packet/SetHealthPacket.es.js';
import '../network/packet/SetLocalPlayerAsInitializedPacket.es.js';
import '../network/packet/SetPlayerGametypePacket.es.js';
import '../network/packet/SetTimePacket.es.js';
import '../network/packet/ShowProfilePacket.es.js';
import '../network/packet/StartGamePacket.es.js';
import '../network/packet/TextPacket.es.js';
import '../network/packet/TickSyncPacket.es.js';
import '../network/packet/TransferPacket.es.js';
import '../network/packet/UpdateAdventureSettingsPacket.es.js';
import '../network/packet/UpdateAttributesPacket.es.js';
import '../network/packet/UpdateBlockPacket.es.js';
import '../network/packet/WorldEventPacket.es.js';
import 'node:path';
import '@jsprismarine/brigadier';
import '../config/Config.es.js';
import playerToggleOperatorEvent from '../events/player/PlayerToggleOperatorEvent.es.js';
import '../network/handler/AnimateHandler.es.js';
import '../network/handler/CommandRequestHandler.es.js';
import '../network/handler/ContainerCloseHandler.es.js';
import '../network/handler/EmoteListHandler.es.js';
import '../network/handler/InteractHandler.es.js';
import '../network/handler/InventoryTransactionHandler.es.js';
import '../network/handler/LevelSoundEventHandler.es.js';
import '../network/handler/LoginHandler.es.js';
import '../network/handler/MobEquipmentHandler.es.js';
import '../network/handler/MovePlayerHandler.es.js';
import '../network/handler/PacketViolationWarningHandler.es.js';
import '../network/handler/PlayerActionHandler.es.js';
import '../network/handler/RequestChunkRadiusHandler.es.js';
import '../network/handler/RequestNetworkSettingsHandler.es.js';
import '../network/handler/ResourcePackResponseHandler.es.js';
import '../network/handler/ServerSettingsRequestHandler.es.js';
import '../network/handler/SetDefaultGametypeHandler.es.js';
import '../network/handler/SetLocalPlayerAsInitializedHandler.es.js';
import '../network/handler/SetPlayerGametypeHandler.es.js';
import '../network/handler/TextHandler.es.js';
import '../network/handler/TickSyncHandler.es.js';
import 'node:process';
import 'node:readline';
import 'heap';
import '../network/packet/UpdateAbilitiesPacket.es.js';
import '@jsprismarine/raknet';
import 'evt';
import 'assert';
const PERMISSION_FILE_NAME = "permissions.json";
const OPS_FILE_NAME = "ops.json";
class PermissionManager {
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(
// FIXME: This overwrites comments in the file.
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), "[]");
}
const ops = parseJSON5((await fs.promises.readFile(withCwd(OPS_FILE_NAME))).toString());
ops.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(
// FIXME: This overwrites comments in the file.
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)
};
}
};
}
}
export { PermissionManager };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVybWlzc2lvbk1hbmFnZXIuZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wZXJtaXNzaW9uL1Blcm1pc3Npb25NYW5hZ2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdub2RlOmZzJztcblxuaW1wb3J0IHsgcGFyc2VKU09ONSB9IGZyb20gJ2NvbmZib3gnO1xuXG5pbXBvcnQgeyBQbGF5ZXJOb3RGb3VuZEVycm9yIH0gZnJvbSAnQGpzcHJpc21hcmluZS9lcnJvcnMnO1xuaW1wb3J0IHR5cGUgeyBQbGF5ZXIsIFNlcnZlciwgU2VydmljZSB9IGZyb20gJy4uLyc7XG5pbXBvcnQgeyB3aXRoQ3dkIH0gZnJvbSAnLi4vJztcbmltcG9ydCBwbGF5ZXJUb2dnbGVPcGVyYXRvckV2ZW50IGZyb20gJy4uL2V2ZW50cy9wbGF5ZXIvUGxheWVyVG9nZ2xlT3BlcmF0b3JFdmVudCc7XG5cbmludGVyZmFjZSBPcFR5cGUge1xuICAgIG5hbWU6IHN0cmluZztcbn1cblxuY29uc3QgUEVSTUlTU0lPTl9GSUxFX05BTUUgPSAncGVybWlzc2lvbnMuanNvbic7XG5jb25zdCBPUFNfRklMRV9OQU1FID0gJ29wcy5qc29uJztcblxuLyoqXG4gKiBQZXJtaXNzaW9uIG1hbmFnZXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBQZXJtaXNzaW9uTWFuYWdlciBpbXBsZW1lbnRzIFNlcnZpY2Uge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc2VydmVyOiBTZXJ2ZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBvcHM6IFNldDxzdHJpbmc+ID0gbmV3IFNldCgpO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgcGVybWlzc2lvbnM6IE1hcDxzdHJpbmcsIHN0cmluZ1tdPiA9IG5ldyBNYXAoKTtcbiAgICBwcml2YXRlIGRlZmF1bHRQZXJtaXNzaW9uczogc3RyaW5nW10gPSBbXTtcbiAgICBwcml2YXRlIGRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgbmV3IHBlcm1pc3Npb24gbWFuYWdlci5cbiAgICAgKiBAcGFyYW0ge1NlcnZlcn0gc2VydmVyIC0gVGhlIHNlcnZlciBpbnN0YW5jZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioc2VydmVyOiBTZXJ2ZXIpIHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW5hYmxlIHRoZSBtYW5hZ2VyIGFuZCBsb2FkIGFsbCBwZXJtaXNzaW9ucy5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgbWFuYWdlciBpcyBlbmFibGVkLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZW5hYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBhcnNlT3BzKCk7XG4gICAgICAgIGF3YWl0IHRoaXMucGFyc2VQZXJtaXNzaW9ucygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNpZ25pZmllcyB0aGF0IHRoZSBtYW5hZ2VyIGlzIGJlaW5nIGRpc2FibGVkIGFuZCBhbGwgcGVybWlzc2lvbnMgc2hvdWxkIGJlIHVubG9hZGVkLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBtYW5hZ2VyIGlzIGRpc2FibGVkLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZGlzYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5vcHMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5jbGVhcigpO1xuICAgICAgICB0aGlzLmRlZmF1bHRQZXJtaXNzaW9ucyA9IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgZGVmYXVsdCBwZXJtaXNzaW9ucy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nW119IFRoZSBkZWZhdWx0IHBlcm1pc3Npb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXREZWZhdWx0UGVybWlzc2lvbnMoKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5kZWZhdWx0UGVybWlzc2lvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcGxheWVyJ3MgcGVybWlzc2lvbnMuXG4gICAgICogQHBhcmFtIHtQbGF5ZXJ9IHBsYXllciAtIFRoZSBwbGF5ZXIgdG8gZ2V0IHBlcm1pc3Npb25zIGZvci5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHBsYXllcidzIHBlcm1pc3Npb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBnZXRQZXJtaXNzaW9ucyhwbGF5ZXI6IFBsYXllcik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIC4uLnRoaXMuZGVmYXVsdFBlcm1pc3Npb25zLFxuICAgICAgICAgICAgLi4uKHRoaXMucGVybWlzc2lvbnMuZ2V0KHBsYXllci5nZXROYW1lKCkpID8/IFtdKSxcbiAgICAgICAgICAgIC4uLihwbGF5ZXIuaXNPcCgpID8gdGhpcy5kZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9ucyA6IFtdKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBhIHBsYXllcidzIHBlcm1pc3Npb25zLlxuICAgICAqXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBUaGlzIHdpbGwgbm90IGJlIHNhdmVkIHRvIHRoZSBwZXJtaXNzaW9ucy5qc29uIGZpbGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gcGxheWVyIC0gVGhlIHBsYXllciB0byBzZXQgcGVybWlzc2lvbnMgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IFtwZXJtaXNzaW9ucz1bXV0gLSBUaGUgcGVybWlzc2lvbnMgdG8gc2V0LlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXRQZXJtaXNzaW9ucyhwbGF5ZXI6IFBsYXllciwgcGVybWlzc2lvbnM6IHN0cmluZ1tdID0gW10pIHtcbiAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5zZXQocGxheWVyLmdldE5hbWUoKSwgcGVybWlzc2lvbnMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcGFyc2VQZXJtaXNzaW9ucygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyh3aXRoQ3dkKFBFUk1JU1NJT05fRklMRV9OQU1FKSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS53YXJuKGBGYWlsZWQgdG8gbG9hZCBwZXJtaXNzaW9ucyBsaXN0IWApO1xuICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBUaGlzIG92ZXJ3cml0ZXMgY29tbWVudHMgaW4gdGhlIGZpbGUuXG4gICAgICAgICAgICAgICAgICAgIHdpdGhDd2QoUEVSTUlTU0lPTl9GSUxFX05BTUUpLFxuICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0UGVybWlzc2lvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21pbmVjcmFmdC5jb21tYW5kLmhlbHAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWluZWNyYWZ0LmNvbW1hbmQubGlzdCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtaW5lY3JhZnQuY29tbWFuZC5tZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdqc3ByaXNtYXJpbmUuY29tbWFuZC5wbHVnaW5zJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2pzcHJpc21hcmluZS5jb21tYW5kLnZlcnNpb24nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnanNwcmlzbWFyaW5lLmNvbW1hbmQudHBzJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnM6IFsnKiddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXllcnM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogJ2ZpbGZhdCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uczogWycqJ11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgNFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcGVybWlzc2lvbnNPYmplY3Q6IFBhcnRpYWw8e1xuICAgICAgICAgICAgICAgIGRlZmF1bHRQZXJtaXNzaW9uczogc3RyaW5nW107XG4gICAgICAgICAgICAgICAgZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnM6IHN0cmluZ1tdO1xuICAgICAgICAgICAgICAgIHBsYXllcnM6IEFycmF5PHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogc3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uczogc3RyaW5nW107XG4gICAgICAgICAgICAgICAgfT47XG4gICAgICAgICAgICB9PiA9IHBhcnNlSlNPTjUoKGF3YWl0IGZzLnByb21pc2VzLnJlYWRGaWxlKHdpdGhDd2QoUEVSTUlTU0lPTl9GSUxFX05BTUUpKSkudG9TdHJpbmcoKSk7XG5cbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdFBlcm1pc3Npb25zID0gcGVybWlzc2lvbnNPYmplY3QuZGVmYXVsdFBlcm1pc3Npb25zIHx8IFtdO1xuICAgICAgICAgICAgdGhpcy5kZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9ucyA9IHBlcm1pc3Npb25zT2JqZWN0LmRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zIHx8IFsnKiddO1xuICAgICAgICAgICAgcGVybWlzc2lvbnNPYmplY3QucGxheWVycz8ubWFwKChwbGF5ZXIpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5zZXQocGxheWVyLm5hbWUsIHBsYXllci5wZXJtaXNzaW9ucy5sZW5ndGggPD0gMCA/IFtdIDogcGxheWVyLnBlcm1pc3Npb25zKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCAke1BFUk1JU1NJT05fRklMRV9OQU1FfSBmaWxlLmApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwYXJzZU9wcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyh3aXRoQ3dkKE9QU19GSUxFX05BTUUpKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLndhcm4oYEZhaWxlZCB0byBsb2FkIG9wZXJhdG9ycyBsaXN0IWApO1xuICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMod2l0aEN3ZChPUFNfRklMRV9OQU1FKSwgJ1tdJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBvcHM6IE9wVHlwZVtdID0gcGFyc2VKU09ONSgoYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUod2l0aEN3ZChPUFNfRklMRV9OQU1FKSkpLnRvU3RyaW5nKCkpO1xuXG4gICAgICAgICAgICBvcHMubWFwKChvcCkgPT4gdGhpcy5vcHMuYWRkKG9wLm5hbWUpKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCAke09QU19GSUxFX05BTUV9IGZpbGUuYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgYSBwbGF5ZXIgYXMgYW4gb3BlcmF0b3IuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcm5hbWUgLSBUaGUgcGxheWVyIHRvIHNldCBhcyBhbiBvcGVyYXRvci5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IG9wIC0gV2hldGhlciB0aGUgcGxheWVyIHNob3VsZCBiZSBhbiBvcGVyYXRvci5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCBhIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBvcGVyYXRpb24gd2FzIHN1Y2Nlc3NmdWwuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNldE9wKHVzZXJuYW1lOiBzdHJpbmcsIG9wOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuc2VydmVyLmdldFNlc3Npb25NYW5hZ2VyKCkuZ2V0UGxheWVyQnlFeGFjdE5hbWUodXNlcm5hbWUpOyAvLyBUT0RPOiBieSBuYW1lIG5vdCBleGFjdFxuICAgICAgICBpZiAoIXRhcmdldCkgdGhyb3cgbmV3IFBsYXllck5vdEZvdW5kRXJyb3IodXNlcm5hbWUpO1xuICAgICAgICBjb25zdCBldmVudCA9IG5ldyBwbGF5ZXJUb2dnbGVPcGVyYXRvckV2ZW50KHRhcmdldCwgb3ApO1xuICAgICAgICB0aGlzLnNlcnZlci5wb3N0KFsncGxheWVyVG9nZ2xlT3BlcmF0b3InLCBldmVudF0pO1xuICAgICAgICBpZiAoZXZlbnQuaXNDYW5jZWxsZWQoKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIGF3YWl0IHRhcmdldC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmRBdmFpbGFibGVDb21tYW5kcygpO1xuXG4gICAgICAgIGlmIChvcCkgdGhpcy5vcHMuYWRkKHVzZXJuYW1lKTtcbiAgICAgICAgZWxzZSB0aGlzLm9wcy5kZWxldGUodXNlcm5hbWUpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy53cml0ZUZpbGUoXG4gICAgICAgICAgICAgICAgLy8gRklYTUU6IFRoaXMgb3ZlcndyaXRlcyBjb21tZW50cyBpbiB0aGUgZmlsZS5cbiAgICAgICAgICAgICAgICB3aXRoQ3dkKE9QU19GSUxFX05BTUUpLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgICAgICBBcnJheS5mcm9tKHRoaXMub3BzLnZhbHVlcygpKS5tYXAoKG5hbWUpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWw6IDRcbiAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICA0XG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgYXdhaXQgdGFyZ2V0LnNlbmRTZXR0aW5ncygpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgYSBwbGF5ZXIgaXMgYW4gb3BlcmF0b3IuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcm5hbWUgLSBUaGUgcGxheWVyIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBwbGF5ZXIgaXMgYW4gb3BlcmF0b3IuXG4gICAgICovXG4gICAgcHVibGljIGlzT3AodXNlcm5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5vcHMuaGFzKHVzZXJuYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBhIHBsYXllciBjYW4gZXhlY3V0ZSBhIGNvbW1hbmQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gZXhlY3V0ZXIgLSBUaGUgcGxheWVyIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtvYmplY3R9IEFuIG9iamVjdCB3aXRoIGFuIGV4ZWN1dGUgbWV0aG9kIHRoYXQgdGFrZXMgYSBwZXJtaXNzaW9uIHN0cmluZyBhbmQgcmV0dXJucyB3aGV0aGVyIHRoZSBwbGF5ZXIgY2FuIGV4ZWN1dGUgdGhlIGNvbW1hbmQuXG4gICAgICovXG4gICAgcHVibGljIGNhbihleGVjdXRlcj86IFBsYXllcikge1xuICAgICAgICBjb25zdCBleGVjdXRlID0gKHBlcm1pc3Npb24/OiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGlmICghZXhlY3V0ZXIpIHRocm93IG5ldyBFcnJvcihgRXhlY3V0ZXIgY2FuJ3QgYmUgdW5kZWZpbmVkIG9yIG51bGxgKTtcblxuICAgICAgICAgICAgaWYgKCFwZXJtaXNzaW9uKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5pc0NvbnNvbGUoKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZXIuaXNPcCgpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKHBlcm1pc3Npb24pKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKCcqJykpIHJldHVybiB0cnVlO1xuXG4gICAgICAgICAgICBjb25zdCBzcGxpdCA9IHBlcm1pc3Npb24uc3BsaXQoJy4nKTtcbiAgICAgICAgICAgIGxldCBzY29wZSA9ICcnO1xuICAgICAgICAgICAgZm9yIChjb25zdCBhY3Rpb24gb2Ygc3BsaXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoc2NvcGUpIHNjb3BlID0gYCR7c2NvcGV9LiR7YWN0aW9ufWA7XG4gICAgICAgICAgICAgICAgZWxzZSBzY29wZSA9IGFjdGlvbjtcblxuICAgICAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKHNjb3BlKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmdldFBlcm1pc3Npb25zKCkuaW5jbHVkZXMoYCR7c2NvcGV9LipgKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXhlY3V0ZSxcbiAgICAgICAgICAgIG5vdDogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGV4ZWN1dGU6IChwZXJtaXNzaW9uPzogc3RyaW5nKSA9PiAhZXhlY3V0ZShwZXJtaXNzaW9uKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxufVxuIl0s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