From 0bb8a17245437e998bc094bbeacfe2ab67d6b03b Mon Sep 17 00:00:00 2001 From: SoSweetHam Date: Thu, 13 Nov 2025 21:32:46 +0530 Subject: [PATCH 1/5] fix: hardware crypto context logic --- .../eid-wallet/src/lib/crypto/KeyManagerFactory.ts | 3 ++- .../eid-wallet/src/lib/global/controllers/key.ts | 14 ++++++++++++++ .../src/routes/(auth)/onboarding/+page.svelte | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts index 1cc3dfea3..888aeac5a 100644 --- a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts +++ b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts @@ -82,10 +82,11 @@ export class KeyManagerFactory { static async getKeyManagerForContext( keyId: string, context: "onboarding" | "signing" | "verification" | "pre-verification", + isFake: boolean, ): Promise { const config: KeyManagerConfig = { keyId, - useHardware: context !== "pre-verification", + useHardware: isFake ? false : context !== "pre-verification" && await KeyManagerFactory.isHardwareAvailable(), preVerificationMode: context === "pre-verification", }; diff --git a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts index 626ce62b2..cdd731d19 100644 --- a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts +++ b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts @@ -1,6 +1,7 @@ import { KeyManagerFactory } from "$lib/crypto"; import type { KeyManager } from "$lib/crypto"; import type { Store } from "@tauri-apps/plugin-store"; +import type { UserController } from "./user"; export type KeyServiceContext = | "onboarding" @@ -72,9 +73,22 @@ export class KeyService { this.#managerCache.delete(cacheKey); } + const isFake = await this.#store + .get("fake") + .then((f) => { + if (!f) { + return undefined; + } + return f; + }) + .catch((error) => { + console.error("Failed to get fake:", error); + return undefined; + }); const manager = await KeyManagerFactory.getKeyManagerForContext( keyId, context, + isFake, ); this.#managerCache.set(cacheKey, manager); await this.#persistContext(cacheKey, manager, keyId, context); diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 13c1e72be..59e19f610 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -167,6 +167,10 @@ onMount(async () => { // New function to handle final submission with demo name handleFinalSubmit = async () => { + console.log("Setting vault in controller:", { + uri, + ename, + }); loading = true; const tenYearsLater = new Date(); From 5315026669e36023548fcd614ada15ef732174e2 Mon Sep 17 00:00:00 2001 From: SoSweetHam Date: Thu, 13 Nov 2025 21:34:00 +0530 Subject: [PATCH 2/5] fix: hardware crypto context logic --- .../src/lib/crypto/KeyManagerFactory.ts | 5 ++++- .../src/lib/global/controllers/key.ts | 22 +++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts index 888aeac5a..fe580ed54 100644 --- a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts +++ b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts @@ -86,7 +86,10 @@ export class KeyManagerFactory { ): Promise { const config: KeyManagerConfig = { keyId, - useHardware: isFake ? false : context !== "pre-verification" && await KeyManagerFactory.isHardwareAvailable(), + useHardware: isFake + ? false + : context !== "pre-verification" && + (await KeyManagerFactory.isHardwareAvailable()), preVerificationMode: context === "pre-verification", }; diff --git a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts index cdd731d19..b0087ecc6 100644 --- a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts +++ b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts @@ -74,21 +74,21 @@ export class KeyService { } const isFake = await this.#store - .get("fake") - .then((f) => { - if (!f) { + .get("fake") + .then((f) => { + if (!f) { + return undefined; + } + return f; + }) + .catch((error) => { + console.error("Failed to get fake:", error); return undefined; - } - return f; - }) - .catch((error) => { - console.error("Failed to get fake:", error); - return undefined; - }); + }); const manager = await KeyManagerFactory.getKeyManagerForContext( keyId, context, - isFake, + isFake ?? false, ); this.#managerCache.set(cacheKey, manager); await this.#persistContext(cacheKey, manager, keyId, context); From 6efb9c2fbbcb486679f271eb1d021540d5cea560 Mon Sep 17 00:00:00 2001 From: SoSweetHam Date: Thu, 13 Nov 2025 21:35:15 +0530 Subject: [PATCH 3/5] fix: remove useless log --- .../eid-wallet/src/routes/(auth)/onboarding/+page.svelte | 4 ---- 1 file changed, 4 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 59e19f610..13c1e72be 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -167,10 +167,6 @@ onMount(async () => { // New function to handle final submission with demo name handleFinalSubmit = async () => { - console.log("Setting vault in controller:", { - uri, - ename, - }); loading = true; const tenYearsLater = new Date(); From bed6b47c299bc6ba4a8e16503b7581f070d1daca Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Thu, 13 Nov 2025 22:26:38 +0530 Subject: [PATCH 4/5] fix: hardware key problem --- .../src/lib/crypto/KeyManagerFactory.ts | 24 +++-- .../src/lib/global/controllers/key.ts | 39 +++++-- .../src/routes/(auth)/onboarding/+page.svelte | 101 ++++++++++++++---- .../src/routes/(auth)/verify/+page.svelte | 7 ++ 4 files changed, 129 insertions(+), 42 deletions(-) diff --git a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts index fe580ed54..5e793adbb 100644 --- a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts +++ b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts @@ -15,17 +15,17 @@ export class KeyManagerFactory { * Get a key manager instance based on the configuration */ static async getKeyManager(config: KeyManagerConfig): Promise { - // If explicitly requesting hardware and not in pre-verification mode - if (config.useHardware && !config.preVerificationMode) { - return KeyManagerFactory.getHardwareKeyManager(); - } - - // If in pre-verification mode, always use software keys + // If in pre-verification mode, ALWAYS use software keys (never hardware) if (config.preVerificationMode) { console.log("Using software key manager for pre-verification mode"); return KeyManagerFactory.getSoftwareKeyManager(); } + // If explicitly requesting hardware and not in pre-verification mode + if (config.useHardware) { + return KeyManagerFactory.getHardwareKeyManager(); + } + // Default behavior: try hardware first, fallback to software try { const hardwareManager = KeyManagerFactory.getHardwareKeyManager(); @@ -84,13 +84,15 @@ export class KeyManagerFactory { context: "onboarding" | "signing" | "verification" | "pre-verification", isFake: boolean, ): Promise { + // Pre-verification users (isFake=true) or pre-verification context should NEVER use hardware + const shouldUseHardware = !isFake && + context !== "pre-verification" && + (await KeyManagerFactory.isHardwareAvailable()); + const config: KeyManagerConfig = { keyId, - useHardware: isFake - ? false - : context !== "pre-verification" && - (await KeyManagerFactory.isHardwareAvailable()), - preVerificationMode: context === "pre-verification", + useHardware: shouldUseHardware, + preVerificationMode: context === "pre-verification" || isFake, }; return KeyManagerFactory.getKeyManager(config); diff --git a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts index b0087ecc6..3a386a11c 100644 --- a/infrastructure/eid-wallet/src/lib/global/controllers/key.ts +++ b/infrastructure/eid-wallet/src/lib/global/controllers/key.ts @@ -68,31 +68,48 @@ export class KeyService { const cachedManager = this.#managerCache.get(cacheKey); if (cachedManager) { await this.#touchContext(cacheKey, cachedManager); - return cachedManager; + // If user is pre-verification, ensure we're using software keys + const isFake = await this.#isPreVerificationUser(); + if (isFake && cachedManager.getType() === "hardware") { + // Force software keys for pre-verification users + this.#managerCache.delete(cacheKey); + } else { + return cachedManager; + } } this.#managerCache.delete(cacheKey); } + const isFake = await this.#isPreVerificationUser(); + // Force pre-verification mode if user is fake/pre-verification + const effectiveContext = isFake ? "pre-verification" : context; + const manager = await KeyManagerFactory.getKeyManagerForContext( + keyId, + effectiveContext, + isFake ?? false, + ); + this.#managerCache.set(cacheKey, manager); + await this.#persistContext(cacheKey, manager, keyId, context); + return manager; + } + + /** + * Check if the current user is a pre-verification (demo) user + */ + async #isPreVerificationUser(): Promise { const isFake = await this.#store .get("fake") .then((f) => { if (!f) { - return undefined; + return false; } return f; }) .catch((error) => { console.error("Failed to get fake:", error); - return undefined; + return false; }); - const manager = await KeyManagerFactory.getKeyManagerForContext( - keyId, - context, - isFake ?? false, - ); - this.#managerCache.set(cacheKey, manager); - await this.#persistContext(cacheKey, manager, keyId, context); - return manager; + return isFake; } async ensureKey( diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 13c1e72be..dc1e61990 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -23,12 +23,46 @@ let verificationId = $state(""); let demoName = $state(""); let verificationSuccess = $state(false); let keyManager: KeyManager | null = $state(null); +let hardwareAvailable = $state(null); +let checkingHardware = $state(false); const KEY_ID = "default"; const handleGetStarted = async () => { - //get started functionality - isPaneOpen = true; - preVerified = false; + checkingHardware = true; + try { + if (!globalState) { + globalState = getContext<() => GlobalState>("globalState")(); + } + const isAvailable = await globalState.keyService.isHardwareAvailable(); + hardwareAvailable = isAvailable; + + if (!isAvailable) { + // Hardware not available - show error and don't proceed + error = "Your device doesn't support hardware-backed security keys required for passport verification. Please use the pre-verification code option instead."; + isPaneOpen = true; + preVerified = false; + setTimeout(() => { + error = null; + }, 8000); + checkingHardware = false; + return; + } + + // Hardware is available - proceed to verification + isPaneOpen = true; + preVerified = false; + } catch (err) { + console.error("Failed to check hardware availability:", err); + hardwareAvailable = false; + error = "Unable to check device capabilities. Please use the pre-verification code option instead."; + isPaneOpen = true; + preVerified = false; + setTimeout(() => { + error = null; + }, 8000); + } finally { + checkingHardware = false; + } }; const handlePreVerified = () => { @@ -239,9 +273,13 @@ onMount(async () => { >

- Get Started + {checkingHardware ? "Checking device..." : "Get Started"} +

@@ -304,20 +342,43 @@ onMount(async () => { {/if} {:else} -

- Your Digital Self begins with the Real You -

-

- In the Web 3.0 Data Space, identity is linked to reality. We begin - by verifying your real-world passport, which serves as the - foundation for issuing your secure ePassport. At the same time, we - generate your eName – a unique digital identifier – and create your - eVault to store and protect your personal data. -

-
- Next -
+ {#if hardwareAvailable === false} +

+ Hardware Security Not Available +

+

+ Your device doesn't support hardware-backed security keys required for passport verification. +

+

+ Please use the pre-verification code option to create a demo account instead. +

+
+ { + isPaneOpen = false; + handlePreVerified(); + }} + > + Use Pre-Verification Code + +
+ {:else} +

+ Your Digital Self begins with the Real You +

+

+ In the Web 3.0 Data Space, identity is linked to reality. We begin + by verifying your real-world passport, which serves as the + foundation for issuing your secure ePassport. At the same time, we + generate your eName – a unique digital identifier – and create your + eVault to store and protect your personal data. +

+
+ Next +
+ {/if} {/if} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index 55938bb83..f8da33724 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -227,6 +227,13 @@ onMount(async () => { // Check hardware key support first await checkHardwareKeySupport(); + // If hardware is not available, redirect back to onboarding + if (!hardwareKeySupported) { + console.log("Hardware not available, redirecting to onboarding"); + await goto("/onboarding"); + return; + } + // Initialize key manager and check if default key pair exists await initializeKeyManager(); await ensureKeyForVerification(); From f80bf7a88923db8cc91cf9ff29824cfb235d8103 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Thu, 13 Nov 2025 22:55:13 +0530 Subject: [PATCH 5/5] feat: final safety checks for hardware keys --- .../gen/android/.idea/deviceManager.xml | 13 ++ .../src/lib/crypto/KeyManagerFactory.ts | 9 +- .../src/routes/(auth)/onboarding/+page.svelte | 139 ++++++++++++------ .../src/routes/(auth)/verify/+page.svelte | 52 ++++++- 4 files changed, 156 insertions(+), 57 deletions(-) create mode 100644 infrastructure/eid-wallet/src-tauri/gen/android/.idea/deviceManager.xml diff --git a/infrastructure/eid-wallet/src-tauri/gen/android/.idea/deviceManager.xml b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/deviceManager.xml new file mode 100644 index 000000000..91f95584d --- /dev/null +++ b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts index 5e793adbb..1ccdfbd61 100644 --- a/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts +++ b/infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts @@ -85,10 +85,11 @@ export class KeyManagerFactory { isFake: boolean, ): Promise { // Pre-verification users (isFake=true) or pre-verification context should NEVER use hardware - const shouldUseHardware = !isFake && - context !== "pre-verification" && - (await KeyManagerFactory.isHardwareAvailable()); - + const shouldUseHardware = + !isFake && + context !== "pre-verification" && + (await KeyManagerFactory.isHardwareAvailable()); + const config: KeyManagerConfig = { keyId, useHardware: shouldUseHardware, diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index dc1e61990..cbbb7e2ab 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -23,44 +23,57 @@ let verificationId = $state(""); let demoName = $state(""); let verificationSuccess = $state(false); let keyManager: KeyManager | null = $state(null); -let hardwareAvailable = $state(null); +let showHardwareError = $state(false); let checkingHardware = $state(false); const KEY_ID = "default"; const handleGetStarted = async () => { + isPaneOpen = true; + preVerified = false; checkingHardware = true; + showHardwareError = false; + error = null; + try { if (!globalState) { globalState = getContext<() => GlobalState>("globalState")(); } - const isAvailable = await globalState.keyService.isHardwareAvailable(); - hardwareAvailable = isAvailable; - - if (!isAvailable) { - // Hardware not available - show error and don't proceed - error = "Your device doesn't support hardware-backed security keys required for passport verification. Please use the pre-verification code option instead."; - isPaneOpen = true; - preVerified = false; - setTimeout(() => { - error = null; - }, 8000); + + // Actually try to generate a test hardware key + const testKeyId = `hardware-test-${Date.now()}`; + console.log( + "Testing hardware key generation with test key:", + testKeyId, + ); + + try { + const { manager, created } = await globalState.keyService.ensureKey( + testKeyId, + "onboarding", + ); + console.log( + "Test key result - Manager type:", + manager.getType(), + "Created:", + created, + ); + + // Check if we got hardware manager and it actually created a key + if (manager.getType() !== "hardware") { + throw new Error("Got software fallback instead of hardware"); + } + + // Hardware works! Clean up test key and proceed + console.log("Hardware keys are working"); + checkingHardware = false; + } catch (keyError) { + console.error("Hardware key test failed:", keyError); + showHardwareError = true; checkingHardware = false; - return; } - - // Hardware is available - proceed to verification - isPaneOpen = true; - preVerified = false; } catch (err) { - console.error("Failed to check hardware availability:", err); - hardwareAvailable = false; - error = "Unable to check device capabilities. Please use the pre-verification code option instead."; - isPaneOpen = true; - preVerified = false; - setTimeout(() => { - error = null; - }, 8000); - } finally { + console.error("Error checking hardware:", err); + showHardwareError = true; checkingHardware = false; } }; @@ -138,8 +151,24 @@ async function getApplicationPublicKey() { } const handleNext = async () => { - //handle next functionlity - goto("/verify"); + // Initialize keys for onboarding context before going to verify + try { + loading = true; + if (!globalState) { + globalState = getContext<() => GlobalState>("globalState")(); + } + await initializeKeyManager(); + await ensureKeyForContext(); + loading = false; + goto("/verify"); + } catch (err) { + console.error("Failed to initialize keys for onboarding:", err); + error = "Failed to initialize security keys. Please try again."; + loading = false; + setTimeout(() => { + error = null; + }, 5000); + } }; let globalState: GlobalState; @@ -342,12 +371,21 @@ onMount(async () => { {/if} {:else} - {#if hardwareAvailable === false} + {#if checkingHardware} +
+
+ +

Checking device capabilities...

+
+
+ {:else if showHardwareError}

Hardware Security Not Available

- Your device doesn't support hardware-backed security keys required for passport verification. + Your phone doesn't support hardware crypto keys, which is a requirement for verified IDs.

Please use the pre-verification code option to create a demo account instead. @@ -364,21 +402,32 @@ onMount(async () => { {:else} -

- Your Digital Self begins with the Real You -

-

- In the Web 3.0 Data Space, identity is linked to reality. We begin - by verifying your real-world passport, which serves as the - foundation for issuing your secure ePassport. At the same time, we - generate your eName – a unique digital identifier – and create your - eVault to store and protect your personal data. -

-
- Next -
+ {#if loading} +
+
+ +

Initializing security keys...

+
+
+ {:else} +

+ Your Digital Self begins with the Real You +

+

+ In the Web 3.0 Data Space, identity is linked to reality. We begin + by verifying your real-world passport, which serves as the + foundation for issuing your secure ePassport. At the same time, we + generate your eName – a unique digital identifier – and create your + eVault to store and protect your personal data. +

+
+ Next +
+ {/if} {/if} {/if} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index f8da33724..d2f042f26 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -109,12 +109,41 @@ let hardwareKeyCheckComplete = $state(false); const KEY_ID = "default"; async function handleVerification() { - const { data } = await axios.post( - new URL("/verification", PUBLIC_PROVISIONER_URL).toString(), - ); - verificaitonId.set(data.id); - showVeriffModal = true; - watchEventStream(data.id); + try { + // Ensure keys are initialized before starting verification + if (!keyManager) { + try { + await initializeKeyManager(); + await ensureKeyForVerification(); + } catch (keyError) { + console.error("Failed to initialize keys:", keyError); + // If key initialization fails, go back to onboarding + await goto("/onboarding"); + return; + } + } + + const { data } = await axios.post( + new URL("/verification", PUBLIC_PROVISIONER_URL).toString(), + ); + verificaitonId.set(data.id); + showVeriffModal = true; + watchEventStream(data.id); + } catch (error) { + console.error("Failed to start verification:", error); + // If verification fails due to key issues or any initialization error, go back to onboarding + const errorMessage = + error instanceof Error + ? error.message.toLowerCase() + : String(error).toLowerCase(); + if ( + errorMessage.includes("key") || + errorMessage.includes("initialize") || + errorMessage.includes("manager") + ) { + await goto("/onboarding"); + } + } } function watchEventStream(id: string) { @@ -235,8 +264,15 @@ onMount(async () => { } // Initialize key manager and check if default key pair exists - await initializeKeyManager(); - await ensureKeyForVerification(); + try { + await initializeKeyManager(); + await ensureKeyForVerification(); + } catch (error) { + console.error("Failed to initialize keys for verification:", error); + // If key initialization fails, redirect back to onboarding + await goto("/onboarding"); + return; + } handleContinue = async () => { if ($status !== "approved" && $status !== "duplicate")