UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

407 lines (406 loc) 17.5 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OperationColors = exports.consoleText_bgGray = exports.consoleText_bgWhite = exports.consoleText_bgCyan = exports.consoleText_bgMagenta = exports.consoleText_bgBlue = exports.consoleText_bgYellow = exports.consoleText_bgGreen = exports.consoleText_bgRed = exports.consoleText_bgBlack = exports.consoleText_fgGray = exports.consoleText_fgWhite = exports.consoleText_fgCyan = exports.consoleText_fgMagenta = exports.consoleText_fgBlue = exports.consoleText_fgYellow = exports.consoleText_fgGreen = exports.consoleText_fgRed = exports.consoleText_fgBlack = exports.consoleText_hidden = exports.consoleText_reverse = exports.consoleText_blink = exports.consoleText_underscore = exports.consoleText_dim = exports.consoleText_bright = exports.consoleText_reset = void 0; const LocalUtilities_1 = __importDefault(require("./LocalUtilities")); const NodeStorage_1 = __importDefault(require("./NodeStorage")); const fs = __importStar(require("fs")); const Utilities_1 = __importDefault(require("../core/Utilities")); const crypto = __importStar(require("crypto")); const worker_threads_1 = require("worker_threads"); const Log_1 = __importStar(require("../core/Log")); exports.consoleText_reset = "\x1b[0m"; exports.consoleText_bright = "\x1b[1m"; exports.consoleText_dim = "\x1b[2m"; exports.consoleText_underscore = "\x1b[4m"; exports.consoleText_blink = "\x1b[5m"; exports.consoleText_reverse = "\x1b[7m"; exports.consoleText_hidden = "\x1b[8m"; exports.consoleText_fgBlack = "\x1b[30m"; exports.consoleText_fgRed = "\x1b[31m"; exports.consoleText_fgGreen = "\x1b[32m"; exports.consoleText_fgYellow = "\x1b[33m"; exports.consoleText_fgBlue = "\x1b[34m"; exports.consoleText_fgMagenta = "\x1b[35m"; exports.consoleText_fgCyan = "\x1b[36m"; exports.consoleText_fgWhite = "\x1b[37m"; exports.consoleText_fgGray = "\x1b[90m"; exports.consoleText_bgBlack = "\x1b[40m"; exports.consoleText_bgRed = "\x1b[41m"; exports.consoleText_bgGreen = "\x1b[42m"; exports.consoleText_bgYellow = "\x1b[43m"; exports.consoleText_bgBlue = "\x1b[44m"; exports.consoleText_bgMagenta = "\x1b[45m"; exports.consoleText_bgCyan = "\x1b[46m"; exports.consoleText_bgWhite = "\x1b[47m"; exports.consoleText_bgGray = "\x1b[100m"; exports.OperationColors = [exports.consoleText_fgGreen, exports.consoleText_fgCyan, exports.consoleText_fgBlue, exports.consoleText_fgMagenta]; class LocalEnvironment { #data; utilities; #isLoaded = false; #prefsStorage; #rootPrefFolder; #configFile; #worldContainerStorage; logToStdError = false; #displayInfo = false; #displayVerbose = false; _inmemTokenEncryptionPassword; _inmemDisplayReadOnlyPasscode; _inmemDisplayReadOnlySessionId; _inmemFullReadOnlyPasscode; _inmemFullReadOnlySessionId; _inmemUpdateStatePasscode; _inmemUpdateStateSessionId; _inmemAdminPasscode; _inmemAdminSessionId; // Experimental SSL config - intentionally not persisted to disk _sslConfig; get sslConfig() { return this._sslConfig; } set sslConfig(config) { this._sslConfig = config; } get pathMappings() { if (this.#data.pathMappings === undefined) { return {}; } return this.#data.pathMappings; } set pathMappings(newVal) { this.#data.pathMappings = newVal; } get displayInfo() { return this.#displayInfo; } set displayInfo(newInfoValue) { this.#displayInfo = newInfoValue; } get displayVerbose() { return this.#displayVerbose; } set displayVerbose(newVerboseValue) { this.#displayVerbose = newVerboseValue; } get worldContainerStorage() { return this.#worldContainerStorage; } get worldContainerPath() { return this.#data.worldContainerPath; } get serverHostPort() { return this.#data.serverHostPort; } set serverHostPort(newPort) { if (newPort !== this.#data.serverHostPort) { this.#data.serverHostPort = newPort; } } get serverDomainName() { return this.#data.serverDomainName; } set serverDomainName(newDomainName) { if (newDomainName !== this.#data.serverDomainName) { this.#data.serverDomainName = newDomainName; } } get serverTitle() { return this.#data.serverTitle; } set serverTitle(newTitle) { if (newTitle !== this.#data.serverTitle) { this.#data.serverTitle = newTitle; } } get serverMessageOfTheDay() { return this.#data.serverMessageOfTheDay; } set serverMessageOfTheDay(messageOfTheDay) { if (messageOfTheDay !== this.#data.serverMessageOfTheDay) { this.#data.serverMessageOfTheDay = messageOfTheDay; } } get allowedCorsOrigins() { return this.#data.allowedCorsOrigins; } set allowedCorsOrigins(newOrigins) { if (newOrigins !== this.#data.allowedCorsOrigins) { this.#data.allowedCorsOrigins = newOrigins; } } get tokenEncryptionKey() { if (this._inmemTokenEncryptionPassword === undefined) { this._inmemTokenEncryptionPassword = this.generateRandomTokenPassword(); } return this._inmemTokenEncryptionPassword; } get displayReadOnlyPasscode() { return this._inmemDisplayReadOnlyPasscode; //this.#data.displayReadOnlyPasscode; } get displayReadOnlySessionId() { return this._inmemDisplayReadOnlySessionId; //this.#data.displayReadOnlySessionId; } setDisplayReadOnlyPasscodeAndRandomizeComplement(newPasscode) { if (newPasscode === undefined) { throw new Error(); } newPasscode = newPasscode.toLowerCase(); newPasscode = newPasscode.replace("-", ""); if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) { throw new Error("Improperly formatted display read-only passcode. Passcodes should be 8 alphanumeric characters."); } this._inmemDisplayReadOnlyPasscode = newPasscode; this._inmemDisplayReadOnlySessionId = this.generateRandomPasscode(); } get fullReadOnlyPasscode() { return this._inmemFullReadOnlyPasscode; } get fullReadOnlySessionId() { return this._inmemFullReadOnlySessionId; } setFullReadOnlyPasscodeAndRandomizeComplement(newPasscode) { if (newPasscode === undefined) { throw new Error(); } newPasscode = newPasscode.toLowerCase(); newPasscode = newPasscode.replace("-", ""); if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) { throw new Error("Improperly formatted full read-only passcode. Passcodes should be 8 alphanumeric characters."); } this._inmemFullReadOnlyPasscode = newPasscode; this._inmemFullReadOnlySessionId = this.generateRandomPasscode(); } get updateStatePasscode() { return this._inmemUpdateStatePasscode; } get updateStateSessionId() { return this._inmemUpdateStateSessionId; } setUpdateStatePasscodeAndRandomizeComplement(newPasscode) { if (newPasscode === undefined) { throw new Error(); } newPasscode = newPasscode.toLowerCase(); newPasscode = newPasscode.replace("-", ""); if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) { throw new Error("Improperly formatted update passcode. Passcodes should be 8 alphanumeric characters."); } this._inmemUpdateStatePasscode = newPasscode; this._inmemUpdateStateSessionId = this.generateRandomPasscode(); } get adminPasscode() { return this._inmemAdminPasscode; } get adminSessionId() { return this._inmemAdminSessionId; } setAdminPasscodeAndRandomizeComplement(newPasscode) { if (newPasscode === undefined) { throw new Error(); } newPasscode = newPasscode.toLowerCase(); newPasscode = newPasscode.replace("-", ""); if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) { throw new Error("Improperly formatted admin passcode. Passcodes should be 8 alphanumeric characters."); } this._inmemAdminPasscode = newPasscode; this._inmemAdminSessionId = this.generateRandomPasscode(); } get iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula() { return this.#data.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula; } set iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula(iAgreeValue) { this.#data.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula = iAgreeValue; } constructor(subscribeToLog) { this.#data = {}; this.load = this.load.bind(this); this.save = this.save.bind(this); this.utilities = new LocalUtilities_1.default(); this.handleNewLogMessage = this.handleNewLogMessage.bind(this); if (subscribeToLog) { Log_1.default.onItemAdded.subscribe(this.handleNewLogMessage); } if (!fs.existsSync(this.utilities.serverWorkingPath)) { fs.mkdirSync(this.utilities.serverWorkingPath, { recursive: true }); } this.#data.worldContainerPath = this.utilities.worldsWorkingPath; if (this.utilities.worldsWorkingPath && !fs.existsSync(this.utilities.worldsWorkingPath)) { fs.mkdirSync(this.utilities.worldsWorkingPath, { recursive: true }); } this.#worldContainerStorage = new NodeStorage_1.default(this.utilities.worldsWorkingPath, ""); if (!fs.existsSync(this.utilities.cliWorkingPath)) { fs.mkdirSync(this.utilities.cliWorkingPath, { recursive: true }); } if (!fs.existsSync(this.utilities.envPrefsPath)) { fs.mkdirSync(this.utilities.envPrefsPath, { recursive: true }); } if (!fs.existsSync(this.utilities.packCachePath)) { fs.mkdirSync(this.utilities.packCachePath, { recursive: true }); } this.#prefsStorage = new NodeStorage_1.default(this.utilities.envPrefsPath, ""); this.#rootPrefFolder = this.#prefsStorage.rootFolder; this.#configFile = this.#rootPrefFolder.ensureFile("envprefs.json"); } setWorldContainerPath(newPath) { if (newPath !== this.#data.worldContainerPath) { this.#data.worldContainerPath = newPath; if (newPath) { if (!fs.existsSync(newPath)) { fs.mkdirSync(newPath, { recursive: true }); } this.#worldContainerStorage = new NodeStorage_1.default(newPath, ""); } } } handleNewLogMessage(log, item) { if (item.level === Log_1.LogItemLevel.verbose && !this.displayVerbose) { return; } // In MCP/stdio mode, only send errors and important messages to stderr. // Regular messages and debug output would show as [warning] in VS Code's // MCP output panel, which is confusing for users. if (this.logToStdError) { let context = ""; if (item.context && item.context.length > 0) { context = item.context + " "; } if (item.level === Log_1.LogItemLevel.error) { console.error(exports.consoleText_fgRed + context + "Error: " + item.message + exports.consoleText_reset); } else if (item.level === Log_1.LogItemLevel.important) { console.error(exports.consoleText_fgYellow + context + item.message + exports.consoleText_reset); } // Suppress message/verbose/debug in MCP mode — they're not actionable return; } let context = ""; if (this.displayVerbose) { context = worker_threads_1.threadId + ": "; } if (item.context && item.context.length > 0) { context = item.context + " "; } if (item.level === Log_1.LogItemLevel.verbose) { console.log(exports.consoleText_fgGray + context + item.message + exports.consoleText_reset); } else if (item.level === Log_1.LogItemLevel.error) { console.error(exports.consoleText_fgRed + context + "Error: " + item.message + exports.consoleText_reset); } else if (item.level === Log_1.LogItemLevel.important) { // NOTE: This is the Log framework's own output handler — using Log.important() // here would cause infinite recursion. console.log with yellow coloring is intentional. console.log(exports.consoleText_fgYellow + context + "Important: " + item.message + exports.consoleText_reset); } else { console.log(context + item.message); } } async load() { if (this.#isLoaded) { return; } if (!this.#configFile.isContentLoaded) { await this.#configFile.loadContent(false); } if (this.#configFile.content !== null && this.#configFile.content !== undefined && typeof this.#configFile.content === "string") { this.#data = JSON.parse(this.#configFile.content); } this.#isLoaded = true; } async setDefaults() { await this.load(); if (this.#data.serverDomainName === undefined) { this.#data.serverDomainName = "localhost"; } if (this.#data.serverHostPort === undefined) { this.#data.serverHostPort = 6126; } if (this._inmemDisplayReadOnlyPasscode === undefined || this._inmemDisplayReadOnlySessionId === undefined) { this.setDisplayReadOnlyPasscodeAndRandomizeComplement(this.generateRandomPasscode()); } if (this._inmemAdminPasscode === undefined || this._inmemAdminSessionId === undefined) { this.setAdminPasscodeAndRandomizeComplement(this.generateRandomPasscode()); } if (this._inmemFullReadOnlyPasscode === undefined || this._inmemFullReadOnlySessionId === undefined) { this.setFullReadOnlyPasscodeAndRandomizeComplement(this.generateRandomPasscode()); } if (this._inmemUpdateStatePasscode === undefined || this._inmemUpdateStateSessionId === undefined) { this.setUpdateStatePasscodeAndRandomizeComplement(this.generateRandomPasscode()); } await this.save(); } generateRandomPasscode() { let newPasscode = ""; for (let i = 0; i < 8; i++) { const rand = crypto.randomInt(34); // don't include 0 and 1 to preclude O/I confusion if (rand <= 7) { newPasscode += String.fromCharCode(rand + 50); } else { newPasscode += String.fromCharCode(rand + 89); // 89 + 8 = starts at A range. } } return newPasscode; } generateRandomTokenPassword() { let newPasscode = ""; for (let i = 0; i < 12; i++) { const rand = crypto.randomInt(36); if (rand <= 9) { newPasscode += String.fromCharCode(rand + 48); } else { newPasscode += String.fromCharCode(rand + 87); // 87 + 10 = starts at A range. } } return newPasscode; } async save() { const content = JSON.stringify(this.#data, null, 2); this.#configFile.setContent(content); this.#configFile.saveContent(); } } exports.default = LocalEnvironment;