UNPKG

@liara/cli

Version:

The command line interface for Liara

220 lines (219 loc) 8.4 kB
import got from 'got'; import chalk from 'chalk'; import fs from 'fs-extra'; import inquirer from 'inquirer'; import { Flags } from '@oclif/core'; import promptEmail from 'email-prompt-ts'; import { validate as validateEmail } from 'email-validator'; import AccountUse from './use.js'; import Command from '../../base.js'; import eraseLines from '../../utils/erase-lines.js'; import { createDebugLogger } from '../../utils/output.js'; import { REGIONS_API_URL, GLOBAL_CONF_PATH, GLOBAL_CONF_VERSION, } from '../../constants.js'; import ora from 'ora'; class AccountAdd extends Command { async run() { const { flags } = await this.parse(AccountAdd); const debug = createDebugLogger(flags.debug); this.spinner = ora(); const liara_json = await this.readGlobalConfig(); const currentAccounts = liara_json.accounts; this.got = got.extend({ prefixUrl: REGIONS_API_URL['iran'] }); if (flags['api-token']) { const user = await this.getMe(flags); if (!user) { this.error('api token is not creditable, please get your api token from https://console.liara.ir/API.'); } const name = flags.account || (await this.promptName(user.email)); this.addNewAccountToConfig(currentAccounts, { name, ...user, api_token: flags['api-token'], }); flags['from-login'] && (await AccountUse.run(['--account', name])); return; } const email = flags.email || (await this.promptEmail()); if (!validateEmail(email)) { this.log(); this.error(`Email validation failed. Please enter a valid email, e.g. me@example.com`); } const userStatus = await this.checkIfExists({ email }, debug); const password = flags.password || (await this.promptPassword()); const totp = userStatus.twoFAEnabled ? await this.promptTwoFA() : undefined; if (flags['from-login']) { flags.account = `${email.split('@')[0]}`; } const name = flags.account || (await this.promptName(email)); const twoFAState = userStatus.twoFAEnabled ? { twoFAType: 'totp', totp } : undefined; const userInfo = { email, password, ...twoFAState }; // debug2(userInfo); const account = await this.login(userInfo); this.addNewAccountToConfig(currentAccounts, { name, ...account, current: false, }); flags['from-login'] && (await AccountUse.run(['--account', name])); const { accountName } = await this.getCurrentAccount(); this.log(`> Auth credentials saved in ${chalk.bold(GLOBAL_CONF_PATH)}`); accountName && this.log(`> Current account is: ${accountName}`); } async checkIfExists(body, debug) { try { const data = await this.got .post('v1/login/check-if-exists', { json: body, headers: { Authorization: undefined }, }) .json(); if (!data.exists) { this.log(); this.error(`The email you entered isn’t registered. To continue, please sign up at: https://console.liara.ir`); } if (!data.socialCompleted) { this.log(); this.error(`No password is set for this account. Set one here: https://console.liara.ir/settings/security Then run 'liara login' or 'liara account:add' again.`); } return data; } catch (error) { debug(error); this.error(`Please check your internet connection and try again. If the issue persists, please submit a ticket at https://console.liara.ir/tickets for further assistance.`); } } async login(body) { try { const data = await this.got .post('v1/login?expiresIn=1y', { json: body, headers: { Authorization: undefined }, }) .json(); return { email: data.email, api_token: data.api_token, fullname: data.fullname, current: data.current, avatar: data.avatar, }; } catch (error) { if (error.response.statusCode == 401 || error.response.statusCode == 400) { this.error(`Authentication failed. The credentials you entered is incorrect. If you’ve forgotten or lost your password/twoFA, reset it at https://console.liara.ir `); } this.error(`Authentication failed. If the issue persists, please open a ticket at https://console.liara.ir/tickets Error: ${error.response.statusMessage} (${error.response.statusCode}) `); } } addNewAccountToConfig(currentAccounts, newAccount) { const accounts = { ...currentAccounts, [newAccount.name]: { email: newAccount.email, api_token: newAccount.api_token, fullname: newAccount.fullname, avatar: newAccount.avatar, current: false, }, }; fs.writeFileSync(GLOBAL_CONF_PATH, JSON.stringify({ accounts, version: GLOBAL_CONF_VERSION })); } async promptName(email) { const { name } = (await inquirer.prompt({ name: 'name', type: 'input', message: 'Enter an optional name for this account:', default: `${email.split('@')[0]}`, })); const liara_json = await this.readGlobalConfig(); const currentAccounts = liara_json.accounts; const currentAccountsName = currentAccounts && Object.keys(currentAccounts); return (currentAccountsName === null || currentAccountsName === void 0 ? void 0 : currentAccountsName.includes(name)) ? this.error('This name has already been used for another account. Please use a different name.') : name; } async promptEmail() { try { return await promptEmail({ start: `${chalk.green('?')} ${chalk.bold('Enter your email:')} `, }); } catch (error) { this.log(); // \n if (error.message === 'User abort') { process.stdout.write(eraseLines(2)); console.log(`${chalk.red('> Aborted!')} No changes made.`); process.exit(0); } if (error.message === 'stdin lacks setRawMode support') { this.error(`Interactive mode not supported – please run ${chalk.green('liara login --email you@domain.com --password your_password')}`); } throw error; } } async promptPassword() { this.log(); const { password } = (await inquirer.prompt({ name: 'password', type: 'password', message: 'Enter your password:', validate(input) { if (input.length === 0) { return false; } return true; }, })); return password; } async getMe(flags) { const { user } = await this.got('v1/me', { headers: { Authorization: `Bearer ${flags['api-token']}` }, }).json(); return user; } async promptTwoFA() { const { totp } = (await inquirer.prompt({ name: 'totp', type: 'input', message: 'Enter your Two-Factor Authentication Code:', validate(input) { if (input.length === 0) { return false; } return true; }, })); return totp; } } AccountAdd.description = 'add an account'; AccountAdd.flags = { ...Command.flags, email: Flags.string({ char: 'e', description: 'your email' }), password: Flags.string({ char: 'p', description: 'your password' }), account: Flags.string({ char: 'a', description: 'account name', required: false, }), 'from-login': Flags.boolean({ required: false, hidden: true, default: false, }), }; export default AccountAdd;