Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/validation": Changed
---

Delivery Logs - additional validation in Endpoint URL and Custom Header Name fields ([#13392](https://github.com/linode/manager/pull/13392))
31 changes: 25 additions & 6 deletions packages/validation/src/delivery.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,31 @@ const clientCertificateDetailsSchema = object({
},
);

const forbiddenCustomHeaderNames = [
'content-type',
'encoding',
'authorization',
'host',
'akamai',
];

const customHeaderSchema = object({
name: string()
.max(maxLength, maxLengthMessage)
.required('Custom Header Name is required.'),
.required('Custom Header Name is required.')
.test(
'forbidden-custom-header-name',
'This header name is not allowed.',
(value) =>
!forbiddenCustomHeaderNames.includes(value.trim().toLowerCase()),
),
value: string()
.max(maxLength, maxLengthMessage)
.required('Custom Header Value is required'),
.required('Custom Header Value is required.'),
});

const urlRgx = /^(https?:\/\/)?(www\.)?[a-zA-Z0-9-]+(\.[a-zA-Z]+)+(\/\S*)?$/;

const customHTTPSDetailsSchema = object({
authentication: authenticationSchema.required(),
client_certificate_details: clientCertificateDetailsSchema.optional(),
Expand All @@ -143,7 +159,10 @@ const customHTTPSDetailsSchema = object({
data_compression: string().oneOf(['gzip', 'None']).required(),
endpoint_url: string()
.max(maxLength, maxLengthMessage)
.required('Endpoint URL is required.'),
.required('Endpoint URL is required.')
.test('is-valid-url', 'Endpoint URL must be a valid URL.', (value) =>
urlRgx.test(value),
),
});

const hostRgx =
Expand Down Expand Up @@ -298,7 +317,7 @@ const detailsShouldNotExistOrBeNull = (schema: MixedSchema) =>

const streamSchemaBase = object({
label: string()
.min(3, 'Stream name must have at least 3 characters')
.min(3, 'Stream name must have at least 3 characters.')
.max(maxLength, maxLengthMessage)
.required('Stream name is required.'),
status: mixed<'active' | 'inactive' | 'provisioning'>().oneOf([
Expand Down Expand Up @@ -338,7 +357,7 @@ export const updateStreamSchema = streamSchemaBase
return detailsShouldNotExistOrBeNull(mixed());
}),
})
.noUnknown('Object contains unknown fields');
.noUnknown('Object contains unknown fields.');

export const streamAndDestinationFormSchema = object({
stream: streamSchemaBase.shape({
Expand All @@ -349,7 +368,7 @@ export const streamAndDestinationFormSchema = object({
otherwise: (schema) =>
schema
.nullable()
.equals([null], 'Details must be null for audit_logs type'),
.equals([null], 'Details must be null for audit_logs type.'),
}) as Schema<InferType<typeof streamDetailsSchema> | null>,
}),
destination: destinationFormSchema.defined().when('stream.destinations', {
Expand Down