From 2e5c10443062ff6c2446b269fb243525840a5acb Mon Sep 17 00:00:00 2001 From: Jacobo Dominguez Date: Wed, 18 Feb 2026 15:38:09 -0600 Subject: [PATCH] fix: handling malformed library ids as not found errors (#66) --- .../ErrorPage/index.test.tsx | 21 ++++++++++++++----- .../libraries-manager/ErrorPage/index.tsx | 9 ++++++-- src/constants.ts | 5 ++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/authz-module/libraries-manager/ErrorPage/index.test.tsx b/src/authz-module/libraries-manager/ErrorPage/index.test.tsx index 3c08a3d..06ac6db 100644 --- a/src/authz-module/libraries-manager/ErrorPage/index.test.tsx +++ b/src/authz-module/libraries-manager/ErrorPage/index.test.tsx @@ -11,7 +11,7 @@ const ThrowError = ({ error }: { error:Error }) => { describe('LibrariesErrorFallback', () => { it('renders Access Denied for 401', () => { - const error = { name: '', message: 'NO_ACCESS', customAtributtes: { httpErrorStatus: 401 } }; + const error = { name: '', message: 'NO_ACCESS', customAttributes: { httpErrorStatus: 401 } }; renderWrapper( @@ -21,8 +21,19 @@ describe('LibrariesErrorFallback', () => { expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument(); }); + it('renders Not Found for 400 error', () => { + const error = { name: '', message: 'Axios Error (Response): 400', customAttributes: { httpErrorStatus: 400 } }; + renderWrapper( + + + , + ); + expect(screen.getByText(/Page Not Found/i)).toBeInTheDocument(); + expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument(); + }); + it('renders Not Found for 404', () => { - const error = { name: '', message: 'NOT_FOUND', customAtributtes: { httpErrorStatus: 404 } }; + const error = { name: '', message: 'NOT_FOUND', customAttributes: { httpErrorStatus: 404 } }; renderWrapper( @@ -33,7 +44,7 @@ describe('LibrariesErrorFallback', () => { }); it('renders Server Error for 500 and shows reload', async () => { - const error = { name: '', message: 'SERVER_ERROR', customAtributtes: { httpErrorStatus: 500 } }; + const error = { name: '', message: 'SERVER_ERROR', customAttributes: { httpErrorStatus: 500 } }; renderWrapper( @@ -45,7 +56,7 @@ describe('LibrariesErrorFallback', () => { }); it('renders generic error for other error error', () => { - const error = { name: '', message: 'SOMETHING_ELSE', customAtributtes: { httpErrorStatus: 418 } }; + const error = { name: '', message: 'SOMETHING_ELSE', customAttributes: { httpErrorStatus: 418 } }; renderWrapper( @@ -59,7 +70,7 @@ describe('LibrariesErrorFallback', () => { // Simulate error with a refetch function const refetch = jest.fn(); const error = { - name: '', message: 'SERVER_ERROR', customAtributtes: { httpErrorStatus: 500 }, refetch, + name: '', message: 'SERVER_ERROR', customAttributes: { httpErrorStatus: 500 }, refetch, }; renderWrapper( diff --git a/src/authz-module/libraries-manager/ErrorPage/index.tsx b/src/authz-module/libraries-manager/ErrorPage/index.tsx index 65d3f15..e93a7d7 100644 --- a/src/authz-module/libraries-manager/ErrorPage/index.tsx +++ b/src/authz-module/libraries-manager/ErrorPage/index.tsx @@ -5,7 +5,9 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { Button, Container, Hyperlink, Row, } from '@openedx/paragon'; -import { CustomErrors, ERROR_STATUS } from '@src/constants'; +import { + CustomErrors, ERROR_STATUS, STATUS_400, STATUS_404, +} from '@src/constants'; import messages from './messages'; @@ -18,11 +20,14 @@ const getErrorConfig = ({ errorMessage, errorStatus }) => { showBackButton: true, }); } + // 400 errors are handled as 404 Not Found to avoid exposing potential sensitive information + // about the existence of resources and handling malformed library ids in the URL if (errorMessage === CustomErrors.NOT_FOUND || ERROR_STATUS.NOT_FOUND.includes(errorStatus)) { + const statusCode = errorStatus === STATUS_400 ? STATUS_404 : errorStatus; return ({ title: messages['error.page.title.notFound'], description: messages['error.page.message.notFound'], - statusCode: errorStatus || ERROR_STATUS.NOT_FOUND[0], + statusCode: statusCode || STATUS_404, showBackButton: true, }); } diff --git a/src/constants.ts b/src/constants.ts index 9a3fed4..fc01102 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -10,8 +10,11 @@ type ErrorStatusCode = { [key in CustomErrors]: number[]; }; +export const STATUS_400 = 400; +export const STATUS_404 = 404; + export const ERROR_STATUS: ErrorStatusCode = { [CustomErrors.NO_ACCESS]: [403, 401], - [CustomErrors.NOT_FOUND]: [404], + [CustomErrors.NOT_FOUND]: [400, 404], [CustomErrors.SERVER_ERROR]: [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511], };