mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
added test for two factor authentication
This commit is contained in:
@@ -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 {
|
||||
</div>
|
||||
{qrCode.data
|
||||
.otpauth_url ? (
|
||||
<QRCode
|
||||
size={
|
||||
230
|
||||
}
|
||||
value={`${qrCode.data.otpauth_url}`}
|
||||
style={{
|
||||
display:
|
||||
'block',
|
||||
margin:
|
||||
'0 auto',
|
||||
}}
|
||||
id="qr-code"
|
||||
/>
|
||||
<>
|
||||
<QRCode
|
||||
size={
|
||||
230
|
||||
}
|
||||
value={`${qrCode.data.otpauth_url}`}
|
||||
style={{
|
||||
display:
|
||||
'block',
|
||||
margin:
|
||||
'0 auto',
|
||||
}}
|
||||
id="qr-code"
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
marginTop:
|
||||
'20px',
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
You
|
||||
can
|
||||
also
|
||||
add
|
||||
the
|
||||
QR
|
||||
code
|
||||
below
|
||||
directly
|
||||
on
|
||||
Google
|
||||
Auhenticator
|
||||
app
|
||||
or
|
||||
Authy
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop:
|
||||
'14px',
|
||||
textAlign:
|
||||
'center',
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
QR
|
||||
Code:
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
textDecoration:
|
||||
'underline',
|
||||
}}
|
||||
id="otpath-url"
|
||||
>
|
||||
{' '}
|
||||
{
|
||||
qrCode.data.otpauth_url.split(
|
||||
'secret='
|
||||
)[1]
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<ListLoader />
|
||||
)}
|
||||
|
||||
@@ -1272,6 +1272,7 @@ export class ProfileSetting extends Component {
|
||||
style={{
|
||||
marginTop: '10px',
|
||||
}}
|
||||
id="twoFactorLabel"
|
||||
>
|
||||
<input
|
||||
className="btn-toggler"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1"
|
||||
"axios": "^0.21.1",
|
||||
"speakeasy": "^2.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
209
tests/saas-tests/dashboard/twoFactorAuthentication.test.js
Normal file
209
tests/saas-tests/dashboard/twoFactorAuthentication.test.js
Normal file
@@ -0,0 +1,209 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
const utils = require('../../test-utils');
|
||||
const init = require('../../test-init');
|
||||
const speakeasy = require('speakeasy');
|
||||
const { expect } = require('chai');
|
||||
|
||||
require('should');
|
||||
const projectName = 'project';
|
||||
|
||||
let browser, page;
|
||||
// user credentials
|
||||
const email = utils.generateRandomBusinessEmail();
|
||||
const password = '1234567890';
|
||||
let token;
|
||||
|
||||
const generateOtp = () => {
|
||||
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
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user