UNPKG

@cto.ai/ops

Version:

💻 CTO.ai - The CLI built for Teams 🚀

176 lines (175 loc) • 7.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const cli_sdk_1 = require("@cto.ai/cli-sdk"); const parser_1 = require("@oclif/parser"); const fs = tslib_1.__importStar(require("fs-extra")); const path = tslib_1.__importStar(require("path")); const base_1 = tslib_1.__importDefault(require("../base")); const opConfig_1 = require("../constants/opConfig"); const utils_1 = require("../utils"); const runUtils_1 = require("../utils/runUtils"); const CustomErrors_1 = require("../errors/CustomErrors"); class Certs extends base_1.default { constructor() { super(...arguments); this.sendAnalytics = async (inputs) => { try { this.services.analytics.track('Ops CLI Certificates Saved', { certKeyName: inputs.certKeyName, keyKeyName: inputs.keyKeyName, username: inputs.config.user.username, }, inputs.config); } catch (err) { this.debug('%O', err); throw new CustomErrors_1.AnalyticsError(err); } return inputs; }; this.setSecrets = async (inputs) => { try { await this.services.api.create(`/private/teams/${inputs.config.team.name}/secrets`, { secrets: { [inputs.certKeyName]: inputs.certFile, [inputs.keyKeyName]: inputs.keyFile, }, }, { headers: { Authorization: this.accessToken }, }); } catch (err) { this.debug('%O', err); switch (err.error[0].code) { case 400: throw new CustomErrors_1.InvalidSecretVault(err); case 401: throw new CustomErrors_1.UserUnauthorized(err); case 403: if (err.error[0].message.includes('invalid secret token')) { throw new CustomErrors_1.InvalidSecretToken(err); } else { throw new CustomErrors_1.NoSecretsProviderFound(err); } default: throw new CustomErrors_1.SetSecretsProvider(err); } } return inputs; }; this.loadContents = (key, prompt) => async (inputs) => { let filepath = inputs[key]; if (!filepath) { const { providedPath } = await this.ux.prompt({ message: `\n${prompt} ${cli_sdk_1.ux.colors.reset.green('→')}`, name: 'providedPath', type: 'input', validate: this.validateValueInput, }); filepath = providedPath; } const content = await fs.readFile(path.resolve(filepath), 'utf8'); return Object.assign(Object.assign({}, inputs), { [key]: content }); }; this.logMessage = (inputs) => { this.log(`\n ${cli_sdk_1.ux.colors.white(`🙌 Great job! Certificate ${cli_sdk_1.ux.colors.callOutCyan(inputs.certKeyName)} and key ${cli_sdk_1.ux.colors.callOutCyan(inputs.keyKeyName)} have been added to your team ${cli_sdk_1.ux.colors.blueBright(inputs.config.team.name)}!`)}`); return inputs; }; this.validateValueInput = async (input) => { if (!input) { return `😞 Sorry, the value cannot be empty`; } return true; }; this.createKeysForSecret = async (inputs) => { this.debug(`Loading YAML file from dir ${inputs.opsYmlPath}`); const { services } = await this.parseYamlFile(inputs.opsYmlPath); if (services == undefined || services.length === 0) { throw new CustomErrors_1.ServiceRequired(); } // Yes, only one service allowed const { domain } = services[0]; if (domain == undefined || domain === '') { throw new CustomErrors_1.NoDomainConfigured(); } return Object.assign(Object.assign({}, inputs), { certKeyName: `ctoai-ssl-cert-${domain}`, keyKeyName: `ctoai-ssl-key-${domain}` }); }; this.parseYamlFile = async (opsPath) => { let content = ''; try { content = await fs.readFile(path.join(path.resolve(opsPath), opConfig_1.OP_FILE), 'utf8'); } catch (err) { console.error('Pretty sure there is a better way to do this..', err); } return (0, utils_1.parseYaml)(content); }; this.customParse = (options, argv) => { const { args, flags: parsedFlags } = (0, parser_1.parse)(argv, Object.assign(Object.assign({}, options), { context: this })); if (!args.nameOrPath && !parsedFlags.help) { throw new CustomErrors_1.MissingRequiredArgument('ops cert'); } if (!args.nameOrPath) { this._help(); } return { args, flags: parsedFlags, opParams: argv.slice(1) }; }; } async run() { const config = await this.isLoggedIn(); try { const { args: { nameOrPath }, flags: { ['cert-file']: certFile, ['key-file']: keyFile }, } = this.customParse(Certs, this.argv); this.debug('inputs', certFile, keyFile); const pipelineInput = { certFile, certKeyName: '', config, keyFile, keyKeyName: '', opsYmlPath: (0, runUtils_1.checkPathOpsYmlExists)(nameOrPath) ? nameOrPath : process.cwd(), }; await (0, utils_1.asyncPipe)(this.createKeysForSecret, this.loadContents('certFile', 'Enter the path to the SSL certificate'), this.loadContents('keyFile', 'Enter the path to the SSL key'), this.setSecrets, this.sendAnalytics, this.logMessage)(pipelineInput); } catch (err) { this.debug('%O', err); this.config.runHook('error', { accessToken: config.tokens.accessToken, err, }); } } } exports.default = Certs; Certs.description = 'Save an SSL certificate and key for your service'; Certs.flags = { 'cert-file': parser_1.flags.string({ description: 'Path to your certificate file', }), help: parser_1.flags.boolean({ char: 'h', description: 'Show help screen', }), 'key-file': parser_1.flags.string({ description: 'Path to your key file', }), }; Certs.args = [ { description: 'The type of certificate to store', name: 'certificateType', options: ['ssl'], parse: (input) => input, required: true, }, { description: 'Name or path of the service to save SSL for.', name: 'nameOrPath', parse: (input) => { return input.toLowerCase(); }, required: true, }, ];