@contentstack/cli-auth
Version:
Contentstack CLI plugin for authentication activities
202 lines (201 loc) • 9.78 kB
JavaScript
;
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();