diff --git a/src/cli/commands/auth/index.ts b/src/cli/commands/auth/index.ts index f2b14f3de3..b3d3ce0624 100644 --- a/src/cli/commands/auth/index.ts +++ b/src/cli/commands/auth/index.ts @@ -12,25 +12,33 @@ import { MisconfiguredAuthInCI } from '../../../lib/errors/misconfigured-auth-in import { AuthFailedError } from '../../../lib/errors/authentication-failed-error'; import {verifyAPI} from './is-authed'; -module.exports = auth; - const apiUrl = url.parse(config.API); const authUrl = apiUrl.protocol + '//' + apiUrl.host; const debug = Debug('snyk-auth'); let attemptsLeft = 0; +module.exports = auth; + function resetAttempts() { attemptsLeft = 30; } type AuthCliCommands = 'wizard' | 'ignore'; +interface WebAuthResponse { + res: object; + body: object; +} -async function webAuth(via: AuthCliCommands) { +async function webAuth(via: AuthCliCommands): Promise { const token = uuid.v4(); // generate a random key const redirects = { wizard: '/authenticated', }; + if (isCI()) { + throw MisconfiguredAuthInCI(); + } + let urlStr = authUrl + '/login?token=' + token; // validate that via comes from our code, and not from user & CLI @@ -38,35 +46,22 @@ async function webAuth(via: AuthCliCommands) { urlStr += '&redirectUri=' + new Buffer(redirects[via]).toString('base64'); } - const msg = + console.log( '\nNow redirecting you to our auth page, go ahead and log in,\n' + 'and once the auth is complete, return to this prompt and you\'ll\n' + 'be ready to start using snyk.\n\nIf you can\'t wait use this url:\n' + - urlStr + '\n'; - - // suppress this message in CI - if (!isCI()) { - console.log(msg); - } else { - return Promise.reject(MisconfiguredAuthInCI()); - } - - const lbl = 'Waiting...'; + urlStr + '\n'); - return spinner(lbl).then(() => { + try { setTimeout(() => { open(urlStr, {wait: false}); }, 2000); // start checking the token immediately in case they've already // opened the url manually return testAuthComplete(token); - }) - // clear spinnger in case of success or failure - .then(spinner.clear(lbl)) - .catch((error) => { - spinner.clear(lbl)(); - throw error; - }); + } catch (error) { + throw error; + } } async function testAuthComplete(token: string) { @@ -79,59 +74,57 @@ async function testAuthComplete(token: string) { method: 'post', }; - return new Promise((resolve, reject) => { - debug(payload); - request(payload, (error, res, body) => { - debug(error, (res || {}).statusCode, body); - if (error) { - return reject(error); - } + debug(payload); + const callBackRes = await request(payload); + const {error, res, body} = callBackRes; + debug(error, (res || {}).statusCode, body); - if (res.statusCode !== 200) { - return reject(AuthFailedError(body.message, res.statusCode)); - } + if (error) { + throw error; + } + + if (res.statusCode !== 200) { + throw AuthFailedError(body.message, res.statusCode); + } - // we have success - if (body.api) { - return resolve({ - res, - body, - }); + if (!body.api) { + // retry request + setTimeout(() => { + attemptsLeft--; + if (attemptsLeft > 0) { + return testAuthComplete(token); } - // we need to wait and poll again in a moment - setTimeout(() => { - attemptsLeft--; - if (attemptsLeft > 0) { - return resolve(testAuthComplete(token)); - } - - reject(TokenExpiredError()); - }, 1000); - }); - }); + throw TokenExpiredError(); + }, 1000); + } + + return { + res, + body, + }; } async function auth(apiToken: string, via: AuthCliCommands) { - let promise; + let authPromise; resetAttempts(); if (apiToken) { // user is manually setting the API token on the CLI - let's trust them - promise = verifyAPI(apiToken); + authPromise = verifyAPI(apiToken); } else { - promise = webAuth(via); + authPromise = webAuth(via); } - return promise.then((data) => { - const res = data.res; - const body = res.body; - debug(body); + const authResponse = await authPromise; + const res = authResponse.res; + const body = res.body; + debug(body); - if (res.statusCode === 200 || res.statusCode === 201) { - snyk.config.set('api', body.api); - return '\nYour account has been authenticated. Snyk is now ready to ' + - 'be used.\n'; - } + if (!(res.statusCode === 200 || res.statusCode === 201)) { throw AuthFailedError(body.message, res.statusCode); - }); + } + + snyk.config.set('api', body.api); + return '\nYour account has been authenticated. Snyk is now ready to ' + + 'be used.\n'; } diff --git a/src/cli/commands/auth/is-authed.ts b/src/cli/commands/auth/is-authed.ts index 1593fd8970..2a4ab8d420 100644 --- a/src/cli/commands/auth/is-authed.ts +++ b/src/cli/commands/auth/is-authed.ts @@ -2,33 +2,30 @@ import * as snyk from '../../../lib'; import * as config from '../../../lib/config'; import * as request from '../../../lib/request'; -export function isAuthed() { +export async function isAuthed() { const token = snyk.config.get('api'); - return verifyAPI(token).then((res: any) => { - return res.body.ok; - }); + const res = await verifyAPI(token); + return res.body.ok; } -export function verifyAPI(api) { +export async function verifyAPI(apiToken) { const payload = { body: { - api, + api: apiToken, }, method: 'POST', url: config.API + '/verify/token', json: true, }; - return new Promise((resolve, reject) => { - request(payload, (error, res, body) => { - if (error) { - return reject(error); - } + const verifyTokenRes = await request(payload); + const {error, res, body} = verifyTokenRes; + if (error) { + throw error; + } - resolve({ - res, - body, - }); - }); - }); + return { + res, + body, + }; }