diff --git a/dashboard/src/components/modals/TwoFactorAuth.js b/dashboard/src/components/modals/TwoFactorAuth.js
index abbef36556..201ae63a8d 100644
--- a/dashboard/src/components/modals/TwoFactorAuth.js
+++ b/dashboard/src/components/modals/TwoFactorAuth.js
@@ -23,7 +23,7 @@ class TwoFactorAuthModal extends Component {
profileSettings: { data },
generateTwoFactorQRCode,
} = this.props;
- generateTwoFactorQRCode(data.id);
+ generateTwoFactorQRCode(data.id || data._id);
window.addEventListener('keydown', this.handleKeyBoard);
}
@@ -72,7 +72,7 @@ class TwoFactorAuthModal extends Component {
verifyTwoFactorAuthToken,
profileSettings,
} = this.props;
- values.userId = profileSettings.data.id;
+ values.userId = profileSettings.data.id || profileSettings.data._id;
verifyTwoFactorAuthToken(values).then(response => {
setTwoFactorAuth(response.data.twoFactorAuthEnabled);
this.props.closeThisDialog();
@@ -221,19 +221,73 @@ class TwoFactorAuthModal extends Component {
{qrCode.data
.otpauth_url ? (
-
+ <>
+
+
+
+ You
+ can
+ also
+ add
+ the
+ QR
+ code
+ below
+ directly
+ on
+ Google
+ Auhenticator
+ app
+ or
+ Authy
+
+
+
+
+
+ QR
+ Code:
+
+
+ {' '}
+ {
+ qrCode.data.otpauth_url.split(
+ 'secret='
+ )[1]
+ }
+
+
+ >
) : (
)}
diff --git a/dashboard/src/components/profileSettings/Profile.js b/dashboard/src/components/profileSettings/Profile.js
index d347854e4b..0257fafea3 100755
--- a/dashboard/src/components/profileSettings/Profile.js
+++ b/dashboard/src/components/profileSettings/Profile.js
@@ -1272,6 +1272,7 @@ export class ProfileSetting extends Component {
style={{
marginTop: '10px',
}}
+ id="twoFactorLabel"
>
{
+ const otp = speakeasy.totp({
+ secret: token.trim(),
+ encoding: 'base32',
+ });
+ return otp;
+};
+
+describe('TwoFactor Authentication API', () => {
+ const operationTimeOut = init.timeout;
+ beforeAll(async done => {
+ jest.setTimeout(360000);
+ browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
+ page = await browser.newPage();
+ await page.setUserAgent(utils.agent);
+
+ const user = {
+ email: email,
+ password: password,
+ };
+ //user login
+ await init.registerUser(user, page);
+ await init.addProject(page, projectName);
+
+ done();
+ });
+
+ afterAll(async done => {
+ browser.close();
+ done();
+ });
+
+ test(
+ 'Should throw an error when invalid otp token is passed',
+ async done => {
+ await page.goto(utils.DASHBOARD_URL, {
+ waitUntil: ['networkidle2'],
+ });
+
+ await init.pageWaitForSelector(page, '#profile-menu');
+ await init.pageClick(page, '#profile-menu');
+ await init.pageWaitForSelector(page, '#userProfile');
+ await init.pageClick(page, '#userProfile');
+ await init.pageWaitForSelector(page, '#profileSettings', {
+ visible: true,
+ timeout: init.timeout,
+ });
+
+ await init.pageWaitForSelector(page, '#twoFactorLabel');
+ await init.pageClick(page, '#twoFactorLabel');
+
+ await init.pageWaitForSelector(page, '#nextFormButton');
+ await init.pageClick(page, '#nextFormButton');
+ await init.pageWaitForSelector(page, '#token');
+ await init.pageType(page, '#token', '432424');
+ await init.pageWaitForSelector(page, '#enableTwoFactorAuthButton');
+ await init.pageClick(page, '#enableTwoFactorAuthButton');
+
+ const message = await init.page$Eval(
+ page,
+ '#modal-message',
+ element => element.innerHTML
+ );
+ expect(message).equal('Invalid token.');
+ done();
+ },
+ operationTimeOut
+ );
+
+ test(
+ 'Should enable twoFactor authentication',
+ async done => {
+ await page.goto(utils.DASHBOARD_URL, {
+ waitUntil: ['networkidle2'],
+ });
+
+ await init.pageWaitForSelector(page, '#profile-menu');
+ await init.pageClick(page, '#profile-menu');
+ await init.pageWaitForSelector(page, '#userProfile');
+ await init.pageClick(page, '#userProfile');
+ await init.pageWaitForSelector(page, '#profileSettings', {
+ visible: true,
+ timeout: init.timeout,
+ });
+
+ await init.pageWaitForSelector(page, '#twoFactorLabel');
+ await init.pageClick(page, '#twoFactorLabel');
+
+ await init.pageWaitForSelector(page, '#otpath-url');
+ token = await init.page$Eval(
+ page,
+ '#otpath-url',
+ element => element.innerHTML
+ );
+ const otp = await generateOtp(token);
+ await init.pageWaitForSelector(page, '#nextFormButton');
+ await init.pageClick(page, '#nextFormButton');
+ await init.pageWaitForSelector(page, '#token');
+ await init.pageType(page, '#token', otp.toString());
+ await init.pageWaitForSelector(page, '#enableTwoFactorAuthButton');
+ await init.pageClick(page, '#enableTwoFactorAuthButton');
+ const isVisible = await init.isElementOnPage(
+ page,
+ '#modal-message'
+ );
+ expect(isVisible).equal(false);
+ await init.saasLogout(page);
+ done();
+ },
+ operationTimeOut
+ );
+ test(
+ 'Should ask a user with two factor enabled when they are about to login again',
+ async done => {
+ await page.goto(utils.ACCOUNTS_URL + '/login', {
+ waitUntil: 'networkidle2',
+ });
+ await init.pageWaitForSelector(page, '#login-button');
+ await init.pageClick(page, 'input[name=email]');
+ await init.pageType(page, 'input[name=email]', email);
+ await init.pageClick(page, 'input[name=password]');
+ await init.pageType(page, 'input[name=password]', password);
+ await init.pageClick(page, 'button[type=submit]');
+ await init.pageWaitForSelector(page, '.message', {
+ visible: true,
+ timeout: init.timeout,
+ });
+
+ const message = await init.page$Eval(
+ page,
+ '.message',
+ element => element.innerHTML
+ );
+ expect(message).equal('Enter your auth token below to login.');
+ done();
+ },
+ operationTimeOut
+ );
+
+ test(
+ 'Should throw an error when invalid otp token is passed during login',
+ async done => {
+ await page.goto(utils.ACCOUNTS_URL + '/login', {
+ waitUntil: 'networkidle2',
+ });
+ await init.pageWaitForSelector(page, '#login-button');
+ await init.pageClick(page, 'input[name=email]');
+ await init.pageType(page, 'input[name=email]', email);
+ await init.pageClick(page, 'input[name=password]');
+ await init.pageType(page, 'input[name=password]', password);
+ await init.pageClick(page, 'button[type=submit]');
+
+ await init.pageWaitForSelector(page, '#token');
+ await init.pageType(page, '#token', '432224');
+ await init.pageWaitForSelector(page, 'button[type=submit]');
+ await init.pageClick(page, 'button[type=submit]');
+
+ const message = await init.page$Eval(
+ page,
+ '.title span',
+ element => element.innerHTML
+ );
+ expect(message).equal('Invalid token.');
+ done();
+ },
+ operationTimeOut
+ );
+ test(
+ 'Should successfully login when valid otp token is passed during login',
+ async done => {
+ await page.goto(utils.ACCOUNTS_URL + '/login', {
+ waitUntil: 'networkidle2',
+ });
+ await init.pageWaitForSelector(page, '#login-button');
+ await init.pageClick(page, 'input[name=email]');
+ await init.pageType(page, 'input[name=email]', email);
+ await init.pageClick(page, 'input[name=password]');
+ await init.pageType(page, 'input[name=password]', password);
+ await init.pageClick(page, 'button[type=submit]');
+
+ const otp = generateOtp();
+ await init.pageWaitForSelector(page, '#token');
+ await init.pageType(page, '#token', otp.toString());
+ await init.pageWaitForSelector(page, 'button[type=submit]');
+ await init.pageClick(page, 'button[type=submit]');
+ await init.pageWaitForSelector(page, '#home', {
+ visible: true,
+ timeout: init.timeout,
+ });
+ done();
+ },
+ operationTimeOut
+ );
+});