Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stricter byte size validation #193529

Merged
merged 1 commit into from
Sep 20, 2024
Merged
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
29 changes: 29 additions & 0 deletions packages/kbn-config-schema/src/byte_size_value/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,40 @@ describe('parsing units', () => {
expect(ByteSizeValue.parse('1Mb').getValueInBytes()).toBe(1024 * 1024);
});

test('parses the max safe integer', () => {
expect(ByteSizeValue.parse('9007199254740991').getValueInBytes()).toBe(9007199254740991);
expect(ByteSizeValue.parse('9007199254740991b').getValueInBytes()).toBe(9007199254740991);
});

test('throws an error when unsupported unit specified', () => {
expect(() => ByteSizeValue.parse('1tb')).toThrowErrorMatchingInlineSnapshot(
`"Failed to parse value as byte value. Value must be either number of bytes, or follow the format <count>[b|kb|mb|gb] (e.g., '1024kb', '200mb', '1gb'), where the number is a safe positive integer."`
);
});

test('throws an error when unsafe integer', () => {
expect(() => ByteSizeValue.parse('9007199254740992')).toThrowErrorMatchingInlineSnapshot(
`"Value in bytes is expected to be a safe positive integer."`
);
});

test('throws an error on unusually long input', () => {
expect(() => ByteSizeValue.parse('19007199254740991kb')).toThrowErrorMatchingInlineSnapshot(
`"Value in bytes is expected to be a safe positive integer."`
);
});

test('throws when string does not start with a digit', () => {
expect(() => ByteSizeValue.parse(' 1kb')).toThrowErrorMatchingInlineSnapshot(
`"Failed to parse value as byte value. Value must be either number of bytes, or follow the format <count>[b|kb|mb|gb] (e.g., '1024kb', '200mb', '1gb'), where the number is a safe positive integer."`
);
});

test('throws when string does not end with a digit or unit', () => {
expect(() => ByteSizeValue.parse('1kb ')).toThrowErrorMatchingInlineSnapshot(
`"Failed to parse value as byte value. Value must be either number of bytes, or follow the format <count>[b|kb|mb|gb] (e.g., '1024kb', '200mb', '1gb'), where the number is a safe positive integer."`
);
});
});

describe('#constructor', () => {
Expand Down
6 changes: 5 additions & 1 deletion packages/kbn-config-schema/src/byte_size_value/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ function renderUnit(value: number, unit: string) {

export class ByteSizeValue {
public static parse(text: string): ByteSizeValue {
const match = /([1-9][0-9]*)(b|kb|mb|gb)/i.exec(text);
if (text.length > 18) {
// Exit early on large input where <count> uses more than 16 digits and is therefore larger than Number.MAX_SAFE_INTEGER
throw new Error('Value in bytes is expected to be a safe positive integer.');
}
const match = /(^[1-9]\d*)(b|kb|mb|gb)$/i.exec(text);
if (!match) {
const number = Number(text);
if (typeof number !== 'number' || isNaN(number)) {
Expand Down