* feat: store KYC document in keychain after receiving TEE attestation
Build a KycData document from the attestation (signature, applicantInfo,
pubkey) and persist it via storePassportData → keychain-backed adapter.
This makes the document available for the proving machine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: KYC document mock is always false
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* provingmachine flow with mock passport
* add yarn.lock
* Fix coderabbit comments
* lint
* update coderabbit comments
* coderabbit comments
* Merge branch 'dev' into feat/didit-keychain-storage
* fix: reorder KYC constants declarations and fix formatting
Constants were declared out of order causing "used before declaration"
TS errors. Reordered to match the 295-byte layout sequentially.
Also ran prettier on common package.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix proving phase handling and add delete catalog debug button
- TunnelProvingScreen: use `phase !== 'disclose'` to handle completion
for both passport (dsc→register→disclose) and kyc/aadhaar (register→disclose)
- KeychainDebugScreen: add Delete Catalog button to clear all documents
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* coderabbit comments
---------
Co-authored-by: ayman <aymanshaik1015@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC register circuit inputs instead of deserialize+reserialize
The deserialize→reserialize path strips the namespace prefix from
id_type, producing different bytes than what the TEE signed. This
causes EdDSA signature verification to fail in the circuit.
Use raw base64-decoded bytes directly, matching the TEE's signed data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC register circuit inputs in common and new-common
The deserialize→reserialize path strips the namespace prefix from
id_type (\x05didit), producing different bytes than what the TEE
signed. This causes EdDSA signature verification to fail in the
register_kyc circuit.
Use raw base64-decoded bytes directly in both common/ and new-common/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC disclose circuit inputs
Same issue as register — .toString('utf-8') corrupts bytes >= 128,
causing Num2Bits assertion failures in vc_and_disclose_kyc circuit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC disclose circuit inputs in new-common
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove dev functions from KYC registry, add upgrade module, clean up debug logs
- Remove devRemoveNullifier and devResetTree (no longer needed)
- Add upgradeKycRegistry ignition module
- Update deployed_addresses.json with new KYC registry proxy
- Remove debug logging from provingMachine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC register circuit inputs instead of deserialize+reserialize
The deserialize→reserialize path strips the namespace prefix from
id_type, producing different bytes than what the TEE signed. This
causes EdDSA signature verification to fail in the circuit.
Use raw base64-decoded bytes directly, matching the TEE's signed data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC register circuit inputs in common and new-common
The deserialize→reserialize path strips the namespace prefix from
id_type (\x05didit), producing different bytes than what the TEE
signed. This causes EdDSA signature verification to fail in the
register_kyc circuit.
Use raw base64-decoded bytes directly in both common/ and new-common/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace unused teeUrl with environment ("prod"/"staging") for endpoint selection. The webview never consumed teeUrl — the proving machine resolves TEE URLs internally from the circuit DNS mapping API based on environment.
Add version (default 1) for config protocol versioning. Add optional verification config fields: scope, disclosures, appName, appEndpoint, resultType — needed for the tunnel flow to render the proof request UI correctly. The webview already parsed these from URL params; the native shells just weren't sending them.
Update webview to parse environment and version from URL params with defensive defaults. Update both test apps to use the new config shape.
* feat: replace Sumsub with Didit JS SDK in webview-app
- Add @didit-protocol/sdk-web, remove @sumsub/websdk
- Create diditProvider.ts with session creation + SDK launch
- Update ProviderLaunchScreen to use Didit embedded mode
- Delete sumsubProvider.ts and sumsub-websdk.d.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add Socket.IO attestation flow to webview KYC
After Didit JS SDK completes, connect Socket.IO to the TEE,
subscribe by sessionId, and wait for signed KYC data (attestation).
Emit ack_success for session cleanup. Attach attestation to the
provider result before navigating to the result screen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update TEE URL to kyc.self.xyz, update SDK test app README for Didit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: only route KYC (Other IDs) to Didit provider, others to Coming Soon
Passport, ID card, and Aadhaar require NFC/MRZ scanning which isn't
available in the WebView. Only "Other IDs" goes through the Didit
JS SDK flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Didit SDK full-width rendering and KYC routing
- Wire onNotListedPress to launch Didit for "View other supported IDs"
- Remove verificationId gate from ProviderLaunchScreen
- Switch to modal mode with CSS overrides for full-screen on mobile
- Force .shadow-card to 100% width/height in WebView context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add camera permissions and file upload to Android WebView
Add WebChromeClient to AndroidWebViewHost:
- onPermissionRequest: auto-grants camera for Didit SDK
- onShowFileChooser: opens system file picker for document upload
- SelfVerificationActivity handles file chooser result callback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: gitignore Gradle build artifacts for native-shell-android
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add runtime camera permission and CAMERA manifest declaration
- Add CAMERA permission to sdk-test-app AndroidManifest.xml
- Request runtime camera permission in onPermissionRequest before granting
- Handle permission result in SelfVerificationActivity
- Store pending PermissionRequest for async grant/deny after user response
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix ios camera
* fix: address CodeRabbit review findings
- Replace ngrok URL with kyc.self.xyz in Android and iOS test apps
- Fix file chooser hang when context is not an Activity
- Move NSCameraUsageDescription to project.yml (survives xcodegen regen)
- Delete manual Info.plist that would be overwritten
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace ngrok URL with kyc.self.xyz in diditProvider and diditAttestation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: explicitly disable Didit SDK debug logging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: webview lint
* fix: validate origin and handle audio permission in WebView permission grants
- Deny permission requests from untrusted origins
- Deny instead of grant when context is not an Activity
- Handle RECORD_AUDIO alongside CAMERA for liveness checks
- Add RECORD_AUDIO to AndroidManifest.xml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: seshanthS <seshanth@protonmail.com>
* Clean up WV-16 settings screens
Fix mock document generation in DevModeScreen — generate button now calls mockDocumentStore.addDocument() with the selected country and document type instead of navigating home without storing anything.
Fix duplicate description on Manage Documents menu item — was incorrectly showing "Recovery phrase, passport data" (copy-paste from Security item), now shows "Your registered passports and IDs".
Add haptic feedback to all settings menu item press handlers.
Add Settings root and Tunnel routes to the DevRouteMenu.
Add navigation and interaction tests for all four settings screens.
* Update WV-16 status in webview SPEC.md
Mark WV-16 as Done and document what was delivered vs deferred. Settings
persistence (notification toggles, backup-enabled state) is explicitly
deferred pending a storage design decision — it does not block UI completeness.
* Add recovery and backup screens (SELF-2423)
Add 5 recovery/backup screen wrappers around euclid components: BackupMethodPickerScreen, RecoveryPhraseScreen, LaunchRecoveryScreen, SecretPhraseInputScreen, and RecoverySuccessScreen. Wire SecurityScreen actions to the new routes instead of /coming-soon. Register all routes in App.tsx.
* Add background image to LaunchRecoveryScreen and animation assets (SELF-2423)
Add dialogue-background.jpg and Lottie animation JSON files to public/ for proper screen rendering. Pass backgroundImage prop to LaunchRecoveryScreen for visual consistency with other dialogue screens.
* add test
* link up
* fixes
* revert fix. we need to fix in euclid
* update euclic
* dev menu dx, add password
* fix launch recovery screen
* fix recovery success screen
* fix recovery phrase tests
* updates
* fixes
* fixes
---------
Co-authored-by: Tranquil-Flow <tranquil_flow@protonmail.com>
* feat(webview-app): add IDDataScreen and ManageDocumentsScreen (SELF-2422)
Screen migration for WV-14. Adds 2 euclid screen wrappers with mock data for the UI mocking pass.
- IDDataScreen at /id-data with ExposedIDCard, identification details, document data
- ManageDocumentsScreen at /manage-documents with document list and manage dialogue
- Wire Settings > Manage Documents to /manage-documents instead of /coming-soon
- Add preview.html for phone-frame screen verification during development
* update
* rename
---------
Co-authored-by: Tranquil-Flow <tranquil_flow@protonmail.com>
* chore: swap @sumsub/react-native-mobilesdk-module for @didit-protocol/sdk-react-native
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: rename SUMSUB_TEE_URL to DIDIT_TEE_URL
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: rename PendingKycVerification.userId to sessionId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add Didit integration module, remove Sumsub integration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add useDiditWebSocket hook, remove useSumsubWebSocket
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add useDiditLauncher hook, remove useSumsubLauncher
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: rename userId to sessionId in pendingKycStore, bump persist version
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: rename sumsub error injection triggers to didit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: rename KycSuccess route param userId to sessionId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: update KycSuccessScreen to use useDiditWebSocket and sessionId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: update all consumer files from Sumsub to Didit
Updates usePendingKycRecovery, selfClientProvider, 5 fallback screens,
LogoConfirmationScreen, HomeScreen, KYCVerifiedScreen, and KycIdCard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: update jest mocks and config for Didit SDK
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* build: swap Sumsub native deps for Didit in Podfile and build.gradle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: remove hardcoded sumsub namespace from nullifier generation
Read namespace from id_type field instead of hardcoding 'sumsub'.
The didit-tee encodes id_type as [namespace_len][namespace][doc_type],
so the namespace is already in the signed data.
Also fix deserializeApplicantInfo to parse the namespaced encoding
and extract just the document type for display.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: lint and formatting issues from Didit migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add register_kyc support to build_r1cs_wasm.sh and build_cpp.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use circuits/node_modules paths in build_r1cs_wasm.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: emit ack_success after receiving KYC data to trigger session deletion
The didit-tee now expects the client to ack receipt of signed data,
which triggers DELETE of the session from Didit's API for data cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw bytes for KYC commitment/nullifier instead of deserialize+reserialize
The deserialize→reserialize path strips the namespace prefix from
id_type, producing different bytes than the TEE signed. Work on the
raw base64-decoded bytes directly to match the circuit inputs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: lint
* Revert "fix: lint"
This reverts commit d3dde1460b.
* fix: lint
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WV-07 covers SelfClient assembly: exporting useProvingStore from the
browser entry point, mapping bridge adapters to SDK interfaces, creating
a keychain-backed DocumentsAdapter via the existing secureStorage bridge,
and wiring a real SelfClient in the webview-app provider.
WV-08 covers the tunnel proving flow: replacing the mock 3-second timer
with real provingMachine integration (register → disclose), storing
Sumsub KYC results as KycData documents in native keychain, and driving
UI from proving state transitions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(webview-app): add Euclid 3.0 settings sub-screens
Add SecurityScreen, NotificationPreferencesScreen, and DevModeScreen
wrappers that import Euclid 3.0 components and wire them with React
Router navigation and bridge adapters. Update SettingsScreen menu items
to navigate to real routes instead of /coming-soon.
Requires @selfxyz/euclid-web to be published with the new screen exports
(SecurityScreen, NotificationPreferencesScreen, DevModeScreen) before
type-check will pass. See docs/superpowers/plans/ for full context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add settings integration plan and handover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: use euclid 1.2.0
* PoC tunnel flow
* updates
* update skills
---------
Co-authored-by: Tranquil-Flow <tranquil_flow@protonmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Leszek Stachowski <leszek.stachowski@self.xyz>
When CDN bundle loading lands, runtime checksum verification (SHA-256
manifest, fail-closed on mismatch) becomes a security boundary. This
adds the backlog item and context so it's picked up at the right time.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add iOS native shell package (NSL-02)
Plain Swift implementation of the WebView host with bridge handlers
for secure storage (Keychain), crypto (EC P-256), and lifecycle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Android native shell package (NSL-01)
Plain Kotlin implementation of the WebView host with bridge handlers
for secure storage (EncryptedSharedPreferences), crypto (Android Keystore
EC P-256), and lifecycle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: integrate Sumsub Web SDK into ProviderLaunchScreen (WV-05)
Rewrites ProviderLaunchScreen to launch Sumsub Web SDK, adds KYC
provider types, result normalization, and a ProviderResultScreen
for displaying verification outcomes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update spec status for NSL-01, NSL-02, WV-05 to in-progress
All three items are code-complete but need integration testing
before marking done.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add build-pipeline workstream specs, update NSL-03 and BP-01 status
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add WebView bundle build pipeline (BP-01)
Build script copies webview-app dist into both native shell asset
directories. Gradle preBuild validation fails fast when bundle is
missing. Root package.json gets build:sdk-* scripts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add SDK test apps for Android and iOS (NSL-03)
Minimal test apps to exercise native shells end-to-end:
- Android: Jetpack Compose app using SelfSdk.launch() via composite build
- iOS: SwiftUI app using SelfSdk.createViewController() via local SPM dep
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* update lockfile
* fix: address CodeRabbit PR review findings for native shells
- Fix iOS double callback: add hasEmittedResult flag to LifecycleHandler
so dismiss() won't fire onCancelled after onResult already emitted
- Fix Android error result codes: use RESULT_FIRST_USER for failed
verifications instead of always RESULT_OK; add dedicated handler in
SelfSdk.handleResult
- Fix iOS production query params: append params to file URL via
URLComponents so WebView receives teeUrl/verificationId/userId
- Fix build:sdk-ios false-green: chain swift build after bundle script
- Add expectedRequestCode param to handleResult for flexibility
- Upgrade security-crypto 1.1.0-alpha06 → 1.1.0 stable
- Improve callback type safety: onSuccess takes raw JSON string,
onFailure takes SelfSdkException instead of generic Exception
- Add requireBiometric intent comments to both SecureStorageHandlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address remaining CodeRabbit PR review findings (round 2)
- iOS BridgeResponse: add requestId/success fields, rename result→data to match JS bridge contract
- iOS test app: fix callback deallocation with Coordinator pattern
- ProviderLaunchScreen: fail closed on missing verificationId, fix retry via retryCount state
- ProviderResultScreen: guard unknown status with fallback to error config
- build-webview-bundle.sh: validate index.html before deleting targets
- Package.swift: fix SPM resource path with target path/sources
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Versions 1.0.20 and 1.0.21 were published manually (not via CI), which bypassed the yarn pack step that resolves workspace:^ protocols. The published packages contain raw workspace:^ dependencies, making them uninstallable for external consumers. This version bump triggers a clean CI publish that correctly resolves @selfxyz/sdk-common to ^1.0.0.