From 9b0cb9adc87b3058d6b4989b7647848867d055fd Mon Sep 17 00:00:00 2001 From: robbond Date: Thu, 5 Nov 2026 16:37:10 +0000 Subject: [PATCH] fix(security): retire legacy direct CRM case creation endpoint --- actions/services/caseDirectService.js | 29 ---- actions/services/caseService.js | 2 - components/newappeal/createCase.js | 7 - pages/api/endpoint/createcase_api.js | 150 ------------------ pages/api/endpoint/createcrmtask_api.js | 43 ----- .../endpoint-handler-contract.test.cjs | 78 +-------- 6 files changed, 6 insertions(+), 303 deletions(-) delete mode 100644 pages/api/endpoint/createcase_api.js diff --git a/actions/services/caseDirectService.js b/actions/services/caseDirectService.js index 04c4649d..253c3c23 100644 --- a/actions/services/caseDirectService.js +++ b/actions/services/caseDirectService.js @@ -76,35 +76,6 @@ export const getAppealID = ( }); }; -export const createNewCase = ( - appealTypeId, - lpaID, - contactid, - createBody, - containerName -) => { - appealTypeId = parseInt(appealTypeId); - - var data = createBody; - - var queryUrl = buildFileQuery("/api/endpoint/createcase_api", { - appealTypeId, - lpaID, - contactid, - containername: containerName - }); - - var config = { - method: "post", - url: withBaseUrl(BASE_URL, queryUrl), - data: data - }; - - return requestJson(config).catch((error) => { - consoleLogger(error); - }); -}; - export const createNewCaseBlob = ( appealTypeId, lpaID, diff --git a/actions/services/caseService.js b/actions/services/caseService.js index 063cc5bb..5148ff92 100644 --- a/actions/services/caseService.js +++ b/actions/services/caseService.js @@ -4,7 +4,6 @@ import { getSIPSEvents, getSIPSMedia, getAppealID, - createNewCase, createNewCaseBlob, updateCase, updateCaseBlob, @@ -26,7 +25,6 @@ export { getSIPSEvents, getSIPSMedia, getAppealID, - createNewCase, createNewCaseBlob, updateCase, updateCaseBlob, diff --git a/components/newappeal/createCase.js b/components/newappeal/createCase.js index c7e60792..46bbd0e7 100644 --- a/components/newappeal/createCase.js +++ b/components/newappeal/createCase.js @@ -393,13 +393,6 @@ let CreateCase = (props) => { delete values.confirmHASCAS; - // createNewCase( - // appTypeCollection.appealTypeID, - // values.lpaTypes, - // props.loggedInUser, - // values, - // props.containerID - // ) const selectedLpaName = props.LPAData.LPAData.value.filter((obj) => { return obj.accountid === values.lpaTypes; })[0].name; diff --git a/pages/api/endpoint/createcase_api.js b/pages/api/endpoint/createcase_api.js deleted file mode 100644 index 469b9e3c..00000000 --- a/pages/api/endpoint/createcase_api.js +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @swagger - * /api/endpoint/createcase_api: - * post: - * tags: [Case] - * description: Create case - * summary: Phase 2 - * parameters: - * - name: body - * in: requestbody - * required: true - * example: {} - * schema: - * type: object - * - name: contactid - * in: query - * required: true - * example: pinswg_planningappeals78s - * schema: - * type: string - * - name: appealTypeId - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * - name: containername - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * - name: lpaID - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * responses: - * 200: - * description: Success - */ - -import axios from "axios"; -import { consoleLogger } from "../../../actions/core/logger"; -import { getToken } from "../../../actions/core/token"; -import { getCaseBlob } from "../../../actions/azurestorage"; -import { hashAPIPath } from "../../../actions/core/hash"; -import { respondError, respondSuccess } from "../middleware/apiResponse"; - -const WEBAPI_URL = - process.env.RELAY_ROOT || - "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; - -export default async function ApiProxy(req, res) { - const createCaseBody = req.body; - const contactid = req.query.contactid; - const appealTypeId = req.query.appealTypeId; - const containerName = req.query.containername; - const lpaID = req.query.lpaID; - const queryUrl = "incidents"; - - if (!createCaseBody || typeof createCaseBody !== "object") { - return respondError(res, { - status: 400, - code: "CASE_PAYLOAD_REQUIRED", - message: "Case payload is required" - }); - } - if (typeof contactid !== "string" || contactid.trim().length === 0) { - return respondError(res, { - status: 400, - code: "CONTACT_ID_REQUIRED", - message: "contactid is required" - }); - } - if (typeof appealTypeId !== "string" || appealTypeId.trim().length === 0) { - return respondError(res, { - status: 400, - code: "APPEAL_TYPE_ID_REQUIRED", - message: "appealTypeId is required" - }); - } - if ( - typeof containerName !== "string" || - containerName.trim().length === 0 - ) { - return respondError(res, { - status: 400, - code: "CONTAINER_NAME_REQUIRED", - message: "containername is required" - }); - } - if (typeof lpaID !== "string" || lpaID.trim().length === 0) { - return respondError(res, { - status: 400, - code: "LPA_ID_REQUIRED", - message: "lpaID is required" - }); - } - - try { - const token = await getToken(); - - const data = { - "title": "insertion test case", - "caseorigincode": 3, - "servicestage": 1, - "customerid_contact@odata.bind": "/contacts(" + contactid + ")", - "pinswg_appealcasetype": appealTypeId, - "pinswg_AssociatedLPA@odata.bind": "/accounts(" + lpaID + ")" - }; - const newData = Object.assign(data, createCaseBody); - - delete newData.lpaTypes; - delete newData.appealTypes; - - console.log("/////Create Case:\n", newData, "\n//////////////"); - - const config = { - method: "post", - url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - headers: { - "OData-MaxVersion": "4.0", - "OData-Version": "4.0", - "Accept": "application/json", - "Prefer": 'odata.include-annotations="*",return=representation', - "Authorization": "Bearer " + token.access_token, - "Content-Type": "application/json" - }, - data: JSON.stringify(newData) - }; - - const { data: responseData } = await axios(config); - await getCaseBlob( - containerName, - responseData.ticketnumber, - createCaseBody - ); - - return respondSuccess(res, responseData); - } catch (error) { - consoleLogger(error); - return respondError(res, { - status: 400, - code: "CASE_CREATE_FAILED", - message: "Failed to create case" - }); - } -} diff --git a/pages/api/endpoint/createcrmtask_api.js b/pages/api/endpoint/createcrmtask_api.js index af2f66b1..964a3247 100644 --- a/pages/api/endpoint/createcrmtask_api.js +++ b/pages/api/endpoint/createcrmtask_api.js @@ -1,46 +1,3 @@ -/** - * @swagger - * /api/endpoint/createcase_api: - * post: - * tags: [Case] - * description: Create case - * summary: Phase 2 - * parameters: - * - name: body - * in: requestbody - * required: true - * example: {} - * schema: - * type: object - * - name: contactid - * in: query - * required: true - * example: pinswg_planningappeals78s - * schema: - * type: string - * - name: appealTypeId - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * - name: containername - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * - name: lpaID - * in: query - * required: true - * example: pinswg_planningappeals78id - * schema: - * type: string - * responses: - * 200: - * description: Success - */ - import axios from "axios"; import { isNonEmptyString, sanitizeString } from "../../../actions/core/guards"; import { consoleLogger } from "../../../actions/core/logger"; diff --git a/tests/phase21/endpoint-handler-contract.test.cjs b/tests/phase21/endpoint-handler-contract.test.cjs index 77eed608..ccdd8dd0 100644 --- a/tests/phase21/endpoint-handler-contract.test.cjs +++ b/tests/phase21/endpoint-handler-contract.test.cjs @@ -4624,76 +4624,6 @@ test("getappealpdfdocuments catch path returns APPEAL_PDF_DOCUMENTS_FETCH_FAILED ); }); -test("createcase returns CASE_PAYLOAD_REQUIRED when body missing", async () => { - const mod = loadModule("pages/api/endpoint/createcase_api.js", { - respondError: respondErrorMock, - respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), - getCaseBlob: async () => {}, - hashAPIPath: () => "&hash=expected", - axios: async () => ({ data: { ticketnumber: "CAS-1" } }), - consoleLogger: () => {} - }); - - const req = { query: {}, body: undefined }; - const res = createRes(); - await mod.default(req, res); - - assert.strictEqual(res.state.statusCode, 400); - assert.strictEqual(res.state.jsonBody.error.code, "CASE_PAYLOAD_REQUIRED"); -}); - -test("createcase returns CONTACT_ID_REQUIRED when contactid missing", async () => { - const mod = loadModule("pages/api/endpoint/createcase_api.js", { - respondError: respondErrorMock, - respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), - getCaseBlob: async () => {}, - hashAPIPath: () => "&hash=expected", - axios: async () => ({ data: { ticketnumber: "CAS-1" } }), - consoleLogger: () => {} - }); - - const req = { - query: { appealTypeId: "a1", containername: "c1", lpaID: "l1" }, - body: { title: "x" } - }; - const res = createRes(); - await mod.default(req, res); - - assert.strictEqual(res.state.statusCode, 400); - assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED"); -}); - -test("createcase catch path returns CASE_CREATE_FAILED", async () => { - const mod = loadModule("pages/api/endpoint/createcase_api.js", { - respondError: respondErrorMock, - respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), - getCaseBlob: async () => {}, - hashAPIPath: () => "&hash=expected", - axios: async () => { - throw new Error("create failed"); - }, - consoleLogger: () => {} - }); - - const req = { - query: { - contactid: "c1", - appealTypeId: "a1", - containername: "container", - lpaID: "l1" - }, - body: { title: "x" } - }; - const res = createRes(); - await mod.default(req, res); - - assert.strictEqual(res.state.statusCode, 400); - assert.strictEqual(res.state.jsonBody.error.code, "CASE_CREATE_FAILED"); -}); - test("updatecase returns CASE_UPDATE_PAYLOAD_REQUIRED when body missing", async () => { const mod = loadModule("pages/api/endpoint/updatecase_api.js", { respondError: respondErrorMock, @@ -4836,7 +4766,8 @@ test("gethash returns UNAUTHENTICATED when session missing", async () => { respondError: respondErrorMock, respondSuccess: respondSuccessMock, hashAPIPath: () => "&hash=expected", - getSession: async () => null, + getServerSession: async () => null, + authOptions: () => ({}), nextConnect: () => { const handler = { registeredGet: null }; handler.get = (cb) => { @@ -4860,7 +4791,10 @@ test("gethash returns INVALID_HASH_PATH when path is invalid", async () => { respondError: respondErrorMock, respondSuccess: respondSuccessMock, hashAPIPath: () => "&hash=expected", - getSession: async () => ({ user: { email: "user@test.local" } }), + getServerSession: async () => ({ + user: { email: "user@test.local" } + }), + authOptions: () => ({}), nextConnect: () => { const handler = { registeredGet: null }; handler.get = (cb) => {