@salesforce/plugin-auth
Version:
plugin for sf auth commands
181 lines • 8.95 kB
JavaScript
/*
* 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