UNPKG

@zendesk/zcli-core

Version:

ZCLI core libraries and services

106 lines (89 loc) 3.75 kB
import { CLIError } from '@oclif/core/lib/errors' import * as chalk from 'chalk' import { CliUx } from '@oclif/core' import Config from './config' import axios from 'axios' import SecureStore from './secureStore' import { Profile } from '../types' import { getAccount, parseSubdomain } from './authUtils' import { getBaseUrl } from './requestUtils' import { SecretType } from './secretType' export interface AuthOptions { secureStore: SecureStore; } export default class Auth { secureStore?: SecureStore config: Config constructor (options?: AuthOptions) { this.secureStore = options?.secureStore this.config = new Config() } // 1. If env vars are set, prepare token using them // 2. If no env vars, check if current profile is set async getAuthorizationToken () { const { ZENDESK_EMAIL, ZENDESK_PASSWORD, ZENDESK_API_TOKEN, ZENDESK_OAUTH_TOKEN } = process.env if (ZENDESK_OAUTH_TOKEN) { return `Bearer ${ZENDESK_OAUTH_TOKEN}` } else if (ZENDESK_EMAIL && ZENDESK_API_TOKEN) { return this.createBasicAuthToken(`${ZENDESK_EMAIL}`, ZENDESK_API_TOKEN) } else if (ZENDESK_EMAIL && ZENDESK_PASSWORD) { return this.createBasicAuthToken(ZENDESK_EMAIL, ZENDESK_PASSWORD, SecretType.PASSWORD) } else { const profile = await this.getLoggedInProfile() if (profile && this.secureStore) { const authToken = await this.secureStore.getSecret(getAccount(profile.subdomain, profile.domain)) return authToken } return undefined } } createBasicAuthToken (user: string, secret: string, secretType: SecretType = SecretType.TOKEN) { const basicBase64 = (str: string) => `Basic ${Buffer.from(str).toString('base64')}` if (secretType === SecretType.TOKEN) { return basicBase64(`${user}/token:${secret}`) } throw new CLIError(chalk.red(`Basic authentication of type '${secretType}' is not supported.`)) } getLoggedInProfile () { return this.config.getConfig('activeProfile') as unknown as Profile } setLoggedInProfile (subdomain: string, domain?: string) { return this.config.setConfig('activeProfile', { subdomain, domain }) } async loginInteractively (options?: Profile) { const subdomain = parseSubdomain(options?.subdomain || await CliUx.ux.prompt('Subdomain')) const domain = options?.domain const account = getAccount(subdomain, domain) const baseUrl = getBaseUrl(subdomain, domain) const email = await CliUx.ux.prompt('Email') const token = await CliUx.ux.prompt('API Token', { type: 'hide' }) const authToken = this.createBasicAuthToken(email, token) const testAuth = await axios.get( `${baseUrl}/api/v2/account/settings.json`, { headers: { Authorization: authToken }, validateStatus: function (status) { return status < 500 }, adapter: 'fetch' }) if (testAuth.status === 200 && this.secureStore) { await this.secureStore.setSecret(account, authToken) await this.setLoggedInProfile(subdomain, domain) return true } return false } async logout () { if (!this.secureStore) { throw new CLIError(chalk.red('Secure credentials store not found.')) } const profile = await this.getLoggedInProfile() if (!profile?.subdomain) throw new CLIError(chalk.red('Failed to log out: no active profile found.')) await this.config.removeConfig('activeProfile') const deleted = await this.secureStore.deleteSecret(getAccount(profile.subdomain, profile.domain)) if (!deleted) throw new CLIError(chalk.red('Failed to log out: Account, Service not found.')) return true } async getSavedProfiles () { return this.secureStore && this.secureStore.getAllCredentials() } }