Skip to content

Commit

Permalink
MGMT-14703: Improving yaml validations and limit size to 2 Mb (#2197)
Browse files Browse the repository at this point in the history
* Improving yaml validations and limit size to 2 Mb

* In UI put a message to limit to 1Mb

* Delete the close button from Alerts

* Add delay when typing custom manifests

* Improving file validation

* Adjusting functions to validate size

* Solving format problems

* Last changes in code

* Change setTimeout method

* Using debounce

* Adding debounde time like a constant

* Revert changes in CodeField

* Improving code to validate yaml fields

* Adjusting changes in code

* Change validation message

---------

Co-authored-by: Jonathan Kilzi <jkilzi@redhat.com>
  • Loading branch information
ammont82 and jkilzi authored Jul 3, 2023
1 parent f75b960 commit db96ba5
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 54 deletions.
1 change: 1 addition & 0 deletions apps/assisted-ui/deploy/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ location /api {
proxy_send_timeout 120;
proxy_read_timeout 120;
send_timeout 120;
client_max_body_size 2M;
}

location / {
Expand Down
1 change: 1 addition & 0 deletions apps/assisted-ui/deploy/nginx_ssl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ events {
}

http {
client_max_body_size 2M;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
Expand Down
2 changes: 2 additions & 0 deletions libs/ui-lib/lib/common/configurations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const MAX_FILE_SIZE_BYTES = 1024 ** 2;
export const MAX_FILE_SIZE_OFFSET_FACTOR = 2;
1 change: 1 addition & 0 deletions libs/ui-lib/lib/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './configurations.ts';
import './styles.css';
import './utils';

Expand Down
21 changes: 17 additions & 4 deletions libs/ui-lib/lib/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import isString from 'lodash-es/isString.js';
import { load } from 'js-yaml';
import { MAX_FILE_SIZE_BYTES, MAX_FILE_SIZE_OFFSET_FACTOR } from './configurations';
import { fileSize } from './components/hosts/utils';

export const FILENAME_REGEX = /^[^\/]*\.(yaml|yml|json)$/;
export const FILE_TYPE_MESSAGE = 'Unsupported file type. Please provide a valid YAML file.';
export const INCORRECT_TYPE_FILE_MESSAGE =
'File type is not supported. File type must be yaml, yml or json.';

export const getErrorMessage = (error: unknown): string => {
if (error instanceof Error) {
Expand Down Expand Up @@ -40,11 +47,17 @@ export const isStringValidJSON = (input: string): boolean => {
}
};

export const validateFileSize = (value: string, fileSize: number): boolean => {
export const validateFileSize = (value: string): boolean => {
const contentFile = new Blob([value], { type: 'text/plain;charset=utf-8' });
return contentFile.size <= fileSize;
return contentFile.size <= MAX_FILE_SIZE_BYTES * MAX_FILE_SIZE_OFFSET_FACTOR;
};

export const getMaxFileSizeMessage = (fileSize: number): string => {
return `File size is too big. Upload a new ${fileSize / 1000} kB or less.`;
export const getMaxFileSizeMessage = `File size is too big. The file size must be less than ${fileSize(
MAX_FILE_SIZE_BYTES,
0,
'si',
)}.`;

export const validateFileName = (fileName: string) => {
return new RegExp(FILENAME_REGEX).test(fileName || '');
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { UniqueStringArrayExtractor } from '../../staticIp/commonValidationSchem
import { CustomManifestValues, ManifestFormData } from '../data/dataTypes';
import {
getMaxFileSizeMessage,
isStringValidYAML,
isStringValidJSON,
validateFileSize,
validateFileName,
validateFileType,
INCORRECT_TYPE_FILE_MESSAGE,
} from '../../../../../common/utils';

const MAX_FILE_SIZE = 100000; //100 kb
const FILENAME_REGEX = /^[^/]*\.(yaml|yml|json)$/;
const INCORRECT_FILENAME = 'Must have a yaml, yml or json extension and can not contain /.';
const INCORRECT_TYPE_FILE = 'File type is not supported. File type must be yaml, yml or json.';

const UNIQUE_FOLDER_FILENAME =
'Ensure unique file names within each folder to avoid conflicts and errors.';

Expand Down Expand Up @@ -42,34 +40,22 @@ export const getUniqueValidationSchema = <FormValues,>(
const getAllManifests: UniqueStringArrayExtractor<ManifestFormData> = (values: ManifestFormData) =>
values.manifests.map((manifest) => `${manifest.folder}_${manifest.filename}`);

export const getFormViewManifestsValidationSchema = Yup.lazy<ManifestFormData>(() =>
Yup.object<ManifestFormData>().shape({
manifests: Yup.array<CustomManifestValues>().of(
Yup.object().shape({
folder: Yup.mixed().required('Required').concat(getUniqueValidationSchema(getAllManifests)),
filename: Yup.string()
.required('Required')
.min(1, 'Number of characters must be 1-255')
.max(255, 'Number of characters must be 1-255')
.test('not-correct-filename', INCORRECT_FILENAME, (value: string) => {
return validateFileName(value);
})
.concat(getUniqueValidationSchema(getAllManifests)),
manifestYaml: Yup.string()
.required('Required')
.test('not-big-file', getMaxFileSizeMessage(MAX_FILE_SIZE), (value: string) =>
validateFileSize(value, MAX_FILE_SIZE),
)
.test('not-valid-file', INCORRECT_TYPE_FILE, validateFileType),
}),
),
}),
);

const validateFileName = (fileName: string) => {
return new RegExp(FILENAME_REGEX).test((fileName || '').toString());
};

const validateFileType = (value: string) => {
return isStringValidYAML(value) || isStringValidJSON(value);
};
export const getFormViewManifestsValidationSchema = Yup.object<ManifestFormData>().shape({
manifests: Yup.array<CustomManifestValues>().of(
Yup.object().shape({
folder: Yup.mixed().required('Required').concat(getUniqueValidationSchema(getAllManifests)),
filename: Yup.string()
.required('Required')
.min(1, 'Number of characters must be 1-255')
.max(255, 'Number of characters must be 1-255')
.test('not-correct-filename', INCORRECT_FILENAME, (value: string) => {
return validateFileName(value);
})
.concat(getUniqueValidationSchema(getAllManifests)),
manifestYaml: Yup.string()
.required('Required')
.test('not-big-file', getMaxFileSizeMessage, validateFileSize)
.test('not-valid-file', INCORRECT_TYPE_FILE_MESSAGE, validateFileType),
}),
),
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export type CustomManifestsFormProps = {
showEmptyValues: boolean;
getInitialValues(customManifests: ListManifestsExtended): ManifestFormData;
getEmptyValues(): ManifestFormData;
validationSchema: Yup.Schema<ManifestFormData>;
validationSchema: Yup.ObjectSchema<{
manifests: object[];
}>;
cluster: Cluster;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,18 @@ import {
UniqueStringArrayExtractor,
} from '../../commonValidationSchemas';
import {
INCORRECT_TYPE_FILE_MESSAGE,
getMaxFileSizeMessage,
isStringValidJSON,
isStringValidYAML,
validateFileSize,
validateFileType,
} from '../../../../../../common/utils';

const MAX_FILE_SIZE = 100000; //100 kb
const requiredMsg = 'A value is required';
const FILE_TYPE_MESSAGE = 'Unsupported file type. Please provide a valid YAML file.';

const networkYamlValidationSchema = Yup.string()
.required(requiredMsg)
.test(
'file-type-yaml',
FILE_TYPE_MESSAGE,
(value: string) => isStringValidYAML(value) && !isStringValidJSON(value),
)
.test('file-size-limit', getMaxFileSizeMessage(MAX_FILE_SIZE), (value: string) =>
validateFileSize(value, MAX_FILE_SIZE),
);
.test('file-size-limit', getMaxFileSizeMessage, validateFileSize)
.test('file-type-yaml', INCORRECT_TYPE_FILE_MESSAGE, validateFileType);

const getAllMacAddresses: UniqueStringArrayExtractor<YamlViewValues> = (
values: YamlViewValues,
Expand Down

0 comments on commit db96ba5

Please sign in to comment.