fix: handling malformed library ids as not found errors (#66)
This commit is contained in:
@@ -11,7 +11,7 @@ const ThrowError = ({ error }: { error:Error }) => {
|
|||||||
|
|
||||||
describe('LibrariesErrorFallback', () => {
|
describe('LibrariesErrorFallback', () => {
|
||||||
it('renders Access Denied for 401', () => {
|
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(
|
renderWrapper(
|
||||||
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
||||||
<ThrowError error={error} />
|
<ThrowError error={error} />
|
||||||
@@ -21,8 +21,19 @@ describe('LibrariesErrorFallback', () => {
|
|||||||
expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument();
|
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(
|
||||||
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
||||||
|
<ThrowError error={error} />
|
||||||
|
</ErrorBoundary>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText(/Page Not Found/i)).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders Not Found for 404', () => {
|
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(
|
renderWrapper(
|
||||||
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
||||||
<ThrowError error={error} />
|
<ThrowError error={error} />
|
||||||
@@ -33,7 +44,7 @@ describe('LibrariesErrorFallback', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders Server Error for 500 and shows reload', async () => {
|
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(
|
renderWrapper(
|
||||||
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
||||||
<ThrowError error={error} />
|
<ThrowError error={error} />
|
||||||
@@ -45,7 +56,7 @@ describe('LibrariesErrorFallback', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders generic error for other error error', () => {
|
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(
|
renderWrapper(
|
||||||
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
|
||||||
<ThrowError error={error} />
|
<ThrowError error={error} />
|
||||||
@@ -59,7 +70,7 @@ describe('LibrariesErrorFallback', () => {
|
|||||||
// Simulate error with a refetch function
|
// Simulate error with a refetch function
|
||||||
const refetch = jest.fn();
|
const refetch = jest.fn();
|
||||||
const error = {
|
const error = {
|
||||||
name: '', message: 'SERVER_ERROR', customAtributtes: { httpErrorStatus: 500 }, refetch,
|
name: '', message: 'SERVER_ERROR', customAttributes: { httpErrorStatus: 500 }, refetch,
|
||||||
};
|
};
|
||||||
renderWrapper(
|
renderWrapper(
|
||||||
<ErrorBoundary FallbackComponent={LibrariesErrorFallback} onReset={refetch}>
|
<ErrorBoundary FallbackComponent={LibrariesErrorFallback} onReset={refetch}>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import { useIntl } from '@edx/frontend-platform/i18n';
|
|||||||
import {
|
import {
|
||||||
Button, Container, Hyperlink, Row,
|
Button, Container, Hyperlink, Row,
|
||||||
} from '@openedx/paragon';
|
} 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';
|
import messages from './messages';
|
||||||
|
|
||||||
@@ -18,11 +20,14 @@ const getErrorConfig = ({ errorMessage, errorStatus }) => {
|
|||||||
showBackButton: true,
|
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)) {
|
if (errorMessage === CustomErrors.NOT_FOUND || ERROR_STATUS.NOT_FOUND.includes(errorStatus)) {
|
||||||
|
const statusCode = errorStatus === STATUS_400 ? STATUS_404 : errorStatus;
|
||||||
return ({
|
return ({
|
||||||
title: messages['error.page.title.notFound'],
|
title: messages['error.page.title.notFound'],
|
||||||
description: messages['error.page.message.notFound'],
|
description: messages['error.page.message.notFound'],
|
||||||
statusCode: errorStatus || ERROR_STATUS.NOT_FOUND[0],
|
statusCode: statusCode || STATUS_404,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ type ErrorStatusCode = {
|
|||||||
[key in CustomErrors]: number[];
|
[key in CustomErrors]: number[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const STATUS_400 = 400;
|
||||||
|
export const STATUS_404 = 404;
|
||||||
|
|
||||||
export const ERROR_STATUS: ErrorStatusCode = {
|
export const ERROR_STATUS: ErrorStatusCode = {
|
||||||
[CustomErrors.NO_ACCESS]: [403, 401],
|
[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],
|
[CustomErrors.SERVER_ERROR]: [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user