diff --git a/README.md b/README.md index 5277715dd0..1a7ddd9c8c 100644 --- a/README.md +++ b/README.md @@ -851,6 +851,7 @@ isBoolean(value); | `@IsOctal()` | Checks if the string is a octal number. | | `@IsMACAddress(options?: IsMACAddressOptions)` | Checks if the string is a MAC Address. | | `@IsIP(version?: "4"\|"6")` | Checks if the string is an IP (version 4 or 6). | +| `@IsIPRange()` | Checks if the string is an IP CIDR range (version 4 only). | | `@IsPort()` | Check if the string is a valid port number. | | `@IsISBN(version?: "10"\|"13")` | Checks if the string is an ISBN (version 10 or 13). | | `@IsEAN()` | Checks if the string is an if the string is an EAN (European Article Number). | diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 41b843f4ae..35f906aad0 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -64,6 +64,7 @@ export * from './string/IsHexColor'; export * from './string/IsHexadecimal'; export * from './string/IsMacAddress'; export * from './string/IsIP'; +export * from './string/IsIPRange'; export * from './string/IsPort'; export * from './string/IsISBN'; export * from './string/IsISIN'; diff --git a/src/decorator/string/IsIPRange.ts b/src/decorator/string/IsIPRange.ts new file mode 100644 index 0000000000..1b658a0f34 --- /dev/null +++ b/src/decorator/string/IsIPRange.ts @@ -0,0 +1,36 @@ +import { ValidationOptions } from '../ValidationOptions'; +import { buildMessage, ValidateBy } from '../common/ValidateBy'; +import isIPRangeValidator from 'validator/lib/isIPRange'; + +export type IsIpRangeVersion = '4' | '6' | 4 | 6; + +export const IS_IP_RANGE = 'isIpRange'; + +/** + * Checks if the string is an IP CIDR range (version 4 only). + * If given value is not a string, then it returns false. + */ +export function isIPRange(value: unknown): boolean { + return typeof value === 'string' && isIPRangeValidator(value); +} + +/** + * Checks if the string is an IP CIDR range (version 4 only). + * If given value is not a string, then it returns false. + */ +export function IsIPRange(version?: IsIpRangeVersion, validationOptions?: ValidationOptions): PropertyDecorator { + return ValidateBy( + { + name: IS_IP_RANGE, + constraints: [version], + validator: { + validate: (value): boolean => isIPRange(value), + defaultMessage: buildMessage( + eachPrefix => eachPrefix + '$property must be an ip address range', + validationOptions + ), + }, + }, + validationOptions + ); +} diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 8e77b7fc79..d2b3f50687 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -29,6 +29,7 @@ import { IsHexColor, IsHexadecimal, IsIP, + IsIPRange, IsISBN, IsISO8601, IsIn, @@ -2726,6 +2727,38 @@ describe('IsIP', () => { }); }); +describe('IsIPRange', () => { + const validValues = ['127.0.0.1/255', '0.0.0.0/12', '255.255.255.1/255', '1.2.3.4/6']; + const invalidValues = [null, undefined, 'abc', '256.0.0.0', '0.0.0.256', '26.0.0.256', '26.0.0.256/abc']; + + class MyClass { + @IsIPRange() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(isIP(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(isIP(value)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'isIpRange'; + const message = 'someProperty must be an ip address range'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +}); + describe('IsISBN version 10', () => { const validValues = [ '3836221195',