From 661a856bfced915a9eedd56956221ead5289e4f5 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 22 Sep 2023 15:07:23 +0200 Subject: [PATCH] [Cases] Validate length of text custom fields. (#167029) ## Summary This PR limits the length of the property value for `text` custom fields. --- .../cases/common/types/api/case/v1.test.ts | 39 +++++++++++++++++++ .../plugins/cases/common/types/api/case/v1.ts | 19 ++++++++- .../cases/common/types/domain/case/v1.ts | 4 +- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/cases/common/types/api/case/v1.test.ts b/x-pack/plugins/cases/common/types/api/case/v1.test.ts index 2ea4a8dfd0f26..cb2f864076092 100644 --- a/x-pack/plugins/cases/common/types/api/case/v1.test.ts +++ b/x-pack/plugins/cases/common/types/api/case/v1.test.ts @@ -17,6 +17,7 @@ import { MAX_TITLE_LENGTH, MAX_CATEGORY_LENGTH, MAX_CUSTOM_FIELDS_PER_CASE, + MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH, } from '../../../constants'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { AttachmentType } from '../../domain/attachment/v1'; @@ -300,6 +301,25 @@ describe('CasePostRequestRt', () => { expect(PathReporter.report(CasePostRequestRt.decode(rest))).toContain('No errors!'); }); + + it(`throws an error when a text customFields is longer than ${MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH}`, () => { + expect( + PathReporter.report( + CasePostRequestRt.decode({ + ...defaultRequest, + customFields: [ + { + key: 'first_custom_field_key', + type: 'text', + field: { value: ['#'.repeat(MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH + 1)] }, + }, + ], + }) + ) + ).toContain( + `The length of the value is too long. The maximum length is ${MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH}.` + ); + }); }); describe('CasesFindRequestRt', () => { @@ -680,6 +700,25 @@ describe('CasePatchRequestRt', () => { `The length of the field customFields is too long. Array must be of length <= ${MAX_CUSTOM_FIELDS_PER_CASE}.` ); }); + + it(`throws an error when a text customFields is longer than ${MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH}`, () => { + expect( + PathReporter.report( + CasePatchRequestRt.decode({ + ...defaultRequest, + customFields: [ + { + key: 'first_custom_field_key', + type: 'text', + field: { value: ['#'.repeat(MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH + 1)] }, + }, + ], + }) + ) + ).toContain( + `The length of the value is too long. The maximum length is ${MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH}.` + ); + }); }); describe('CasesPatchRequestRt', () => { diff --git a/x-pack/plugins/cases/common/types/api/case/v1.ts b/x-pack/plugins/cases/common/types/api/case/v1.ts index 69fcb7242ca6b..328aed95bfdbb 100644 --- a/x-pack/plugins/cases/common/types/api/case/v1.ts +++ b/x-pack/plugins/cases/common/types/api/case/v1.ts @@ -22,6 +22,7 @@ import { MAX_CATEGORY_FILTER_LENGTH, MAX_ASSIGNEES_PER_CASE, MAX_CUSTOM_FIELDS_PER_CASE, + MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH, } from '../../../constants'; import { limitedStringSchema, @@ -29,19 +30,35 @@ import { NonEmptyString, paginationSchema, } from '../../../schema'; +import { CustomFieldTextTypeRt } from '../../domain'; import { CaseRt, CaseSettingsRt, CaseSeverityRt, CasesRt, CaseStatusRt, + CustomFieldToggle, + customFieldValue, RelatedCaseRt, - CustomFieldRt, } from '../../domain/case/v1'; import { CaseConnectorRt } from '../../domain/connector/v1'; import { CaseUserProfileRt, UserRt } from '../../domain/user/v1'; import { CasesStatusResponseRt } from '../stats/v1'; +const CustomFieldText = rt.strict({ + key: rt.string, + type: CustomFieldTextTypeRt, + field: customFieldValue( + limitedStringSchema({ + fieldName: 'value', + min: 0, + max: MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH, + }) + ), +}); + +const CustomFieldRt = rt.union([CustomFieldText, CustomFieldToggle]); + const CustomFieldsRt = limitedArraySchema({ codec: CustomFieldRt, fieldName: 'customFields', diff --git a/x-pack/plugins/cases/common/types/domain/case/v1.ts b/x-pack/plugins/cases/common/types/domain/case/v1.ts index 73f13c2af3ecd..fa2b7aeb2abbf 100644 --- a/x-pack/plugins/cases/common/types/domain/case/v1.ts +++ b/x-pack/plugins/cases/common/types/domain/case/v1.ts @@ -52,7 +52,7 @@ export const CaseSettingsRt = rt.strict({ syncAlerts: rt.boolean, }); -const customFieldValue = (codec: C) => +export const customFieldValue = (codec: C) => rt.strict({ value: rt.union([rt.array(codec), rt.null]) }); const CustomFieldText = rt.strict({ @@ -61,7 +61,7 @@ const CustomFieldText = rt.strict({ field: customFieldValue(rt.string), }); -const CustomFieldToggle = rt.strict({ +export const CustomFieldToggle = rt.strict({ key: rt.string, type: CustomFieldToggleTypeRt, field: customFieldValue(rt.boolean),