fix(auth): preserve MFA continuation through field hydration
This commit is contained in:
1 parent
24f15e8b78
commit
a077515336
5 files changed
+79
-3
No files matched your search
@@ -0,0 +1,53 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { Window } from "happy-dom";
|
||||
|
||||
test("MFA uses the nested Select and restores continuation after hydration without reviving expired challenges", async () => {
|
||||
const window = new Window({ url: "https://sso.example.test/mfa" });
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
"wrnexus.auth.mfa",
|
||||
JSON.stringify({
|
||||
mfaToken: "synthetic-test-challenge",
|
||||
requires: { mfa: ["totp"] },
|
||||
}),
|
||||
);
|
||||
window.document.body.innerHTML = `<section data-auth-mfa-challenge data-mfa-initial-method="totp">
|
||||
<form data-auth-mfa-form>
|
||||
<input type="hidden" name="mfaToken">
|
||||
<input type="hidden" name="challengeId">
|
||||
<div data-auth-mfa-method><select name="method"><option value="totp">Authenticator app</option><option value="email-otp">Email</option></select></div>
|
||||
<input name="code"><p data-auth-mfa-status></p><button type="submit">Verify</button>
|
||||
</form><a data-auth-mfa-restart hidden href="/login">Back to sign in</a>
|
||||
</section>`;
|
||||
window.eval(readFileSync(new URL("../assets/client/auth.js", import.meta.url), "utf8"));
|
||||
(window as any).WRNexusAuth.mount(window.document);
|
||||
const form = window.document.querySelector("form")!;
|
||||
const token = form.querySelector<HTMLInputElement>('[name="mfaToken"]')!;
|
||||
expect(token.value).toBe("synthetic-test-challenge");
|
||||
expect(form.querySelector<HTMLOptionElement>('option[value="email-otp"]')!.disabled).toBe(true);
|
||||
token.value = ""; // Hydration reapplies the component's initial empty prop.
|
||||
form.dispatchEvent(new window.Event("submit", { bubbles: true, cancelable: true }));
|
||||
expect(token.value).toBe("synthetic-test-challenge");
|
||||
form.dispatchEvent(
|
||||
new window.CustomEvent("wrn:error", { bubbles: true, detail: { code: "mfa-invalid" } }),
|
||||
);
|
||||
expect(token.value).toBe("synthetic-test-challenge");
|
||||
form.dispatchEvent(
|
||||
new window.CustomEvent("wrn:error", {
|
||||
bubbles: true,
|
||||
detail: { code: "mfa-transaction-expired" },
|
||||
}),
|
||||
);
|
||||
expect(window.sessionStorage.getItem("wrnexus.auth.mfa")).toBeNull();
|
||||
expect(window.document.querySelector<HTMLElement>("[data-auth-mfa-restart]")!.hidden).toBe(
|
||||
false,
|
||||
);
|
||||
const retry = new window.Event("submit", { bubbles: true, cancelable: true });
|
||||
form.dispatchEvent(retry);
|
||||
expect(retry.defaultPrevented).toBe(true);
|
||||
expect(token.value).toBe("");
|
||||
} finally {
|
||||
await window.happyDOM.close();
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user