All files / src/authentication authPortalIntent.js

96.87% Statements 31/32
100% Branches 24/24
100% Functions 9/9
96.66% Lines 29/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75      5x 5x             16x 16x 5x   11x 3x   8x       6x 6x             15x 15x             13x 13x             8x     8x 8x 8x 8x       13x 4x   9x 4x   5x       18x 3x   15x 2x   13x    
import { normalizeAuth0RolesClaim, ROLES_CLAIM } from "@/authentication/auth0";
import { getStoredRole } from "@/authentication/session";
 
export const AUTH_PORTAL_INTENT_KEY = "erudition_auth_portal_intent";
export const AUTH_PORTAL_REJECTED_MSG_KEY = "erudition_auth_portal_rejected_msg";
 
/**
 * Only teacher and student routes set a strict portal intent before Auth0 login.
 * Other guards (e.g. graph editor with multiple roles) return null so login is not restricted.
 */
export function computeStrictPortalIntent(allowedRole) {
    const roles = (Array.isArray(allowedRole) ? allowedRole : [allowedRole]).map((r) => String(r).toLowerCase());
    if (roles.length === 1 && roles[0] === "teacher") {
        return "teacher";
    }
    if (roles.length === 1 && roles[0] === "student") {
        return "student";
    }
    return null;
}
 
export function setAuthPortalIntent(portal) {
    try {
        sessionStorage.setItem(AUTH_PORTAL_INTENT_KEY, portal);
    } catch {
        // ignore
    }
}
 
export function getAuthPortalIntent() {
    try {
        return sessionStorage.getItem(AUTH_PORTAL_INTENT_KEY);
    } catch {
        return null;
    }
}
 
export function clearAuthPortalIntent() {
    try {
        sessionStorage.removeItem(AUTH_PORTAL_INTENT_KEY);
    } catch {
        // ignore
    }
}
 
export function getRolesForPortalCheck(user, isAuthenticated) {
    const fromProfile = isAuthenticated && user ? normalizeAuth0RolesClaim(user[ROLES_CLAIM]) : [];
    // BFF (ADR-001 Phase 2): the token is no longer client-readable; use the
    // server-verified role cached at login / by the /auth/me probe.
    const storedRole = getStoredRole();
    const fromStored = storedRole ? [storedRole] : [];
    const merged = [...fromProfile, ...fromStored].map((r) => String(r).toLowerCase());
    return [...new Set(merged)];
}
 
export function rolesMatchStrictPortal(portal, normalizedRoles) {
    if (portal === "teacher") {
        return normalizedRoles.includes("teacher");
    }
    if (portal === "student") {
        return normalizedRoles.includes("student");
    }
    return true;
}
 
export function getPortalMismatchMessage(portal) {
    if (portal === "teacher") {
        return "This login is for teachers only. Students must sign in from the student portal.";
    }
    if (portal === "student") {
        return "This login is for students only. Teachers must sign in from the teacher portal.";
    }
    return "You do not have access to sign in from this portal.";
}