AmountInput's currency rule has an unescaped . in its regex, so it accepts any character where the decimal separator should be:
// components/AmountInput.vue
isCurrency: (v: string) => {
const amount = v.trim()
return /^[0-9]+(.[0-9]{1,2})?$/.test(amount) || 'Please enter valid amount'
}
. outside a character class matches anything, so (.[0-9]{1,2})? reads as "any character followed by one or two digits" rather than "a decimal point followed by one or two digits".
What gets through
The component applies four rules together — isRequired, isNumber, isCurrency, positive — and these pass all four:
| input |
verdict |
10.50 |
accepted (intended) |
10x50 |
accepted |
10,50 |
accepted |
10 5 |
accepted |
abc |
rejected |
0.00 |
rejected (not positive) |
The other three rules do not catch it either: parseInt('10x50') is 10, so isNumber passes, and parseFloat('10x50') is 10, so positive passes.
Fix
Escaping the dot is enough — with \. all three rows above are rejected and 10.50 still passes:
return /^[0-9]+(\.[0-9]{1,2})?$/.test(amount) || 'Please enter valid amount'
Two related spots, if you want them in the same pass
helpers/validation.ts has the same permissiveness from a different cause:
isNumber is !isNaN(parseInt(v)), and parseInt stops at the first non-numeric character, so 12abc, 100 USD and 0x10 are all "valid numbers".
validDecimal destructures v.split('.') and only looks at the second element, so 1.23.45 and 1.23.99.77 pass. It also rejects 10.5, which may be deliberate given the "Decimal must be two digits" message.
Those two are used together on the amount field in pages/debug/paymentIntents/create.vue, where 12abc currently satisfies both.
I kept this to a report rather than a PR since the fix is one character and you may want to settle the helpers/validation.ts behaviour at the same time. Happy to send a PR for whichever shape you prefer, with tests — jest.config.js is configured but the repo has no test files yet, so I would be adding the first ones.
Verified against master at fd2ca1f by running the rule functions directly.
AmountInput's currency rule has an unescaped.in its regex, so it accepts any character where the decimal separator should be:.outside a character class matches anything, so(.[0-9]{1,2})?reads as "any character followed by one or two digits" rather than "a decimal point followed by one or two digits".What gets through
The component applies four rules together —
isRequired,isNumber,isCurrency,positive— and these pass all four:10.5010x5010,5010 5abc0.00The other three rules do not catch it either:
parseInt('10x50')is10, soisNumberpasses, andparseFloat('10x50')is10, sopositivepasses.Fix
Escaping the dot is enough — with
\.all three rows above are rejected and10.50still passes:Two related spots, if you want them in the same pass
helpers/validation.tshas the same permissiveness from a different cause:isNumberis!isNaN(parseInt(v)), andparseIntstops at the first non-numeric character, so12abc,100 USDand0x10are all "valid numbers".validDecimaldestructuresv.split('.')and only looks at the second element, so1.23.45and1.23.99.77pass. It also rejects10.5, which may be deliberate given the "Decimal must be two digits" message.Those two are used together on the amount field in
pages/debug/paymentIntents/create.vue, where12abccurrently satisfies both.I kept this to a report rather than a PR since the fix is one character and you may want to settle the
helpers/validation.tsbehaviour at the same time. Happy to send a PR for whichever shape you prefer, with tests —jest.config.jsis configured but the repo has no test files yet, so I would be adding the first ones.Verified against
masteratfd2ca1fby running the rule functions directly.