@unito/integration-cli
Version:
Integration CLI
124 lines (120 loc) • 7.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const configuration_1 = require("../resources/configuration");
const Oauth2Resource = tslib_1.__importStar(require("../resources/oauth2"));
const IntegrationsPlatform = tslib_1.__importStar(require("../services/integrationsPlatform"));
const configurationTypes_1 = require("../configurationTypes");
const errors_1 = require("../errors");
const globalConfiguration_1 = require("../resources/globalConfiguration");
const decryption_1 = require("../resources/decryption");
class Oauth2 extends core_1.Command {
static summary = `Perform an OAuth2 workflow to either populate or refresh a test account's credentials.`;
static description = `The Oauth2 command allows you to perform an OAuth2 workflow to populate the specified test account's accessToken and refreshToken to be used by the 'test' and 'dev' commands.
If the test-account is already populated, the command will refresh the credentials if the refresh token is available.
If you want to force a new OAuth2 flow to change the connected account or something else, use the --reauth flag.`;
static examples = [
'<%= config.bin %> <%= command.id %>',
'<%= config.bin %> <%= command.id %> --reauth --test-account=compliance',
];
static flags = {
'test-account': core_1.Flags.string({
description: 'Test account to use.',
options: Object.values(configuration_1.CredentialScope),
default: configuration_1.CredentialScope.DEVELOPMENT,
}),
environment: core_1.Flags.custom({
description: 'the environment of the platform',
options: Object.values(globalConfiguration_1.Environment),
default: globalConfiguration_1.Environment.Production,
hidden: true,
})(),
reauth: core_1.Flags.boolean({
description: `triggers a new oauth2 flow to overwrite the test account's current credentials`,
default: false,
}),
'config-path': core_1.Flags.string({
summary: 'relative path to a custom ".unito.json" file',
description: `Use a custom configuration file instead of the default '.unito.json' or other environment specific
ones.
If you want to force the CLI to use a specific configuration file, you can use this flag to specify the relative
path from your integration's root folder (with a leading '/').
Usage: <%= config.bin %> <%= command.id %> --config-path=/myCustomConfig.json`,
}),
};
async catch(error) {
/* istanbul ignore if */
if ((0, errors_1.handleError)(this, error)) {
this.exit(-1);
}
throw error;
}
async run() {
const { flags } = await this.parse(Oauth2);
const environment = flags.environment ?? globalConfiguration_1.Environment.Production;
const customConfigPath = flags['config-path'];
const configuration = await (0, configuration_1.getConfiguration)(environment, customConfigPath);
// First check for development oauth2 authorization scheme
let oauth2 = configuration.authorizations?.find(authorization => authorization.method === configurationTypes_1.Method.OAUTH2 && authorization.development)?.oauth2;
// Try for any oauth2 authorization scheme if there was no development one
if (!oauth2) {
oauth2 = configuration.authorizations?.find(authorization => authorization.method === configurationTypes_1.Method.OAUTH2)?.oauth2;
}
if (!oauth2) {
throw new errors_1.MissingAuth2AuthorizationError();
}
// Decrypt any encrypted oauth2 fields (mainly clientSecret)
const decryptedEntries = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, oauth2);
if (decryptedEntries.failed.length) {
throw new errors_1.EntryDecryptionError(decryptedEntries.failed.at(0), environment);
}
oauth2 = decryptedEntries.successful;
const testAccount = flags['test-account'];
const testAccountCredentials = configuration.testAccounts?.[testAccount];
const testAccountsToRefresh = new Set([testAccount]);
// Figure out if we want to refresh other test account at the same time (like if they currently have the same values)
for (const [account, accountCredentials] of Object.entries(configuration.testAccounts ?? {})) {
if (!testAccountsToRefresh.has(account) &&
accountCredentials?.accessToken === testAccountCredentials?.accessToken &&
accountCredentials?.refreshToken === testAccountCredentials?.refreshToken) {
testAccountsToRefresh.add(account);
}
}
let decryptionResult;
if (testAccountCredentials) {
decryptionResult = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, testAccountCredentials);
}
let credentials;
if (!testAccountCredentials?.accessToken || flags.reauth) {
core_1.ux.log(`Starting OAuth2 flow for test account: ${testAccount}`);
credentials = await Oauth2Resource.performOAuth2Flow(oauth2, environment, testAccountCredentials);
core_1.ux.log(`OAuth2 flow... Done`);
}
else {
if (!testAccountCredentials?.refreshToken) {
core_1.ux.log(chalk_1.default.redBright('No refresh token found, nothing to do.'));
return;
}
const refreshToken = decryptionResult?.successful.refreshToken;
core_1.ux.action.start(`Refreshing test account ${testAccount}`, undefined, { stdout: true });
credentials = await Oauth2Resource.updateToken(oauth2, refreshToken, decryptionResult?.successful, environment);
// If provider response doesn't contain a new refresh token, use the existing one
credentials.refreshToken = credentials.refreshToken ?? refreshToken;
core_1.ux.action.stop();
}
// Always encrypt credentials before saving them
credentials.accessToken = (await IntegrationsPlatform.encryptData(configuration.name, credentials.accessToken, false)).encryptedData;
if (credentials.refreshToken) {
credentials.refreshToken = (await IntegrationsPlatform.encryptData(configuration.name, credentials.refreshToken, false)).encryptedData;
}
// Save credentials for all test accounts needing refresh
for (const account of testAccountsToRefresh) {
core_1.ux.action.start(`Saving credentials for account: ${account}`, undefined, { stdout: true });
await (0, configuration_1.writeTestAccount)(configuration, environment, customConfigPath, credentials, account);
core_1.ux.action.stop();
}
}
}
exports.default = Oauth2;