This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/tests/acceptance/second-factor-auth-test.js
Alan Guo Xiang Tan fde9e6bc25
DEV: Migrate sidebar site settings (#19336)
This new site setting replaces the
`enable_experimental_sidebar_hamburger` and `enable_sidebar` site
settings as the sidebar feature exits the experimental phase.

Note that we're replacing this without depreciation since the previous
site setting was considered experimental.

Internal Ref: /t/86563
2022-12-08 09:44:29 +08:00

295 lines
8.8 KiB
JavaScript

import {
acceptance,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import { click, currentURL, fillIn, visit } from "@ember/test-helpers";
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import { test } from "qunit";
const { TOTP, BACKUP_CODE, SECURITY_KEY } = SECOND_FACTOR_METHODS;
const RESPONSES = {
failed: {
status: 404,
error: "could not find an active challenge in your session",
},
ok111111: {
totp_enabled: true,
backup_enabled: true,
security_keys_enabled: true,
allowed_methods: [TOTP, BACKUP_CODE, SECURITY_KEY],
},
ok111110: {
totp_enabled: true,
backup_enabled: true,
security_keys_enabled: true,
allowed_methods: [TOTP, BACKUP_CODE],
},
ok110111: {
totp_enabled: true,
backup_enabled: true,
security_keys_enabled: false,
allowed_methods: [TOTP, BACKUP_CODE, SECURITY_KEY],
},
ok100111: {
totp_enabled: true,
backup_enabled: false,
security_keys_enabled: false,
allowed_methods: [TOTP, BACKUP_CODE, SECURITY_KEY],
},
ok111010: {
totp_enabled: true,
backup_enabled: true,
security_keys_enabled: true,
allowed_methods: [BACKUP_CODE],
},
};
Object.keys(RESPONSES).forEach((k) => {
if (k.startsWith("ok")) {
const response = RESPONSES[k];
if (!response.description) {
response.description =
"This is an additional description that can be customized per action";
}
}
});
const WRONG_TOTP = "124323";
let callbackCount = 0;
acceptance("Second Factor Auth Page", function (needs) {
needs.user();
needs.pretender((server, { parsePostData, response }) => {
server.get("/session/2fa.json", (request) => {
const responseBody = { ...RESPONSES[request.queryParams.nonce] };
const status = responseBody.status || 200;
delete responseBody.status;
return response(status, responseBody);
});
server.post("/session/2fa", (request) => {
const params = parsePostData(request.requestBody);
if (params.second_factor_token === WRONG_TOTP) {
return response(401, {
error: "invalid token man",
ok: false,
});
} else {
return response({
ok: true,
callback_method: "PUT",
callback_path: "/callback-path",
redirect_url: "/",
});
}
});
server.put("/callback-path", () => {
callbackCount++;
return response(200, {
whatever: true,
});
});
});
needs.hooks.beforeEach(() => (callbackCount = 0));
test("when challenge data fails to load", async function (assert) {
await visit("/session/2fa?nonce=failed");
assert.equal(
query(".alert-error").textContent,
"could not find an active challenge in your session",
"load error message is shown"
);
});
test("default 2FA method", async function (assert) {
await visit("/session/2fa?nonce=ok111111");
assert.ok(
exists("#security-key-authenticate-button"),
"security key is the default method"
);
assert.ok(
!exists("form.totp-token"),
"totp is not shown by default when security key is allowed"
);
assert.ok(
!exists("form.backup-code-token"),
"backup code form is not shown by default when security key is allowed"
);
await visit("/");
await visit("/session/2fa?nonce=ok111110");
assert.ok(
!exists("#security-key-authenticate-button"),
"security key method is not shown when it's not allowed"
);
assert.ok(
exists("form.totp-token"),
"totp is the default method when security key is not allowed"
);
assert.ok(
!exists("form.backup-code-token"),
"backup code form is not shown by default when TOTP is allowed"
);
await visit("/");
await visit("/session/2fa?nonce=ok110111");
assert.ok(
!exists("#security-key-authenticate-button"),
"security key method is not shown when it's not enabled"
);
assert.ok(
exists("form.totp-token"),
"totp is the default method when security key is not enabled"
);
assert.ok(
!exists("form.backup-code-token"),
"backup code form is not shown by default when TOTP is enabled"
);
});
test("alternative 2FA methods", async function (assert) {
await visit("/session/2fa?nonce=ok111111");
assert.ok(
exists(".toggle-second-factor-method.totp"),
"TOTP is shown as an alternative method if it's enabled and allowed"
);
assert.ok(
exists(".toggle-second-factor-method.backup-code"),
"backup code is shown as an alternative method if it's enabled and allowed"
);
assert.ok(
!exists(".toggle-second-factor-method.security-key"),
"security key is not shown as an alternative method when it's selected"
);
await visit("/");
await visit("/session/2fa?nonce=ok100111");
assert.ok(
!exists(".toggle-second-factor-method"),
"no alternative methods are shown if only 1 method is enabled"
);
await visit("/");
await visit("/session/2fa?nonce=ok111010");
assert.ok(
!exists(".toggle-second-factor-method"),
"no alternative methods are shown if only 1 method is allowed"
);
});
test("switching 2FA methods", async function (assert) {
await visit("/session/2fa?nonce=ok111111");
assert.ok(
exists("#security-key-authenticate-button"),
"security key form is shown because it's the default"
);
assert.ok(
exists(".toggle-second-factor-method.totp"),
"TOTP is shown as an alternative method"
);
assert.ok(
exists(".toggle-second-factor-method.backup-code"),
"backup code is shown as an alternative method"
);
assert.ok(
!exists(".toggle-second-factor-method.security-key"),
"security key is not shown as an alternative method because it's selected"
);
await click(".toggle-second-factor-method.totp");
assert.ok(exists("form.totp-token"), "TOTP form is now shown");
assert.ok(
exists(".toggle-second-factor-method.security-key"),
"security key is now shown as alternative method"
);
assert.ok(
exists(".toggle-second-factor-method.backup-code"),
"backup code is still shown as an alternative method"
);
assert.ok(
!exists(".toggle-second-factor-method.totp"),
"TOTP is no longer shown as an alternative method"
);
await click(".toggle-second-factor-method.backup-code");
assert.ok(
exists("form.backup-code-token"),
"backup code form is now shown"
);
assert.ok(
exists(".toggle-second-factor-method.security-key"),
"security key is still shown as alternative method"
);
assert.ok(
exists(".toggle-second-factor-method.totp"),
"TOTP is now shown as an alternative method"
);
assert.ok(
!exists(".toggle-second-factor-method.backup-code"),
"backup code is no longer shown as an alternative method"
);
await click(".toggle-second-factor-method.security-key");
assert.ok(
exists("#security-key-authenticate-button"),
"security key form is back"
);
assert.ok(
!exists(".toggle-second-factor-method.security-key"),
"security key is no longer shown as alternative method"
);
assert.ok(
exists(".toggle-second-factor-method.totp"),
"TOTP is now shown as an alternative method"
);
assert.ok(
exists(".toggle-second-factor-method.backup-code"),
"backup code is now shown as an alternative method"
);
});
test("2FA action description", async function (assert) {
await visit("/session/2fa?nonce=ok111111");
assert.equal(
query(".action-description").textContent.trim(),
"This is an additional description that can be customized per action",
"action description is rendered on the page"
);
});
test("error when submitting 2FA form", async function (assert) {
await visit("/session/2fa?nonce=ok110111");
await fillIn("form.totp-token .second-factor-token-input", WRONG_TOTP);
await click('form.totp-token .btn-primary[type="submit"]');
assert.equal(
query(".alert-error").textContent.trim(),
"invalid token man",
"error message from the server is displayed"
);
});
test("successful 2FA form submit", async function (assert) {
await visit("/session/2fa?nonce=ok110111");
await fillIn("form.totp-token .second-factor-token-input", "323421");
await click('form.totp-token .btn-primary[type="submit"]');
assert.equal(
currentURL(),
"/",
"user has been redirected to the redirect_url"
);
assert.equal(callbackCount, 1, "callback request has been performed");
});
test("sidebar is disabled on 2FA route", async function (assert) {
this.siteSettings.navigation_menu = "sidebar";
await visit("/session/2fa?nonce=ok110111");
assert.notOk(exists(".sidebar-container"), "does not display the sidebar");
});
});