UNPKG

@zowe/imperative

Version:
308 lines 13.5 kB
"use strict"; /* * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * * Copyright Contributors to the Zowe Project. * */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigUtils = void 0; const fs = require("fs"); const os = require("os"); const path = require("path"); const glob = require("fast-glob"); const jsonfile = require("jsonfile"); const CredentialManagerFactory_1 = require("../../security/src/CredentialManagerFactory"); const utilities_1 = require("../../utilities"); const error_1 = require("../../error"); const LoggerManager_1 = require("../../logger/src/LoggerManager"); const LoggingConfigurer_1 = require("../../imperative/src/LoggingConfigurer"); const Logger_1 = require("../../logger/src/Logger"); const EnvironmentalVariableSettings_1 = require("../../imperative/src/env/EnvironmentalVariableSettings"); class ConfigUtils { /** * Retrieves the Zowe CLI home directory. In the situation Imperative has * not initialized it we use a default value. * @returns {string} - Returns the Zowe home directory */ static getZoweDir() { var _a; const defaultHome = path.join(os.homedir(), ".zowe"); if (((_a = utilities_1.ImperativeConfig.instance.loadedConfig) === null || _a === void 0 ? void 0 : _a.defaultHome) !== defaultHome) { utilities_1.ImperativeConfig.instance.loadedConfig = { name: "zowe", defaultHome, envVariablePrefix: "ZOWE" }; } return utilities_1.ImperativeConfig.instance.cliHome; } /** * Reads the `extenders.json` file from the CLI home directory. * Called once in `readProfilesFromDisk` and cached to minimize I/O operations. * @internal * @throws If the extenders.json file cannot be created when it does not exist. * @throws If the extenders.json file cannot be read. */ static readExtendersJson() { const cliHome = utilities_1.ImperativeConfig.instance.loadedConfig != null ? utilities_1.ImperativeConfig.instance.cliHome : ConfigUtils.getZoweDir(); const extenderJsonPath = path.join(cliHome, "extenders.json"); if (!fs.existsSync(extenderJsonPath)) { jsonfile.writeFileSync(extenderJsonPath, { profileTypes: {} }, { spaces: 4 }); return { profileTypes: {} }; } else { return jsonfile.readFileSync(extenderJsonPath); } } /** * Attempts to write to the `extenders.json` file in the CLI home directory. * @returns `true` if written successfully; `false` otherwise * @internal */ static writeExtendersJson(obj) { try { const extenderJsonPath = path.join(ConfigUtils.getZoweDir(), "extenders.json"); jsonfile.writeFileSync(extenderJsonPath, obj, { spaces: 4 }); } catch (err) { return false; } return true; } /** * Coerces string property value to a boolean or number type. * @param value String value * @param type Property type defined in the schema * @returns Boolean, number, or string */ static coercePropValue(value, type) { if (type === "boolean" || type === "number") { // For boolean or number, parse the string and throw on failure return JSON.parse(value); } else if (type == null) { // For unknown type, try to parse the string and ignore failure try { return JSON.parse(value); } catch (_a) { return value; } } else { // For string or other type, don't do any parsing return value.toString(); } } /** * Retrieves the name of the active profile for the given type. If no such * profile exists, returns the default name which can be used to create a new profile. * @param profileType The type of CLI profile * @param cmdArguments CLI arguments which may specify a profile * @param defaultProfileName Name to fall back to if profile doesn't exist. If * not specified, the profile type will be used. * @returns The profile name */ static getActiveProfileName(profileType, cmdArguments, defaultProfileName) { var _a; // Look for profile name first in command line arguments, second in // default profiles defined in config, and finally fall back to using // the profile type as the profile name. return (cmdArguments === null || cmdArguments === void 0 ? void 0 : cmdArguments[`${profileType}-profile`]) || ((_a = utilities_1.ImperativeConfig.instance.config) === null || _a === void 0 ? void 0 : _a.properties.defaults[profileType]) || defaultProfileName || profileType; } /** * Checks if partial path is equal to or nested inside full path * @param fullPath JSON path to profile 1 * @param partialPath JSON path to profile 2 */ static jsonPathMatches(fullPath, partialPath) { return fullPath === partialPath || fullPath.startsWith(partialPath + ".profiles."); } /** * Returns an indicator that the user has no team configuration, but we * detected the existence of old-school V1 profiles. We will not work with the * V1 profiles. This function can let you tell a user that they are incorrectly * trying to use V1 profiles. * * @returns True - Means there is *NO* team config *AND* we detected that a V1 profile exists. * False otherwise. */ static get onlyV1ProfilesExist() { var _a; if ((_a = utilities_1.ImperativeConfig.instance.config) === null || _a === void 0 ? void 0 : _a.exists) { // we have a team config return false; } // look for V1 profiles in the CLI home directory const v1ProfilePaths = glob.sync("profiles/**/*.yaml", { cwd: utilities_1.ImperativeConfig.instance.cliHome }) .filter(filename => { // ignore meta yaml files const { dir, name } = path.parse(filename); return name !== path.basename(dir) + "_meta"; }); return v1ProfilePaths.length > 0; } /** * Form an error message for failures to securely save a value. * @param solution Text that our caller can supply for a solution. * @returns ImperativeError to be thrown */ static secureSaveError(solution) { let details = CredentialManagerFactory_1.CredentialManagerFactory.manager.secureErrorDetails(); if (solution != null) { details = details != null ? details + `\n - ${solution}` : solution; } return new error_1.ImperativeError({ msg: "Unable to securely save credentials.", additionalDetails: details }); } // _______________________________________________________________________ /** * Perform a rudimentary initialization of some Imperative utilities. * We must do this because VSCode apps do not typically call imperative.init. * @internal */ static initImpUtils(appName) { // create a rudimentary ImperativeConfig if it has not been initialized if (utilities_1.ImperativeConfig.instance.loadedConfig == null) { let homeDir = null; const envVarPrefix = appName.toUpperCase(); const envVarNm = envVarPrefix + EnvironmentalVariableSettings_1.EnvironmentalVariableSettings.CLI_HOME_SUFFIX; if (process.env[envVarNm] === undefined) { // use OS home directory homeDir = path.join(os.homedir(), "." + appName.toLowerCase()); } else { // use the available environment variable homeDir = path.normalize(process.env[envVarNm]); } utilities_1.ImperativeConfig.instance.loadedConfig = { name: appName, defaultHome: homeDir, envVariablePrefix: envVarPrefix }; utilities_1.ImperativeConfig.instance.rootCommandName = appName; } // initialize logging if (LoggerManager_1.LoggerManager.instance.isLoggerInit === false) { const loggingConfig = LoggingConfigurer_1.LoggingConfigurer.configureLogger(utilities_1.ImperativeConfig.instance.cliHome, utilities_1.ImperativeConfig.instance.loadedConfig); Logger_1.Logger.fromLog4jsToWinston(loggingConfig); } return Logger_1.Logger.getImperativeLogger(); } // _______________________________________________________________________ /** * Form a profile name of a given profile type to be used as a default * profile name. The name can vary based on whether the configuration to * contain the profile is a global config or a project config. * * Currently, we only form a different global/project profile name for * a base profile. The profile name for any other profile type is currently * set to the profile type string. * * @param profileType * The profile type for which we will form a name. * * @param globalConfig * Indicator that the caller knows that the profile name will be * for a globalConfig (true) or project config (false). * If globalConfig is not supplied, we interrogate any existing * Config object to determine whether to form a global or project * profile name. * * @returns * A string to be used as the profile name for the specified profile type. */ static formGlobOrProjProfileNm(profileType, globalConfig = null) { if (profileType !== "base") { // everything except base profiles use profile type as the profile name return profileType; } // were we told that this is for a global or project config? if (globalConfig === true) { return `global_${profileType}`; } else if (globalConfig === false) { return `project_${profileType}`; } else { // determine from existing config whether the profile is intended for a project config const existingConfig = utilities_1.ImperativeConfig.instance.config; for (const nextLayer of existingConfig.layers) { // if desired profile type exists in the project layer, it wins if (nextLayer.global === false) { if (ConfigUtils.findProfTypeInNestedProfiles(profileType, existingConfig.layerProfiles(nextLayer))) { return `project_${profileType}`; } } } } // since we did not find the profile type at the project layers, return a global name return `global_${profileType}`; } // _______________________________________________________________________ /** * Find the specified profile type in the specified (or nested) profiles. * * @param profileType * The profile type to search for. * * @param profilesObj * The profile object in which we should search. * * @returns * True if we find the profile type. False otherwise. */ static findProfTypeInNestedProfiles(profileType, profilesObj) { for (const nextProfileObj of Object.values(profilesObj)) { if ((nextProfileObj === null || nextProfileObj === void 0 ? void 0 : nextProfileObj.type) === profileType) { return true; } // The specified type was not in nextProfileObj. Recursively look in its nested profiles. if (nextProfileObj === null || nextProfileObj === void 0 ? void 0 : nextProfileObj.profiles) { if (ConfigUtils.findProfTypeInNestedProfiles(profileType, nextProfileObj.profiles)) { return true; } } } return false; } /** * Checks if the given token has expired. Supports JSON web tokens only. * * @param {string} token - The JSON web token to check * @returns {boolean} * Whether the token has expired. Returns `false` if the token cannot * be decoded or an expire time is not specified in the payload. */ static hasTokenExpired(token) { // JWT format: [header].[payload].[signature] const tokenParts = token.split("."); try { const payloadJson = JSON.parse(Buffer.from(tokenParts[1], "base64url").toString("utf8")); if ("exp" in payloadJson) { // The expire time is stored in seconds since UNIX epoch. // The Date constructor expects a timestamp in milliseconds. const msPerSec = 1000; const expireDate = new Date(payloadJson.exp * msPerSec); return expireDate < new Date(); } } catch (err) { return false; } return false; } } exports.ConfigUtils = ConfigUtils; //# sourceMappingURL=ConfigUtils.js.map