diff --git a/library/.eslintrc.cjs b/library/.eslintrc.cjs index 8aa33a9db..0b59fdf21 100644 --- a/library/.eslintrc.cjs +++ b/library/.eslintrc.cjs @@ -4,15 +4,45 @@ module.exports = { extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', + 'plugin:regexp/recommended', + 'plugin:security/recommended', ], parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'import'], + plugins: ['@typescript-eslint', 'import', 'redos-detector'], rules: { + // Enable rules ----------------------------------------------------------- + + // Import + 'import/extensions': ['error', 'always'], // Require file extensions + + // Regexp + 'regexp/no-super-linear-move': 'error', // Prevent DoS regexps + 'regexp/no-control-character': 'error', // Avoid unneeded regexps characters + 'regexp/no-octal': 'error', // Avoid unneeded regexps characters + 'regexp/no-standalone-backslash': 'error', // Avoid unneeded regexps characters + 'regexp/prefer-escape-replacement-dollar-char': 'error', // Avoid unneeded regexps characters + 'regexp/prefer-quantifier': 'error', // Avoid unneeded regexps characters + 'regexp/hexadecimal-escape': ['error', 'always'], // Avoid unneeded regexps characters + 'regexp/sort-alternatives': 'error', // Avoid unneeded regexps characters + 'regexp/require-unicode-regexp': 'error', // /u flag is faster and enables regexp strict mode + 'regexp/prefer-regexp-exec': 'error', // Enforce that RegExp#exec is used instead of String#match if no global flag is provided, as exec is faster + + // Redos detector + 'redos-detector/no-unsafe-regex': ['error', { ignoreError: true }], // Prevent DoS regexps + + // Disable rules ---------------------------------------------------------- + + // Default + 'no-duplicate-imports': 'off', + + // TypeScript '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/consistent-type-imports': 'warn', '@typescript-eslint/no-non-null-assertion': 'off', - 'no-duplicate-imports': 'off', - 'import/extensions': ['error', 'always'], + + // Security + 'security/detect-object-injection': 'off', // Too many false positives + 'security/detect-unsafe-regex': 'off', // Too many false positives, see https://github.com/eslint-community/eslint-plugin-security/issues/28 - we use the redos-detector plugin instead }, }; diff --git a/library/CHANGELOG.md b/library/CHANGELOG.md index 94e22ef59..35394a599 100644 --- a/library/CHANGELOG.md +++ b/library/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to the library will be documented in this file. - Add `getRestAndDefaultArgs` utility function - Add new `rest` argument to `object` and `objectAsync` schema - Fix type check in `date` and `dateAsync` for invalid dates (pull request #214) +- Improve security of regular expressions (pull request #202) - Change `ObjectSchema` and `ObjectSchemaAsync` type - Change type check in `tuple` and `tupleAsync` to be less strict - Rename `ObjectShape` and `ObjectShapeAsync` types to `ObjectEntries` and `ObjectEntriesAsync` diff --git a/library/package.json b/library/package.json index 249e18f76..ba28b7be5 100644 --- a/library/package.json +++ b/library/package.json @@ -58,6 +58,9 @@ "@vitest/coverage-v8": "^0.33.0", "eslint": "^8.43.0", "eslint-plugin-import": "^2.28.1", + "eslint-plugin-redos-detector": "^2.1.1", + "eslint-plugin-regexp": "^1.15.0", + "eslint-plugin-security": "^1.7.1", "jsdom": "^22.1.0", "tsup": "^7.1.0", "typescript": "^5.1.3", diff --git a/library/src/schemas/special/special.test.ts b/library/src/schemas/special/special.test.ts index d9e85f41d..52dd32f41 100644 --- a/library/src/schemas/special/special.test.ts +++ b/library/src/schemas/special/special.test.ts @@ -5,7 +5,7 @@ import { special } from './special.ts'; type PixelString = `${number}px`; const isPixelString = (input: unknown) => - typeof input === 'string' && /^\d+px$/.test(input); + typeof input === 'string' && /^\d+px$/u.test(input); describe('special', () => { test('should pass only pixel strings', () => { diff --git a/library/src/schemas/special/specialAsync.test.ts b/library/src/schemas/special/specialAsync.test.ts index b1a8c71ae..99c1680f9 100644 --- a/library/src/schemas/special/specialAsync.test.ts +++ b/library/src/schemas/special/specialAsync.test.ts @@ -5,7 +5,7 @@ import { specialAsync } from './specialAsync.ts'; type PixelString = `${number}px`; const isPixelString = (input: unknown) => - typeof input === 'string' && /^\d+px$/.test(input); + typeof input === 'string' && /^\d+px$/u.test(input); describe('specialAsync', () => { test('should pass only pixel strings', async () => { diff --git a/library/src/utils/isLuhnAlgo/isLuhnAlgo.ts b/library/src/utils/isLuhnAlgo/isLuhnAlgo.ts index 95da980be..520a17abc 100644 --- a/library/src/utils/isLuhnAlgo/isLuhnAlgo.ts +++ b/library/src/utils/isLuhnAlgo/isLuhnAlgo.ts @@ -7,7 +7,7 @@ */ export function isLuhnAlgo(input: string) { // Remove any non-digit chars - const number = input.replace(/\D/g, ''); + const number = input.replace(/\D/gu, ''); // Create necessary variables let length = number.length; diff --git a/library/src/validations/cuid2/cuid2.ts b/library/src/validations/cuid2/cuid2.ts index 0e30229f0..e364fba5d 100644 --- a/library/src/validations/cuid2/cuid2.ts +++ b/library/src/validations/cuid2/cuid2.ts @@ -10,7 +10,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function cuid2(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^[a-z][a-z0-9]*$/.test(input) + !/^[a-z][\da-z]*$/u.test(input) ? getPipeIssues('cuid2', error || 'Invalid cuid2', input) : getOutput(input); } diff --git a/library/src/validations/email/email.ts b/library/src/validations/email/email.ts index 0a541ad22..f57ea8a30 100644 --- a/library/src/validations/email/email.ts +++ b/library/src/validations/email/email.ts @@ -2,7 +2,7 @@ import type { ErrorMessage, PipeResult } from '../../types.ts'; import { getOutput, getPipeIssues } from '../../utils/index.ts'; /** - * Creates a validation function that validates an email. + * Creates a validation function that validates a email. * * @param error The error message. * @@ -10,7 +10,9 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function email(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^[\w+-]+(?:\.[\w+-]+)*@[\da-z]+(?:[.-][\da-z]+)*\.[a-z]{2,}$/i.test(input) + !/^[\w+-]+(?:\.[\w+-]+)*@[\da-z]+(?:[.-][\da-z]+)*\.[a-z]{2,}$/iu.test( + input + ) ? getPipeIssues('email', error || 'Invalid email', input) : getOutput(input); } diff --git a/library/src/validations/emoji/emoji.ts b/library/src/validations/emoji/emoji.ts index 83ade0a6b..de8a8b120 100644 --- a/library/src/validations/emoji/emoji.ts +++ b/library/src/validations/emoji/emoji.ts @@ -10,7 +10,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function emoji(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u.test(input) + !/^[\p{Extended_Pictographic}\p{Emoji_Component}]+$/u.test(input) ? getPipeIssues('emoji', error || 'Invalid emoji', input) : getOutput(input); } diff --git a/library/src/validations/imei/imei.ts b/library/src/validations/imei/imei.ts index 47ea6718c..896beb67f 100644 --- a/library/src/validations/imei/imei.ts +++ b/library/src/validations/imei/imei.ts @@ -12,8 +12,7 @@ import { getOutput, getPipeIssues, isLuhnAlgo } from '../../utils/index.ts'; */ export function imei(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^\d{2}[ |/|-]?\d{6}[ |/|-]?\d{6}[ |/|-]?\d$/.test(input) || - !isLuhnAlgo(input) + !/^\d{2}(?:[ /|-]?\d{6}){2}[ /|-]?\d$/u.test(input) || !isLuhnAlgo(input) ? getPipeIssues('imei', error || 'Invalid IMEI', input) : getOutput(input); } diff --git a/library/src/validations/ip/ip.ts b/library/src/validations/ip/ip.ts index a72efd5c0..0297fb1e1 100644 --- a/library/src/validations/ip/ip.ts +++ b/library/src/validations/ip/ip.ts @@ -10,8 +10,9 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function ip(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/.test(input) && - !/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test( + // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive + !/^(?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)\.?\b){4}$/u.test(input) && + !/^(?:(?:[\da-f]{1,4}:){7}[\da-f]{1,4}|(?:[\da-f]{1,4}:){1,7}:|(?:[\da-f]{1,4}:){1,6}:[\da-f]{1,4}|(?:[\da-f]{1,4}:){1,5}(?::[\da-f]{1,4}){1,2}|(?:[\da-f]{1,4}:){1,4}(?::[\da-f]{1,4}){1,3}|(?:[\da-f]{1,4}:){1,3}(?::[\da-f]{1,4}){1,4}|(?:[\da-f]{1,4}:){1,2}(?::[\da-f]{1,4}){1,5}|[\da-f]{1,4}:(?::[\da-f]{1,4}){1,6}|:(?:(?::[\da-f]{1,4}){1,7}|:)|fe80:(?::[\da-f]{0,4}){0,4}%[\da-z]+|::(?:f{4}(?::0{1,4})?:)?(?:(?:25[0-5]|(?:2[0-4]|1?\d)?\d)\.){3}(?:25[0-5]|(?:2[0-4]|1?\d)?\d)|(?:[\da-f]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1?\d)?\d)\.){3}(?:25[0-5]|(?:2[0-4]|1?\d)?\d))$/iu.test( input ) ? getPipeIssues('ip', error || 'Invalid IP', input) diff --git a/library/src/validations/ipv4/ipv4.ts b/library/src/validations/ipv4/ipv4.ts index 4559c3178..4e0b46fbe 100644 --- a/library/src/validations/ipv4/ipv4.ts +++ b/library/src/validations/ipv4/ipv4.ts @@ -10,7 +10,8 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function ipv4(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/.test(input) + // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive + !/^(?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)\.?\b){4}$/u.test(input) ? getPipeIssues('ipv4', error || 'Invalid IP v4', input) : getOutput(input); } diff --git a/library/src/validations/ipv6/ipv6.ts b/library/src/validations/ipv6/ipv6.ts index 5f15e97e3..d8489d197 100644 --- a/library/src/validations/ipv6/ipv6.ts +++ b/library/src/validations/ipv6/ipv6.ts @@ -10,7 +10,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function ipv6(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test( + !/^(?:(?:[\da-f]{1,4}:){7}[\da-f]{1,4}|(?:[\da-f]{1,4}:){1,7}:|(?:[\da-f]{1,4}:){1,6}:[\da-f]{1,4}|(?:[\da-f]{1,4}:){1,5}(?::[\da-f]{1,4}){1,2}|(?:[\da-f]{1,4}:){1,4}(?::[\da-f]{1,4}){1,3}|(?:[\da-f]{1,4}:){1,3}(?::[\da-f]{1,4}){1,4}|(?:[\da-f]{1,4}:){1,2}(?::[\da-f]{1,4}){1,5}|[\da-f]{1,4}:(?::[\da-f]{1,4}){1,6}|:(?:(?::[\da-f]{1,4}){1,7}|:)|fe80:(?::[\da-f]{0,4}){0,4}%[\da-z]+|::(?:f{4}(?::0{1,4})?:)?(?:(?:25[0-5]|(?:2[0-4]|1?\d)?\d)\.){3}(?:25[0-5]|(?:2[0-4]|1?\d)?\d)|(?:[\da-f]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1?\d)?\d)\.){3}(?:25[0-5]|(?:2[0-4]|1?\d)?\d))$/iu.test( input ) ? getPipeIssues('ipv6', error || 'Invalid IP v6', input) diff --git a/library/src/validations/isoDate/isoDate.ts b/library/src/validations/isoDate/isoDate.ts index 83a37402d..9e3e918c0 100644 --- a/library/src/validations/isoDate/isoDate.ts +++ b/library/src/validations/isoDate/isoDate.ts @@ -2,7 +2,7 @@ import type { ErrorMessage, PipeResult } from '../../types.ts'; import { getOutput, getPipeIssues } from '../../utils/index.ts'; /** - * Creates a validation function that validates an date. + * Creates a validation function that validates a date. * * Format: yyyy-mm-dd * @@ -16,7 +16,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoDate(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^\d{4}-(0[1-9]|1[0-2])-([12]\d|0[1-9]|3[01])$/.test(input) + !/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])$/u.test(input) ? getPipeIssues('iso_date', error || 'Invalid date', input) : getOutput(input); } diff --git a/library/src/validations/isoDateTime/isoDateTime.ts b/library/src/validations/isoDateTime/isoDateTime.ts index 5fe6081be..4a856cb99 100644 --- a/library/src/validations/isoDateTime/isoDateTime.ts +++ b/library/src/validations/isoDateTime/isoDateTime.ts @@ -2,7 +2,7 @@ import type { ErrorMessage, PipeResult } from '../../types.ts'; import { getOutput, getPipeIssues } from '../../utils/index.ts'; /** - * Creates a validation function that validates an datetime. + * Creates a validation function that validates a datetime. * * Format: yyyy-mm-ddThh:mm * @@ -16,7 +16,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoDateTime(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^\d{4}-(0[1-9]|1[0-2])-([12]\d|0[1-9]|3[01])T(0[0-9]|1\d|2[0-3]):[0-5]\d$/.test( + !/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])T(?:0\d|1\d|2[0-3]):[0-5]\d$/u.test( input ) ? getPipeIssues('iso_date_time', error || 'Invalid datetime', input) diff --git a/library/src/validations/isoTime/isoTime.ts b/library/src/validations/isoTime/isoTime.ts index 68a0bc977..587179cb5 100644 --- a/library/src/validations/isoTime/isoTime.ts +++ b/library/src/validations/isoTime/isoTime.ts @@ -12,7 +12,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoTime(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^(0[0-9]|1\d|2[0-3]):[0-5]\d$/.test(input) + !/^(?:0\d|1\d|2[0-3]):[0-5]\d$/u.test(input) ? getPipeIssues('iso_time', error || 'Invalid time', input) : getOutput(input); } diff --git a/library/src/validations/isoTimeSecond/isoTimeSecond.ts b/library/src/validations/isoTimeSecond/isoTimeSecond.ts index b65f66a3e..06ae583a9 100644 --- a/library/src/validations/isoTimeSecond/isoTimeSecond.ts +++ b/library/src/validations/isoTimeSecond/isoTimeSecond.ts @@ -12,7 +12,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoTimeSecond(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^(0[0-9]|1\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(input) + !/^(?:0\d|1\d|2[0-3])(?::[0-5]\d){2}$/u.test(input) ? getPipeIssues('iso_time_second', error || 'Invalid time', input) : getOutput(input); } diff --git a/library/src/validations/isoTimestamp/isoTimestamp.ts b/library/src/validations/isoTimestamp/isoTimestamp.ts index 10773d75c..3233c2d96 100644 --- a/library/src/validations/isoTimestamp/isoTimestamp.ts +++ b/library/src/validations/isoTimestamp/isoTimestamp.ts @@ -16,7 +16,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoTimestamp(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^\d{4}-(0[1-9]|1[0-2])-([12]\d|0[1-9]|3[01])T(0[0-9]|1\d|2[0-3]):[0-5]\d:[0-5]\d\.\d{3}Z$/.test( + !/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])T(?:0\d|1\d|2[0-3])(?::[0-5]\d){2}\.\d{3}Z$/u.test( input ) ? getPipeIssues('iso_timestamp', error || 'Invalid timestamp', input) diff --git a/library/src/validations/isoWeek/isoWeek.ts b/library/src/validations/isoWeek/isoWeek.ts index 222096c57..bb2142e9e 100644 --- a/library/src/validations/isoWeek/isoWeek.ts +++ b/library/src/validations/isoWeek/isoWeek.ts @@ -16,7 +16,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function isoWeek(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^\d{4}-W(0[1-9]|[1-4]\d|5[0-3])$/.test(input) + !/^\d{4}-W(?:0[1-9]|[1-4]\d|5[0-3])$/u.test(input) ? getPipeIssues('iso_week', error || 'Invalid week', input) : getOutput(input); } diff --git a/library/src/validations/regex/regex.test.ts b/library/src/validations/regex/regex.test.ts index dc21d5eb1..5c40e9b76 100644 --- a/library/src/validations/regex/regex.test.ts +++ b/library/src/validations/regex/regex.test.ts @@ -3,7 +3,7 @@ import { regex } from './regex.ts'; describe('regex', () => { test('should pass only valid strings', () => { - const validate = regex(/^ID-\d{3}$/); + const validate = regex(/^ID-\d{3}$/u); expect(validate('ID-000').output).toBe('ID-000'); expect(validate('ID-123').output).toBe('ID-123'); expect(validate('123').issues).toBeTruthy(); @@ -13,7 +13,7 @@ describe('regex', () => { test('should return custom error message', () => { const error = 'Value does not match the regex!'; - const validate = regex(/^ID-\d{3}$/, error); + const validate = regex(/^ID-\d{3}$/u, error); expect(validate('test').issues?.[0].message).toBe(error); }); }); diff --git a/library/src/validations/ulid/ulid.ts b/library/src/validations/ulid/ulid.ts index 395470f20..c7ae0a009 100644 --- a/library/src/validations/ulid/ulid.ts +++ b/library/src/validations/ulid/ulid.ts @@ -10,7 +10,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function ulid(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^[0-9A-HJKMNPQ-TV-Z]{26}$/i.test(input) + !/^[\da-hjkmnp-tv-z]{26}$/iu.test(input) ? getPipeIssues('ulid', error || 'Invalid ULID', input) : getOutput(input); } diff --git a/library/src/validations/uuid/uuid.ts b/library/src/validations/uuid/uuid.ts index 9e683705c..575334802 100644 --- a/library/src/validations/uuid/uuid.ts +++ b/library/src/validations/uuid/uuid.ts @@ -10,9 +10,7 @@ import { getOutput, getPipeIssues } from '../../utils/index.ts'; */ export function uuid(error?: ErrorMessage) { return (input: TInput): PipeResult => - !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test( - input - ) + !/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/iu.test(input) ? getPipeIssues('uuid', error || 'Invalid UUID', input) : getOutput(input); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8779f069c..177abb943 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,15 @@ importers: eslint-plugin-import: specifier: ^2.28.1 version: 2.28.1(@typescript-eslint/parser@5.60.0)(eslint@8.43.0) + eslint-plugin-redos-detector: + specifier: ^2.1.1 + version: 2.1.1(eslint@8.43.0) + eslint-plugin-regexp: + specifier: ^1.15.0 + version: 1.15.0(eslint@8.43.0) + eslint-plugin-security: + specifier: ^1.7.1 + version: 1.7.1 jsdom: specifier: ^22.1.0 version: 22.1.0 @@ -523,7 +532,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 espree: 9.6.1 globals: 13.20.0 ignore: 5.2.4 @@ -639,7 +648,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2293,7 +2302,7 @@ packages: '@typescript-eslint/scope-manager': 5.60.0 '@typescript-eslint/type-utils': 5.60.0(eslint@8.43.0)(typescript@5.1.3) '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@5.1.3) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 eslint: 8.43.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 @@ -2348,7 +2357,7 @@ packages: '@typescript-eslint/scope-manager': 5.60.0 '@typescript-eslint/types': 5.60.0 '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.1.3) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 eslint: 8.43.0 typescript: 5.1.3 transitivePeerDependencies: @@ -2404,7 +2413,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.1.3) '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@5.1.3) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 eslint: 8.43.0 tsutils: 3.21.0(typescript@5.1.3) typescript: 5.1.3 @@ -2474,7 +2483,7 @@ packages: dependencies: '@typescript-eslint/types': 5.60.0 '@typescript-eslint/visitor-keys': 5.60.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 @@ -2707,6 +2716,15 @@ packages: hasBin: true dev: true + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /agent-base@6.0.2(supports-color@9.4.0): resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -3979,6 +3997,11 @@ packages: repeat-string: 1.6.1 dev: true + /comment-parser@1.4.0: + resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==} + engines: {node: '>= 12.0.0'} + dev: true + /common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} dev: true @@ -4274,6 +4297,18 @@ packages: ms: 2.1.3 dev: true + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + /debug@4.3.4(supports-color@9.4.0): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -5013,6 +5048,37 @@ packages: jsx-ast-utils: 3.3.4 dev: true + /eslint-plugin-redos-detector@2.1.1(eslint@8.43.0): + resolution: {integrity: sha512-YZRY2iHiFFHWwRdkb05HYmEmpRBjzWfmYS5Xj5+HV5B4RL/iP1cq+qcGhBQqDuWZvsc9+1KUnOI5LXO/dvFXeA==} + peerDependencies: + eslint: '>=6' + dependencies: + eslint: 8.43.0 + dev: true + + /eslint-plugin-regexp@1.15.0(eslint@8.43.0): + resolution: {integrity: sha512-YEtQPfdudafU7RBIFci81R/Q1yErm0mVh3BkGnXD2Dk8DLwTFdc2ITYH1wCnHKim2gnHfPFgrkh+b2ozyyU7ag==} + engines: {node: ^12 || >=14} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) + '@eslint-community/regexpp': 4.5.1 + comment-parser: 1.4.0 + eslint: 8.43.0 + grapheme-splitter: 1.0.4 + jsdoctypeparser: 9.0.0 + refa: 0.11.0 + regexp-ast-analysis: 0.6.0 + scslre: 0.2.0 + dev: true + + /eslint-plugin-security@1.7.1: + resolution: {integrity: sha512-sMStceig8AFglhhT2LqlU5r+/fn9OwsA72O5bBuQVTssPCdQAOQzL+oMn/ZcpeUY6KcNfLJArgcrsSULNjYYdQ==} + dependencies: + safe-regex: 2.1.1 + dev: true + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -5057,7 +5123,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.0 @@ -6551,8 +6617,8 @@ packages: engines: {node: '>= 6'} dependencies: '@tootallnate/once': 2.0.0 - agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.4(supports-color@9.4.0) + agent-base: 6.0.2 + debug: 4.3.4 transitivePeerDependencies: - supports-color dev: true @@ -6594,6 +6660,16 @@ packages: resolve-alpn: 1.2.1 dev: true + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /https-proxy-agent@5.0.1(supports-color@9.4.0): resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -7329,7 +7405,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 istanbul-lib-coverage: 3.2.0 source-map: 0.6.1 transitivePeerDependencies: @@ -7410,6 +7486,12 @@ packages: argparse: 2.0.1 dev: true + /jsdoctypeparser@9.0.0: + resolution: {integrity: sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==} + engines: {node: '>=10'} + hasBin: true + dev: true + /jsdom@22.1.0: resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} engines: {node: '>=16'} @@ -7427,7 +7509,7 @@ packages: form-data: 4.0.0 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1(supports-color@9.4.0) + https-proxy-agent: 5.0.1 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.7 parse5: 7.1.2 @@ -9827,6 +9909,22 @@ packages: postcss: 8.4.27 dev: true + /postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 2.3.1 + dev: true + /postcss-load-config@4.0.1(postcss@8.4.27): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} @@ -10345,6 +10443,13 @@ packages: engines: {node: '>= 12.13.0'} dev: true + /refa@0.11.0: + resolution: {integrity: sha512-486O8/pQXwj9jV0mVvUnTsxq0uknpBnNJ0eCUhkZqJRQ8KutrT1PhzmumdCeM1hSBF2eMlFPmwECRER4IbKXlQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dependencies: + '@eslint-community/regexpp': 4.5.1 + dev: true + /refractor@3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} dependencies: @@ -10361,6 +10466,14 @@ packages: safe-regex: 1.1.0 dev: true + /regexp-ast-analysis@0.6.0: + resolution: {integrity: sha512-OLxjyjPkVH+rQlBLb1I/P/VTmamSjGkvN5PTV5BXP432k3uVz727J7H29GA5IFiY0m7e1xBN7049Wn59FY3DEQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dependencies: + '@eslint-community/regexpp': 4.5.1 + refa: 0.11.0 + dev: true + /regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -10711,6 +10824,12 @@ packages: ret: 0.1.15 dev: true + /safe-regex@2.1.1: + resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} + dependencies: + regexp-tree: 0.1.27 + dev: true + /safe-stable-stringify@2.4.3: resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} engines: {node: '>=10'} @@ -10727,6 +10846,14 @@ packages: xmlchars: 2.2.0 dev: true + /scslre@0.2.0: + resolution: {integrity: sha512-4hc49fUMmX3jM0XdFUAPBrs1xwEcdHa0KyjEsjFs+Zfc66mpFpq5YmRgDtl+Ffo6AtJIilfei+yKw8fUn3N88w==} + dependencies: + '@eslint-community/regexpp': 4.5.1 + refa: 0.11.0 + regexp-ast-analysis: 0.6.0 + dev: true + /secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} dev: true @@ -11853,12 +11980,12 @@ packages: bundle-require: 4.0.1(esbuild@0.18.15) cac: 6.7.14 chokidar: 3.5.3 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 esbuild: 0.18.15 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.27) + postcss-load-config: 4.0.1 resolve-from: 5.0.0 rollup: 3.26.3 source-map: 0.8.0-beta.0 @@ -12430,7 +12557,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 mlly: 1.4.0 pathe: 1.1.1 picocolors: 1.0.0 @@ -12542,7 +12669,7 @@ packages: acorn-walk: 8.2.0 cac: 6.7.14 chai: 4.3.7 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4 jsdom: 22.1.0 local-pkg: 0.4.3 magic-string: 0.30.1