rdme
Version:
ReadMe's official CLI and GitHub Action.
85 lines (84 loc) • 3.16 kB
JavaScript
import chalk from 'chalk';
import isEmail from 'validator/lib/isEmail.js';
import configStore from './configstore.js';
import getCurrentConfig from './getCurrentConfig.js';
import { debug } from './logger.js';
import promptTerminal from './promptWrapper.js';
import { handleAPIv1Res, readmeAPIv1Fetch } from './readmeAPIFetch.js';
import { validateSubdomain } from './validatePromptInput.js';
function loginFetch(body) {
return readmeAPIv1Fetch('/api/v1/login', {
method: 'post',
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
}
/**
* The prompt flow for logging a user in and writing the credentials to
* `configstore`. This is a separate lib function because we reuse it both
* in the `login` command as well as any time a user omits an API key.
*
* @returns A Promise-wrapped string with the logged-in user's credentials
*/
export default async function loginFlow(
/**
* An optional one-time passcode, if the user passes one in
* via a flag to the the `login` command
*/
otp) {
const storedConfig = getCurrentConfig();
const { email, password, project } = await promptTerminal([
{
type: 'text',
name: 'email',
message: 'What is your email address?',
initial: storedConfig.email,
validate(val) {
return isEmail.default(val) ? true : 'Please provide a valid email address.';
},
},
{
type: 'invisible',
name: 'password',
message: 'What is your password?',
},
{
type: 'text',
name: 'project',
message: 'What project subdomain are you logging into?',
initial: storedConfig.project,
validate: validateSubdomain,
},
]);
if (!project) {
return Promise.reject(new Error('No project subdomain provided. Please use `--project`.'));
}
if (!isEmail.default(email)) {
return Promise.reject(new Error('You must provide a valid email address.'));
}
const payload = { email, password, project };
// if the user passed in a `otp` option, include that in the login payload
if (otp)
payload.token = otp;
return loginFetch(payload)
.then(handleAPIv1Res)
.catch(async (err) => {
// if the user's login requires 2FA, let's prompt them for the token!
if (err.code === 'LOGIN_TWOFACTOR') {
debug('2FA error response, prompting for 2FA code');
const otpPrompt = await promptTerminal({
type: 'text',
name: 'otp',
message: 'What is your 2FA token?',
});
return loginFetch({ email, password, project, token: otpPrompt.otp }).then(handleAPIv1Res);
}
throw err;
})
.then(res => {
configStore.set('apiKey', res.apiKey);
configStore.set('email', email);
configStore.set('project', project);
return `Successfully logged in as ${chalk.green(email)} to the ${chalk.blue(project)} project.`;
});
}