@liara/cli
Version:
The command line interface for Liara
220 lines (219 loc) • 8.4 kB
JavaScript
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;