| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /* @vitest-environment node */
- import { describe, it, expect } from "vitest";
- import {
- MUST_CHANGE_PASSWORD_GATE_PARAM,
- MUST_CHANGE_PASSWORD_GATE_VALUE,
- isProfilePath,
- sanitizeMustChangePasswordNext,
- shouldRedirectToProfileForPasswordChange,
- buildMustChangePasswordRedirectUrl,
- parseMustChangePasswordGateParams,
- resolveMustChangePasswordResumePath,
- } from "./mustChangePasswordGate.js";
- describe("lib/frontend/auth/mustChangePasswordGate", () => {
- describe("isProfilePath", () => {
- it("returns true for /profile and profile subpaths", () => {
- expect(isProfilePath("/profile")).toBe(true);
- expect(isProfilePath("/profile/security")).toBe(true);
- });
- it("returns false for non-profile routes", () => {
- expect(isProfilePath("/")).toBe(false);
- expect(isProfilePath("/NL01")).toBe(false);
- expect(isProfilePath("/NL01/search")).toBe(false);
- });
- });
- describe("sanitizeMustChangePasswordNext", () => {
- it("accepts safe internal non-profile targets", () => {
- expect(sanitizeMustChangePasswordNext("/NL01")).toBe("/NL01");
- expect(sanitizeMustChangePasswordNext("/NL01/search?scope=all")).toBe(
- "/NL01/search?scope=all"
- );
- });
- it("rejects unsafe or profile targets", () => {
- expect(sanitizeMustChangePasswordNext("//evil.com")).toBe(null);
- expect(sanitizeMustChangePasswordNext("https://evil.com")).toBe(null);
- expect(sanitizeMustChangePasswordNext("/profile")).toBe(null);
- expect(sanitizeMustChangePasswordNext("/profile?x=1")).toBe(null);
- });
- });
- describe("shouldRedirectToProfileForPasswordChange", () => {
- it("forces redirect for non-profile routes while flag is true", () => {
- expect(
- shouldRedirectToProfileForPasswordChange({
- pathname: "/NL01",
- mustChangePassword: true,
- })
- ).toBe(true);
- });
- it("does not force redirect when already on profile or flag is false", () => {
- expect(
- shouldRedirectToProfileForPasswordChange({
- pathname: "/profile",
- mustChangePassword: true,
- })
- ).toBe(false);
- expect(
- shouldRedirectToProfileForPasswordChange({
- pathname: "/NL01",
- mustChangePassword: false,
- })
- ).toBe(false);
- });
- });
- describe("buildMustChangePasswordRedirectUrl", () => {
- it("builds profile URL with marker and safe next", () => {
- expect(buildMustChangePasswordRedirectUrl("/NL01/search")).toBe(
- "/profile?mustChangePasswordGate=1&next=%2FNL01%2Fsearch"
- );
- });
- it("always includes gate marker and drops invalid next", () => {
- expect(buildMustChangePasswordRedirectUrl("//evil.com")).toBe(
- `/profile?${MUST_CHANGE_PASSWORD_GATE_PARAM}=${MUST_CHANGE_PASSWORD_GATE_VALUE}`
- );
- });
- });
- describe("parseMustChangePasswordGateParams", () => {
- it("parses marker and next from URLSearchParams", () => {
- const sp = new URLSearchParams({
- mustChangePasswordGate: "1",
- next: "/NL01",
- });
- expect(parseMustChangePasswordGateParams(sp)).toEqual({
- isGateMarker: true,
- next: "/NL01",
- });
- });
- it("normalizes invalid input", () => {
- const sp = new URLSearchParams({
- mustChangePasswordGate: "yes",
- next: "/profile",
- });
- expect(parseMustChangePasswordGateParams(sp)).toEqual({
- isGateMarker: false,
- next: null,
- });
- });
- });
- describe("resolveMustChangePasswordResumePath", () => {
- it("returns next only when marker is set, route is profile, and flag is false", () => {
- const sp = new URLSearchParams({
- mustChangePasswordGate: "1",
- next: "/NL01/search",
- });
- expect(
- resolveMustChangePasswordResumePath({
- pathname: "/profile",
- searchParams: sp,
- mustChangePassword: false,
- })
- ).toBe("/NL01/search");
- });
- it("returns null when any resume condition is not satisfied", () => {
- const sp = new URLSearchParams({
- mustChangePasswordGate: "1",
- next: "/NL01/search",
- });
- expect(
- resolveMustChangePasswordResumePath({
- pathname: "/profile",
- searchParams: sp,
- mustChangePassword: true,
- })
- ).toBe(null);
- expect(
- resolveMustChangePasswordResumePath({
- pathname: "/NL01",
- searchParams: sp,
- mustChangePassword: false,
- })
- ).toBe(null);
- expect(
- resolveMustChangePasswordResumePath({
- pathname: "/profile",
- searchParams: new URLSearchParams({
- mustChangePasswordGate: "0",
- next: "/NL01/search",
- }),
- mustChangePassword: false,
- })
- ).toBe(null);
- });
- });
- });
|