UNPKG

@salesforce/plugin-auth

Version:
181 lines 8.95 kB
/* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import os from 'node:os'; import { AuthInfo, AuthRemover, ConfigAggregator, Global, Messages, Mode, OrgConfigProperties, } from '@salesforce/core'; import checkbox, { Separator } from '@inquirer/checkbox'; import { Flags, loglevel, SfCommand, StandardColors } from '@salesforce/sf-plugins-core'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'logout'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); export default class Logout extends SfCommand { static summary = messages.getMessage('summary'); static description = messages.getMessage('description'); static examples = messages.getMessages('examples'); static deprecateAliases = true; static aliases = ['force:auth:logout', 'auth:logout']; static flags = { 'target-org': Flags.string({ summary: messages.getMessage('flags.target-org.summary'), char: 'o', aliases: ['targetusername', 'u'], deprecateAliases: true, }), 'client-app': Flags.string({ char: 'c', summary: messages.getMessage('flags.client-app.summary'), dependsOn: ['target-org'], }), all: Flags.boolean({ char: 'a', summary: messages.getMessage('flags.all.summary'), description: messages.getMessage('flags.all.description'), required: false, default: false, exclusive: ['target-org'], }), 'no-prompt': Flags.boolean({ char: 'p', summary: commonMessages.getMessage('flags.no-prompt.summary'), required: false, deprecateAliases: true, aliases: ['noprompt'], }), loglevel, }; // eslint-disable-next-line complexity async run() { const { flags } = await this.parse(Logout); const targetUsername = flags['target-org'] ?? (await ConfigAggregator.create()).getInfo(OrgConfigProperties.TARGET_ORG).value; // if no-prompt, there must be a resolved target-org or --all if (flags['no-prompt'] && !targetUsername && !flags.all) { throw messages.createError('noOrgSpecifiedWithNoPrompt'); } if (flags['client-app']) { return this.logoutClientApp(flags['client-app'], targetUsername); } if (this.jsonEnabled() && !targetUsername && !flags.all) { throw messages.createError('noOrgSpecifiedWithJson'); } const shouldFindAllAuths = targetUsername && !flags.all ? false : flags.all || Global.getEnvironmentMode() === Mode.DEMO || !flags['no-prompt']; const orgAuths = shouldFindAllAuths ? await AuthInfo.listAllAuthorizations() : targetUsername ? (await AuthInfo.listAllAuthorizations()).filter((orgAuth) => orgAuth.username === targetUsername || !!orgAuth.aliases?.includes(targetUsername)) : []; if (orgAuths.length === 0) { if (flags['target-org']) { this.warn(messages.createWarning('warning.NoAuthFoundForTargetOrg', [flags['target-org']])); // user specified a target org but it was not resolved, issue success message and return this.logSuccess(messages.getMessage('logoutOrgCommandSuccess', [flags['target-org']])); return [flags['target-org']]; } this.info(messages.getMessage('noOrgsFound')); return []; } const skipPrompt = flags['no-prompt'] || this.jsonEnabled(); const selectedOrgs = this.maybeWarnScratchOrgs(skipPrompt ? orgAuths : await promptForOrgsToRemove(orgAuths, flags.all)); if (skipPrompt || (await this.confirm({ message: getOrgConfirmationMessage(selectedOrgs, orgAuths.length) }))) { const remover = await AuthRemover.create(); const loggedOutUsernames = selectedOrgs.map((org) => org.username); await Promise.all(loggedOutUsernames.map((username) => remover.removeAuth(username))); this.logSuccess(messages.getMessage('logoutOrgCommandSuccess', [loggedOutUsernames.join(os.EOL)])); return loggedOutUsernames; } else { this.info(messages.getMessage('noOrgsSelected')); return []; } } async logoutClientApp(clientApp, username) { const authInfo = await AuthInfo.create({ username, }); const authFields = authInfo.getFields(true); if (!authFields.clientApps) { throw messages.createError('error.noLinkedApps', [username]); } if (authFields.clientApps && !(clientApp in authFields.clientApps)) { throw messages.createError('error.invalidClientApp', [username, clientApp]); } // if logging out of the last client app, remove the whole `clientApps` object from the auth fields if (Object.keys(authFields.clientApps).length === 1) { await authInfo.save({ clientApps: undefined, }); } else { // just remove the specific client app entry delete authFields.clientApps[clientApp]; await authInfo.save({ clientApps: authFields.clientApps, }); } this.logSuccess(messages.getMessage('logoutClientAppSuccess', [clientApp, username])); return [clientApp]; } /** Warning about logging out of a scratch org and losing access to it */ maybeWarnScratchOrgs(orgs) { if (orgs.some((org) => org.isScratchOrg)) { this.warn(messages.getMessage('warning')); } return orgs; } } const promptForOrgsToRemove = async (orgAuths, all) => orgAuths.length === 1 ? orgAuths : checkbox({ message: messages.getMessage('prompt.select-envs'), // pick the orgs to delete - if flags.all - set each org to selected // otherwise prompt the user to select the orgs to delete choices: buildChoices(orgAuths, all), loop: true, }); const getOrgConfirmationMessage = (selectedOrgs, originalOrgCount) => { if (selectedOrgs.length === 1) { return messages.getMessage('prompt.confirm.single', [selectedOrgs[0].username]); } return selectedOrgs.length === originalOrgCount ? messages.getMessage('prompt.confirm-all') : messages.getMessage('prompt.confirm', [selectedOrgs.length, selectedOrgs.length > 1 ? 's' : '']); }; /** A whole bunch of custom formatting to make the list look nicer */ const buildChoices = (orgAuths, all) => { const maxUsernameLength = Math.max('Username'.length, ...orgAuths.map((orgAuth) => orgAuth.username.length)); const maxAliasLength = Math.max('Aliases'.length, ...orgAuths.map((orgAuth) => (orgAuth.aliases ? orgAuth.aliases.join(',') : '').length)); const maxConfigLength = Math.max('Configs'.length, ...orgAuths.map((orgAuth) => (orgAuth.configs ? orgAuth.configs.join(',') : '').length)); const maxTypeLength = Math.max('Type'.length, ...orgAuths.map((orgAuth) => { if (orgAuth.isScratchOrg) { return 'Scratch'.length; } if (orgAuth.isDevHub) { return 'DevHub'.length; } if (orgAuth.isSandbox) { return 'Sandbox'.length; } return 0; })); const choices = orgAuths .map((orgAuth) => { const aliasString = (orgAuth.aliases ? orgAuth.aliases.join(',') : '').padEnd(maxAliasLength, ' '); const configString = (orgAuth.configs ? orgAuth.configs.join(',') : '').padEnd(maxConfigLength, ' '); const typeString = StandardColors.info((orgAuth.isScratchOrg ? 'Scratch' : orgAuth.isDevHub ? 'DevHub' : orgAuth.isSandbox ? 'Sandbox' : '').padEnd(maxTypeLength, ' ')); // username - aliases - configs const key = `${orgAuth.username.padEnd(maxUsernameLength)} | ${typeString} | ${aliasString} | ${StandardColors.warning(configString)}`; return { name: key, value: orgAuth, checked: all, short: `${os.EOL}${orgAuth.username}` }; }) .sort((a, b) => a.value.username.localeCompare(b.value.username)); const userHeader = `${'Username'.padEnd(maxUsernameLength, ' ')}`; const aliasHeader = `${'Aliases'.padEnd(maxAliasLength, ' ')}`; const configHeader = `${'Configs'.padEnd(maxConfigLength, ' ')}`; const typeHeader = `${'Type'.padEnd(maxTypeLength, ' ')}`; return [new Separator(` ${userHeader} | ${typeHeader} | ${aliasHeader} | ${configHeader}`), ...choices]; }; //# sourceMappingURL=logout.js.map