diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aeaed4b16..c1d5ed241 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: jobs: build: - uses: powsybl/github-ci/.github/workflows/build-frontend-lib-generic.yml@0f2f06b6f3a89497d4b7e1abe0c74503f3df9fda + uses: powsybl/github-ci/.github/workflows/build-frontend-lib-generic.yml@852670523f7fb3699d16efcbdd6d7500d5730b2f with: eventType: commons_ui_updated licensercPath: .github/config/.licenserc.yaml diff --git a/src/components/flatParameters/FlatParameters.tsx b/src/components/flatParameters/FlatParameters.tsx index a8e5284f0..682ba3f54 100644 --- a/src/components/flatParameters/FlatParameters.tsx +++ b/src/components/flatParameters/FlatParameters.tsx @@ -45,7 +45,44 @@ const styles = { }, }; -const FloatRE = /^-?\d*[.,]?\d*([eE]-?\d*)?$/; +const isFloatNumberPrefix = (val: string) => { + // no possessive qualifier in javascripts native regexp, + // replace /^-?\d*[.,]?\d*([eE]-?\d*)?$/ with code not + // vulnerable to catastrophic backtracking (ON^2) + // TODO find a better way for this code + let idx = 0; + if (idx < val.length && val.charAt(idx) === '-') { + idx += 1; + } + while (idx < val.length && val.charCodeAt(idx) >= 48 && val.charCodeAt(idx) <= 57) { + // [0-9] + idx += 1; + } + if (idx === val.length) { + return true; + } + if (val.charAt(idx) === '.' || val.charAt(idx) === ',') { + idx += 1; + while (idx < val.length && val.charCodeAt(idx) >= 48 && val.charCodeAt(idx) <= 57) { + // [0-9] + idx += 1; + } + } + if (idx === val.length) { + return true; + } + if (val.charAt(idx) === 'e' || val.charAt(idx) === 'E') { + idx += 1; + if (idx < val.length && val.charAt(idx) === '-') { + idx += 1; + } + while (idx < val.length && val.charCodeAt(idx) >= 48 && val.charCodeAt(idx) <= 57) { + // [0-9] + idx += 1; + } + } + return idx === val.length; +}; const IntegerRE = /^-?\d*$/; const ListRE = /^\[(.*)]$/; const sepRE = /[, ]/; @@ -279,7 +316,7 @@ export function FlatParameters({ onFocus={() => onUncommitted(param, true)} onBlur={() => onUncommitted(param, false)} onChange={(e) => { - const m = FloatRE.exec(e.target.value); + const m = isFloatNumberPrefix(e.target.value); if (m) { onFieldChange(outputTransformFloatString(e.target.value), param); } diff --git a/src/components/inputs/reactHookForm/numbers/utils.ts b/src/components/inputs/reactHookForm/numbers/utils.ts index 153b8d029..0fa9f15e5 100644 --- a/src/components/inputs/reactHookForm/numbers/utils.ts +++ b/src/components/inputs/reactHookForm/numbers/utils.ts @@ -8,6 +8,29 @@ export const isIntegerNumber = (val: string) => { return /^-?[0-9]*$/.test(val); }; +// checks if it is a prefix export const isFloatNumber = (val: string) => { - return /^-?[0-9]*[.,]?[0-9]*$/.test(val); + // no possessive qualifier in javascripts native regexp, + // replace /^-?[0-9]*[.,]?[0-9]*$/ with code not + // vulnerable to catastrophic backtracking (ON^2) + // TODO find a better way for this code + let idx = 0; + if (idx < val.length && val.charAt(idx) === '-') { + idx += 1; + } + while (idx < val.length && val.charCodeAt(idx) >= 48 && val.charCodeAt(idx) <= 57) { + // [0-9] + idx += 1; + } + if (idx === val.length) { + return true; + } + if (val.charAt(idx) === '.' || val.charAt(idx) === ',') { + idx += 1; + while (idx < val.length && val.charCodeAt(idx) >= 48 && val.charCodeAt(idx) <= 57) { + // [0-9] + idx += 1; + } + } + return idx === val.length; };