Skip to content

Commit

Permalink
Ask preferred 2FA method during registration
Browse files Browse the repository at this point in the history
Fix #115
  • Loading branch information
Mikescops committed Jul 27, 2023
1 parent 120da96 commit e10b871
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 9 deletions.
8 changes: 6 additions & 2 deletions src/endpoints/getAuthenticationMethodsForDevice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { requestAppApi } from '../requestApi';

type SupportedAuthenticationMethod = 'email_token' | 'totp' | 'duo_push' | 'dashlane_authenticator';
import { SupportedAuthenticationMethod } from '../types';

const defaultSupportedMethods: SupportedAuthenticationMethod[] = [
'email_token',
Expand All @@ -26,6 +25,7 @@ interface GetAuthenticationMethodsForDeviceResult {
isNitroProvider?: boolean;
};
}
| Record<string, never>
| {
type: 'email_token' | 'totp' | 'duo_push' | 'dashlane_authenticator';
}
Expand All @@ -39,6 +39,10 @@ interface GetAuthenticationMethodsForDeviceResult {
}[];
}
)[];
/**
* Indicates the type of account the user owns
*/
accountType: 'masterPassword' | 'invisibleMasterPassword';
}

// Unused for now
Expand Down
24 changes: 18 additions & 6 deletions src/middleware/registerDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import {
performEmailTokenVerification,
performTotpVerification,
} from '../endpoints';
import { askOtp, askToken } from '../utils';
import { askOtp, askToken, askVerificationMethod } from '../utils';
import { getAuthenticationMethodsForDevice } from '../endpoints/getAuthenticationMethodsForDevice';
import { requestEmailTokenVerification } from '../endpoints/requestEmailTokenVerification';
import { SupportedAuthenticationMethod } from '../types';

interface RegisterDevice {
login: string;
Expand All @@ -22,20 +23,31 @@ export const registerDevice = async (
winston.debug('Registering the device...');

// Log in via a compatible verification method
const { verifications } = await getAuthenticationMethodsForDevice({ login });
const { verifications, accountType } = await getAuthenticationMethodsForDevice({ login });

if (accountType === 'invisibleMasterPassword') {
throw new Error('Master password-less is currently not supported');
}

const selectedVerificationMethod =
verifications.length > 1
? await askVerificationMethod(verifications.map((method) => method.type as SupportedAuthenticationMethod))
: verifications[0].type;

let authTicket: string;
if (verifications.find((method) => method.type === 'duo_push')) {
if (selectedVerificationMethod === 'duo_push') {
winston.info('Please accept the Duo push notification on your phone');
({ authTicket } = await performDuoPushVerification({ login }));
} else if (verifications.find((method) => method.type === 'dashlane_authenticator')) {
} else if (selectedVerificationMethod === 'dashlane_authenticator') {
winston.info('Please accept the Dashlane Authenticator push notification on your phone');
({ authTicket } = await performDashlaneAuthenticatorVerification({ login }));
} else if (verifications.find((method) => method.type === 'totp')) {
} else if (selectedVerificationMethod === 'totp') {
const otp = await askOtp();
({ authTicket } = await performTotpVerification({
login,
otp,
}));
} else if (verifications.find((method) => method.type === 'email_token')) {
} else if (selectedVerificationMethod === 'email_token') {
await requestEmailTokenVerification({ login });

const token = await askToken();
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,5 @@ export class PrintableVaultNote {
return this.vaultNote.title.trim();
}
}

export type SupportedAuthenticationMethod = 'email_token' | 'totp' | 'duo_push' | 'dashlane_authenticator';
23 changes: 22 additions & 1 deletion src/utils/dialogs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import inquirer from 'inquirer';
import inquirerSearchList from 'inquirer-search-list';
import { PrintableVaultCredential, PrintableVaultNote, VaultCredential, VaultNote } from '../types';
import { removeUnderscoresAndCapitalize } from './strings';
import {
PrintableVaultCredential,
PrintableVaultNote,
SupportedAuthenticationMethod,
VaultCredential,
VaultNote,
} from '../types';
import PromptConstructor = inquirer.prompts.PromptConstructor;

export const prompt = inquirer.createPromptModule({ output: process.stderr });
Expand Down Expand Up @@ -138,3 +145,17 @@ export const askToken = async () => {
]);
return response.token;
};

export const askVerificationMethod = async (verificationMethods: SupportedAuthenticationMethod[]) => {
const response = await inquirer.prompt<{ verificationMethod: string }>([
{
type: 'list',
name: 'verificationMethod',
message: 'What second factor method would you like to use?',
choices: verificationMethods.map((method) => {
return { name: removeUnderscoresAndCapitalize(method), value: method };
}),
},
]);
return response.verificationMethod;
};
8 changes: 8 additions & 0 deletions src/utils/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ export const getTeamDeviceCredentialsFromEnv = (): TeamDeviceCredentials | null
return null;
}
};

/** Remove underscores and capitalize string */
export const removeUnderscoresAndCapitalize = (string: string): string => {
return string
.split('_')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(' ');
};

0 comments on commit e10b871

Please sign in to comment.