From d0b2fd077a52014c1a86dac9f435838f828af948 Mon Sep 17 00:00:00 2001 From: Robert Bond Date: Thu, 14 May 2026 08:55:49 +0000 Subject: [PATCH] Merged PR 2315: Auth stabilistatiion and hardening Related work items: #23020 --- .../representation/utils/buildRepsArrRules.js | 12 +- components/header.js | 12 +- components/myportal.js | 12 +- components/myportal/servicebanner.js | 16 +- components/timeout/index.js | 19 +- context/auth-session-reliability.md | 34 ++++ context/current-platform-state.md | 38 ++++ context/performance-and-stability-baseline.md | 29 +++ context/phase1-stabilisation-plan.md | 62 ++++++ lib/auth/sessionClient.js | 47 +++++ lib/forms/readFormXml.js | 10 + lib/myportal/loadMyPortalAppealPage.js | 96 ++++++++-- lib/newappeal/fileListHelpers.js | 2 +- lib/newappeal/loadNewAppealPage.js | 97 +++++++++- lib/representation/pageLoaders.js | 166 +++++++++++----- pages/api/auth/[...nextauth].js | 128 +++++++------ .../endpoint/getadvancedsearchpaged_api.js | 4 +- pages/api/endpoint/getdnscoords_api.js | 2 +- pages/api/file/generatepdf.js | 5 +- pages/auth/error.js | 12 +- pages/case/[ticketnumber].js | 4 +- pages/case/id/[incident].js | 6 +- pages/contactus.js | 12 +- pages/dns/[developmentName].js | 4 +- pages/furtherdetails.js | 12 +- pages/myportal/addresssearchresults.js | 14 +- pages/myportal/advancedsearchresults.js | 106 +++++++++-- pages/myportal/case/[ticketnumber].js | 177 +++++++----------- pages/myportal/case/id/[incident].js | 4 +- pages/myportal/contactus.js | 12 +- pages/myportal/dns/[developmentName].js | 4 +- pages/myportal/dnsapplications.js | 18 +- pages/myportal/index.js | 55 +++++- pages/myportal/searchresults.js | 14 +- pages/unsubscribe/[watchlistid].js | 5 +- tests/phase22/index.test.cjs | 8 + tests/phase22/myportal-loader-guards.test.cjs | 122 ++++++++++++ .../phase22/newappeal-loader-guards.test.cjs | 122 ++++++++++++ ...presentation-build-reps-arr-rules.test.cjs | 108 ++++++----- .../representation-loader-guards.test.cjs | 136 ++++++++++++++ .../phase22/session-client-behaviour.test.cjs | 134 +++++++++++++ 41 files changed, 1462 insertions(+), 418 deletions(-) create mode 100644 context/auth-session-reliability.md create mode 100644 context/current-platform-state.md create mode 100644 context/performance-and-stability-baseline.md create mode 100644 context/phase1-stabilisation-plan.md create mode 100644 lib/auth/sessionClient.js create mode 100644 tests/phase22/myportal-loader-guards.test.cjs create mode 100644 tests/phase22/newappeal-loader-guards.test.cjs create mode 100644 tests/phase22/representation-loader-guards.test.cjs create mode 100644 tests/phase22/session-client-behaviour.test.cjs diff --git a/components/case/representation/utils/buildRepsArrRules.js b/components/case/representation/utils/buildRepsArrRules.js index b9439c8f..c917cabc 100644 --- a/components/case/representation/utils/buildRepsArrRules.js +++ b/components/case/representation/utils/buildRepsArrRules.js @@ -169,20 +169,28 @@ export const addStatements = (options, ctx) => { }; export const addFinalComments = (options, ctx) => { - const canSubmitFinalComments = + const canSubmitFinalCommentsDefault = ctx.isSelectedAppellant || ctx.isSelectedAgent || ctx.isSelectedInterestedParty || ctx.isLPA; + const canSubmitFinalComments = ctx.isDNS + ? ctx.isLPA + : canSubmitFinalCommentsDefault; + const isSpecialistNonHearing = ctx.specialistProcess !== SPECIALIST_PROCESS.HEARING; + const finalCommentsWindowStart = ctx.isDNS + ? ctx.startDate + : ctx.statementDueDate; + const canAdd = canSubmitFinalComments && isWithinWindow( ctx.now, - ctx.statementDueDate, + finalCommentsWindowStart, ctx.finalCommentsDueDate ) && (ctx.appealType !== APPEAL_TYPES.HOUSEHOLDER || isSpecialistNonHearing); diff --git a/components/header.js b/components/header.js index 090dacd9..2e6568ca 100644 --- a/components/header.js +++ b/components/header.js @@ -7,7 +7,7 @@ import { connect } from "react-redux"; import Banner from "../components/banner"; import { setLogout } from "../store/accountDetails/action"; -import { signOut } from "next-auth/react"; +import { performPortalSignOut } from "../lib/auth/sessionClient"; const Header = (props) => { let { t, lang } = useTranslation(); @@ -84,15 +84,7 @@ const Header = (props) => { } const handleLogout = () => { - console.info("////////////\n" + "logout" + "\n////////////"); - (window.localStorage.clear(), - destroyCookie(null, "next-auth.csrf-token", { path: "/" }), - destroyCookie(null, "next-auth.callback-url", { path: "/" }), - destroyCookie(null, "pedw_locale", { path: "/" }), - destroyCookie(null, "pinsUser", { path: "/" }), - signOut({ - callbackUrl: locale == "cy" ? "/cy/allgofnodi" : "/logout" - })); + performPortalSignOut(locale); }; //const switchLocale = locale === "en" ? "cy" : "en"; diff --git a/components/myportal.js b/components/myportal.js index 4597b5a8..6b31f3e5 100644 --- a/components/myportal.js +++ b/components/myportal.js @@ -2,7 +2,6 @@ import { signOut } from "next-auth/react"; import useTranslation from "next-translate/useTranslation"; import Link from "next/link"; import { useRouter } from "next/router"; -import { destroyCookie } from "nookies"; import TimeOut from "../components/timeout"; import AwaitingSubmissionFromBlob from "./myportal/awaitingsubmissionfromblob"; @@ -17,6 +16,7 @@ import MySubmittedReps from "./myportal/mysubmittedrepresentations"; import ServiceBanner from "./myportal/servicebanner"; import { JSONPath as jsonpath } from "jsonpath-plus"; import transLookup from "../data/lookuptranslations.json"; +import { performPortalSignOut } from "../lib/auth/sessionClient"; const MyPortal = (props) => { const { showFileUpload, showLoginCheck, docsOffline } = props; @@ -26,15 +26,7 @@ const MyPortal = (props) => { const { locale } = router; const handleLogout = () => { - console.info("////////////\n" + "logout" + "\n////////////"); - (window.localStorage.clear(), - destroyCookie(null, "next-auth.csrf-token", { path: "/" }), - destroyCookie(null, "next-auth.callback-url", { path: "/" }), - destroyCookie(null, "pedw_locale", { path: "/" }), - destroyCookie(null, "pinsUser", { path: "/" }), - signOut({ - callbackUrl: locale == "cy" ? "/cy/allgofnodi" : "/logout" - })); + performPortalSignOut({ locale, signOutFn: signOut }); }; const isLPA = diff --git a/components/myportal/servicebanner.js b/components/myportal/servicebanner.js index 6f6768e1..d69a1dcb 100644 --- a/components/myportal/servicebanner.js +++ b/components/myportal/servicebanner.js @@ -1,8 +1,7 @@ import useTranslation from "next-translate/useTranslation"; import router from "next/router"; import Link from "next/link"; -import { destroyCookie } from "nookies"; -import { signOut } from "next-auth/react"; +import { performPortalSignOut } from "../../lib/auth/sessionClient"; const ServiceBanner = (props) => { props = props.props; @@ -19,23 +18,14 @@ const ServiceBanner = (props) => { }; const handleLogout = (locale) => { - console.info("////////////\n" + "logout" + "\n////////////"); - window.localStorage.clear(), - destroyCookie(null, "next-auth.csrf-token"), - { path: "/" }, - destroyCookie(null, "next-auth.callback-url", { path: "/" }), - destroyCookie(null, "pedw_locale", { path: "/" }), - destroyCookie(null, "pinsUser", { path: "/" }), - signOut({ - callbackUrl: locale == "cy" ? "/cy/allgofnodi" : "/logout", - }); + performPortalSignOut(locale); }; const portalLogoLink = [ "/myportal/[appealtypes]", "/newappeal", "/newappeal/[appealtypes]", - "/myportal/representation", + "/myportal/representation" ]; return (
diff --git a/components/timeout/index.js b/components/timeout/index.js index 76f56ab3..ae6c993f 100644 --- a/components/timeout/index.js +++ b/components/timeout/index.js @@ -1,10 +1,9 @@ -import { signOut } from "next-auth/react"; import useTranslation from "next-translate/useTranslation"; import { useRouter } from "next/router"; -import { destroyCookie } from "nookies"; import { useState, useEffect } from "react"; import { useIdleTimer } from "react-idle-timer"; import TimeoutModal from "./timeoutmodal"; +import { performPortalSignOut } from "../../lib/auth/sessionClient"; const TimeOut = (props) => { let { t } = useTranslation(); @@ -20,15 +19,7 @@ const TimeOut = (props) => { const onIdle = () => { setState("Idle"); - console.info("////////////\n" + "logout" + "\n////////////"); - window.localStorage.clear(), - destroyCookie(null, "next-auth.csrf-token", { path: "/" }), - destroyCookie(null, "next-auth.callback-url", { path: "/" }), - destroyCookie(null, "pedw_locale", { path: "/" }), - destroyCookie(null, "pinsUser", { path: "/" }), - signOut({ - callbackUrl: locale == "cy" ? "/cy/allgofnodi" : "/logout", - }); + performPortalSignOut(locale); setOpen(false); }; @@ -48,7 +39,7 @@ const TimeOut = (props) => { onPrompt, timeout, promptBeforeIdle, - throttle: 500, + throttle: 500 }); useEffect(() => { @@ -89,14 +80,14 @@ const TimeOut = (props) => {

{t("common:login-modal-message", { - remaining: remaining, + remaining: remaining })}