From 1e0da2ee3929bdd0ef2036076cd750af8df679ed Mon Sep 17 00:00:00 2001 From: 0xYYBB | ZYY | Bobo <128128010+the-dev-z@users.noreply.github.com> Date: Wed, 12 Nov 2025 09:52:14 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20fix=20two-stage=20private=20key=20i?= =?UTF-8?q?nput=20validation=20to=20support=200x=20prefix=20(#917)=20##=20?= =?UTF-8?q?Problem=20Users=20entering=20private=20keys=20with=20"0x"=20pre?= =?UTF-8?q?fix=20failed=20validation=20incorrectly:=20**Scenario:**=20-=20?= =?UTF-8?q?User=20inputs:=20`0x1234...`=20(34=20characters=20including=20"?= =?UTF-8?q?0x")=20-=20Expected=20part1=20length:=2032=20characters=20-=20*?= =?UTF-8?q?*Bug**:=20Code=20checks=20`part1.length=20<=2032`=20=E2=86=92?= =?UTF-8?q?=20`34=20<=2032`=20=E2=86=92=20=E2=9D=8C=20FALSE=20=E2=86=92=20?= =?UTF-8?q?"Key=20too=20long"=20error=20-=20**Actual**:=20Should=20normali?= =?UTF-8?q?ze=20to=20`1234...`=20(32=20chars)=20=E2=86=92=20=E2=9C=85=20Va?= =?UTF-8?q?lid=20**Impact:**=20-=20Users=20cannot=20paste=20keys=20from=20?= =?UTF-8?q?wallets=20(most=20include=20"0x")=20-=20Confusing=20UX=20-=20va?= =?UTF-8?q?lid=20keys=20rejected=20-=20Forces=20manual=20"0x"=20removal=20?= =?UTF-8?q?##=20Root=20Cause=20**File**:=20`web/src/components/TwoStageKey?= =?UTF-8?q?Modal.tsx`=20**Lines=2077-84**=20(handleStage1Next):=20```types?= =?UTF-8?q?cript=20//=20=E2=9D=8C=20Bug:=20Checks=20length=20before=20norm?= =?UTF-8?q?alizing=20if=20(part1.length=20<=20expectedPart1Length)=20{=20?= =?UTF-8?q?=20=20//=20Fails=20for=20"0x..."=20inputs=20}=20```=20**Lines?= =?UTF-8?q?=20132-143**=20(handleStage2Complete):=20```typescript=20//=20?= =?UTF-8?q?=E2=9D=8C=20Bug:=20Same=20issue=20if=20(part2.length=20<=20expe?= =?UTF-8?q?ctedPart2Length)=20{=20=20=20//=20Fails=20for=20"0x..."=20input?= =?UTF-8?q?s=20}=20//=20=E2=9D=8C=20Bug:=20Concatenates=20without=20normal?= =?UTF-8?q?izing=20part1=20const=20fullKey=20=3D=20part1=20+=20part2=20//?= =?UTF-8?q?=20May=20have=20double=20"0x"=20```=20##=20Solution=20###=20Fix?= =?UTF-8?q?=201:=20Normalize=20before=20validation=20**Lines=2077-79**:=20?= =?UTF-8?q?```typescript=20//=20=E2=9C=85=20Normalize=20first,=20then=20va?= =?UTF-8?q?lidate=20const=20normalized1=20=3D=20part1.startsWith('0x')=20?= =?UTF-8?q?=3F=20part1.slice(2)=20:=20part1=20if=20(normalized1.length=20=20Co-authored-by:=20tinkle-comm?= =?UTF-8?q?unity=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/TwoStageKeyModal.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/web/src/components/TwoStageKeyModal.tsx b/web/src/components/TwoStageKeyModal.tsx index 97e856dd..5de79886 100644 --- a/web/src/components/TwoStageKeyModal.tsx +++ b/web/src/components/TwoStageKeyModal.tsx @@ -74,7 +74,9 @@ export function TwoStageKeyModal({ }, [isOpen, stage]) const handleStage1Next = async () => { - if (part1.length < expectedPart1Length) { + // ✅ Normalize input (remove possible 0x prefix) before validating length + const normalized1 = part1.startsWith('0x') ? part1.slice(2) : part1 + if (normalized1.length < expectedPart1Length) { setError( t('errors.privatekeyIncomplete', language, { expected: expectedPart1Length, @@ -129,7 +131,9 @@ export function TwoStageKeyModal({ } const handleStage2Complete = () => { - if (part2.length < expectedPart2Length) { + // ✅ Normalize input (remove possible 0x prefix) before validating length + const normalized2 = part2.startsWith('0x') ? part2.slice(2) : part2 + if (normalized2.length < expectedPart2Length) { setError( t('errors.privatekeyIncomplete', language, { expected: expectedPart2Length, @@ -138,7 +142,9 @@ export function TwoStageKeyModal({ return } - const fullKey = part1 + part2 + // ✅ Concatenate after removing 0x prefix from both parts + const normalized1 = part1.startsWith('0x') ? part1.slice(2) : part1 + const fullKey = normalized1 + normalized2 if (!validatePrivateKeyFormat(fullKey, expectedLength)) { setError(t('errors.privatekeyInvalidFormat', language)) return