UNPKG

@contentstack/cli-auth

Version:

Contentstack CLI plugin for authentication activities

202 lines (201 loc) 9.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cli_utilities_1 = require("@contentstack/cli-utilities"); const interactive_1 = require("./interactive"); /** * @class * Auth handler */ class AuthHandler { set client(contentStackClient) { cli_utilities_1.log.debug('Setting ContentStack client', { module: 'auth-handler' }); this._client = contentStackClient; } set host(contentStackHost) { cli_utilities_1.log.debug(`Setting ContentStack host: ${contentStackHost}`, { module: 'auth-handler' }); this._host = contentStackHost; } /** * * * Login into Contentstack * @param {string} email Contentstack email address * @param {string} password User's password for contentstack account * @returns {Promise} Promise object returns authtoken on success * TBD: take out the otp implementation from login and create a new method/function to handle otp */ /** * Handle the OTP flow for 2FA authentication * @param tfaToken Optional pre-provided TFA token * @param loginPayload Login payload containing user credentials * @returns Promise<string> The TFA token to use for authentication */ async handleOTPFlow(tfaToken, loginPayload) { try { if (tfaToken) { cli_utilities_1.log.info('Using provided TFA token', { module: 'auth-handler' }); return tfaToken; } cli_utilities_1.log.debug('2FA required, requesting OTP channel', { module: 'auth-handler' }); const otpChannel = await (0, interactive_1.askOTPChannel)(); cli_utilities_1.log.debug(`OTP channel selected: ${otpChannel}`, { module: 'auth-handler' }); if (otpChannel === 'sms') { try { await this.requestSMSOTP(loginPayload); } catch (error) { cli_utilities_1.log.debug('SMS OTP request failed', { module: 'auth-handler', error }); cli_utilities_1.cliux.print('CLI_AUTH_SMS_OTP_FAILED', { color: 'red' }); throw error; } } cli_utilities_1.log.debug('Requesting OTP input', { module: 'auth-handler', channel: otpChannel }); return await (0, interactive_1.askOTP)(); } catch (error) { cli_utilities_1.log.debug('2FA flow failed', { module: 'auth-handler', error }); throw error; } } /** * Request SMS OTP for 2FA authentication * @param loginPayload Login payload containing user credentials * @throws CLIError if SMS request fails */ async requestSMSOTP(loginPayload) { cli_utilities_1.log.debug('Sending SMS OTP request', { module: 'auth-handler' }); try { await this._client.axiosInstance.post('/user/request_token_sms', { user: loginPayload }); cli_utilities_1.log.debug('SMS OTP request successful', { module: 'auth-handler' }); cli_utilities_1.cliux.print('CLI_AUTH_LOGIN_SECURITY_CODE_SEND_SUCCESS'); } catch (error) { cli_utilities_1.log.debug('SMS OTP request failed', { module: 'auth-handler', error }); throw error; } } async login(email, password, tfaToken) { const hasCredentials = typeof password === 'string' && password.length > 0; const hasTfaToken = typeof tfaToken === 'string' && tfaToken.length > 0; cli_utilities_1.log.debug('Starting login process', { module: 'auth-handler', email, hasCredentials, hasTfaToken, }); return new Promise((resolve, reject) => { if (email && password) { const loginPayload = { email, password }; if (tfaToken) { loginPayload.tfa_token = tfaToken; cli_utilities_1.log.debug('Adding TFA token to login payload', { module: 'auth-handler' }); } cli_utilities_1.log.debug('Making login API call', { module: 'auth-handler', payload: { email, hasCredentials, hasTfaToken }, }); this._client .login(loginPayload) .then(async (result) => { cli_utilities_1.log.debug('Login API response received', { module: 'auth-handler', hasUser: !!result.user, errorCode: result.error_code, }); if (result.user) { cli_utilities_1.log.debug('Login successful, user found', { module: 'auth-handler', userEmail: result.user.email }); resolve(result.user); } else if (result.error_code === 294) { const tfToken = await this.handleOTPFlow(tfaToken, loginPayload); try { resolve(await this.login(email, password, tfToken)); } catch (error) { cli_utilities_1.log.debug('Login with TFA token failed', { module: 'auth-handler', error }); cli_utilities_1.cliux.print('CLI_AUTH_2FA_FAILED', { color: 'red' }); reject(error); } } else { cli_utilities_1.log.debug('Login failed - no user found', { module: 'auth-handler', result }); reject(new Error(cli_utilities_1.messageHandler.parse('CLI_AUTH_LOGIN_NO_USER'))); } }) .catch((error) => { cli_utilities_1.log.debug('Login API call failed', { module: 'auth-handler', error: (error === null || error === void 0 ? void 0 : error.errorMessage) || error }); cli_utilities_1.cliux.print('CLI_AUTH_LOGIN_FAILED', { color: 'yellow' }); (0, cli_utilities_1.handleAndLogError)(error, { module: 'auth-handler' }); }); } else { const hasEmail = !!email; const hasCredentials = !!password; cli_utilities_1.log.debug('Login failed - missing credentials', { module: 'auth-handler', hasEmail, hasCredentials, }); cli_utilities_1.log.debug('Login failed - missing credentials', { module: 'auth-handler', hasEmail, hasCredentials }); reject(new Error(cli_utilities_1.messageHandler.parse('CLI_AUTH_LOGIN_NO_CREDENTIALS'))); } }); } /** * Logout from Contentstack * @param {string} authtoken authtoken that needs to invalidated when logging out * @returns {Promise} Promise object returns response object from Contentstack */ async logout(authtoken) { cli_utilities_1.log.debug('Starting logout process', { module: 'auth-handler', hasAuthToken: !!authtoken }); return new Promise((resolve, reject) => { if (authtoken) { cli_utilities_1.log.debug('Making logout API call', { module: 'auth-handler' }); this._client .logout(authtoken) .then(function (response) { cli_utilities_1.log.debug('Logout API call successful', { module: 'auth-handler', response }); return resolve(response); }) .catch((error) => { cli_utilities_1.log.debug('Logout API call failed', { module: 'auth-handler', error: error.message }); cli_utilities_1.cliux.print('CLI_AUTH_LOGOUT_FAILED', { color: 'yellow' }); reject(error); }); } else { cli_utilities_1.log.debug('Logout failed - no auth token provided', { module: 'auth-handler' }); reject(new Error(cli_utilities_1.messageHandler.parse('CLI_AUTH_LOGOUT_NO_TOKEN'))); } }); } /** * Validate token * @param {string} authtoken * @returns {Promise} Promise object returns response object from Contentstack */ async validateAuthtoken(authtoken) { cli_utilities_1.log.debug('Starting token validation', { module: 'auth-handler', hasAuthToken: !!authtoken }); return new Promise((resolve, reject) => { if (authtoken) { cli_utilities_1.log.debug('Making token validation API call', { module: 'auth-handler' }); this._client .getUser() .then((user) => { cli_utilities_1.log.debug('Token validation successful', { module: 'auth-handler', user }); resolve(user); }) .catch((error) => { cli_utilities_1.log.debug('Token validation failed', { module: 'auth-handler', error: error.message }); cli_utilities_1.cliux.print('CLI_AUTH_TOKEN_VALIDATION_FAILED', { color: 'yellow' }); (0, cli_utilities_1.handleAndLogError)(error, { module: 'auth-handler' }); }); } else { cli_utilities_1.log.debug('Token validation failed - no auth token provided', { module: 'auth-handler' }); reject(new Error(cli_utilities_1.messageHandler.parse('CLI_AUTH_TOKEN_VALIDATION_NO_TOKEN'))); } }); } } exports.default = new AuthHandler();