Skip to content

Conversation

@remicolin
Copy link
Collaborator

@remicolin remicolin commented Sep 10, 2025

Summary by CodeRabbit

  • New Features

    • Aadhaar registration flow: header/progress, upload, success and error screens; photo‑library QR upload on iOS & Android; "I have an Aadhaar Card" button on Launch.
  • Enhancements

    • Broad Aadhaar support across the app: Id card display, Manage Documents ("Add Aadhaar"), mock data, storage, validation, proving/recovery flows, new analytics events and constants.
  • UX Changes

    • Removed Cancel button from QR scanner view; updated onboarding copy to include Aadhaar.
  • Chores

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds Aadhaar support and photo-library QR scanning: native iOS/Android pickers and detectors, React Native bridge and JS helpers, UI/screens and flows for Aadhaar upload, common Aadhaar types/crypto/mock-data, proving/circuits integration, and related build/manifest updates.

Changes

Cohort / File(s) Summary
iOS Photo Library QR scan
app/ios/PhotoLibraryQRScannerViewController.swift
New view controller: requests photo permission, presents image picker, detects QR via Core Image CIDetector, returns decoded string via completionHandler or reports NSError via errorHandler.
iOS RN bridge additions
app/ios/QRScannerBridge.m, app/ios/QRScannerBridge.swift
Exposes scanQRCodeFromPhotoLibrary to RN; presents PhotoLibraryQRScannerViewController on main thread and resolves/rejects promise.
iOS project config
app/ios/Self.xcodeproj/.../project.pbxproj
Adds Swift source to Xcode project and normalizes OTHER_LDFLAGS formatting.
Android photo picker & theme
app/android/app/src/main/AndroidManifest.xml, app/android/app/src/main/res/values/styles.xml
Declares translucent PhotoPickerActivity, GMS ModuleDependencies stub, and Theme.AppCompat.Translucent.
Android photo picker Activity & deps
app/android/app/src/main/java/.../PhotoPickerActivity.java, app/android/app/build.gradle
Adds PhotoPickerActivity using Activity Result API; adds androidx.activity and activity-ktx deps.
Android QR scanner native module
app/android/app/src/main/java/.../QRCodeScannerModule.java, app/android/app/src/main/java/.../QRCodeScannerPackage.java
Registers module, implements lifecycle listener, adds scanQRCodeFromPhotoLibrary with legacy/modern picker paths and activity-result handling; resolves/rejects Promise after image→QR processing.
Android QR detection improvements
app/android/app/src/main/java/.../utils/QrCodeDetectorProcessor.kt
Multi-scale and multi-binarizer QR detection, TRY_HARDER hints, async bitmap API, tolerant error handling, expanded logging.
RN QR utility
app/src/utils/qrScanner.ts
Platform-aware bridge: exports scanQRCodeWithCamera() and scanQRCodeFromPhotoLibrary() and availability helpers.
Aadhaar UI & navigation
app/src/components/NavBar/AadhaarNavBar.tsx, app/src/navigation/home.ts, app/src/screens/system/LaunchScreen.tsx, app/src/screens/dev/DevSettingsScreen.tsx
Adds AadhaarNavBar, routes (AadhaarUpload/AadhaarUploadSuccess/AadhaarUploadError), Launch screen button, and DevSettings entry.
Aadhaar upload screens
app/src/screens/document/aadhaar/*.tsx
New Aadhaar Upload, Success, and Error screens; scan from photo library, validate/extract QR payload and timestamp, persist Aadhaar data, and navigate accordingly.
Prove flow adjustments
app/src/screens/prove/QRCodeViewFinderScreen.tsx, app/src/screens/prove/ConfirmBelongingScreen.tsx
Removes Cancel UI; proving init now loads selected document and chooses circuits based on documentCategory (aadhaar vs others).
Recovery screens
app/src/screens/recovery/*.tsx
For Aadhaar, use aadhaar.public_keys as alternative CSCA source in registration checks.
Document storage/provider
app/src/providers/passportDataProvider.tsx
Storage/dedup accepts `PassportData
Home card rendering
app/src/components/homeScreen/idCard.tsx
IdCardLayout accepts `PassportData
Mock data & generator UI
app/src/hooks/useMockDataForm.ts, app/src/screens/dev/CreateMockScreen.tsx, common/src/utils/passports/genMockIdDoc.ts
Adds mock_aadhaar option, UI conditionals, and genMockAadhaarDoc producing AadhaarData.
Tests
app/tests/src/navigation.test.ts
Updates navigation test to include AadhaarUpload.
Common types & exports
common/src/utils/types.ts, common/index.ts, common/src/utils/index.ts, common/tsup.config.ts
Adds AadhaarData, BaseIDData, IDDocument, type guards, re-exports Aadhaar utilities, and tsup entries for Aadhaar utils.
Common Aadhaar utils & mock data
common/src/utils/aadhaar/*.ts
QR parsing/packing helpers, getAadharRegistrationWindow() (on-chain read fallback), cryptographic helpers, and refactored mock-data generators with new exported APIs.
Common proving & circuits
common/src/utils/circuits/*, common/src/utils/proving.ts
Adds Aadhaar circuit names (register_aadhaar, disclose_aadhaar), Aadhaar TEE input generators and selector helpers, widens payload/proof type unions.
Common passport helpers & validation
common/src/utils/passports/*
calculateContentHash widened to Aadhaar, new Aadhaar nullifier/commitment flows (generateCommitmentInAppAadhaar), and validation functions accept IDDocument.
Common constants & mock certs
common/src/constants/constants.ts, common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
Adds identity verification hub addresses and dev-only mock Aadhaar PEM cert constants.
Contracts & error selectors
contracts/error-selectors.json
Adds Aadhaar-related error selectors and new error entries across identity contracts.
Build & infra
.gitleaks.toml, .gitguardian.yml, packages/mobile-sdk-alpha/mobile-sdk-alpha.podspec
Adds gitleaks allowlist and gitguardian path ignores for mock certs and generators; updates podspec author contact to [email protected].
Home screen & flow
app/src/screens/home/HomeScreen.tsx
Reworks document loading on focus, adds loading state, removes in-screen QR scan path and related UI, navigates to IdDetails on selection.
Various UI/type updates
multiple files
Numerous type signature updates to accept IDDocument / AadhaarData, plus UI additions and analytics event additions across the app and SDK.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant RN as React Native (JS)
  participant Bridge as QRScanner Bridge
  participant Native as Native (iOS VC / Android Activity)
  participant Detector as QR Detector

  User->>RN: Tap "Upload QR code"
  RN->>Bridge: scanQRCodeFromPhotoLibrary()
  Bridge->>Native: present Photo picker / VC
  activate Native
  Native->>Native: Request permission if needed
  Native->>User: Present photo picker
  User-->>Native: Select image / Cancel
  Native->>Detector: Detect QR in image
  alt QR found
    Detector-->>Native: messageString
    Native-->>Bridge: resolve(result)
    Bridge-->>RN: Promise resolved (QR string)
  else Error/No QR/Denied
    Detector-->>Native: error
    Native-->>Bridge: reject(error)
    Bridge-->>RN: Promise rejected
  end
  deactivate Native
  RN->>RN: Process QR → validate → navigate to Success/Error
Loading
sequenceDiagram
  autonumber
  participant App as App Screen
  participant SDK as Self SDK
  participant Store as Document Store
  participant Prover as Proving Init

  App->>SDK: loadSelectedDocument()
  SDK-->>App: IDDocument (category)
  App->>Prover: init(selfClient, category)
  alt category == aadhaar
    Prover->>Prover: use register_aadhaar / Aadhaar inputs
  else passport/id_card
    Prover->>Prover: use dsc/register circuits and MRZ flows
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~150 minutes

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • aaronmgdr
  • shazarre

Poem

A photo picked, a code revealed,
New types and circuits all congealed.
Bridges, pickers, proofs align—
Aadhaar lands and flows combine.
Merge on, little QR, shine bright. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely highlights the two primary changes in the PR — an iOS QR-code opener and an Aadhaar screen — which map to the added iOS PhotoLibraryQRScannerViewController/bridge and the new Aadhaar UI and flows; it is therefore relevant and readable. It is slightly narrow (mentions iOS only) even though the PR also adds Android photo-picker support and wide-ranging Aadhaar integrations, but this does not make the title misleading.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch app/add-aadhaar-onboarding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@remicolin remicolin marked this pull request as draft September 10, 2025 02:38
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🧹 Nitpick comments (2)
app/ios/PhotoLibraryQRScannerViewController.swift (2)

63-71: (If you keep legacy picker) open Settings on denial.

If you stick with PHPhotoLibrary permissions, offer a direct Settings link to reduce dead-ends:

if let url = URL(string: UIApplication.openSettingsURLString) {
  UIApplication.shared.open(url)
}

Prefer PHPicker to avoid this altogether.


1-16: Header duplication.

Two differing file headers (“Self” vs “OpenPassport”) can confuse license scanners. Keep one consistent header.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a65afa and ef2f6a7.

⛔ Files ignored due to path filters (1)
  • app/src/images/512w.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • app/ios/PhotoLibraryQRScannerViewController.swift (1 hunks)
  • app/ios/QRScannerBridge.m (1 hunks)
  • app/ios/QRScannerBridge.swift (2 hunks)
  • app/ios/Self.xcodeproj/project.pbxproj (6 hunks)
  • app/src/components/NavBar/AadhaarNavBar.tsx (1 hunks)
  • app/src/navigation/home.ts (2 hunks)
  • app/src/screens/dev/DevSettingsScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1 hunks)
  • app/src/screens/prove/QRCodeViewFinderScreen.tsx (3 hunks)
  • app/src/screens/system/LaunchScreen.tsx (2 hunks)
  • app/src/utils/qrScanner.ts (1 hunks)
  • common/src/utils/aadhaar/assets/dataInput.d.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • app/src/navigation/home.ts
  • app/src/components/NavBar/AadhaarNavBar.tsx
  • common/src/utils/aadhaar/assets/dataInput.d.ts
  • app/src/utils/qrScanner.ts
  • app/src/screens/dev/DevSettingsScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/system/LaunchScreen.tsx
  • app/src/screens/prove/QRCodeViewFinderScreen.tsx
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/navigation/home.ts
  • app/src/components/NavBar/AadhaarNavBar.tsx
  • app/src/utils/qrScanner.ts
  • app/src/screens/dev/DevSettingsScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/system/LaunchScreen.tsx
  • app/src/screens/prove/QRCodeViewFinderScreen.tsx
common/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

common/src/**/*.{ts,tsx,js,jsx}: Review shared utilities for:

  • Reusability and modular design
  • Type safety and error handling
  • Side-effect management
  • Documentation and naming clarity

Files:

  • common/src/utils/aadhaar/assets/dataInput.d.ts
app/ios/**/*

⚙️ CodeRabbit configuration file

app/ios/**/*: Review iOS-specific code for:

  • Platform-specific implementations
  • Performance considerations
  • Security best practices for mobile

Files:

  • app/ios/QRScannerBridge.m
  • app/ios/PhotoLibraryQRScannerViewController.swift
  • app/ios/QRScannerBridge.swift
  • app/ios/Self.xcodeproj/project.pbxproj
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to native/ios/**/*.{swift} : iOS NFC: implement custom PassportReader as a Swift module
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to src/navigation/**/*.{ts,tsx} : Use react-navigation/native with createStaticNavigation for type-safe navigation

Applied to files:

  • app/src/navigation/home.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to src/navigation/**/*.{ts,tsx} : Set platform-specific initial routes: web → Home, mobile → Splash

Applied to files:

  • app/src/navigation/home.ts
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/navigation/home.ts
📚 Learning: 2025-07-16T02:20:44.173Z
Learnt from: transphorm
PR: selfxyz/self#636
File: app/src/components/native/QRCodeScanner.tsx:135-142
Timestamp: 2025-07-16T02:20:44.173Z
Learning: In app/src/components/native/QRCodeScanner.tsx, the Android camera dimension multipliers (screenWidth * 3 and screenHeight * 2) are intentionally set to these values and should not be changed. These multipliers are correct and any visual issues with black areas in the camera preview are caused by other factors, not the dimension calculations.

Applied to files:

  • app/src/utils/qrScanner.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Use custom hooks for complex state (useModal, useHapticNavigation)

Applied to files:

  • app/src/screens/system/LaunchScreen.tsx
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to native/ios/**/*.{swift} : iOS NFC: implement custom PassportReader as a Swift module

Applied to files:

  • app/ios/Self.xcodeproj/project.pbxproj
🧬 Code graph analysis (8)
app/src/navigation/home.ts (1)
app/src/components/NavBar/AadhaarNavBar.tsx (1)
  • AadhaarNavBar (16-89)
app/src/components/NavBar/AadhaarNavBar.tsx (5)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/haptic/index.ts (1)
  • buttonTap (18-18)
app/src/utils/colors.ts (3)
  • slate100 (33-33)
  • black (8-8)
  • slate300 (37-37)
app/src/components/NavBar/BaseNavBar.tsx (1)
  • NavBar (128-133)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
common/src/utils/aadhaar/assets/dataInput.d.ts (1)
common/src/utils/aadhaar/assets/dataInput.ts (1)
  • testQRData (1-4)
app/src/utils/qrScanner.ts (3)
app/android/react-native-passport-reader/index.android.js (1)
  • NativeModules (5-5)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
app/src/screens/AppScreen.tsx (1)
  • useUserStore (16-106)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (5)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/colors.ts (8)
  • slate100 (33-33)
  • slate200 (35-35)
  • slate500 (43-43)
  • slate400 (39-39)
  • white (59-59)
  • slate50 (41-41)
  • slate300 (37-37)
  • black (8-8)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
app/src/screens/system/LaunchScreen.tsx (3)
app/src/components/buttons/AbstractButton.tsx (1)
  • AbstractButton (38-89)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • AppEvents (5-12)
app/src/utils/colors.ts (2)
  • white (59-59)
  • black (8-8)
app/src/screens/prove/QRCodeViewFinderScreen.tsx (4)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • ProofEvents (105-165)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
app/src/utils/qrScanner.ts (2)
  • scanQRCodeFromPhotoLibrary (40-46)
  • isQRScannerPhotoLibraryAvailable (58-60)
app/src/components/buttons/SecondaryButton.tsx (1)
  • SecondaryButton (12-32)
app/ios/QRScannerBridge.swift (1)
app/src/utils/qrScanner.ts (1)
  • scanQRCodeFromPhotoLibrary (40-46)
🪛 GitHub Actions: Mobile CI
app/src/navigation/home.ts

[error] 5-5: simple-import-sort/imports: Run autofix to sort these imports.

app/src/components/NavBar/AadhaarNavBar.tsx

[warning] 7-7: ESLint: 'Text' is defined but never used. (@typescript-eslint/no-unused-vars)


[warning] 12-12: ESLint: 'slate200' is defined but never used. (@typescript-eslint/no-unused-vars)


[warning] 12-12: ESLint: 'white' is defined but never used. (@typescript-eslint/no-unused-vars)


[warning] 80-80: prettier/prettier: Replace inline formatting with multiline formatting.


[warning] 82-82: prettier/prettier: Replace inline formatting with multiline formatting.


[warning] 83-83: prettier/prettier: Replace inline formatting with multiline formatting.


[warning] 84-84: prettier/prettier: Replace inline formatting with multiline formatting.

🪛 GitHub Check: build-deps
app/src/components/NavBar/AadhaarNavBar.tsx

[warning] 84-84:
Replace ·flex={1}·height={4}·backgroundColor={slate300}·borderRadius={2} with ⏎············flex={1}⏎············height={4}⏎············backgroundColor={slate300}⏎············borderRadius={2}⏎·········


[warning] 83-83:
Replace ·flex={1}·height={4}·backgroundColor={slate300}·borderRadius={2} with ⏎············flex={1}⏎············height={4}⏎············backgroundColor={slate300}⏎············borderRadius={2}⏎·········


[warning] 82-82:
Replace ·flex={1}·height={4}·backgroundColor="#00D4FF"·borderRadius={2} with ⏎············flex={1}⏎············height={4}⏎············backgroundColor="#00D4FF"⏎············borderRadius={2}⏎·········


[warning] 80-80:
Replace ·paddingHorizontal={20}·paddingBottom={15}·backgroundColor={slate100} with ⏎········paddingHorizontal={20}⏎········paddingBottom={15}⏎········backgroundColor={slate100}⏎······


[warning] 12-12:
'white' is defined but never used


[warning] 12-12:
'slate200' is defined but never used


[warning] 7-7:
'Text' is defined but never used

app/src/utils/qrScanner.ts

[failure] 63-63:
Too many blank lines at the end of file. Max of 0 allowed


[failure] 62-62:
Expected QRScanner before isQRScannerPhotoLibraryAvailable


[failure] 51-51:
Expected isQRScannerCameraAvailable before scanQRCodeFromPhotoLibrary


[failure] 40-40:
Expected scanQRCodeFromPhotoLibrary before scanQRCodeWithCamera

app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[failure] 5-5:
Run autofix to sort these imports!

🪛 GitHub Actions: Common CI
common/src/utils/aadhaar/assets/dataInput.d.ts

[warning] 1-1: Prettier formatting issues detected in src/utils/aadhaar/assets/dataInput.d.ts. Run 'Prettier --write' to fix.

⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e-ios
🔇 Additional comments (14)
app/src/screens/system/LaunchScreen.tsx (1)

27-27: LGTM: Aadhaar navigation handler added

Hooking AadhaarUpload via useHapticNavigation is consistent with the existing pattern.

app/src/components/NavBar/AadhaarNavBar.tsx (1)

30-87: LGTM: Solid header implementation with safe-area and progress segments

Structure, haptics, and styling align with existing NavBar patterns.

app/src/screens/dev/DevSettingsScreen.tsx (1)

127-127: LGTM: Dev screen added to selector

Adding AadhaarUpload improves testability and QA access.

app/ios/Self.xcodeproj/project.pbxproj (2)

21-21: LGTM: PhotoLibraryQRScannerViewController added to target and groups

File reference and build phase wiring look correct.

Also applies to: 61-61, 107-107, 411-411


792-792: Confirm OTHER_LDFLAGS change at the project level

Switched from array to a string "$(inherited) ". Ensure this doesn’t override target-level flags in future merges (e.g., -ObjC, -lc++), which are still set at the target. Prefer keeping consistent array form for safety.

-				OTHER_LDFLAGS = "$(inherited)  ";
+				OTHER_LDFLAGS = (
+					"$(inherited)",
+				);

Also applies to: 882-882

app/src/navigation/home.ts (1)

53-60: LGTM: AadhaarUpload route registered with custom header

Route config and header wiring look correct.

app/ios/QRScannerBridge.m (1)

17-18: LGTM: Promise-based photo-library scanning method exported

Signature matches the existing scan method; aligns with RN bridge expectations.

app/ios/QRScannerBridge.swift (1)

13-14: Imports look fine.

No issues from adding UIKit/CoreImage here.

app/src/screens/prove/QRCodeViewFinderScreen.tsx (3)

182-183: Copy update LGTM.

Conditional hinting about the gallery option improves UX.


32-33: Import LGTM.

Platform-aware gating via qrScanner util is appropriate.


117-145: Remove duplicate QR_SCAN_REQUESTED fire and strengthen cancel check

  • Drop trackEvent={ProofEvents.QR_SCAN_REQUESTED} on the SecondaryButton to avoid firing both legacy (AbstractButton) and SDK events; rely on the manual call in onPhotoLibraryPress.
  • In onPhotoLibraryPress, guard against user cancellation with:
    if (
      (error as any)?.code === 'USER_CANCELLED' ||
      (error instanceof Error && error.message.toLowerCase().includes('cancelled'))
    ) {
      return;
    }
    Verify that the native QR scanner bridge indeed rejects with code === 'USER_CANCELLED'.
app/ios/PhotoLibraryQRScannerViewController.swift (1)

18-22: Info.plist usage description and bridge export verified
NSPhotoLibraryUsageDescription is present in OpenPassport/Info.plist and scanQRCodeFromPhotoLibrary is exposed in QRScannerBridge.m.

app/src/utils/qrScanner.ts (2)

28-34: Validate native return types and cancel semantics

If the iOS module can resolve null (e.g., user cancels or no QR detected), these functions should reflect that in their types or normalize to a consistent rejection. Please verify the native contract and adjust to Promise<string | null> or reject with a distinct cancel code to prevent ambiguous handling downstream.

Also applies to: 40-46


40-40: Fix CI failures: reorder declarations/exports and trim EOF newline

The build-deps check is blocking. Reorder to satisfy “Expected … before …” and remove the trailing blank line.

Apply:

@@
-/**
- * Scans QR code using device camera
- * @returns Promise that resolves with the QR code content
- */
-export const scanQRCodeWithCamera = async (): Promise<string> => {
-  if (!QRScanner?.scanQRCode) {
-    throw new Error('QR Scanner not available on this platform');
-  }
-
-  return await QRScanner.scanQRCode();
-};
+/**
+ * Check if QR scanner camera is available
+ */
+export const isQRScannerCameraAvailable = (): boolean => {
+  return QRScanner?.scanQRCode != null;
+};
 
 /**
- * Scans QR code from photo library
- * @returns Promise that resolves with the QR code content
+ * Check if QR scanner photo library is available
  */
-export const scanQRCodeFromPhotoLibrary = async (): Promise<string> => {
-  if (!QRScanner?.scanQRCodeFromPhotoLibrary) {
-    throw new Error('QR Scanner photo library not available on this platform');
-  }
-
-  return await QRScanner.scanQRCodeFromPhotoLibrary();
-};
+export { QRScanner };
+
+export const isQRScannerPhotoLibraryAvailable = (): boolean => {
+  return QRScanner?.scanQRCodeFromPhotoLibrary != null;
+};
 
 /**
- * Check if QR scanner camera is available
+ * Scans QR code from photo library
+ * @returns Promise that resolves with the QR code content
  */
-export const isQRScannerCameraAvailable = (): boolean => {
-  return QRScanner?.scanQRCode != null;
-};
+export const scanQRCodeFromPhotoLibrary = async (): Promise<string> => {
+  if (!QRScanner?.scanQRCodeFromPhotoLibrary) {
+    throw new Error('QR Scanner photo library not available on this platform');
+  }
+  return await QRScanner.scanQRCodeFromPhotoLibrary();
+};
 
-/**
- * Check if QR scanner photo library is available
- */
-export const isQRScannerPhotoLibraryAvailable = (): boolean => {
-  return QRScanner?.scanQRCodeFromPhotoLibrary != null;
-};
+/**
+ * Scans QR code using device camera
+ * @returns Promise that resolves with the QR code content
+ */
+export const scanQRCodeWithCamera = async (): Promise<string> => {
+  if (!QRScanner?.scanQRCode) {
+    throw new Error('QR Scanner not available on this platform');
+  }
+  return await QRScanner.scanQRCode();
+};
@@
-export { QRScanner };
-
-
+```


Also applies to: 51-51, 62-63

<details>
<summary>⛔ Skipped due to learnings</summary>

Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{/*.test.{ts,tsx},/tests/**/*.{ts,tsx}} : Verify extractMRZInfo() using published sample MRZ strings (e.g., ICAO examples)


</details>

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +18 to +24
import Foundation
import UIKit
import CoreImage
import Photos

class PhotoLibraryQRScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var completionHandler: ((String) -> Void)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Adopt PhotosUI and update protocol conformance.

Add PhotosUI and conform to PHPickerViewControllerDelegate:

 import Foundation
 import UIKit
 import CoreImage
 import Photos
+import PhotosUI
 
-class PhotoLibraryQRScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
+class PhotoLibraryQRScannerViewController: UIViewController, PHPickerViewControllerDelegate, UINavigationControllerDelegate {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import Foundation
import UIKit
import CoreImage
import Photos
class PhotoLibraryQRScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var completionHandler: ((String) -> Void)?
import Foundation
import UIKit
import CoreImage
import Photos
import PhotosUI
class PhotoLibraryQRScannerViewController: UIViewController, PHPickerViewControllerDelegate, UINavigationControllerDelegate {
var completionHandler: ((String) -> Void)?

Comment on lines +27 to +31
override func viewDidLoad() {
super.viewDidLoad()
checkPhotoLibraryPermissionAndPresentPicker()
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Switch to PHPicker on load.

   override func viewDidLoad() {
     super.viewDidLoad()
-    checkPhotoLibraryPermissionAndPresentPicker()
+    presentPHPicker()
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
override func viewDidLoad() {
super.viewDidLoad()
checkPhotoLibraryPermissionAndPresentPicker()
}
override func viewDidLoad() {
super.viewDidLoad()
presentPHPicker()
}

Comment on lines +32 to +53
private func checkPhotoLibraryPermissionAndPresentPicker() {
let status = PHPhotoLibrary.authorizationStatus()

switch status {
case .authorized, .limited:
presentImagePicker()
case .notDetermined:
PHPhotoLibrary.requestAuthorization { [weak self] status in
DispatchQueue.main.async {
if status == .authorized || status == .limited {
self?.presentImagePicker()
} else {
self?.handlePermissionDenied()
}
}
}
case .denied, .restricted:
handlePermissionDenied()
@unknown default:
handlePermissionDenied()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use PHPicker (no permission prompt) instead of legacy permission flow.

UIImagePickerController + PHPhotoLibrary.requestAuthorization() is legacy and increases friction. PHPickerViewController requires no permission, aligns with modern privacy, and reduces denial-path errors.

Replace the permission block with a PHPicker presenter:

-  private func checkPhotoLibraryPermissionAndPresentPicker() {
-    let status = PHPhotoLibrary.authorizationStatus()
-    switch status {
-    case .authorized, .limited:
-      presentImagePicker()
-    case .notDetermined:
-      PHPhotoLibrary.requestAuthorization { [weak self] status in
-        DispatchQueue.main.async {
-          if status == .authorized || status == .limited {
-            self?.presentImagePicker()
-          } else {
-            self?.handlePermissionDenied()
-          }
-        }
-      }
-    case .denied, .restricted:
-      handlePermissionDenied()
-    @unknown default:
-      handlePermissionDenied()
-    }
-  }
+  private func presentPHPicker() {
+    var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
+    config.filter = .images
+    config.selectionLimit = 1
+    let picker = PHPickerViewController(configuration: config)
+    picker.delegate = self
+    present(picker, animated: true)
+  }

And in viewDidLoad call presentPHPicker() instead of the permission gate (see diff in next comment).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private func checkPhotoLibraryPermissionAndPresentPicker() {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized, .limited:
presentImagePicker()
case .notDetermined:
PHPhotoLibrary.requestAuthorization { [weak self] status in
DispatchQueue.main.async {
if status == .authorized || status == .limited {
self?.presentImagePicker()
} else {
self?.handlePermissionDenied()
}
}
}
case .denied, .restricted:
handlePermissionDenied()
@unknown default:
handlePermissionDenied()
}
}
private func presentPHPicker() {
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
config.filter = .images
config.selectionLimit = 1
let picker = PHPickerViewController(configuration: config)
picker.delegate = self
present(picker, animated: true)
}
🤖 Prompt for AI Agents
In app/ios/PhotoLibraryQRScannerViewController.swift around lines 32 to 53,
replace the legacy PHPhotoLibrary.authorizationStatus() +
UIImagePickerController flow with a PHPicker-based presenter: remove the
permission switch and requestAuthorization usage and implement a
presentPHPicker() helper that configures a PHPickerConfiguration (set filter to
images and selectionLimit as needed), creates a PHPickerViewController with a
delegate, and presents it on the main thread; update viewDidLoad to call
presentPHPicker() instead of checkPhotoLibraryPermissionAndPresentPicker(), and
ensure the delegate handles picked UIImage results and denial paths where
appropriate.

Comment on lines +55 to +61
private func presentImagePicker() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.mediaTypes = ["public.image"]
present(imagePicker, animated: true, completion: nil)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove UIImagePicker presenter (replaced by PHPicker).

The presentImagePicker() flow becomes obsolete with PHPicker. Delete this method.

🤖 Prompt for AI Agents
In app/ios/PhotoLibraryQRScannerViewController.swift around lines 55 to 61, the
presentImagePicker() method that creates and presents a UIImagePickerController
is obsolete because the project uses PHPicker; remove this entire method and any
direct references/calls to presentImagePicker(), and if those calls exist
replace them with the PHPicker-based flow already implemented (or call the
existing PHPicker wrapper) so there are no unused UIImagePickerController
presenters or dead method references left.

Comment on lines +75 to +91
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
picker.dismiss(animated: true) { [weak self] in
guard let self = self else { return }

if let selectedImage = info[.originalImage] as? UIImage {
self.detectQRCode(in: selectedImage)
} else {
let error = NSError(
domain: "QRScannerError",
code: 1002,
userInfo: [NSLocalizedDescriptionKey: "Failed to load the selected image."]
)
self.errorHandler?(error)
self.dismiss(animated: true, completion: nil)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace UIImagePicker delegates with PHPicker delegate and handle cancellation.

-  func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
-    picker.dismiss(animated: true) { [weak self] in
-      guard let self = self else { return }
-      if let selectedImage = info[.originalImage] as? UIImage {
-        self.detectQRCode(in: selectedImage)
-      } else {
-        let error = NSError(
-          domain: "QRScannerError",
-          code: 1002,
-          userInfo: [NSLocalizedDescriptionKey: "Failed to load the selected image."]
-        )
-        self.errorHandler?(error)
-        self.dismiss(animated: true, completion: nil)
-      }
-    }
-  }
-
-  func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
-    picker.dismiss(animated: true) { [weak self] in
-      let error = NSError(
-        domain: "QRScannerError",
-        code: 1003,
-        userInfo: [NSLocalizedDescriptionKey: "User cancelled photo selection."]
-      )
-      self?.errorHandler?(error)
-      self?.dismiss(animated: true, completion: nil)
-    }
-  }
+  func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
+    picker.dismiss(animated: true) { [weak self] in
+      guard let self = self else { return }
+      guard let provider = results.first?.itemProvider else {
+        let error = NSError(
+          domain: "QRScannerError",
+          code: 1003,
+          userInfo: [NSLocalizedDescriptionKey: "User cancelled photo selection."]
+        )
+        self.errorHandler?(error)
+        self.dismiss(animated: true)
+        return
+      }
+      if provider.canLoadObject(ofClass: UIImage.self) {
+        provider.loadObject(ofClass: UIImage.self) { object, loadError in
+          DispatchQueue.main.async {
+            if let loadError = loadError {
+              let error = NSError(
+                domain: "QRScannerError",
+                code: 1002,
+                userInfo: [NSLocalizedDescriptionKey: loadError.localizedDescription]
+              )
+              self.errorHandler?(error)
+              self.dismiss(animated: true)
+            } else if let image = object as? UIImage {
+              self.detectQRCode(in: image)
+            } else {
+              let error = NSError(
+                domain: "QRScannerError",
+                code: 1002,
+                userInfo: [NSLocalizedDescriptionKey: "Failed to load the selected image."]
+              )
+              self.errorHandler?(error)
+              self.dismiss(animated: true)
+            }
+          }
+        }
+      } else {
+        let error = NSError(
+          domain: "QRScannerError",
+          code: 1002,
+          userInfo: [NSLocalizedDescriptionKey: "Unsupported item type."]
+        )
+        self.errorHandler?(error)
+        self.dismiss(animated: true)
+      }
+    }
+  }

Also applies to: 93-103

🤖 Prompt for AI Agents
In app/ios/PhotoLibraryQRScannerViewController.swift around lines 75-91 (and
similarly 93-103), you are using UIImagePickerController delegates; replace them
with PHPickerViewController and implement PHPickerViewControllerDelegate
methods: create a PHPickerConfiguration (filter images, selectionLimit 1),
present PHPickerViewController, and implement picker(_:didFinishPicking:) to
dismiss the picker, extract the UIImage from the PHPickerResult's itemProvider
(loadObject of class UIImage), then call detectQRCode(in:) on the loaded image;
also handle cancellation or empty results by dismissing and invoking
errorHandler? with a suitable NSError (e.g., code 1002) so cancellation/failed
loads are reported and no retain cycles occur (use [weak self] where
appropriate).

Comment on lines 40 to 67
<YStack paddingHorizontal={25} backgroundColor={white} paddingBottom={bottom + extraYPadding + 35} paddingTop={25}>
<XStack gap="$3" alignItems="stretch">
<YStack flex={1}>
<PrimaryButton>Upload QR code</PrimaryButton>
</YStack>
<Button
aspectRatio={1}

backgroundColor={slate200}
borderRadius="$2"
justifyContent="center"
alignItems="center"
pressStyle={{
backgroundColor: slate50,
scale: 0.98,
}}
hoverStyle={{
backgroundColor: slate300,
}}
onPress={() => {
// Handle QR scanner action
console.log('Open QR scanner');
}}
>
<ScanIcon width={28} height={28} color={black} />
</Button>
</XStack>
</YStack>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wire buttons to actual QR flows (photo library + camera) instead of no-ops

  • “Upload QR code” currently does nothing.
  • The scan icon only logs to console.

Hook these to the new bridge/util to complete the flow and surface errors.

-          <YStack flex={1}>
-            <PrimaryButton>Upload QR code</PrimaryButton>
-          </YStack>
+          <YStack flex={1}>
+            <PrimaryButton onPress={handleUploadQRPress}>Upload QR code</PrimaryButton>
+          </YStack>
@@
-            onPress={() => {
-              // Handle QR scanner action
-              console.log('Open QR scanner');
-            }}
+            onPress={onScanPress}

Add the following supporting code (outside the selected range):

// imports
import useHapticNavigation from '@/hooks/useHapticNavigation';
import { scanQRCodeFromPhotoLibrary } from '@/utils/qrScanner';

// inside component
const onScanPress = useHapticNavigation('QRCodeViewFinder');

async function handleUploadQRPress() {
  try {
    const qr = await scanQRCodeFromPhotoLibrary();
    // TODO: route or parse QR for Aadhaar flow
  } catch (e) {
    // TODO: show toast/alert for cancellation or parse failure
  }
}
🤖 Prompt for AI Agents
In app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx around lines 40-67,
the "Upload QR code" button and scan icon are no-ops; wire them to the QR
scanning utilities and haptic hook: import useHapticNavigation and
scanQRCodeFromPhotoLibrary at the top of the file, create an onScanPress using
useHapticNavigation('QRCodeViewFinder'), implement async
handlers—handleUploadQRPress to call scanQRCodeFromPhotoLibrary() and
handleScanPress to open the camera scanner (or reuse bridge util)—wrap both in
try/catch to surface errors via toast/alert, and replace the current onPress
implementations to call these handlers so the upload button launches
photo-library scanning and the icon triggers the camera viewfinder.

Comment on lines 91 to 99
<AbstractButton
trackEvent={AppEvents.GET_STARTED}
onPress={onAadhaarPress}
bgColor={white}
color={black}
testID="launch-get-started-button"
>
I have an Aadhaar Card
</AbstractButton>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Differentiate analytics and testID for the Aadhaar CTA

Using the same event (AppEvents.GET_STARTED) and duplicate testID as the passport button makes analytics ambiguous and E2E brittle. Emit a distinct event label and a unique testID.

-          <AbstractButton
-            trackEvent={AppEvents.GET_STARTED}
+          <AbstractButton
+            trackEvent="Get Started - Aadhaar"
             onPress={onAadhaarPress}
             bgColor={white}
             color={black}
-            testID="launch-get-started-button"
+            testID="launch-get-started-aadhaar-button"
           >
             I have an Aadhaar Card
           </AbstractButton>

Note: AbstractButton strips the category before the first colon; avoid colons in the label to preserve “Aadhaar” in analytics.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<AbstractButton
trackEvent={AppEvents.GET_STARTED}
onPress={onAadhaarPress}
bgColor={white}
color={black}
testID="launch-get-started-button"
>
I have an Aadhaar Card
</AbstractButton>
<AbstractButton
trackEvent="Get Started - Aadhaar"
onPress={onAadhaarPress}
bgColor={white}
color={black}
testID="launch-get-started-aadhaar-button"
>
I have an Aadhaar Card
</AbstractButton>
🤖 Prompt for AI Agents
In app/src/screens/system/LaunchScreen.tsx around lines 91 to 99, the Aadhaar
CTA reuses AppEvents.GET_STARTED and the same testID as the passport CTA which
confuses analytics and E2E tests; change the trackEvent to a distinct event
(e.g., AppEvents.GET_STARTED_AADHAAR or a new constant) and give the button a
unique testID such as "launch-get-started-aadhaar-button"; ensure the event
label passed to AbstractButton contains no colon (so "Aadhaar" is preserved) and
update any tests or event enum imports accordingly.

Comment on lines 13 to 22
if (Platform.OS === 'ios') {
QRScanner = NativeModules.QRScannerBridge || null;
} else if (Platform.OS === 'android') {
// Android implementation would go here if needed
// For now, we'll focus on iOS
QRScanner = null;
} else {
console.warn('QRScanner: Unsupported platform');
QRScanner = null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Android path disabled—verify callers or add a safe fallback

On Android, QRScanner is null; calling scanQRCodeWithCamera/scanQRCodeFromPhotoLibrary will reject. Confirm all call sites gate with isQRScannerCameraAvailable/isQRScannerPhotoLibraryAvailable, or provide an Android fallback (e.g., RNPassportReader) to avoid regressions.

Run to locate risky call sites and existing Android reader usage:


🏁 Script executed:

#!/bin/bash
# Where are the new APIs called?
rg -nP -C3 --glob '!**/node_modules/**' '\bscanQRCodeWithCamera\b|\bscanQRCodeFromPhotoLibrary\b'

# Do we already have an Android reader?
rg -nP -C3 --glob '!**/node_modules/**' '\bRNPassportReader\b|\bNativeModules\.RNPassportReader\b'

Length of output: 297


The previous ripgrep didn’t hit any files—let’s run a focused search in app/src to locate all scanner calls and check for an Android fallback:


🏁 Script executed:

#!/bin/bash
# Find all QR scanner API call sites in source
rg -n --no-ignore --color never 'scanQRCodeWithCamera|scanQRCodeFromPhotoLibrary' -C3 app/src

# Check for existing Android reader fallback (RNPassportReader)
rg -n --no-ignore --color never 'RNPassportReader' -C3 app/src

Length of output: 3872


Guard Android QRScanner calls or provide a fallback
In QRCodeViewFinderScreen.tsx (line 127) scanQRCodeFromPhotoLibrary() is invoked without checking isQRScannerPhotoLibraryAvailable()—on Android this will throw since QRScanner is null. Wrap these calls in an availability check or ship an Android fallback (e.g. via RNPassportReader).

🤖 Prompt for AI Agents
In app/src/utils/qrScanner.ts around lines 13 to 22, the module sets QRScanner
to null on Android which causes callers (e.g., QRCodeViewFinderScreen.tsx line
127) to throw when calling scanQRCodeFromPhotoLibrary(); update the file to
either export an isQRScannerPhotoLibraryAvailable() function that returns false
on Android or implement a platform-specific fallback (e.g., wire
RNPassportReader or another Android-compatible implementation) and ensure
exported scanQRCodeFromPhotoLibrary() safely guards against QRScanner being null
by rejecting/throwing a clear error or delegating to the fallback; then update
callers to check isQRScannerPhotoLibraryAvailable() before invoking
photo-library scanning or handle the rejection accordingly.

Comment on lines 1 to 3
export declare const testQRData: {
testQRData: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove redundant .d.ts next to .ts to avoid duplicate declarations

This declaration shadows the existing dataInput.ts export and can trigger duplicate identifier/type drift. Keep the .ts source and let the build emit types.

Apply this minimal stopgap if deletion must wait:

-export declare const testQRData: {
-    testQRData: string;
-};
+// Intentionally left empty; types come from dataInput.ts
+export {};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export declare const testQRData: {
testQRData: string;
};
// common/src/utils/aadhaar/assets/dataInput.d.ts
// Intentionally left empty; types come from dataInput.ts
export {};
🧰 Tools
🪛 GitHub Actions: Common CI

[warning] 1-1: Prettier formatting issues detected in src/utils/aadhaar/assets/dataInput.d.ts. Run 'Prettier --write' to fix.

🤖 Prompt for AI Agents
common/src/utils/aadhaar/assets/dataInput.d.ts lines 1-3: this .d.ts duplicates
the export from dataInput.ts and causes duplicate identifier/type drift; fix by
deleting this .d.ts file so the .ts source is the single source of truth, or if
deletion must wait, replace its export with an empty module declaration (no
exported symbols) to avoid shadowing the .ts export.

@transphorm transphorm changed the title add iOS qrcode opener and aadhaar screen SELF-725: add iOS qrcode opener and aadhaar screen Sep 11, 2025
remicolin and others added 5 commits September 16, 2025 15:00
* add image-picker android

* fix validation
…haarNavBar with dynamic progress indication

- Added AadhaarUploadedSuccessScreen and AadhaarUploadErrorScreen components for handling upload outcomes.
- Updated AadhaarNavBar to reflect current upload step with dynamic progress bar.
- Integrated new screens into navigation flow for Aadhaar upload process.
- Introduced blue check and warning SVG icons for visual feedback on success and error states.
* feat: generate mock aadhar

* add yarn.lock

* update yarn.lock
@gitguardian
Copy link

gitguardian bot commented Sep 17, 2025

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
21022104 Triggered Generic Private Key fdcb6d9 common/src/mock_certificates/aadhaar/mockAadhaarCert.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

remicolin and others added 8 commits September 17, 2025 16:22
* Register mock aadhar

* fix ofac

* temp: generate name

* fix dob
- Integrated Aadhaar icon and conditional rendering in IdCardLayout.
- Updated AadhaarUploadScreen to process QR codes and store Aadhaar data.
- Modified navigation and button text in AadhaarUploadedSuccessScreen.
- Added mock data generation for Aadhaar in the mobile SDK.
- Updated ManageDocumentsScreen to include Aadhaar document type.
- Enhanced error handling and validation for Aadhaar QR code processing.
- Added utility functions for Aadhaar data extraction and commitment processing.
* Fix - android aadhar qr scanner

* fixes

* update text
@remicolin remicolin marked this pull request as ready for review September 19, 2025 18:48
cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 29

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (12)
common/src/utils/types.ts (2)

39-46: Type safety regression: documentType widened to string.

This weakens compile-time guarantees across the app. Keep it as DocumentType.

-  documentType: string; // passport, mock_passport, id_card, etc.
+  documentType: DocumentType; // strictly typed

56-76: Missing core types required by guidelines (IdentityCommitment, DSCKeyCommitment, VerificationConfig).

Define and export these here to align consumers and avoid ad-hoc shapes.

@@
 export type IDDocument = AadhaarData | PassportData;
+
+// Core commitments/config (shared across app/common)
+export interface IdentityCommitment {
+  // Poseidon hash (hex string prefixed with 0x)
+  commitment: string;
+  // Domain-separated nullifier (hex string prefixed with 0x)
+  nullifier: string;
+  // UTC epoch seconds
+  timestamp: number;
+  // Circuit version identifier
+  version: string;
+  // Restrict per spec: only MRZ-based docs use this today
+  documentType: 'passport' | 'eu_id_card';
+}
+
+export interface DSCKeyCommitment {
+  // Poseidon hash of the DSC public key (0x...)
+  publicKeyHash: string;
+  // Certificate chain hashes (leaf -> root), hex strings
+  certificateChain: string[];
+  // Current revocation status
+  revocationStatus: boolean;
+  // Country code (ISO 3166-1 alpha-2)
+  issuer: string;
+}
+
+export interface VerificationConfig {
+  // Circuit semver (e.g., "1.2.0")
+  circuitVersion: string;
+  // Business/compliance rules applied at verify time
+  complianceRules: string[];
+  // Validity window in seconds (default 24h)
+  timeWindow: number;
+  // Allowed clock drift in seconds (±5min)
+  clockDrift: number;
+  // Trust anchors (CSCA or Aadhaar pubkeys)
+  trustAnchors: string[];
+  // Revocation roots (CRL/OCSP or equivalent)
+  revocationRoots: string[];
+  // Time source identifier (e.g., "pool.ntp.org")
+  timeSource: string;
+  // Domain separation for nullifiers
+  nullifierScope: string;
+}
app/src/providers/passportDataProvider.tsx (2)

182-204: Fix TS2322: widen context types to accept Aadhaar (IDDocument union).

State assigns functions that now return/accept Aadhaar, but IPassportContext still references PassportData, causing the CI error. Update the interface and call sites to use IDDocument.

Apply these diffs:

@@
-  const getData = useCallback(
-    () => _getSecurely<PassportData>(loadPassportData, str => JSON.parse(str)),
+  const getData = useCallback(
+    () => _getSecurely<IDDocument>(loadPassportData, str => JSON.parse(str)),
     [_getSecurely],
   );
@@
-  const getSelectedData = useCallback(() => {
-    return _getSecurely<PassportData>(
+  const getSelectedData = useCallback(() => {
+    return _getSecurely<IDDocument>(
       () => loadSelectedPassportData(),
       str => JSON.parse(str),
     );
   }, [_getSecurely]);
@@
-  const getPassportDataAndSecret = useCallback(
-    () =>
-      _getSecurely<{ passportData: PassportData; secret: string }>(
+  const getPassportDataAndSecret = useCallback(
+    () =>
+      _getSecurely<{ passportData: IDDocument; secret: string }>(
         loadPassportDataAndSecret,
         str => JSON.parse(str),
       ),
     [_getSecurely],
   );
@@
-  const getSelectedPassportDataAndSecret = useCallback(() => {
-    return _getSecurely<{ passportData: PassportData; secret: string }>(
+  const getSelectedPassportDataAndSecret = useCallback(() => {
+    return _getSecurely<{ passportData: IDDocument; secret: string }>(
       () => loadSelectedPassportDataAndSecret(),
       str => JSON.parse(str),
     );
   }, [_getSecurely]);

And update imports and the context interface:

@@
-import type {
-  AadhaarData,
-  DocumentCatalog,
-  DocumentMetadata,
-  PassportData,
-} from '@selfxyz/common/utils/types';
+import type {
+  AadhaarData,
+  IDDocument,
+  DocumentCatalog,
+  DocumentMetadata,
+  PassportData,
+} from '@selfxyz/common/utils/types';
@@
 interface IPassportContext {
-  getData: () => Promise<{ signature: string; data: PassportData } | null>;
+  getData: () => Promise<{ signature: string; data: IDDocument } | null>;
   getSelectedData: () => Promise<{
-    signature: string;
-    data: PassportData;
+    signature: string;
+    data: IDDocument;
   } | null>;
-  getAllData: () => Promise<{ [service: string]: PassportData }>;
+  getAllData: () => Promise<{ [service: string]: IDDocument }>;
   getAvailableTypes: () => Promise<string[]>;
-  setData: (data: PassportData) => Promise<void>;
+  setData: (data: IDDocument) => Promise<void>;
   getPassportDataAndSecret: () => Promise<{
-    data: { passportData: PassportData; secret: string };
+    data: { passportData: IDDocument; secret: string };
     signature: string;
   } | null>;
   getSelectedPassportDataAndSecret: () => Promise<{
-    data: { passportData: PassportData; secret: string };
+    data: { passportData: IDDocument; secret: string };
     signature: string;
   } | null>;
@@
-  getAllDocuments: () => Promise<{
-    [documentId: string]: { data: PassportData; metadata: DocumentMetadata };
-  }>;
+  getAllDocuments: () => Promise<{
+    [documentId: string]: { data: IDDocument; metadata: DocumentMetadata };
+  }>;

406-433: Propagate IDDocument through direct-load helpers.

Ensure the helpers reflect the union to keep types consistent across consumers.

Apply these diffs:

@@
-export async function loadDocumentByIdDirectlyFromKeychain(
-  documentId: string,
-): Promise<PassportData | null> {
+export async function loadDocumentByIdDirectlyFromKeychain(
+  documentId: string,
+): Promise<IDDocument | null> {
@@
-export async function loadSelectedDocumentDirectlyFromKeychain(): Promise<{
-  data: PassportData;
+export async function loadSelectedDocumentDirectlyFromKeychain(): Promise<{
+  data: IDDocument;
   metadata: DocumentMetadata;
 } | null> {
@@
-export const getAllDocumentsDirectlyFromKeychain = async (): Promise<{
-  [documentId: string]: { data: PassportData; metadata: DocumentMetadata };
+export const getAllDocumentsDirectlyFromKeychain = async (): Promise<{
+  [documentId: string]: { data: IDDocument; metadata: DocumentMetadata };
 }> => {
-  const allDocs: {
-    [documentId: string]: { data: PassportData; metadata: DocumentMetadata };
-  } = {};
+  const allDocs: {
+    [documentId: string]: { data: IDDocument; metadata: DocumentMetadata };
+  } = {};

Also applies to: 530-571, 836-852

common/src/utils/passports/passport.ts (1)

192-206: Unify generateNullifier return type (Aadhaar path returns bigint; passport path may return non-bigint)

nullifierHash() returns bigint; packBytesAndPoseidon result type may differ. Mixed return types break consumers and hashing consistency. Return bigint in all cases.

Apply this diff:

-export function generateNullifier(passportData: IDDocument) {
+export function generateNullifier(passportData: IDDocument): bigint {
   if (isAadhaarDocument(passportData)) {
     return nullifierHash(passportData.extractedFields);
   }
   const signedAttr_shaBytes = hash(
     passportData.passportMetadata.signedAttrHashFunction,
     Array.from(passportData.signedAttr),
     'bytes'
   );
   const signedAttr_packed_hash = packBytesAndPoseidon(
     (signedAttr_shaBytes as number[]).map((byte) => byte & 0xff)
   );
-  return signedAttr_packed_hash;
+  return BigInt(signedAttr_packed_hash);
}

If packBytesAndPoseidon already returns bigint, drop the BigInt() cast and annotate accordingly.

app/src/utils/proving/provingMachine.ts (1)

1469-1501: Fix payload type narrowing for disclose/aadhaar

You cast circuitTypeWithDocumentExtension to register/dsc-only union, then rely on runtime value 'disclose'. TypeScript won’t catch mismatches. Pass the correct union including disclose and aadhaar.

Apply this diff:

-        const {
+        const {
           inputs,
           circuitName,
           endpointType,
           endpoint,
           circuitTypeWithDocumentExtension,
         } = await _generateCircuitInputs(
           circuitType as 'disclose' | 'register' | 'dsc',
           secret,
           passportData,
           env,
         );
@@
-        const payload = getPayload(
+        const payload = getPayload(
           inputs,
-          circuitTypeWithDocumentExtension as
-            | 'register_id'
-            | 'dsc_id'
-            | 'register'
-            | 'dsc',
+          circuitTypeWithDocumentExtension as
+            | 'register'
+            | 'register_id'
+            | 'register_aadhaar'
+            | 'dsc'
+            | 'dsc_id'
+            | 'disclose'
+            | 'disclose_id'
+            | 'disclose_aadhaar',
           circuitName as string,
           endpointType as EndpointType,
           endpoint as string,
           selfApp?.version,
           userDefinedData,
         );
app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java (1)

39-77: Camera permission flow is broken (callback not wired), scanner won’t start after grant

requestPermissions is invoked, but you don’t handle onRequestPermissionsResult via RN’s ActivityEventListener or PermissionAwareActivity. The method defined at Lines 217–231 won’t be called by RN.

Apply this diff to handle permission result:

 private final ActivityEventListener activityEventListener = new BaseActivityEventListener() {
   @Override
   public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
     ...
   }
+
+  @Override
+  public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions, int[] grantResults) {
+    if (requestCode == PERMISSION_REQUEST_CAMERA) {
+      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+        Activity currentActivity = getCurrentActivity();
+        if (currentActivity != null) {
+          startQRScanner(currentActivity);
+        }
+      } else if (scanPromise != null) {
+        scanPromise.reject("PERMISSION_DENIED", "Camera permission was denied");
+        scanPromise = null;
+      }
+    }
+  }
 };

And remove the unused public onRequestPermissionsResult method at Lines 217–231 to avoid confusion.

-    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-      ...
-    }
common/src/utils/passports/validate.ts (4)

126-139: Guard against non-passport input; function will crash for Aadhaar.

checkIfPassportDscIsInTree accepts IDDocument but unconditionally dereferences dsc_parsed/csca_parsed. For Aadhaar this throws.

Apply:

 export async function checkIfPassportDscIsInTree(
-  passportData: IDDocument,
+  passportData: IDDocument,
   dscTree: string
 ): Promise<boolean> {
+  if (passportData.documentCategory !== 'passport') {
+    console.warn('checkIfPassportDscIsInTree called with non-passport document');
+    return false;
+  }
   const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]);

143-176: Hard crash risk: non-null assertion on passportMetadata.

passportMetadata! will throw if caller forgets to pre-check. Add explicit guard with actionable error.

Apply:

 export function generateCommitmentInApp(
   secret: string,
   attestation_id: string,
   passportData: PassportData,
   alternativeCSCA: AlternativeCSCA
 ) {
+  if (!passportData.passportMetadata) {
+    throw new Error('generateCommitmentInApp: missing passportMetadata');
+  }
   const dg1_packed_hash = packBytesAndPoseidon(formatMrz(passportData.mrz));

235-269: Avoid logging sensitive identifiers; tighten error handling.

  • console.log('checking for nullifier', ...) leaks a linkable identifier.
  • Typo in erorr hinders debugging.

Apply:

-  console.log('checking for nullifier', nullifierHex, attestationId);
+  // Avoid logging nullifier/attestation_id in production; consider debug flag if needed.
@@
-  } catch (e) {
-    const erorr = e instanceof Error ? e : new Error(String(e));
+  } catch (e) {
+    const err = e instanceof Error ? e : new Error(String(e));
@@
-      `isDocumentNullified request failed: ${erorr.name} ${erorr.message} \n ${erorr.stack}`
+      `isDocumentNullified request failed: ${err.name} ${err.message} \n ${err.stack}`
     );

235-308: Privacy spec gap: domain-separated nullifier is required.

Per guidelines, nullifiers must be domain-separated (e.g., by nullifierScope). Current Aadhaar nullifier lacks scope.

Proposed direction:

  • Extend nullifierHash(...) to accept a scope and mix it (e.g., Poseidon with a constant domain tag).
  • Thread nullifierScope from a VerificationConfig into all call sites (Aadhaar and passport).

I can draft a migration PR plan if helpful.

common/src/utils/aadhaar/mockData.ts (1)

438-446: RSA signature verification likely incorrect input type to node-forge.

publicKey.verify expects a byte-string/ByteBuffer; you pass a Uint8Array. This will cause verification failures.

Apply:

-        const isValid = publicKey.verify(md.digest().getBytes(), signatureBytes);
+        const signatureStr = forge.util.binary.raw.encode(signatureBytes);
+        const isValid = publicKey.verify(md.digest().getBytes(), signatureStr);
♻️ Duplicate comments (4)
app/src/screens/dev/CreateMockScreen.tsx (1)

386-436: Fix: wrong disable condition allows negative expiry years.

Decrease button uses age <= 0 instead of expiryYears <= 0; users can drive expiry negative.

Apply:

-                    disabled={age <= 0}
+                    disabled={expiryYears <= 0}
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (3)

266-266: Fix typo in user-facing text: "mAadaar" → "mAadhaar"

The official app name should be spelled correctly in the UI.

-          Generate a QR code from the mAadaar app
+          Generate a QR code from the mAadhaar app

22-22: Fix import path: use actual react-native-safe-area-context

Importing from the mocks directory will cause runtime failures in production builds. Use the actual library import.

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

262-263: Replace unsupported CSS logical border properties

borderBlockWidth and borderBlockColor are not valid React Native style properties and will be ignored at runtime.

-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderTopColor={slate200}
🧹 Nitpick comments (5)
app/src/providers/passportDataProvider.tsx (1)

745-752: Harden Keychain storage (access control & secure hardware).

Documents and the catalog should use strongest feasible defaults. This avoids weaker accessibility classes and pushes Android into hardware-backed keystore where available.

Apply these diffs:

@@
-import Keychain from 'react-native-keychain';
+import Keychain from 'react-native-keychain';
+import { Platform } from 'react-native';
@@
 export async function saveDocumentCatalogDirectlyToKeychain(
   catalog: DocumentCatalog,
 ): Promise<void> {
-  await Keychain.setGenericPassword('catalog', JSON.stringify(catalog), {
-    service: 'documentCatalog',
-  });
+  await Keychain.setGenericPassword('catalog', JSON.stringify(catalog), {
+    service: 'documentCatalog',
+    accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
+    securityLevel:
+      Platform.OS === 'android'
+        ? Keychain.SECURITY_LEVEL.SECURE_HARDWARE
+        : undefined,
+  });
 }
@@
 async function storeDocumentDirectlyToKeychain(
   contentHash: string,
   passportData: PassportData | AadhaarData,
 ): Promise<void> {
   await Keychain.setGenericPassword(contentHash, JSON.stringify(passportData), {
     service: `document-${contentHash}`,
+    accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
+    securityLevel:
+      Platform.OS === 'android'
+        ? Keychain.SECURITY_LEVEL.SECURE_HARDWARE
+        : undefined,
   });
 }

Also applies to: 717-723, 44-46

common/src/utils/passports/genMockIdDoc.ts (2)

10-11: Clean up hardcoded test certificates and private keys

Hardcoded test certificates and private keys should be moved to a dedicated test configuration file or constants module, not embedded directly in production code. This improves maintainability and makes it clearer that these are test-only resources.

Consider moving AADHAAR_MOCK_PRIVATE_KEY_PEM and AADHAAR_MOCK_PUBLIC_KEY_PEM to a separate test constants file:

// common/src/utils/aadhaar/testConstants.ts
export const AADHAAR_MOCK_CERTIFICATES = {
  PRIVATE_KEY_PEM: `...`,
  PUBLIC_KEY_PEM: `...`
};

Then import them in this file:

-// Hardcoded Aadhaar test certificates. TODO Move it to correct place.
-const AADHAAR_MOCK_PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----
-...
------END PRIVATE KEY-----
-`;
-
-// TODO: Move it to correct place.
-const AADHAAR_MOCK_PUBLIC_KEY_PEM = `-----BEGIN CERTIFICATE-----
-...
------END CERTIFICATE-----
-`;
+import { AADHAAR_MOCK_CERTIFICATES } from '../aadhaar/testConstants.js';

And update the usage:

-  const qrData = processQRData(
-    AADHAAR_MOCK_PRIVATE_KEY_PEM,
+  const qrData = processQRData(
+    AADHAAR_MOCK_CERTIFICATES.PRIVATE_KEY_PEM,

Also applies to: 116-162


125-126: Remove debug console.log statements

Debug logging statements should be removed from production code. These logs expose internal data processing details and can impact performance.

-  console.log('genMockAadhaarDoc', input);
-  console.log('dateOfBirth', dateOfBirth);
...
-  console.log('qrDataString', qrDataString);
...
-  console.log('qrData.extractedFields', qrData.extractedFields);

Also applies to: 141-141

app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1)

52-52: Remove console.log statements from production code

Debug logging statements should be removed before merging. They expose internal processing details and can impact performance.

Remove all console.log statements throughout the file, including:

  • Line 52: Permission modal initialization
  • Line 69, 83, 93: QR processing steps
  • Line 122-123, 126-127: Data storage
  • Line 168, 172-173, 179-180, etc.: Error handling logs

Consider using a proper logging library with configurable log levels if debug information is needed in production.

Also applies to: 69-69, 83-83, 93-93, 122-123, 126-127, 168-168

common/src/utils/passports/validate.ts (1)

343-351: Follow-up to unused attestation_id in Aadhaar helper: update call site.

If you adopt “Option A” (drop arg), update invocation.

Apply:

-    const result = generateCommitmentInAppAadhaar(
-      secret,
-      AttestationIdHex.aadhaar,
-      passportData as AadhaarData,
-      alternativePublicKeys
-    );
+    const result = generateCommitmentInAppAadhaar(
+      secret,
+      passportData as AadhaarData,
+      alternativePublicKeys
+    );
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef2f6a7 and a33580e.

⛔ Files ignored due to path filters (3)
  • app/src/images/blue_check.svg is excluded by !**/*.svg
  • app/src/images/icons/aadhaar.svg is excluded by !**/*.svg
  • app/src/images/warning.svg is excluded by !**/*.svg
📒 Files selected for processing (39)
  • app/android/app/build.gradle (1 hunks)
  • app/android/app/src/main/AndroidManifest.xml (1 hunks)
  • app/android/app/src/main/java/com/proofofpassportapp/PhotoPickerActivity.java (1 hunks)
  • app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java (5 hunks)
  • app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerPackage.java (1 hunks)
  • app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt (1 hunks)
  • app/android/app/src/main/res/values/styles.xml (1 hunks)
  • app/ios/Self.xcodeproj/project.pbxproj (6 hunks)
  • app/src/components/NavBar/AadhaarNavBar.tsx (1 hunks)
  • app/src/components/homeScreen/idCard.tsx (14 hunks)
  • app/src/hooks/useMockDataForm.ts (2 hunks)
  • app/src/navigation/home.ts (2 hunks)
  • app/src/providers/passportDataProvider.tsx (5 hunks)
  • app/src/screens/dev/CreateMockScreen.tsx (8 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx (1 hunks)
  • app/src/screens/prove/ConfirmBelongingScreen.tsx (2 hunks)
  • app/src/screens/prove/QRCodeViewFinderScreen.tsx (0 hunks)
  • app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx (1 hunks)
  • app/src/screens/recovery/RecoverWithPhraseScreen.tsx (1 hunks)
  • app/src/screens/settings/ManageDocumentsScreen.tsx (1 hunks)
  • app/src/screens/system/LaunchScreen.tsx (2 hunks)
  • app/src/utils/proving/provingMachine.ts (12 hunks)
  • app/src/utils/qrScanner.ts (1 hunks)
  • app/tests/src/navigation.test.ts (1 hunks)
  • common/index.ts (3 hunks)
  • common/src/constants/constants.ts (1 hunks)
  • common/src/utils/aadhaar/mockData.ts (11 hunks)
  • common/src/utils/aadhaar/utils.ts (7 hunks)
  • common/src/utils/circuits/circuitsName.ts (3 hunks)
  • common/src/utils/circuits/registerInputs.ts (4 hunks)
  • common/src/utils/index.ts (4 hunks)
  • common/src/utils/passports/genMockIdDoc.ts (5 hunks)
  • common/src/utils/passports/passport.ts (6 hunks)
  • common/src/utils/passports/validate.ts (6 hunks)
  • common/src/utils/proving.ts (3 hunks)
  • common/src/utils/types.ts (6 hunks)
  • common/tsup.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • app/src/screens/prove/QRCodeViewFinderScreen.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/ios/Self.xcodeproj/project.pbxproj
  • app/src/screens/system/LaunchScreen.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • app/src/screens/settings/ManageDocumentsScreen.tsx
  • app/tests/src/navigation.test.ts
  • app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx
  • app/src/screens/recovery/RecoverWithPhraseScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • common/tsup.config.ts
  • app/src/screens/prove/ConfirmBelongingScreen.tsx
  • common/src/constants/constants.ts
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx
  • app/src/utils/qrScanner.ts
  • common/src/utils/circuits/circuitsName.ts
  • common/index.ts
  • app/src/hooks/useMockDataForm.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • app/src/navigation/home.ts
  • app/src/providers/passportDataProvider.tsx
  • common/src/utils/passports/passport.ts
  • common/src/utils/index.ts
  • common/src/utils/aadhaar/utils.ts
  • app/src/screens/dev/CreateMockScreen.tsx
  • app/src/components/homeScreen/idCard.tsx
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/types.ts
  • common/src/utils/proving.ts
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • common/src/utils/circuits/registerInputs.ts
  • common/src/utils/passports/validate.ts
  • common/src/utils/aadhaar/mockData.ts
  • app/src/components/NavBar/AadhaarNavBar.tsx
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/screens/settings/ManageDocumentsScreen.tsx
  • app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx
  • app/src/screens/recovery/RecoverWithPhraseScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/screens/prove/ConfirmBelongingScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx
  • app/src/utils/qrScanner.ts
  • app/src/hooks/useMockDataForm.ts
  • app/src/navigation/home.ts
  • app/src/providers/passportDataProvider.tsx
  • app/src/screens/dev/CreateMockScreen.tsx
  • app/src/components/homeScreen/idCard.tsx
  • app/src/utils/proving/provingMachine.ts
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/components/NavBar/AadhaarNavBar.tsx
**/*.{test,spec}.{ts,js,tsx,jsx}

⚙️ CodeRabbit configuration file

**/*.{test,spec}.{ts,js,tsx,jsx}: Review test files for:

  • Test coverage completeness
  • Test case quality and edge cases
  • Mock usage appropriateness
  • Test readability and maintainability

Files:

  • app/tests/src/navigation.test.ts
app/android/**/*

⚙️ CodeRabbit configuration file

app/android/**/*: Review Android-specific code for:

  • Platform-specific implementations
  • Performance considerations
  • Security best practices for mobile

Files:

  • app/android/app/src/main/java/com/proofofpassportapp/PhotoPickerActivity.java
  • app/android/app/build.gradle
  • app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt
  • app/android/app/src/main/res/values/styles.xml
  • app/android/app/src/main/AndroidManifest.xml
  • app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerPackage.java
  • app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java
common/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

common/src/**/*.{ts,tsx,js,jsx}: Review shared utilities for:

  • Reusability and modular design
  • Type safety and error handling
  • Side-effect management
  • Documentation and naming clarity

Files:

  • common/src/constants/constants.ts
  • common/src/utils/circuits/circuitsName.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • common/src/utils/passports/passport.ts
  • common/src/utils/index.ts
  • common/src/utils/aadhaar/utils.ts
  • common/src/utils/types.ts
  • common/src/utils/proving.ts
  • common/src/utils/circuits/registerInputs.ts
  • common/src/utils/passports/validate.ts
  • common/src/utils/aadhaar/mockData.ts
🧠 Learnings (21)
📚 Learning: 2025-08-29T15:30:12.210Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-08-29T15:30:12.210Z
Learning: Document complex native module changes for AI review

Applied to files:

  • app/src/screens/settings/ManageDocumentsScreen.tsx
  • app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerPackage.java
  • common/index.ts
  • app/src/screens/dev/CreateMockScreen.tsx
  • app/src/components/homeScreen/idCard.tsx
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')

Applied to files:

  • app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx
  • common/src/constants/constants.ts
  • common/src/utils/circuits/circuitsName.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • common/src/utils/passports/passport.ts
  • common/src/utils/index.ts
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/types.ts
  • common/src/utils/passports/validate.ts
  • common/src/utils/aadhaar/mockData.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to src/utils/**/*.{ts,tsx} : Place shared utilities in @/utils

Applied to files:

  • common/tsup.config.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to tests/src/**/*.{ts,tsx,js,jsx} : Use tests/ alias for test imports

Applied to files:

  • common/tsup.config.ts
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Use actual imports from selfxyz/mobile-sdk-alpha in tests

Applied to files:

  • common/tsup.config.ts
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Applies to packages/mobile-sdk-alpha/src/index.ts : Re-export new SDK modules via packages/mobile-sdk-alpha/src/index.ts

Applied to files:

  • common/tsup.config.ts
📚 Learning: 2025-08-26T14:49:11.190Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/passport/PassportNFCScanScreen.tsx:28-31
Timestamp: 2025-08-26T14:49:11.190Z
Learning: SelfClientProvider is wrapped in app/App.tsx, providing context for useSelfClient() hook usage throughout the React Native app navigation stacks.

Applied to files:

  • app/src/screens/prove/ConfirmBelongingScreen.tsx
📚 Learning: 2025-08-26T14:49:11.190Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/passport/PassportNFCScanScreen.tsx:28-31
Timestamp: 2025-08-26T14:49:11.190Z
Learning: The main App.tsx file is located at app/App.tsx (not in app/src), and it properly wraps the entire app with SelfClientProvider at the top of the provider hierarchy, enabling useSelfClient() hook usage throughout all navigation screens.

Applied to files:

  • app/src/screens/prove/ConfirmBelongingScreen.tsx
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to src/navigation/**/*.{ts,tsx} : Use react-navigation/native with createStaticNavigation for type-safe navigation

Applied to files:

  • app/src/screens/prove/ConfirmBelongingScreen.tsx
  • app/src/navigation/home.ts
  • app/src/components/NavBar/AadhaarNavBar.tsx
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to contracts/contracts/IdentityVerificationHubImplV2.sol : Identity Verification Hub: manage multi-step verification for passports and EU ID cards, handle document attestation via ZK proofs, and implement E-PASSPORT and EU_ID_CARD paths in IdentityVerificationHubImplV2.sol

Applied to files:

  • common/src/constants/constants.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-07-16T02:20:44.173Z
Learnt from: transphorm
PR: selfxyz/self#636
File: app/src/components/native/QRCodeScanner.tsx:135-142
Timestamp: 2025-07-16T02:20:44.173Z
Learning: In app/src/components/native/QRCodeScanner.tsx, the Android camera dimension multipliers (screenWidth * 3 and screenHeight * 2) are intentionally set to these values and should not be changed. These multipliers are correct and any visual issues with black areas in the camera preview are caused by other factors, not the dimension calculations.

Applied to files:

  • app/src/utils/qrScanner.ts
📚 Learning: 2025-07-12T22:00:02.041Z
Learnt from: transphorm
PR: selfxyz/self#636
File: app/src/utils/cameraPermission.ts:19-21
Timestamp: 2025-07-12T22:00:02.041Z
Learning: The Android permission handling in app/src/utils/cameraPermission.ts is robust and properly implemented using PermissionsAndroid.request() and PermissionsAndroid.check(). Previous issues with Android permission assumptions have been resolved in the current implementation.

Applied to files:

  • app/src/utils/qrScanner.ts
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Verify extractMRZInfo() using published sample MRZ strings (e.g., ICAO examples)

Applied to files:

  • app/src/utils/qrScanner.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • common/src/utils/index.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to circuits/circuits/disclose/vc_and_disclose.circom : Disclosure circuit must support document type disclosure: passport vs EU ID card

Applied to files:

  • common/src/utils/circuits/circuitsName.ts
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/circuits/registerInputs.ts
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Test isPassportDataValid() with realistic synthetic passport data (never real user data)

Applied to files:

  • common/src/utils/circuits/circuitsName.ts
  • common/index.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • app/src/providers/passportDataProvider.tsx
  • common/src/utils/passports/passport.ts
  • common/src/utils/index.ts
  • app/src/screens/dev/CreateMockScreen.tsx
  • app/src/components/homeScreen/idCard.tsx
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/types.ts
  • common/src/utils/circuits/registerInputs.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/navigation/home.ts
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-09-10T14:47:40.945Z
Learnt from: shazarre
PR: selfxyz/self#1041
File: app/src/providers/passportDataProvider.tsx:297-301
Timestamp: 2025-09-10T14:47:40.945Z
Learning: In app/src/providers/passportDataProvider.tsx: The deleteDocumentDirectlyFromKeychain function is a low-level utility used by the DocumentsAdapter and should not include error handling since callers like deleteDocument() already implement appropriate try/catch with logging for Keychain operations.

Applied to files:

  • app/src/providers/passportDataProvider.tsx
  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Passport verification workflow: NFC data extraction → MRZ validation → DSC verification → Register proof → compliance via ZK → attestation

Applied to files:

  • app/src/providers/passportDataProvider.tsx
  • app/src/utils/proving/provingMachine.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)

Applied to files:

  • common/src/utils/passports/passport.ts
  • common/src/utils/types.ts
  • common/src/utils/proving.ts
  • common/src/utils/passports/validate.ts
📚 Learning: 2025-09-11T19:41:16.601Z
Learnt from: aaronmgdr
PR: selfxyz/self#1055
File: app/src/components/homeScreen/idCard.tsx:6-6
Timestamp: 2025-09-11T19:41:16.601Z
Learning: The React Native app in selfxyz/self does not implement responsive layouts for orientation changes. The codebase consistently uses Dimensions.get('window') rather than useWindowDimensions(), indicating that orientation handling is not a priority or architectural pattern in this project.

Applied to files:

  • app/src/components/homeScreen/idCard.tsx
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to circuits/circuits/disclose/vc_and_disclose.circom : Disclosure circuit must preserve privacy so no raw PII leaves the device; only commitments are output

Applied to files:

  • app/src/utils/proving/provingMachine.ts
🧬 Code graph analysis (21)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (6)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • black (8-8)
  • slate500 (43-43)
  • white (59-59)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
app/src/components/buttons/SecondaryButton.tsx (1)
  • SecondaryButton (12-32)
app/src/screens/prove/ConfirmBelongingScreen.tsx (3)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • loadSelectedDocument (79-115)
packages/mobile-sdk-alpha/src/index.ts (1)
  • loadSelectedDocument (79-79)
packages/mobile-sdk-alpha/src/browser.ts (1)
  • loadSelectedDocument (46-46)
app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx (5)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • black (8-8)
  • slate500 (43-43)
  • white (59-59)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
app/src/utils/qrScanner.ts (1)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
common/src/utils/circuits/circuitsName.ts (1)
common/src/utils/types.ts (1)
  • IDDocument (56-56)
common/src/utils/passports/genMockIdDoc.ts (2)
common/src/utils/types.ts (3)
  • AadhaarData (15-22)
  • DocumentType (48-54)
  • PassportData (65-76)
common/src/utils/aadhaar/mockData.ts (2)
  • processQRData (561-595)
  • convertByteArrayToBigInt (52-58)
app/src/navigation/home.ts (1)
app/src/components/NavBar/AadhaarNavBar.tsx (1)
  • AadhaarNavBar (17-114)
app/src/providers/passportDataProvider.tsx (2)
common/src/utils/types.ts (3)
  • PassportData (65-76)
  • AadhaarData (15-22)
  • isMRZDocument (168-174)
packages/mobile-sdk-alpha/src/documents/utils.ts (2)
  • storeDocumentWithDeduplication (158-201)
  • storePassportData (203-205)
common/src/utils/passports/passport.ts (2)
common/src/utils/types.ts (6)
  • PassportData (65-76)
  • AadhaarData (15-22)
  • isMRZDocument (168-174)
  • IDDocument (56-56)
  • isAadhaarDocument (162-166)
  • DocumentCategory (37-37)
common/src/utils/aadhaar/mockData.ts (1)
  • nullifierHash (98-109)
common/src/utils/index.ts (2)
common/src/utils/generateInputs.ts (3)
  • generateCircuitInputsRegister (30-133)
  • generateCircuitInputsDisclose (135-181)
  • generateCircuitInputsProve (240-271)
app/src/utils/nfcScanner.ts (2)
  • response (187-262)
  • response (116-185)
app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java (3)
app/android/app/src/main/java/com/proofofpassportapp/PhotoPickerActivity.java (1)
  • PhotoPickerActivity (16-77)
app/src/utils/qrScanner.ts (1)
  • scanQRCodeFromPhotoLibrary (42-48)
app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt (5)
  • detectQrCodeInBitmap (194-211)
  • onSuccess (214-218)
  • onSuccess (215-215)
  • onFailure (216-216)
  • onCompletedFrame (217-217)
common/src/utils/aadhaar/utils.ts (2)
common/src/utils/index.ts (1)
  • getAadharRegistrationWindow (48-48)
common/src/constants/constants.ts (2)
  • RPC_URL (170-170)
  • IDENTITY_VERIFICATION_HUB_ADDRESS (100-100)
app/src/screens/dev/CreateMockScreen.tsx (5)
app/src/utils/haptic/index.ts (1)
  • buttonTap (18-18)
app/src/utils/colors.ts (4)
  • slate200 (35-35)
  • black (8-8)
  • slate500 (43-43)
  • textBlack (57-57)
app/src/utils/fonts.ts (1)
  • plexMono (9-10)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • MockDataEvents (61-76)
common/index.ts (1)
  • countryCodes (49-49)
app/src/components/homeScreen/idCard.tsx (1)
common/src/utils/types.ts (4)
  • PassportData (65-76)
  • AadhaarData (15-22)
  • isMRZDocument (168-174)
  • isAadhaarDocument (162-166)
app/src/utils/proving/provingMachine.ts (3)
common/src/utils/types.ts (3)
  • IDDocument (56-56)
  • PassportData (65-76)
  • DocumentCategory (37-37)
common/src/utils/circuits/registerInputs.ts (2)
  • generateTEEInputsRegister (240-265)
  • generateTEEInputsDSC (109-119)
common/src/utils/passports/validate.ts (1)
  • checkIfPassportDscIsInTree (126-139)
common/src/utils/types.ts (2)
common/src/utils/certificate_parsing/dataStructure.ts (1)
  • CertificateData (3-24)
common/src/utils/aadhaar/utils.ts (1)
  • ExtractedQRData (18-29)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (7)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/hooks/useModal.ts (1)
  • useModal (15-54)
common/src/utils/aadhaar/utils.ts (2)
  • getAadharRegistrationWindow (382-398)
  • extractQRDataFields (245-326)
common/src/utils/types.ts (1)
  • AadhaarData (15-22)
app/src/providers/passportDataProvider.tsx (1)
  • storePassportData (800-804)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • ProofEvents (105-165)
app/src/utils/qrScanner.ts (2)
  • scanQRCodeFromPhotoLibrary (42-48)
  • isQRScannerPhotoLibraryAvailable (34-36)
common/src/utils/circuits/registerInputs.ts (4)
common/src/utils/index.ts (8)
  • generateTEEInputsAadhaarDisclose (63-63)
  • AadhaarData (1-1)
  • SelfApp (14-14)
  • DocumentCategory (1-1)
  • calculateUserIdentifierHash (32-32)
  • hashEndpointWithScope (19-19)
  • generateTEEInputsAadhaarRegister (64-64)
  • SelfAppDisclosureConfig (16-16)
common/src/utils/types.ts (4)
  • AadhaarData (15-22)
  • DocumentCategory (37-37)
  • OfacTree (58-62)
  • IDDocument (56-56)
common/src/utils/aadhaar/mockData.ts (2)
  • prepareAadhaarDiscloseData (148-282)
  • prepareAadhaarRegisterData (405-481)
common/src/constants/constants.ts (2)
  • attributeToPosition (276-286)
  • attributeToPosition_ID (287-297)
common/src/utils/passports/validate.ts (5)
common/src/utils/types.ts (5)
  • IDDocument (56-56)
  • DeployedCircuits (24-30)
  • PassportData (65-76)
  • DocumentCategory (37-37)
  • AadhaarData (15-22)
common/src/utils/circuits/circuitsName.ts (1)
  • getCircuitNameFromPassportData (3-12)
common/src/utils/aadhaar/mockData.ts (4)
  • nullifierHash (98-109)
  • computePackedCommitment (61-72)
  • processQRDataSimple (111-146)
  • computeCommitment (75-83)
common/src/utils/passports/passport.ts (2)
  • generateNullifier (192-206)
  • generateCommitment (145-174)
common/src/constants/constants.ts (2)
  • PASSPORT_ATTESTATION_ID (162-162)
  • ID_CARD_ATTESTATION_ID (105-105)
common/src/utils/aadhaar/mockData.ts (7)
common/src/utils/aadhaar/utils.ts (4)
  • extractQRDataFields (245-326)
  • stringToAsciiArray (448-450)
  • calculateAge (64-89)
  • generateTestData (328-380)
common/src/utils/hash.ts (1)
  • packBytesAndPoseidon (185-188)
common/src/utils/shaPad.ts (1)
  • shaPad (86-105)
common/src/utils/circuits/generateInputs.ts (2)
  • findIndexInTree (45-56)
  • formatInput (58-78)
common/src/utils/trees.ts (4)
  • generateMerkleProof (156-172)
  • getNameDobLeafAadhaar (551-561)
  • getNameYobLeafAahaar (676-685)
  • generateSMTProof (174-223)
common/src/utils/bytes.ts (1)
  • splitToWords (140-153)
common/src/utils/aadhaar/assets/dataInput.ts (1)
  • testQRData (1-4)
app/src/components/NavBar/AadhaarNavBar.tsx (6)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/haptic/index.ts (1)
  • buttonTap (18-18)
app/src/utils/colors.ts (3)
  • slate100 (33-33)
  • black (8-8)
  • slate300 (37-37)
app/src/components/NavBar/BaseNavBar.tsx (1)
  • NavBar (128-133)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/utils/fonts.ts (1)
  • dinot (8-8)
🪛 GitHub Check: build-deps
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[warning] 12-12:
'Title' is defined but never used

app/src/providers/passportDataProvider.tsx

[warning] 47-47:
'isAadhaarDocument' is defined but never used

app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 223-223:
React Hook useCallback has missing dependencies: 'navigation' and 'showPermissionModal'. Either include them or remove the dependency array


[warning] 143-143:
React Hook useCallback has a missing dependency: 'validateAAdhaarTimestamp'. Either include it or remove the dependency array

app/src/components/NavBar/AadhaarNavBar.tsx

[warning] 12-12:
'white' is defined but never used


[warning] 12-12:
'slate200' is defined but never used


[warning] 7-7:
'Text' is defined but never used

🪛 GitHub Check: workspace-lint
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[warning] 12-12:
'Title' is defined but never used

app/src/providers/passportDataProvider.tsx

[warning] 47-47:
'isAadhaarDocument' is defined but never used

app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 223-223:
React Hook useCallback has missing dependencies: 'navigation' and 'showPermissionModal'. Either include them or remove the dependency array


[warning] 143-143:
React Hook useCallback has a missing dependency: 'validateAAdhaarTimestamp'. Either include it or remove the dependency array

app/src/components/NavBar/AadhaarNavBar.tsx

[warning] 12-12:
'white' is defined but never used


[warning] 12-12:
'slate200' is defined but never used


[warning] 7-7:
'Text' is defined but never used

🪛 detekt (1.23.8)
app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt

[warning] 191-192: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🪛 GitHub Actions: Common CI
app/src/providers/passportDataProvider.tsx

[error] 182-182: TS2322: Type '{ getData: () => Promise<SignedPayload | null>; getSelectedData: () => Promise<SignedPayload | null>; ... 15 more ...; checkAndUpdateRegistrationStates: () => Promise; }' is not assignable to type 'IPassportContext'.

🪛 GitHub Actions: Workspace CI
app/src/providers/passportDataProvider.tsx

[error] 182-182: TS2322: Type '{ getData: () => Promise<SignedPayload | null>; getSelectedData: () => Promise<SignedPayload | null>; ... 15 more ...; checkAndUpdateRegistrationStates: () => Promise; }' is not assignable to type 'IPassportContext'.

⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build-android
  • GitHub Check: build-ios
  • GitHub Check: e2e-ios
  • GitHub Check: android-build-test

Comment on lines +55 to +57
if (selectedUri != null) {
Log.d(TAG, "Photo picker returned URI: " + selectedUri);
finishWithResult(selectedUri);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Don’t log selected URIs (privacy/PII).

URIs can reveal local paths or cloud provider IDs. Avoid emitting them in production logs.

-            Log.d(TAG, "Photo picker returned URI: " + selectedUri);
+            Log.d(TAG, "Photo picker returned URI");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (selectedUri != null) {
Log.d(TAG, "Photo picker returned URI: " + selectedUri);
finishWithResult(selectedUri);
if (selectedUri != null) {
Log.d(TAG, "Photo picker returned URI");
finishWithResult(selectedUri);
🤖 Prompt for AI Agents
In app/android/app/src/main/java/com/proofofpassportapp/PhotoPickerActivity.java
around lines 55-57, the code currently logs the selectedUri which may expose
local paths or cloud IDs; remove the direct logging of the URI and instead
either (1) omit the Log.d call entirely and only call
finishWithResult(selectedUri), or (2) if you need a debug trace, wrap a log that
does not include the URI (e.g., Log.d(TAG, "Photo picker returned a URI" ) )
behind a BuildConfig.DEBUG check; ensure no production logs emit the raw URI and
if any identifier is logged, mask or hash it first.

Comment on lines +112 to +151
@ReactMethod
public void scanQRCodeFromPhotoLibrary(Promise promise) {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
promise.reject("ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist");
return;
}

photoLibraryPromise = promise;

// we first try with the recomended approach. This should be sufficient for most devices with play service.
// It fallsback to document picker if photo-picker is not available.
try {
android.util.Log.d("QRCodeScanner", "Using recommended PickVisualMedia photo picker via dedicated activity");
Intent intent = new Intent(currentActivity, PhotoPickerActivity.class);
currentActivity.startActivityForResult(intent, REQUEST_CODE_MODERN_PHOTO_PICK);
return;
} catch (Exception e) {
android.util.Log.d("QRCodeScanner", "Modern photo picker activity failed: " + e.getMessage());
}

// Fallback to intent-based photo picker for Android 13+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
android.util.Log.d("QRCodeScanner", "Using intent-based modern photo picker (Android 13+)");
Intent intent = new Intent("android.provider.action.PICK_IMAGES");
intent.setType("image/*");
currentActivity.startActivityForResult(intent, REQUEST_CODE_PHOTO_PICK);
return;
} catch (Exception e) {
android.util.Log.d("QRCodeScanner", "Intent-based modern photo picker failed: " + e.getMessage());
}
}

// Final fallback to legacy photo picker
android.util.Log.d("QRCodeScanner", "Using legacy Intent.ACTION_PICK photo picker");
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
currentActivity.startActivityForResult(intent, REQUEST_CODE_PHOTO_PICK);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Legacy photo picker lacks storage permission handling (pre‑Android 13)

ACTION_PICK on API < 33 can require READ_EXTERNAL_STORAGE. Without requesting it, selection may fail on older devices.

Apply this diff to request permission before legacy fallback:

   public void scanQRCodeFromPhotoLibrary(Promise promise) {
     ...
-    // Final fallback to legacy photo picker
+    // Final fallback to legacy photo picker (requires READ_EXTERNAL_STORAGE on pre-Android 13)
     android.util.Log.d("QRCodeScanner", "Using legacy Intent.ACTION_PICK photo picker");
-    Intent intent = new Intent(Intent.ACTION_PICK);
-    intent.setType("image/*");
-    currentActivity.startActivityForResult(intent, REQUEST_CODE_PHOTO_PICK);
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU &&
+        ContextCompat.checkSelfPermission(currentActivity, Manifest.permission.READ_EXTERNAL_STORAGE)
+            != PackageManager.PERMISSION_GRANTED) {
+      ActivityCompat.requestPermissions(
+        currentActivity,
+        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+        REQUEST_CODE_PHOTO_PICK /* reuse same code for simplicity */
+      );
+      return;
+    }
+    Intent intent = new Intent(Intent.ACTION_PICK);
+    intent.setType("image/*");
+    currentActivity.startActivityForResult(intent, REQUEST_CODE_PHOTO_PICK);
   }

Note: If you want stricter separation, introduce a dedicated permission request code and handle it.

Comment on lines +158 to +215
private void processImageForQRCode(Uri imageUri) {
try {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist");
photoLibraryPromise = null;
}
return;
}

InputStream inputStream = currentActivity.getContentResolver().openInputStream(imageUri);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();

if (bitmap == null) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("IMAGE_LOAD_FAILED", "Failed to load selected image");
photoLibraryPromise = null;
}
return;
}

// use the exising qrcode processor we already have.
QrCodeDetectorProcessor processor = new QrCodeDetectorProcessor();
processor.detectQrCodeInBitmap(bitmap, new QrCodeDetectorProcessor.Listener() {
@Override
public void onSuccess(String results, FrameMetadata frameMetadata, long timeRequired, Bitmap bitmap) {
if (photoLibraryPromise != null) {
photoLibraryPromise.resolve(results);
photoLibraryPromise = null;
}
}

@Override
public void onFailure(Exception e, long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image: " + e.getMessage());
photoLibraryPromise = null;
}
}

@Override
public void onCompletedFrame(long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image");
photoLibraryPromise = null;
}
}
});

} catch (Exception e) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("IMAGE_PROCESSING_ERROR", "Error processing image: " + e.getMessage());
photoLibraryPromise = null;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Decode large images off the UI thread and downsample to avoid OOM/ANR

BitmapFactory.decodeStream runs on UI thread and loads full-resolution images; this can freeze or crash on modern photos. Move decode to a background thread and sample down to a sane max size.

Apply this diff to downsample and offload:

-  private void processImageForQRCode(Uri imageUri) {
-    try {
-      Activity currentActivity = getCurrentActivity();
-      ...
-      InputStream inputStream = currentActivity.getContentResolver().openInputStream(imageUri);
-      Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
-      inputStream.close();
-      if (bitmap == null) { ... }
-      // use the exising qrcode processor we already have.
-      QrCodeDetectorProcessor processor = new QrCodeDetectorProcessor();
-      processor.detectQrCodeInBitmap(bitmap, new QrCodeDetectorProcessor.Listener() {
+  private void processImageForQRCode(Uri imageUri) {
+    Activity currentActivity = getCurrentActivity();
+    if (currentActivity == null) {
+      if (photoLibraryPromise != null) {
+        photoLibraryPromise.reject("ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist");
+        photoLibraryPromise = null;
+      }
+      return;
+    }
+    new Thread(() -> {
+      try (InputStream isBounds = currentActivity.getContentResolver().openInputStream(imageUri)) {
+        if (isBounds == null) throw new Exception("Cannot open image");
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inJustDecodeBounds = true;
+        BitmapFactory.decodeStream(isBounds, null, opts);
+        int req = 1600; // max dimension
+        int scale = 1;
+        while ((opts.outWidth / scale) > req || (opts.outHeight / scale) > req) {
+          scale *= 2;
+        }
+        BitmapFactory.Options decodeOpts = new BitmapFactory.Options();
+        decodeOpts.inSampleSize = Math.max(1, scale);
+        try (InputStream isDecode = currentActivity.getContentResolver().openInputStream(imageUri)) {
+          Bitmap bitmap = BitmapFactory.decodeStream(isDecode, null, decodeOpts);
+          if (bitmap == null) throw new Exception("Failed to decode image");
+          QrCodeDetectorProcessor processor = new QrCodeDetectorProcessor();
+          processor.detectQrCodeInBitmap(bitmap, new QrCodeDetectorProcessor.Listener() {
             @Override
             public void onSuccess(String results, FrameMetadata frameMetadata, long timeRequired, Bitmap bitmap) {
               if (photoLibraryPromise != null) {
                 photoLibraryPromise.resolve(results);
                 photoLibraryPromise = null;
               }
             }
             @Override
             public void onFailure(Exception e, long timeRequired) {
               if (photoLibraryPromise != null) {
                 photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image: " + e.getMessage());
                 photoLibraryPromise = null;
               }
             }
             @Override
             public void onCompletedFrame(long timeRequired) {
               if (photoLibraryPromise != null) {
                 photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image");
                 photoLibraryPromise = null;
               }
             }
-      });
-    } catch (Exception e) {
-      if (photoLibraryPromise != null) {
-        photoLibraryPromise.reject("IMAGE_PROCESSING_ERROR", "Error processing image: " + e.getMessage());
-        photoLibraryPromise = null;
-      }
-    }
+          });
+        }
+      } catch (Exception e) {
+        if (photoLibraryPromise != null) {
+          photoLibraryPromise.reject("IMAGE_PROCESSING_ERROR", "Error processing image: " + e.getMessage());
+          photoLibraryPromise = null;
+        }
+      }
+    }).start();
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void processImageForQRCode(Uri imageUri) {
try {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist");
photoLibraryPromise = null;
}
return;
}
InputStream inputStream = currentActivity.getContentResolver().openInputStream(imageUri);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
if (bitmap == null) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("IMAGE_LOAD_FAILED", "Failed to load selected image");
photoLibraryPromise = null;
}
return;
}
// use the exising qrcode processor we already have.
QrCodeDetectorProcessor processor = new QrCodeDetectorProcessor();
processor.detectQrCodeInBitmap(bitmap, new QrCodeDetectorProcessor.Listener() {
@Override
public void onSuccess(String results, FrameMetadata frameMetadata, long timeRequired, Bitmap bitmap) {
if (photoLibraryPromise != null) {
photoLibraryPromise.resolve(results);
photoLibraryPromise = null;
}
}
@Override
public void onFailure(Exception e, long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image: " + e.getMessage());
photoLibraryPromise = null;
}
}
@Override
public void onCompletedFrame(long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image");
photoLibraryPromise = null;
}
}
});
} catch (Exception e) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("IMAGE_PROCESSING_ERROR", "Error processing image: " + e.getMessage());
photoLibraryPromise = null;
}
}
}
private void processImageForQRCode(Uri imageUri) {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist");
photoLibraryPromise = null;
}
return;
}
new Thread(() -> {
try (InputStream isBounds = currentActivity.getContentResolver().openInputStream(imageUri)) {
if (isBounds == null) throw new Exception("Cannot open image");
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeStream(isBounds, null, opts);
int req = 1600; // max dimension
int scale = 1;
while ((opts.outWidth / scale) > req || (opts.outHeight / scale) > req) {
scale *= 2;
}
BitmapFactory.Options decodeOpts = new BitmapFactory.Options();
decodeOpts.inSampleSize = Math.max(1, scale);
try (InputStream isDecode = currentActivity.getContentResolver().openInputStream(imageUri)) {
Bitmap bitmap = BitmapFactory.decodeStream(isDecode, null, decodeOpts);
if (bitmap == null) throw new Exception("Failed to decode image");
QrCodeDetectorProcessor processor = new QrCodeDetectorProcessor();
processor.detectQrCodeInBitmap(bitmap, new QrCodeDetectorProcessor.Listener() {
@Override
public void onSuccess(String results, FrameMetadata frameMetadata, long timeRequired, Bitmap bitmap) {
if (photoLibraryPromise != null) {
photoLibraryPromise.resolve(results);
photoLibraryPromise = null;
}
}
@Override
public void onFailure(Exception e, long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image: " + e.getMessage());
photoLibraryPromise = null;
}
}
@Override
public void onCompletedFrame(long timeRequired) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("QR_DETECTION_FAILED", "No QR code found in selected image");
photoLibraryPromise = null;
}
}
});
}
} catch (Exception e) {
if (photoLibraryPromise != null) {
photoLibraryPromise.reject("IMAGE_PROCESSING_ERROR", "Error processing image: " + e.getMessage());
photoLibraryPromise = null;
}
}
}).start();
}
🤖 Prompt for AI Agents
In app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java
around lines 158 to 215, the current implementation decodes the full-resolution
image on the UI thread which can cause OOMs and ANRs; move image loading and
downsampling to a background thread and only run QR detection on the
decoded/downsampled bitmap. Specifically: open the InputStream, read image
bounds with BitmapFactory.Options(inJustDecodeBounds=true) to compute a safe
inSampleSize for a configured max dimension (e.g. 1024px), then reopen the
stream and decode with that inSampleSize off the UI thread using an Executor or
other background worker, ensure streams are closed in finally blocks, and post
the decoded bitmap back to the main thread before invoking the existing
QrCodeDetectorProcessor callbacks so promises are resolved/rejected on the UI
thread; also keep existing null/exception handling and clear photoLibraryPromise
in all code paths.

Comment on lines +129 to +140
// If original fails, try with scaled up image (better for small QR codes)
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width * 2, bitmap.height * 2, true)
result = tryDetectInBitmap(scaledBitmap, qRCodeDetectorReader)
if (result != null) return result

// If still fails, try with scaled down image (better for very large QR codes)
val scaledDownBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width / 2, bitmap.height / 2, true)
result = tryDetectInBitmap(scaledDownBitmap, qRCodeDetectorReader)
if (result != null) return result

return null
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Bitmap scaling can OOM and create invalid 0-dimension bitmaps. Guard, clamp, and recycle.

Doubling large images can exceed heap; halving 1px dimensions yields 0 and throws. Recycle temporaries.

-        // If original fails, try with scaled up image (better for small QR codes)
-        val scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width * 2, bitmap.height * 2, true)
-        result = tryDetectInBitmap(scaledBitmap, qRCodeDetectorReader)
-        if (result != null) return result
+        // Try scaled up image (guarded + clamped)
+        val maxDim = 2048
+        val maxSrc = maxOf(bitmap.width, bitmap.height)
+        val upScale = minOf(2f, maxDim.toFloat() / maxSrc.toFloat())
+        if (upScale > 1.01f) {
+            val upW = maxOf(1, (bitmap.width * upScale).toInt())
+            val upH = maxOf(1, (bitmap.height * upScale).toInt())
+            val scaledBitmap = Bitmap.createScaledBitmap(bitmap, upW, upH, true)
+            try {
+                result = tryDetectInBitmap(scaledBitmap, qRCodeDetectorReader)
+                if (result != null) return result
+            } finally {
+                if (scaledBitmap != bitmap && !scaledBitmap.isRecycled) scaledBitmap.recycle()
+            }
+        }
 
-        // If still fails, try with scaled down image (better for very large QR codes)
-        val scaledDownBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width / 2, bitmap.height / 2, true)
-        result = tryDetectInBitmap(scaledDownBitmap, qRCodeDetectorReader)
-        if (result != null) return result
+        // Try scaled down image (guard against 0-dimension)
+        if (bitmap.width >= 2 && bitmap.height >= 2) {
+            val downW = maxOf(1, bitmap.width / 2)
+            val downH = maxOf(1, bitmap.height / 2)
+            val scaledDownBitmap = Bitmap.createScaledBitmap(bitmap, downW, downH, true)
+            try {
+                result = tryDetectInBitmap(scaledDownBitmap, qRCodeDetectorReader)
+                if (result != null) return result
+            } finally {
+                if (!scaledDownBitmap.isRecycled) scaledDownBitmap.recycle()
+            }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// If original fails, try with scaled up image (better for small QR codes)
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width * 2, bitmap.height * 2, true)
result = tryDetectInBitmap(scaledBitmap, qRCodeDetectorReader)
if (result != null) return result
// If still fails, try with scaled down image (better for very large QR codes)
val scaledDownBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width / 2, bitmap.height / 2, true)
result = tryDetectInBitmap(scaledDownBitmap, qRCodeDetectorReader)
if (result != null) return result
return null
}
// Try scaled up image (guarded + clamped)
val maxDim = 2048
val maxSrc = maxOf(bitmap.width, bitmap.height)
val upScale = minOf(2f, maxDim.toFloat() / maxSrc.toFloat())
if (upScale > 1.01f) {
val upW = maxOf(1, (bitmap.width * upScale).toInt())
val upH = maxOf(1, (bitmap.height * upScale).toInt())
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, upW, upH, true)
try {
result = tryDetectInBitmap(scaledBitmap, qRCodeDetectorReader)
if (result != null) return result
} finally {
if (scaledBitmap != bitmap && !scaledBitmap.isRecycled) scaledBitmap.recycle()
}
}
// Try scaled down image (guard against 0-dimension)
if (bitmap.width >= 2 && bitmap.height >= 2) {
val downW = maxOf(1, bitmap.width / 2)
val downH = maxOf(1, bitmap.height / 2)
val scaledDownBitmap = Bitmap.createScaledBitmap(bitmap, downW, downH, true)
try {
result = tryDetectInBitmap(scaledDownBitmap, qRCodeDetectorReader)
if (result != null) return result
} finally {
if (!scaledDownBitmap.isRecycled) scaledDownBitmap.recycle()
}
}
return null
}
🤖 Prompt for AI Agents
In
app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt
around lines 129-140, the current scaling logic can cause OOMs and create
0-dimension bitmaps; update it to validate and clamp dimensions before scaling,
avoid creating scales that exceed a safe max or produce width/height < 1, wrap
Bitmap.createScaledBitmap calls in try/catch to handle
OOM/IllegalArgumentException, and ensure any temporary scaled bitmaps are
recycled after use (or recycled in finally) to free memory; specifically compute
safeTargetWidth/Height using min/max clamps, skip scaling if target dimensions
are invalid, attempt detection in a try block, recycle the scaled bitmap
promptly whether detection succeeds or fails, and on OOM simply skip that
scaling pass and continue.

Comment on lines +157 to 167
for (binarizer in binarizers) {
val binaryBitMap = BinaryBitmap(binarizer)

try {
return qRCodeDetectorReader.decode(binaryBitMap)
try {
val result = qRCodeDetectorReader.decode(binaryBitMap)
println("QR Code detected successfully with ${binarizer.javaClass.simpleName}")
return result
} catch (e: Exception) {
println("Detection failed with ${binarizer.javaClass.simpleName}: ${e.message}")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Always reset QRCodeReader between decode attempts to avoid stale state.

ZXing readers expect reset() across attempts; reuse without reset risks false negatives.

-            try {
-                val result = qRCodeDetectorReader.decode(binaryBitMap)
+            try {
+                val result = qRCodeDetectorReader.decode(binaryBitMap)
                 println("QR Code detected successfully with ${binarizer.javaClass.simpleName}")
                 return result
             } catch (e: Exception) {
                 println("Detection failed with ${binarizer.javaClass.simpleName}: ${e.message}")
+            } finally {
+                try { qRCodeDetectorReader.reset() } catch (_: Exception) {}
             }
-            try {
-                val result = qRCodeDetectorReader.decode(binaryBitMap, hints)
+            try {
+                val result = qRCodeDetectorReader.decode(binaryBitMap, hints)
                 println("QR Code detected successfully with hints and ${binarizer.javaClass.simpleName}")
                 return result
             } catch (e: Exception) {
                 println("Detection with hints failed with ${binarizer.javaClass.simpleName}: ${e.message}")
+            } finally {
+                try { qRCodeDetectorReader.reset() } catch (_: Exception) {}
             }

Also applies to: 175-185

🤖 Prompt for AI Agents
In
app/android/app/src/main/java/com/proofofpassportapp/utils/QrCodeDetectorProcessor.kt
around lines 157-167 (and similarly 175-185), the ZXing QRCodeReader is reused
across decode attempts without calling reset(), which can leave stale internal
state and cause false negatives; before each decode call invoke
qRCodeDetectorReader.reset() (or create a fresh reader per attempt) and ensure
reset() is called in the loop prior to decode and also in any catch/finally path
so the reader is clean for the next binarizer attempt.

Comment on lines +105 to 124
const { isValid: isRegisterValid, circuitName: registerCircuitName } =
validateRegistrationCircuit(passportData, deployedCircuits);
if (!isRegisterValid) {
return {
status: 'registration_circuit_not_supported',
details: circuitNameRegister,
details: registerCircuitName,
};
}
const circuitNameDsc = getCircuitNameFromPassportData(passportData, 'dsc');
if (
!circuitNameDsc ||
!(
deployedCircuits.DSC.includes(circuitNameDsc) ||
deployedCircuits.DSC_ID.includes(circuitNameDsc)
)
) {
console.warn('DSC circuit not supported:', circuitNameDsc);
return { status: 'dsc_circuit_not_supported', details: circuitNameDsc };

const { isValid: isDscValid, circuitName: dscCircuitName } = validateDscCircuit(
passportData as PassportData,
deployedCircuits
);
if (!isDscValid) {
console.warn('DSC circuit not supported:', dscCircuitName);
return { status: 'dsc_circuit_not_supported', details: dscCircuitName };
}
return { status: 'passport_supported', details: 'null' };

return { status: 'passport_supported', details: dscCircuitName };
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Same nullability issue for DSC circuit path.

dscCircuitName can be null; return type must allow null or coerce.

No extra diff needed if you adopt the previous return-type change.

🤖 Prompt for AI Agents
In common/src/utils/passports/validate.ts around lines 105 to 124, the DSC
branch returns dscCircuitName which can be null; update the function so the
returned details type accepts null (e.g., union type allowing null) or coerce
the value to a non-null representation (e.g., use dscCircuitName ?? undefined or
a string placeholder) and mirror the same nullable change you applied for the
registration path so the function signature and all callers accept the nullable
details.

Comment on lines +192 to +233
export function generateCommitmentInAppAadhaar(
secret: string,
attestation_id: string,
passportData: AadhaarData,
alternativePublicKeys: Record<string, string>
) {
const nullifier = nullifierHash(passportData.extractedFields);
const packedCommitment = computePackedCommitment(passportData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(passportData.qrData);

const publicKey_list: string[] = [];
const commitment_list: string[] = [];

// For Aadhaar, we can also use the document's own public key
const allPublicKeys = {
document_public_key: passportData.publicKey,
...alternativePublicKeys,
};

for (const [keyName, publicKeyValue] of Object.entries(allPublicKeys)) {
try {
const commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();

publicKey_list.push(publicKeyValue);
commitment_list.push(commitment);
} catch (error) {
console.warn(`Failed to process public key for ${keyName}:`, error);
}
}

if (commitment_list.length === 0) {
console.error('No valid public keys found for Aadhaar');
}

return { commitment_list, publicKey_list };
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

API design bug: attestation_id is accepted but not used in Aadhaar commitment.

This misleads callers and diverges from passport flow (where attestation_id contributes to the commitment). Either include domain separation with attestation_id or drop the parameter and update call sites.

Option A (minimal, remove unused arg):

-export function generateCommitmentInAppAadhaar(
-  secret: string,
-  attestation_id: string,
-  passportData: AadhaarData,
-  alternativePublicKeys: Record<string, string>
-) {
+export function generateCommitmentInAppAadhaar(
+  secret: string,
+  passportData: AadhaarData,
+  alternativePublicKeys: Record<string, string>
+) {

And update the call (see lines 343-348 below).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generateCommitmentInAppAadhaar(
secret: string,
attestation_id: string,
passportData: AadhaarData,
alternativePublicKeys: Record<string, string>
) {
const nullifier = nullifierHash(passportData.extractedFields);
const packedCommitment = computePackedCommitment(passportData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(passportData.qrData);
const publicKey_list: string[] = [];
const commitment_list: string[] = [];
// For Aadhaar, we can also use the document's own public key
const allPublicKeys = {
document_public_key: passportData.publicKey,
...alternativePublicKeys,
};
for (const [keyName, publicKeyValue] of Object.entries(allPublicKeys)) {
try {
const commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();
publicKey_list.push(publicKeyValue);
commitment_list.push(commitment);
} catch (error) {
console.warn(`Failed to process public key for ${keyName}:`, error);
}
}
if (commitment_list.length === 0) {
console.error('No valid public keys found for Aadhaar');
}
return { commitment_list, publicKey_list };
}
export function generateCommitmentInAppAadhaar(
secret: string,
passportData: AadhaarData,
alternativePublicKeys: Record<string, string>
) {
const nullifier = nullifierHash(passportData.extractedFields);
const packedCommitment = computePackedCommitment(passportData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(passportData.qrData);
const publicKey_list: string[] = [];
const commitment_list: string[] = [];
// For Aadhaar, we can also use the document's own public key
const allPublicKeys = {
document_public_key: passportData.publicKey,
...alternativePublicKeys,
};
for (const [keyName, publicKeyValue] of Object.entries(allPublicKeys)) {
try {
const commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();
publicKey_list.push(publicKeyValue);
commitment_list.push(commitment);
} catch (error) {
console.warn(`Failed to process public key for ${keyName}:`, error);
}
}
if (commitment_list.length === 0) {
console.error('No valid public keys found for Aadhaar');
}
return { commitment_list, publicKey_list };
}
🤖 Prompt for AI Agents
common/src/utils/passports/validate.ts around lines 192 to 233: the function
generateCommitmentInAppAadhaar accepts attestation_id but never uses it, causing
an API mismatch with passport flow; remove the unused attestation_id parameter
from the function signature, delete its usages in any local references, update
exported type definitions and JSDoc/comments, and then update all call sites
(e.g., the invocation around lines 343–348 and any other imports) to stop
passing attestation_id; run type checks and tests to ensure no remaining
references to the removed parameter.

Comment on lines 271 to +303
export async function isUserRegistered(
passportData: PassportData,
documentData: PassportData | AadhaarData,
secret: string,
getCommitmentTree: (docCategory: DocumentCategory) => string
) {
if (!passportData) {
if (!documentData) {
return false;
}
const attestationId =
passportData.documentCategory === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID;
const commitment = generateCommitment(secret, attestationId, passportData);
const document: DocumentCategory = passportData.documentCategory;

const document: DocumentCategory = documentData.documentCategory;
let commitment: string;

if (document === 'aadhaar') {
const aadhaarData = documentData as AadhaarData;
const nullifier = nullifierHash(aadhaarData.extractedFields);
const packedCommitment = computePackedCommitment(aadhaarData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(aadhaarData.qrData);

commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();

console.log('commitment', commitment);
} else {
const attestationId =
document === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID;
commitment = generateCommitment(secret, attestationId, documentData as PassportData);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Aadhaar path logs full commitment.

Commitments are linkable across sessions; avoid logging them.

Apply:

-    console.log('commitment', commitment);
+    // Do not log commitment in production.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function isUserRegistered(
passportData: PassportData,
documentData: PassportData | AadhaarData,
secret: string,
getCommitmentTree: (docCategory: DocumentCategory) => string
) {
if (!passportData) {
if (!documentData) {
return false;
}
const attestationId =
passportData.documentCategory === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID;
const commitment = generateCommitment(secret, attestationId, passportData);
const document: DocumentCategory = passportData.documentCategory;
const document: DocumentCategory = documentData.documentCategory;
let commitment: string;
if (document === 'aadhaar') {
const aadhaarData = documentData as AadhaarData;
const nullifier = nullifierHash(aadhaarData.extractedFields);
const packedCommitment = computePackedCommitment(aadhaarData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(aadhaarData.qrData);
commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();
console.log('commitment', commitment);
} else {
const attestationId =
document === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID;
commitment = generateCommitment(secret, attestationId, documentData as PassportData);
}
export async function isUserRegistered(
documentData: PassportData | AadhaarData,
secret: string,
getCommitmentTree: (docCategory: DocumentCategory) => string
) {
if (!documentData) {
return false;
}
const document: DocumentCategory = documentData.documentCategory;
let commitment: string;
if (document === 'aadhaar') {
const aadhaarData = documentData as AadhaarData;
const nullifier = nullifierHash(aadhaarData.extractedFields);
const packedCommitment = computePackedCommitment(aadhaarData.extractedFields);
const { qrHash, photoHash } = processQRDataSimple(aadhaarData.qrData);
commitment = computeCommitment(
BigInt(secret),
BigInt(qrHash),
nullifier,
packedCommitment,
photoHash
).toString();
// Do not log commitment in production.
} else {
const attestationId =
document === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID;
commitment = generateCommitment(secret, attestationId, documentData as PassportData);
}
🤖 Prompt for AI Agents
In common/src/utils/passports/validate.ts around lines 271 to 303, the Aadhaar
branch currently logs the full computed commitment which is sensitive and
linkable; remove the console.log('commitment', commitment) call and, if
telemetry is required, replace it with a non-identifying/redacted message (e.g.,
log only a fixed string, a truncated/hashed prefix, or a boolean success
indicator) so the full commitment is never written to logs; ensure no other
statements in this block output the full commitment.

@@ -1,9 +1,30 @@
import type { ExtractedQRData } from './aadhaar/utils.js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Wrong extension in TS import breaks builds.

Importing a TS file with .js will fail under common TS module resolution.

-import type { ExtractedQRData } from './aadhaar/utils.js';
+import type { ExtractedQRData } from './aadhaar/utils';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { ExtractedQRData } from './aadhaar/utils.js';
import type { ExtractedQRData } from './aadhaar/utils';
🤖 Prompt for AI Agents
In common/src/utils/types.ts around line 1, the import uses a .js extension
which breaks TypeScript module resolution; change the import to the
TypeScript-compatible path (remove the extension or use .ts) e.g. import type {
ExtractedQRData } from './aadhaar/utils' so TS can resolve the module during
build, update any other similar imports in the repo, and run the TypeScript
build to verify the fix.

Comment on lines +23 to +24
'src/utils/aadhaar/utils': 'src/utils/aadhaar/utils.ts',
'src/utils/aadhaar/mockData': 'src/utils/aadhaar/mockData.ts',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Add exports/types for new entry points or consumers will break.

You introduced two new public subpath entry points. If package.json "exports" (and types) aren’t updated for:

  • ./src/utils/aadhaar/utils
  • ./src/utils/aadhaar/mockData

ESM/CJS consumers will fail to resolve them, and d.ts may be missing (tsup dts=false here). Ensure:

  • package.json exports map includes both subpaths for import and require.
  • The types build (build:types) emits declarations for these files and the types are reachable via exports/typesVersions.

Run this to verify exports are present in the common package:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# 1) Locate common package.json
COMMON_PKG="$(fd -a package.json common | head -n1)"
echo "Using: $COMMON_PKG"

# 2) Show exports keys
jq -r '.exports|keys[]?' "$COMMON_PKG" || echo "No exports field."

# 3) Check required subpaths exist in exports
for key in "./src/utils/aadhaar/utils" "./src/utils/aadhaar/mockData"; do
  echo "--- checking $key"
  jq -e --arg k "$key" '.exports[$k]' "$COMMON_PKG" >/dev/null && echo "OK: $key exported" || { echo "MISSING: $key in exports"; missing=1; }
done

# 4) Confirm source files exist
fd -a common/src/utils/aadhaar/{utils.ts,mockData.ts}

# 5) Optional: confirm a types build will cover them (heuristic – look for build:types script)
jq -r '.scripts["build:types"]?' "$COMMON_PKG"
test -z "${missing:-}" || exit 1

Length of output: 1914


Missing exports & types for the new aadhaar entrypoints — fix before publishing

  • Verified: common/package.json does NOT export "./src/utils/aadhaar/utils" or "./src/utils/aadhaar/mockData" (script output: MISSING) — consumers will fail to resolve these new subpaths.
  • Also: fd failed to locate common/src/utils/aadhaar/{utils.ts,mockData.ts}; confirm the source paths (existing exports use ./utils/... not ./src/utils/...).
  • Action (required): update common/package.json exports to include both subpaths (ESM/CJS entry mappings) and expose types (add exports/types or typesVersions). Ensure .d.ts are produced (enable tsup dts or add build:types that covers these files) or remove the tsup entrypoints if they aren’t meant to be public. See common/tsup.config.ts (lines ~23–24) and common/package.json.

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
common/src/utils/passports/genMockIdDoc.ts (1)

73-74: Remove debug console.log statements before production.

Debug logging statements leak potentially sensitive data including dateOfBirth, qrDataString, and extractedFields. These should be removed or replaced with proper logging.

-  console.log('genMockAadhaarDoc', input);
-  console.log('dateOfBirth', dateOfBirth);
-  console.log('qrDataString', qrDataString);
-  console.log('qrData.extractedFields', qrData.extractedFields);

Also applies to: 88-89, 98-98

🧹 Nitpick comments (2)
contracts/error-selectors.json (2)

80-85: Mixed error-naming conventions across V1/V2 will complicate client decoders.

V1 uses ALL_CAPS (e.g., INVALID_OFAC_ROOT), while V2 introduces CamelCase variants (e.g., InvalidOfacRoots, CrossChainIsNotSupportedYet). Either standardize before release or document a mapping in the client decoder to avoid brittle name-based routing.

Also applies to: 199-204, 318-323, 409-414


14-15: “line” pointers are fragile; prefer codegen or remove from the contract-facing schema.

Many entries only shift line numbers. Unless generated, these will constantly rot after refactors. Best practice: generate this file from build artifacts (via solc/Foundry src maps) during CI and commit, or drop “line” from the runtime-consumed schema and keep it in a dev-only index.

Also applies to: 28-29, 35-36, 42-43, 49-50, 56-57, 63-64, 98-99, 112-113, 129-134, 139-141, 196-197, 206-211, 213-218, 234-239, 248-253, 286-288, 339-344, 402-407, 423-428, 445-449, 458-463, 465-470, 507-512, 514-519

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a33580e and ea89c5f.

📒 Files selected for processing (6)
  • .gitleaks.toml (1 hunks)
  • app/src/screens/settings/ManageDocumentsScreen.tsx (3 hunks)
  • common/src/mock_certificates/aadhaar/mockAadhaarCert.ts (1 hunks)
  • common/src/utils/passports/genMockIdDoc.ts (5 hunks)
  • contracts/error-selectors.json (18 hunks)
  • packages/mobile-sdk-alpha/src/constants/analytics.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/screens/settings/ManageDocumentsScreen.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
  • common/src/utils/passports/genMockIdDoc.ts
  • common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/mobile-sdk-alpha/AGENTS.md)

packages/mobile-sdk-alpha/**/*.{ts,tsx}: Use strict TypeScript type checking across the codebase
Follow ESLint TypeScript-specific rules
Avoid introducing circular dependencies

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}: Review alpha mobile SDK code for:

  • API consistency with core SDK
  • Platform-neutral abstractions
  • Performance considerations
  • Clear experimental notes or TODOs

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
common/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

common/src/**/*.{ts,tsx,js,jsx}: Review shared utilities for:

  • Reusability and modular design
  • Type safety and error handling
  • Side-effect management
  • Documentation and naming clarity

Files:

  • common/src/utils/passports/genMockIdDoc.ts
  • common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
🧠 Learnings (6)
📚 Learning: 2025-08-25T14:25:57.586Z
Learnt from: aaronmgdr
PR: selfxyz/self#951
File: app/src/providers/authProvider.web.tsx:17-18
Timestamp: 2025-08-25T14:25:57.586Z
Learning: The selfxyz/mobile-sdk-alpha/constants/analytics import path is properly configured with SDK exports, Metro aliases, and TypeScript resolution. Import changes from @/consts/analytics to this path are part of valid analytics migration, not TypeScript resolution issues.

Applied to files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Test isPassportDataValid() with realistic synthetic passport data (never real user data)

Applied to files:

  • common/src/utils/passports/genMockIdDoc.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')

Applied to files:

  • common/src/utils/passports/genMockIdDoc.ts
  • contracts/error-selectors.json
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)

Applied to files:

  • common/src/mock_certificates/aadhaar/mockAadhaarCert.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to contracts/contracts/registry/IdentityRegistryImplV1.sol : Identity Registry Management: separate registries for passports and ID cards, DSC key commitment registration, and nullifier tracking in IdentityRegistryImplV1.sol

Applied to files:

  • contracts/error-selectors.json
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to contracts/contracts/IdentityVerificationHubImplV2.sol : Identity Verification Hub: manage multi-step verification for passports and EU ID cards, handle document attestation via ZK proofs, and implement E-PASSPORT and EU_ID_CARD paths in IdentityVerificationHubImplV2.sol

Applied to files:

  • contracts/error-selectors.json
🧬 Code graph analysis (1)
common/src/utils/passports/genMockIdDoc.ts (3)
common/src/utils/types.ts (3)
  • AadhaarData (15-22)
  • DocumentType (48-54)
  • PassportData (65-76)
common/src/utils/aadhaar/mockData.ts (2)
  • processQRData (561-595)
  • convertByteArrayToBigInt (52-58)
common/src/mock_certificates/aadhaar/mockAadhaarCert.ts (2)
  • AADHAAR_MOCK_PRIVATE_KEY_PEM (4-32)
  • AADHAAR_MOCK_PUBLIC_KEY_PEM (34-56)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test
  • GitHub Check: build-android
  • GitHub Check: build-ios
  • GitHub Check: Cursor Bugbot
  • GitHub Check: analyze-android
  • GitHub Check: e2e-ios
  • GitHub Check: analyze-ios
🔇 Additional comments (11)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)

50-51: Align Aadhaar event label and confirm PII-safe instrumentation

File: packages/mobile-sdk-alpha/src/constants/analytics.ts — DocumentEvents

-  ADD_NEW_AADHAAR_SELECTED: 'Document: Add Aadhaar',
+  ADD_NEW_AADHAAR_SELECTED: 'Document: Add New Document via Aadhaar',
  • Rename to preserve analytics taxonomy/grouping (matches Mock/Scan events).
  • Verify dashboards/queries that regex on "^Document: Add New Document via" include Aadhaar after the change.
  • Ensure the event payload contains no Aadhaar number, QR contents, image/base64 blobs — only high-level metadata (e.g., docType='aadhaar'); gate any sensitive props behind explicit user consent and regional compliance.
  • No analytics call sites/dashboards were located by automated search; confirm there are no upstream consumers depending on the old label before deploying the rename.
.gitleaks.toml (1)

25-25: LGTM - Proper expansion of gitleaks ignore rules.

The addition of common/dist/.*/mock_certificates/.* correctly extends the existing ignore pattern to cover built distribution artifacts containing mock certificates. This prevents false positives during secret scanning while maintaining appropriate coverage of the source tree.

common/src/mock_certificates/aadhaar/mockAadhaarCert.ts (1)

1-56: LGTM - Well-documented mock certificates with clear dev-only usage.

The file properly exports hardcoded mock certificates with clear header comments indicating development-only usage and production prohibition. The PEM format follows standard conventions and the structure is consistent with the existing mock certificate approach in the codebase.

common/src/utils/passports/genMockIdDoc.ts (6)

30-30: Update type union to reflect new Aadhaar support.

The IdDocInput.idType has been correctly extended to include 'mock_aadhaar' alongside the existing passport and ID card types.


41-44: Clean addition of Aadhaar-specific fields.

The optional pincode and state fields are appropriately typed and documented for Aadhaar document generation.


64-110: Solid Aadhaar mock generation implementation.

The genMockAadhaarDoc function correctly:

  • Handles name generation with fallback to generateRandomName()
  • Uses appropriate defaults for gender, pincode, and state
  • Properly integrates with the existing QR data processing utilities
  • Returns a well-structured AadhaarData object matching the expected interface
  • Maintains consistency with the existing mock data approach

The implementation follows the established patterns and integrates cleanly with the broader Aadhaar mock data flow.


115-118: Proper routing logic for Aadhaar documents.

The conditional branching correctly routes Aadhaar document requests to the new genMockAadhaarDoc function while preserving existing passport/ID card functionality.


188-201: Well-implemented random name generation utility.

The generateRandomName function provides a clean fallback for cases where name isn't provided, generating realistic-looking random names with appropriate length variation.


163-163: Type casting maintains backward compatibility.

The cast to PassportData in genMockIdDocAndInitDataParsing appropriately handles the widened return type while maintaining the function's passport-specific contract.

contracts/error-selectors.json (2)

2-8: Aadhaar registry errors: confirm declarations and usage align with access-control/expiry checks.

New entries for IdentityRegistryAadhaarImplV1 (HUB_NOT_SET, HUB_ADDRESS_ZERO, ONLY_HUB_CAN_ACCESS, REGISTERED_COMMITMENT, EXPIRY_IN_PAST). Please verify the contract actually reverts with these exact error identifiers on the intended paths (hub wiring, caller gating, commitment reuse, expiry). A mismatch will surface as undecodable errors in the mobile client and monitoring.

Also applies to: 86-92, 142-148, 374-379, 416-421


2-8: Automate validation of contracts/error-selectors.json (selectors ⇄ signatures ⇄ line refs)

This JSON is runtime-facing for revert decoding; stale selectors, collisions, or wrong line pointers will break client error handling. Add a CI job that:

  • recomputes selector = keccak256(signature)[0:4] and fails on mismatches,
  • detects selector collisions (one selector → multiple signatures) and fails,
  • verifies each referenced Solidity file exists and the recorded line number is within the file's line count,
  • confirms an error <Name>(...) declaration exists in the referenced file,
  • runs on PRs/main and emits a machine-readable report + PR annotations on failure.

Validation couldn't be completed in this environment — run the repo validation script in CI or locally and fix any reported mismatches.

- Updated the AadhaarUploadErrorScreen to display different messages based on the error type (general or expired).
- Modified the AadhaarUploadScreen to pass the appropriate error type when navigating to the error screen.
- Set initial parameters for the home screen to include a default error type.
…nt category

- Modified the handling of country code in the useProvingStore to return 'IND' for Aadhaar documents.
- Ensured that the country code is only fetched from passport metadata for non-Aadhaar documents.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (6)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (2)

15-15: Replace test mock with real safe‑area hook (production blocker).

Importing from the mocks module will break insets on devices and can cause layout issues on notched/gesture devices. Use the real library.

Apply this diff:

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

Verify there are no other mock imports lingering:

#!/bin/bash
set -euo pipefail
# Find any remaining imports of the mock safe-area hook
rg -nP --no-heading -C2 "mocks/react-native-safe-area-context"

5-18: Fix lint failures: remove unused import and sort imports.

CI is failing on simple-import-sort and an unused Title import. This also folds in the safe‑area import fix above.

Apply this diff:

-import React from 'react';
-import { XStack, YStack } from 'tamagui';
-import { useNavigation, useRoute } from '@react-navigation/native';
-import type { RouteProp } from '@react-navigation/native';
-
-import { PrimaryButton } from '@/components/buttons/PrimaryButton';
-import { SecondaryButton } from '@/components/buttons/SecondaryButton';
-import { BodyText } from '@/components/typography/BodyText';
-import { Title } from '@/components/typography/Title';
-import WarningIcon from '@/images/warning.svg';
-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
-import { black, slate100, slate200, slate500, white } from '@/utils/colors';
-import { extraYPadding } from '@/utils/constants';
+import React from 'react';
+import { useNavigation, useRoute } from '@react-navigation/native';
+import type { RouteProp } from '@react-navigation/native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import { XStack, YStack } from 'tamagui';
+
+import { PrimaryButton } from '@/components/buttons/PrimaryButton';
+import { SecondaryButton } from '@/components/buttons/SecondaryButton';
+import { BodyText } from '@/components/typography/BodyText';
+import WarningIcon from '@/images/warning.svg';
+import { black, slate100, slate200, slate500, white } from '@/utils/colors';
+import { extraYPadding } from '@/utils/constants';
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (4)

22-22: Use the real safe-area hook; mock import will crash on device

Replace the mock import with the production hook.

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

148-149: Add missing hook dependencies to prevent stale closures

Include the timestamp validator (and nav/modal) in deps to avoid subtle bugs.

-    [navigation, trackEvent],
+    [navigation, trackEvent, validateAAdhaarTimestamp],
-  }, [isProcessing, trackEvent, processAadhaarQRCode]);
+  }, [isProcessing, trackEvent, processAadhaarQRCode, navigation, showPermissionModal]);

Also applies to: 228-229


262-269: Replace unsupported borderBlock props (ignored on RN) with explicit border props*

These Tamagui/RN styles are not recognized; the divider won’t render.

-      <YStack
+      <YStack
         paddingHorizontal={20}
         paddingTop={20}
         alignItems="center"
         paddingVertical={25}
-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderTopColor={slate200}
       >

271-271: Fix user-facing typo: “mAadaar” → “mAadhaar”

Visible copy; impacts trust.

-          Generate a QR code from the mAadaar app
+          Generate a QR code from the mAadhaar app
🧹 Nitpick comments (1)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (1)

23-26: Strengthen route typing to the concrete route name.

Using Record<string, …>, string loses type safety. Bind to the actual route id to catch param mistakes at compile time.

Apply this diff:

-type AadhaarUploadErrorRoute = RouteProp<
-  Record<string, AadhaarUploadErrorRouteParams>,
-  string
->;
+type AadhaarUploadErrorRoute = RouteProp<
+  Record<'AadhaarUploadError', AadhaarUploadErrorRouteParams>,
+  'AadhaarUploadError'
+>;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea89c5f and 3474761.

📒 Files selected for processing (3)
  • app/src/navigation/home.ts (2 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/navigation/home.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
🧠 Learnings (3)
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Do NOT mock selfxyz/mobile-sdk-alpha in tests (avoid jest.mock('selfxyz/mobile-sdk-alpha') and replacing real functions with mocks)

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Use actual imports from selfxyz/mobile-sdk-alpha in tests

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
🧬 Code graph analysis (2)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (6)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • black (8-8)
  • slate500 (43-43)
  • white (59-59)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
app/src/components/buttons/SecondaryButton.tsx (1)
  • SecondaryButton (12-32)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (11)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/hooks/useModal.ts (1)
  • useModal (15-54)
common/src/utils/aadhaar/utils.ts (2)
  • getAadharRegistrationWindow (382-398)
  • extractQRDataFields (245-326)
common/src/utils/types.ts (1)
  • AadhaarData (15-22)
app/src/providers/passportDataProvider.tsx (1)
  • storePassportData (800-804)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • ProofEvents (106-166)
app/src/utils/qrScanner.ts (2)
  • scanQRCodeFromPhotoLibrary (42-48)
  • isQRScannerPhotoLibraryAvailable (34-36)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • slate500 (43-43)
  • slate400 (39-39)
  • white (59-59)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
🪛 GitHub Check: build-deps
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[warning] 45-45:
Insert ⏎·······


[warning] 39-39:
Insert ⏎·········


[warning] 13-13:
'Title' is defined but never used


[failure] 5-5:
Run autofix to sort these imports!

🪛 GitHub Check: workspace-lint
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[warning] 45-45:
Insert ⏎·······


[warning] 39-39:
Insert ⏎·········


[warning] 13-13:
'Title' is defined but never used


[failure] 5-5:
Run autofix to sort these imports!

🪛 GitHub Actions: Mobile CI
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[error] 5-5: yarn lint failed: simple-import-sort/imports: Run autofix to sort these imports!

🪛 GitHub Actions: Workspace CI
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx

[error] 5-5: simple-import-sort/imports: Run autofix to sort these imports.

⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: e2e-ios
  • GitHub Check: analyze-ios

Comment on lines +69 to +71
borderBlockWidth={1}
borderBlockColor={slate200}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

borderBlock props aren’t supported on RN; borders won’t render on native.*

Tamagui/RN don’t support logical CSS properties like borderBlockWidth/borderBlockColor. Use explicit top/bottom borders.

Apply this diff:

-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderBottomWidth={1}
+        borderColor={slate200}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
borderBlockWidth={1}
borderBlockColor={slate200}
>
borderTopWidth={1}
borderBottomWidth={1}
borderColor={slate200}
>
🤖 Prompt for AI Agents
In app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx around lines
69-71, the Component is using unsupported logical CSS properties
borderBlockWidth and borderBlockColor which won't render on React Native;
replace them with explicit RN-supported properties by setting borderTopWidth and
borderBottomWidth to 1 and borderTopColor and borderBottomColor to slate200 (or
use the same color variable) so both top and bottom borders render correctly on
native.

Comment on lines +111 to +120
const aadhaarData: AadhaarData = {
documentType: 'aadhaar',
documentCategory: 'aadhaar',
mock: false,
qrData: qrCodeData,
extractedFields: extractedFields,
signature: [],
publicKey: '',
photoHash: '',
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

AadhaarData shape and integrity: remove unknown field and avoid placeholder crypto

  • Type likely has no documentType; this object literal will fail type-checking.
  • Storing empty signature/publicKey undermines verification.
-        const aadhaarData: AadhaarData = {
-          documentType: 'aadhaar',
+        const aadhaarData: AadhaarData = {
           documentCategory: 'aadhaar',
           mock: false,
           qrData: qrCodeData,
           extractedFields: extractedFields,
-          signature: [],
-          publicKey: '',
+          // TODO: populate real signature/publicKey from the QR payload or trust anchor
+          signature: [],
+          publicKey: '',
           photoHash: '',
         };

Follow-up:

  • Populate signature/publicKey from the QR payload (or extend common utils to expose them). If not immediately available, gate persistence or make these fields optional in the type, then fill before verification.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const aadhaarData: AadhaarData = {
documentType: 'aadhaar',
documentCategory: 'aadhaar',
mock: false,
qrData: qrCodeData,
extractedFields: extractedFields,
signature: [],
publicKey: '',
photoHash: '',
};
const aadhaarData: AadhaarData = {
documentCategory: 'aadhaar',
mock: false,
qrData: qrCodeData,
extractedFields: extractedFields,
// TODO: populate real signature/publicKey from the QR payload or trust anchor
signature: [],
publicKey: '',
photoHash: '',
};

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
app/src/utils/proving/provingMachine.ts (3)

1494-1504: Disclose payload type mismatch with getPayload – this will break disclose flows

circuitTypeWithDocumentExtension is set to "disclose" for disclose flows, but you cast it to a union that excludes "disclose" when calling getPayload. If getPayload doesn’t handle "disclose", runtime behavior is undefined and can fail silently.

Fix either by extending getPayload to support "disclose" (recommended), or by introducing a dedicated disclose payload builder. Also remove the unsafe cast so TS catches future regressions.

Apply this diff here (assumes common getPayload is updated to accept "disclose"):

-        const payload = getPayload(
-          inputs,
-          circuitTypeWithDocumentExtension as
-            | 'register_id'
-            | 'dsc_id'
-            | 'register'
-            | 'dsc',
-          circuitName as string,
-          endpointType as EndpointType,
-          endpoint as string,
-          selfApp?.version,
-          userDefinedData,
-        );
+        type PayloadCircuit = 'register_id' | 'dsc_id' | 'register' | 'dsc' | 'disclose';
+        const payloadCircuit: PayloadCircuit =
+          (circuitTypeWithDocumentExtension as PayloadCircuit);
+        const payload = getPayload(
+          inputs,
+          payloadCircuit,
+          circuitName as string,
+          endpointType as EndpointType,
+          endpoint as string,
+          selfApp?.version,
+          userDefinedData,
+        );

If getPayload cannot be changed immediately, gate disclose behind a separate helper (e.g., getDisclosePayload) and call that here.


70-93: Guard against ‘dsc’ for Aadhaar to prevent wrong circuit mapping

When circuitType === 'dsc', Aadhaar currently falls through to 'DSC_ID'. Aadhaar doesn’t have a DSC flow and this will resolve to an invalid Socket URL/mapping.

Apply this diff:

 const getMappingKey = (
   circuitType: 'disclose' | 'register' | 'dsc',
   documentCategory: DocumentCategory,
 ): string => {
   if (circuitType === 'disclose') {
     if (documentCategory === 'passport') return 'DISCLOSE';
     if (documentCategory === 'id_card') return 'DISCLOSE_ID';
     if (documentCategory === 'aadhaar') return 'DISCLOSE_AADHAAR';
     throw new Error(
       `Unsupported document category for disclose: ${documentCategory}`,
     );
   }
   if (circuitType === 'register') {
     if (documentCategory === 'passport') return 'REGISTER';
     if (documentCategory === 'id_card') return 'REGISTER_ID';
     if (documentCategory === 'aadhaar') return 'REGISTER_AADHAAR';
     throw new Error(
       `Unsupported document category for register: ${documentCategory}`,
     );
   }
-  // circuitType === 'dsc'
-  return documentCategory === 'passport' ? 'DSC' : 'DSC_ID';
+  // circuitType === 'dsc'
+  if (documentCategory === 'aadhaar') {
+    throw new Error(`Unsupported document category for dsc: ${documentCategory}`);
+  }
+  return documentCategory === 'passport' ? 'DSC' : 'DSC_ID';
 };

95-107: Use IDDocument in resolveWebSocketUrl to avoid unsafe casts and future bugs

resolveWebSocketUrl is typed to PassportData, but you pass AadhaarData too (via cast at call site). This undermines type safety and can hide bugs as the code evolves.

Apply this diff:

-const resolveWebSocketUrl = (
-  circuitType: 'disclose' | 'register' | 'dsc',
-  passportData: PassportData,
-  circuitName: string,
-): string | undefined => {
-  const { documentCategory } = passportData;
+const resolveWebSocketUrl = (
+  circuitType: 'disclose' | 'register' | 'dsc',
+  passportData: IDDocument,
+  circuitName: string,
+): string | undefined => {
+  const { documentCategory } = passportData;
   const circuitsMapping =
     useProtocolStore.getState()[documentCategory].circuits_dns_mapping;
   const mappingKey = getMappingKey(circuitType, documentCategory);
   return circuitsMapping?.[mappingKey]?.[circuitName];
 };

And update the call:

-      const wsRpcUrl = resolveWebSocketUrl(
-        circuitType,
-        passportData as PassportData,
-        circuitName,
-      );
+      const wsRpcUrl = resolveWebSocketUrl(
+        circuitType,
+        passportData,
+        circuitName,
+      );

Also applies to: 1231-1235

app/src/utils/email.ts (1)

23-31: Harden mail compose flow and centralize support address.

Linking.openURL('mailto:…') is used unguarded in app/src/utils/email.ts (sendCountrySupportNotification and sendFeedbackEmail) and the support address is hard-coded. Add a single SUPPORT_EMAIL constant, import Alert, implement openEmail(recipient, subject, body) that uses Linking.canOpenURL(url) + try/catch and shows an Alert fallback, replace both mailto calls with await openEmail(recipient, subject, body), and default recipient params to SUPPORT_EMAIL. Verify on iOS/Android devices without a configured mail client and with very long email bodies.

app/src/screens/home/HomeScreen.tsx (1)

44-61: Prevent overlapping loads and stale state; also sanitize error logging

useFocusEffect re-triggers loadDocuments on every focus. Without an in‑flight guard/cleanup, concurrent calls can race and set state after navigation/unmount. Also, console.warn(error) risks leaking sensitive details. Add a load token and sanitize logs.

Apply this diff:

@@
-  const loadDocuments = useCallback(async () => {
-    setLoading(true);
-    try {
-      const catalog = await loadDocumentCatalog();
-      const docs = await getAllDocuments();
-
-      setDocumentCatalog(catalog);
-      setAllDocuments(docs);
-
-      if (catalog.documents.length === 0) {
-        navigation.navigate('Launch' as never);
-      }
-    } catch (error) {
-      console.warn('Failed to load documents:', error);
-      navigation.navigate('Launch' as never);
-    }
-    setLoading(false);
-  }, [loadDocumentCatalog, getAllDocuments, navigation]);
+  const latestLoadIdRef = React.useRef(0);
+  const loadDocuments = useCallback(async () => {
+    const loadId = ++latestLoadIdRef.current;
+    setLoading(true);
+    try {
+      const [catalog, docs] = await Promise.all([
+        loadDocumentCatalog(),
+        getAllDocuments(),
+      ]);
+      if (loadId !== latestLoadIdRef.current) return;
+      setDocumentCatalog(catalog);
+      setAllDocuments(docs);
+      if (catalog.documents.length === 0) {
+        navigation.navigate('Launch' as never);
+      }
+    } catch {
+      if (loadId !== latestLoadIdRef.current) return;
+      // Avoid leaking error details in logs
+      console.warn('Failed to load documents');
+      navigation.navigate('Launch' as never);
+    } finally {
+      if (loadId === latestLoadIdRef.current) {
+        setLoading(false);
+      }
+    }
+  }, [loadDocumentCatalog, getAllDocuments, navigation]);
@@
-  useFocusEffect(
-    useCallback(() => {
-      loadDocuments();
-    }, [loadDocuments]),
-  );
+  useFocusEffect(
+    useCallback(() => {
+      loadDocuments();
+      return () => {
+        // Invalidate any in-flight load on blur/unfocus
+        latestLoadIdRef.current++;
+      };
+    }, [loadDocuments]),
+  );

Additionally, ensure the React import includes useRef if not using React.useRef directly:

import React, { useCallback, useRef, useState } from 'react';

Also applies to: 63-67

♻️ Duplicate comments (7)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (6)

275-276: Fix user‑facing typo (“mAadaar” → “mAadhaar”)

Brand/copy correctness.

-          Generate a QR code from the mAadaar app
+          Generate a QR code from the mAadhaar app

118-127: AadhaarData shape mismatch and placeholder crypto undermine integrity

documentType is not in AadhaarData; signature/publicKey placeholders risk downstream verification.

-        const aadhaarData: AadhaarData = {
-          documentType: 'aadhaar',
+        const aadhaarData: AadhaarData = {
           documentCategory: 'aadhaar',
           mock: false,
           qrData: qrCodeData,
           extractedFields: extractedFields,
           signature: [],
           publicKey: '',
           photoHash: '',
         };

Follow‑up: either (a) derive signature/publicKey from the QR payload utilities before persisting, or (b) make them optional and gate persistence until available.


76-76: Remove PII from logs (QR blob and extracted fields)

Logging QR payload and parsed identity data risks PII leakage.

-        console.log('Processing Aadhaar QR code:', qrCodeData);
+        console.log('Processing Aadhaar QR code');
@@
-          console.log('Extracted Aadhaar fields:', extractedFields);
+          console.log('Extracted Aadhaar fields parsed');

Also applies to: 100-101


22-22: Do not import mock safe‑area hook in production

Mocks will crash on device/release. Use the real package.

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

271-273: Unsupported RN/Tamagui props: borderBlock are ignored*

Swap to explicit borderTopWidth/borderTopColor to render the divider.

-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderTopColor={slate200}

61-71: Timestamp parsing is non‑portable; compare against seconds with drift

new Date("YYYY-MM-DD HH:MM") is platform‑dependent. Also, allowedWindow is seconds. Parse as UTC and compare seconds with ±5m drift.

-  const validateAAdhaarTimestamp = useCallback(async (timestamp: string) => {
-    //timestamp is in YYYY-MM-DD HH:MM format
-    const currentTimestamp = new Date().getTime();
-    const timestampDate = new Date(timestamp);
-    const timestampTimestamp = timestampDate.getTime();
-    const diff = currentTimestamp - timestampTimestamp;
-    const diffMinutes = diff / (1000 * 60);
-
-    const allowedWindow = await getAadharRegistrationWindow();
-    return diffMinutes <= allowedWindow;
-  }, []);
+  const validateAAdhaarTimestamp = useCallback(async (timestamp: string) => {
+    // Expected "YYYY-MM-DD HH:MM" (no TZ). Parse deterministically as UTC.
+    const m = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})$/.exec(timestamp);
+    if (!m) return false;
+    const [, y, mo, d, h, mi] = m;
+    const tsMs = Date.UTC(+y, +mo - 1, +d, +h, +mi);
+    if (!Number.isFinite(tsMs)) return false;
+    const nowMs = Date.now();
+    const ageSec = Math.abs((nowMs - tsMs) / 1000);
+    const windowRaw = await getAadharRegistrationWindow();
+    const windowSec = Number(windowRaw) || 120;
+    const driftSec = 300; // ±5 min
+    return ageSec <= windowSec + driftSec;
+  }, []);
app/src/screens/system/LaunchScreen.tsx (1)

88-96: Duplicate testID for two primary CTAs breaks E2E and creates ambiguity

Both buttons use testID="launch-get-started-button". Give Aadhaar a unique testID; analytics events are already distinct.

           <AbstractButton
             trackEvent={AppEvents.GET_STARTED_BIOMETRIC}
             onPress={onStartPress}
             bgColor={white}
             color={black}
-            testID="launch-get-started-button"
+            testID="launch-get-started-button"
           >
             I have a Passport or Biometric ID
           </AbstractButton>
           <AbstractButton
             trackEvent={AppEvents.GET_STARTED_AADHAAR}
             onPress={onAadhaarPress}
             bgColor={white}
             color={black}
-            testID="launch-get-started-button"
+            testID="launch-get-started-aadhaar-button"
           >
             I have an Aadhaar Card
           </AbstractButton>

Also applies to: 97-105

🧹 Nitpick comments (2)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)

5-16: Add explicit “cancelled” signal for photo-library flow

Differentiate user cancellations from failures to keep funnels clean.

 export const AadhaarEvents = {
   UPLOAD_SCREEN_OPENED: 'Aadhaar: Upload Screen Opened',
   QR_UPLOAD_REQUESTED: 'Aadhaar: QR Upload Requested',
   QR_UPLOAD_SUCCESS: 'Aadhaar: QR Upload Success',
   QR_UPLOAD_FAILED: 'Aadhaar: QR Upload Failed',
+  QR_UPLOAD_CANCELLED: 'Aadhaar: QR Upload Cancelled',
   PERMISSION_MODAL_OPENED: 'Aadhaar: Permission Modal Opened',
   PERMISSION_MODAL_DISMISSED: 'Aadhaar: Permission Modal Dismissed',
   PERMISSION_SETTINGS_OPENED: 'Aadhaar: Permission Settings Opened',
   PROCESSING_STARTED: 'Aadhaar: Processing Started',
   PROCESSING_FAILED: 'Aadhaar: Processing Failed',
   VALIDATION_FAILED: 'Aadhaar: Validation Failed',
 };
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1)

9-9: Type navigation to remove as any and catch route typos at compile time

Use a typed NavigationProp for the Aadhaar routes.

-import { useNavigation } from '@react-navigation/native';
+import { useNavigation, type NavigationProp } from '@react-navigation/native';
@@
-  const navigation = useNavigation();
+  type AadhaarRoutes = {
+    AadhaarUploadSuccess: undefined;
+    AadhaarUploadError: { errorType: 'expired' | 'general' };
+  };
+  const navigation = useNavigation<NavigationProp<AadhaarRoutes>>();
@@
-        (navigation.navigate as any)('AadhaarUploadError', { errorType });
+        navigation.navigate('AadhaarUploadError', { errorType });
@@
-        (navigation.navigate as any)('AadhaarUploadError', {
+        navigation.navigate('AadhaarUploadError', {
           errorType: 'general',
         });
@@
-      (navigation.navigate as any)('AadhaarUploadError', {
+      navigation.navigate('AadhaarUploadError', {
         errorType: 'general',
       });

Also applies to: 33-33, 150-151, 222-231

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63f4076 and 9d60335.

📒 Files selected for processing (13)
  • app/src/components/NavBar/AadhaarNavBar.tsx (1 hunks)
  • app/src/providers/passportDataProvider.tsx (5 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx (1 hunks)
  • app/src/screens/home/HomeScreen.tsx (3 hunks)
  • app/src/screens/prove/ConfirmBelongingScreen.tsx (3 hunks)
  • app/src/screens/recovery/AccountVerifiedSuccessScreen.tsx (1 hunks)
  • app/src/screens/system/LaunchScreen.tsx (5 hunks)
  • app/src/utils/email.ts (2 hunks)
  • app/src/utils/proving/provingMachine.ts (13 hunks)
  • packages/mobile-sdk-alpha/mobile-sdk-alpha.podspec (2 hunks)
  • packages/mobile-sdk-alpha/src/constants/analytics.ts (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • app/src/screens/recovery/AccountVerifiedSuccessScreen.tsx
  • packages/mobile-sdk-alpha/mobile-sdk-alpha.podspec
  • app/src/providers/passportDataProvider.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/src/screens/prove/ConfirmBelongingScreen.tsx
  • app/src/components/NavBar/AadhaarNavBar.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • app/src/utils/email.ts
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/home/HomeScreen.tsx
  • app/src/screens/system/LaunchScreen.tsx
  • packages/mobile-sdk-alpha/src/constants/analytics.ts
  • app/src/utils/proving/provingMachine.ts
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/utils/email.ts
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/home/HomeScreen.tsx
  • app/src/screens/system/LaunchScreen.tsx
  • app/src/utils/proving/provingMachine.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/mobile-sdk-alpha/AGENTS.md)

packages/mobile-sdk-alpha/**/*.{ts,tsx}: Use strict TypeScript type checking across the codebase
Follow ESLint TypeScript-specific rules
Avoid introducing circular dependencies

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}: Review alpha mobile SDK code for:

  • API consistency with core SDK
  • Platform-neutral abstractions
  • Performance considerations
  • Clear experimental notes or TODOs

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
🧠 Learnings (13)
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Never log PII, credentials, or private keys (especially in production); redact sensitive fields consistently

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: No raw PII should appear in logs or network traffic

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-29T15:30:12.210Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-08-29T15:30:12.210Z
Learning: Ensure no sensitive data (PII, credentials, tokens) appears in logs

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-29T15:30:12.210Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-08-29T15:30:12.210Z
Learning: Document complex native module changes for AI review

Applied to files:

  • app/src/screens/home/HomeScreen.tsx
  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-09-10T14:47:40.945Z
Learnt from: shazarre
PR: selfxyz/self#1041
File: app/src/providers/passportDataProvider.tsx:297-301
Timestamp: 2025-09-10T14:47:40.945Z
Learning: In app/src/providers/passportDataProvider.tsx: The deleteDocumentDirectlyFromKeychain function is a low-level utility used by the DocumentsAdapter and should not include error handling since callers like deleteDocument() already implement appropriate try/catch with logging for Keychain operations.

Applied to files:

  • app/src/screens/home/HomeScreen.tsx
  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Use custom hooks for complex state (useModal, useHapticNavigation)

Applied to files:

  • app/src/screens/system/LaunchScreen.tsx
📚 Learning: 2025-08-25T14:25:57.586Z
Learnt from: aaronmgdr
PR: selfxyz/self#951
File: app/src/providers/authProvider.web.tsx:17-18
Timestamp: 2025-08-25T14:25:57.586Z
Learning: The selfxyz/mobile-sdk-alpha/constants/analytics import path is properly configured with SDK exports, Metro aliases, and TypeScript resolution. Import changes from @/consts/analytics to this path are part of valid analytics migration, not TypeScript resolution issues.

Applied to files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Test isPassportDataValid() with realistic synthetic passport data (never real user data)

Applied to files:

  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to circuits/circuits/disclose/vc_and_disclose.circom : Disclosure circuit must support document type disclosure: passport vs EU ID card

Applied to files:

  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Passport verification workflow: NFC data extraction → MRZ validation → DSC verification → Register proof → compliance via ZK → attestation

Applied to files:

  • app/src/utils/proving/provingMachine.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to circuits/circuits/disclose/vc_and_disclose.circom : Disclosure circuit must preserve privacy so no raw PII leaves the device; only commitments are output

Applied to files:

  • app/src/utils/proving/provingMachine.ts
🧬 Code graph analysis (4)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (8)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/hooks/useModal.ts (1)
  • useModal (15-54)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • AadhaarEvents (5-16)
common/src/utils/aadhaar/utils.ts (2)
  • getAadharRegistrationWindow (382-398)
  • extractQRDataFields (245-326)
common/src/utils/types.ts (1)
  • AadhaarData (15-22)
app/src/providers/passportDataProvider.tsx (1)
  • storePassportData (800-804)
app/src/utils/qrScanner.ts (2)
  • scanQRCodeFromPhotoLibrary (42-48)
  • isQRScannerPhotoLibraryAvailable (34-36)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
app/src/screens/home/HomeScreen.tsx (4)
packages/mobile-sdk-alpha/src/context.tsx (1)
  • useSelfClient (64-68)
app/src/hooks/useConnectionModal.ts (1)
  • useConnectionModal (35-67)
app/src/providers/passportDataProvider.tsx (1)
  • usePassport (824-826)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • DocumentEvents (62-75)
app/src/screens/system/LaunchScreen.tsx (4)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • AppEvents (18-27)
app/src/utils/colors.ts (2)
  • white (59-59)
  • black (8-8)
app/src/components/buttons/AbstractButton.tsx (1)
  • AbstractButton (38-89)
app/src/utils/proving/provingMachine.ts (3)
common/src/utils/types.ts (3)
  • IDDocument (56-56)
  • PassportData (65-76)
  • DocumentCategory (37-37)
common/src/utils/circuits/registerInputs.ts (2)
  • generateTEEInputsRegister (240-265)
  • generateTEEInputsDSC (109-119)
common/src/utils/passports/validate.ts (1)
  • checkIfPassportDscIsInTree (126-139)
🪛 GitHub Check: build-deps
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 230-230:
Unexpected any. Specify a different type


[warning] 222-222:
Unexpected any. Specify a different type


[warning] 150-150:
Unexpected any. Specify a different type

🪛 GitHub Check: workspace-lint
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 230-230:
Unexpected any. Specify a different type


[warning] 222-222:
Unexpected any. Specify a different type


[warning] 150-150:
Unexpected any. Specify a different type

⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: build-ios
  • GitHub Check: build-android
  • GitHub Check: test
  • GitHub Check: Cursor Bugbot
  • GitHub Check: e2e-ios
  • GitHub Check: analyze-ios
  • GitHub Check: analyze-android
🔇 Additional comments (3)
app/src/utils/proving/provingMachine.ts (2)

1218-1236: Double‑check DNS mapping for disclose_aadhaar is deployed in both envs

You resolve circuitName to 'disclose_aadhaar' for Aadhaar then look it up via circuits_dns_mapping. If that mapping key is missing in staging or prod, wsRpcUrl is undefined and the flow fails at connection.

Please confirm:

  • circuits_dns_mapping contains DISCLOSE_AADHAAR.disclose_aadhaar for both 'stg' and 'prod'
  • The relayer actually serves a WS endpoint at the resolved URL

204-210: AES‑GCM nonce strategy verified — no changes required

encryptAES256GCM (common/src/utils/proving.ts) uses forge.random.getBytesSync(12) to generate a fresh 12‑byte (96‑bit) IV per call and sets tagLength: 128 (16 bytes). Meets CSPRNG IV and >=16‑byte auth‑tag requirements.

app/src/utils/email.ts (1)

81-87: Prevent leakage of sensitive data in error payloads; bound the size.

The sanitized error is emailed in clear text. If sanitizeErrorMessage misses something, users could inadvertently send secrets (Aadhaar number, PAN, seed phrase/private key, MRZ, QR contents). At minimum, clamp the size and revisit redaction.

Apply this minimal guard and reuse the safe opener here as well:

 export const sendFeedbackEmail = async ({
   message,
   origin,
   subject = 'SELF App Feedback',
-  recipient = '[email protected]',
+  recipient = SUPPORT_EMAIL,
 }: SendFeedbackEmailOptions): Promise<void> => {
@@
-    ['error', sanitizeErrorMessage(message)],
+    // Bound the size to reduce accidental leakage and mailto truncation.
+    ['error', sanitizeErrorMessage(message).slice(0, 512)],
@@
-  await Linking.openURL(
-    `mailto:${recipient}?subject=${encodeURIComponent(
-      subject,
-    )}&body=${encodeURIComponent(body)}`,
-  );
+  await openEmail(recipient, subject, body);

Please verify the sanitizer covers:

  • Aadhaar (12 digits; redact or mask), PAN (AAAPL1234A‑like), MRZ lines, QR payloads.
  • Keys/seeds: 0x-prefixed 64‑hex, base64‑like blobs, and 12/24‑word BIP‑39 mnemonics.

Run this script to locate the sanitizer and quickly assess existing redactors; share findings:

Happy to draft a robust redaction helper (with tests) if desired.

Also applies to: 97-101, 110-115

Comment on lines 123 to 127
selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
document_id: metadata.id,
document_type: documentData.data.documentType,
document_category: documentData.data.documentCategory,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Remove or pseudonymize document_id in analytics to avoid PII leakage

Sending raw document_id with DOCUMENT_SELECTED can expose sensitive identifiers (compliance/privacy risk). Either drop it or send a one‑way, keyed, domain‑separated hash computed on‑device.

Minimal safe change (drop identifier):

-                selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
-                  document_id: metadata.id,
-                  document_type: documentData.data.documentType,
-                  document_category: documentData.data.documentCategory,
-                });
+                selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
+                  document_type: documentData.data.documentType,
+                  document_category: documentData.data.documentCategory,
+                });

If you must retain per-document telemetry, switch to a pseudonymous ID (e.g., HMAC-SHA256(appScopedKey, doc:${metadata.id})) stored in secure storage; do not log the raw ID.

Run this to find other occurrences emitting document_id:


🏁 Script executed:

#!/bin/bash
# Find analytics calls that send document_id (repo-wide)
rg -n -C2 -S "trackEvent\\(" --type=ts --type=tsx
rg -n -C1 -S "\\bdocument_id\\b" --type=ts --type=tsx

Length of output: 55


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Searching repo for analytics calls and any usages of document identifiers..."

PATTERNS=(
  "selfClient\.trackEvent"
  "trackEvent\s*\("
  "\bdocument_id\b"
  "\bdocumentId\b"
  "\bdoc_id\b"
  "\bdocId\b"
  "metadata\.id"
  "DOCUMENT_SELECTED"
)

if command -v rg >/dev/null 2>&1; then
  for p in "${PATTERNS[@]}"; do
    echo "=== PATTERN: $p ==="
    rg -n -S --hidden -g '!*node_modules/**' -g '**/*.{ts,tsx,js,jsx,json,md}' -C2 "$p" || true
  done
else
  echo "rg not available, falling back to git grep"
  git grep -n --untracked -E "$(IFS='|'; echo "${PATTERNS[*]}")" || true
fi

Length of output: 127372


Remove/pseudonymize document IDs from analytics — critical PII leak

Raw document identifiers are being sent to analytics in multiple places; remove them or replace with a one‑way pseudonym (PII/compliance risk).

  • Immediate locations to fix:

    • app/src/screens/home/HomeScreen.tsx — DOCUMENT_SELECTED includes document_id: metadata.id.
    • app/src/utils/proving/validateDocument.ts — multiple events (VALIDATE_DOCUMENT_FAILED, DOCUMENT_VALIDATED, etc.) include documentId.
    • app/src/screens/prove/ProveScreen.tsx — events include documentId in payloads.
    • app/src/providers/passportDataProvider.tsx — avoid console logs or telemetry that expose documentId; Keychain service names include documentId (internal only).
    • packages/mobile-sdk-alpha/src/documents/utils.ts — metadata.id is used; ensure it is not forwarded raw to analytics.
  • Minimal safe change (apply at HomeScreen and mirror elsewhere):

-                selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
-                  document_id: metadata.id,
-                  document_type: documentData.data.documentType,
-                  document_category: documentData.data.documentCategory,
-                });
+                selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
+                  document_type: documentData.data.documentType,
+                  document_category: documentData.data.documentCategory,
+                });
  • If per‑document telemetry is required, derive a stable pseudonymous id on‑device and send that instead — e.g.:
    • id = BASE64URL(HMAC_SHA256(appScopedSecret, doc:${documentId}))
    • Store appScopedSecret in secure device storage (iOS Keychain / Android Keystore), compute on‑device, cache the mapping, never log or transmit the raw documentId.

Run a repo‑wide fix for any analytics payload containing document_id/documentId/docId and update analytics consumers to accept the pseudonymized field.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
document_id: metadata.id,
document_type: documentData.data.documentType,
document_category: documentData.data.documentCategory,
});
selfClient.trackEvent(DocumentEvents.DOCUMENT_SELECTED, {
document_type: documentData.data.documentType,
document_category: documentData.data.documentCategory,
});

export function genMockIdDocAndInitDataParsing(userInput: Partial<IdDocInput> = {}) {
return initPassportDataParsing({
...genMockIdDoc(userInput),
...(genMockIdDoc(userInput) as PassportData),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: IDDocument Type Casting Causes Runtime Errors

Functions like genMockIdDocAndInitDataParsing and checkIfPassportDscIsInTree incorrectly assume IDDocument is always PassportData. This leads to explicit or implicit type casting issues, causing runtime errors when processing AadhaarData documents that lack PassportData-specific fields like dsc_parsed or csca_parsed.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/providers/passportDataProvider.tsx (1)

781-792: Do not store raw Aadhaar QR data in catalog metadata

Catalog is a master index; putting full qrData here increases PII exposure surface unnecessarily. Use contentHash as ID and keep Aadhaar metadata minimal (or derived, e.g., last4).

Apply:

   const metadata: DocumentMetadata = {
     id: contentHash,
     documentType: passportData.documentType,
     documentCategory:
       passportData.documentCategory ||
       inferDocumentCategory(
         (passportData as PassportData | AadhaarData).documentType,
       ),
-    data: isMRZDocument(passportData)
-      ? (passportData as PassportData).mrz
-      : (passportData as AadhaarData).qrData || '', // Store MRZ for passports/IDs, relevant data for aadhaar
+    data: isMRZDocument(passportData)
+      ? (passportData as PassportData).mrz
+      : '', // Avoid persisting raw Aadhaar QR in catalog metadata
     mock: passportData.mock || false,
     isRegistered: false,
   };

If UI needs Aadhaar preview, load the full document (as HomeScreen already does) and derive a safe display value from extractedFields.

♻️ Duplicate comments (8)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (4)

23-23: Do not import mock hooks in production

Using '@/mocks/react-native-safe-area-context' will break on device/release.

Apply:

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

270-277: Unsupported border props in RN/Tamagui will be ignored

borderBlockWidth/borderBlockColor aren’t supported; the divider won’t render.

Apply:

-      <YStack
+      <YStack
         paddingHorizontal={20}
         paddingTop={20}
         alignItems="center"
         paddingVertical={25}
-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderTopColor={slate200}
       >

68-91: Timestamp validation: non-ISO parse + unit mismatch (seconds vs minutes)

new Date('YYYY-MM-DD HH:MM') is platform-dependent; allowedWindow is seconds from chain. This risks accepting stale/invalid QRs.

Apply:

-  const validateAAdhaarTimestamp = useCallback(
-    async (timestamp: string) => {
-      //timestamp is in YYYY-MM-DD HH:MM format
-      trackEvent(AadhaarEvents.TIMESTAMP_VALIDATION_STARTED);
-
-      const currentTimestamp = new Date().getTime();
-      const timestampDate = new Date(timestamp);
-      const timestampTimestamp = timestampDate.getTime();
-      const diff = currentTimestamp - timestampTimestamp;
-      const diffMinutes = diff / (1000 * 60);
-
-      const allowedWindow = await getAadharRegistrationWindow();
-      const isValid = diffMinutes <= allowedWindow;
+  const validateAAdhaarTimestamp = useCallback(
+    async (timestamp: string) => {
+      // Expected: "YYYY-MM-DD HH:MM" (no TZ) — parse deterministically as UTC
+      trackEvent(AadhaarEvents.TIMESTAMP_VALIDATION_STARTED);
+      const m = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})$/.exec(timestamp);
+      if (!m) return false;
+      const [, y, mo, d, h, mi] = m;
+      const tsMs = Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi));
+      if (!Number.isFinite(tsMs)) return false;
+      const nowMs = Date.now();
+      const ageSeconds = Math.abs((nowMs - tsMs) / 1000);
+      const windowRaw = await getAadharRegistrationWindow();
+      const windowSeconds = Number(windowRaw) || 120;
+      const driftSeconds = 300; // ±5m drift tolerance
+      const isValid = ageSeconds <= windowSeconds + driftSeconds;

141-150: Do not persist empty signature/publicKey for Aadhaar — require real crypto before storing

Persisting placeholders (signature: [], publicKey: '') in app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx creates a false “valid” state while common/src/utils/types.ts declares these fields as required; this undermines downstream verification/proof-generation.

  • Fix options (pick one):

    • Gate persistence: refuse to call storePassportData(...) until signature and publicKey are extracted and non-empty; surface a user error if missing. (Immediate, minimal-change.)
    • Make fields optional: change AadhaarData in common/src/utils/types.ts to signature?: number[] and publicKey?: string, remove placeholders from the screen, and ensure all consumers handle the optional fields. Impacted files to update: common/src/utils/circuits/registerInputs.ts, common/src/utils/passports/validate.ts, app/src/providers/passportDataProvider.tsx, packages/mobile-sdk-alpha/src/documents/utils.ts (and related tests/circuits).
  • Short actionable patch (if choosing gating): in AadhaarUploadScreen before storePassportData:

    • if (!signature?.length || !publicKey) throw / show error and do not persist.

Files to change:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (lines ~141–150)
  • common/src/utils/types.ts (AadhaarData)
app/src/screens/home/HomeScreen.tsx (1)

123-126: Good: removed document_id from HomeScreen — but analytics still emit documentId (PII risk)

validateDocument.ts contains multiple trackEvent payloads that include documentId; remove or anonymize (hash/replace with non-identifying metadata) before emitting.

  • app/src/utils/proving/validateDocument.ts — trackEvent payloads include documentId (occurrences around lines 46, 91, 109, 141, 153, 157; e.g., DocumentEvents.VALIDATE_DOCUMENT_FAILED, DocumentEvents.DOCUMENT_VALIDATED).
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (3)

109-116: Avoid shipping a no‑op “Need Help?” button.

Until help flow exists, disable the button to prevent user confusion and flaky QA.

-            <SecondaryButton
-              onPress={() => {
-                trackEvent(AadhaarEvents.HELP_BUTTON_PRESSED, { errorType });
-                // TODO: Implement help functionality
-              }}
-            >
+            <SecondaryButton disabled onPress={undefined}>
               Need Help?
             </SecondaryButton>

Follow‑up: wire this to your support route or help center URL and re‑enable.


17-17: Fix: replace test‑mock safe‑area import with the real library.

Mock insets break layout on devices and can mask issues in QA builds.

Apply this diff:

-import { useSafeAreaInsets } from '@/mocks/react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';

Run to ensure no other mock imports remain:

#!/bin/bash
set -euo pipefail
rg -n -S "@/mocks/react-native-safe-area-context|mocks/react-native-safe-area-context" app/src || echo "OK: no mock safe-area imports"

74-76: Fix: borderBlock not supported in React Native/Tamagui; borders won’t render.*

Use explicit top/bottom borders.

-        borderBlockWidth={1}
-        borderBlockColor={slate200}
+        borderTopWidth={1}
+        borderBottomWidth={1}
+        borderColor={slate200}
🧹 Nitpick comments (2)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (2)

7-9: Tighten navigation/route typing to avoid unsafe “string” routes.

Current Record<string,...> weakens TS guarantees and risks mis‑navigation. Prefer a typed param list.

 import type { RouteProp } from '@react-navigation/native';
 import { useNavigation, useRoute } from '@react-navigation/native';
+import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
@@
-type AadhaarUploadErrorRoute = RouteProp<
-  Record<string, AadhaarUploadErrorRouteParams>,
-  string
->;
+type AadhaarStackParamList = {
+  AadhaarUploadError: AadhaarUploadErrorRouteParams;
+};
+type AadhaarUploadErrorRoute = RouteProp<
+  AadhaarStackParamList,
+  'AadhaarUploadError'
+>;
@@
-  const navigation = useNavigation();
+  const navigation = useNavigation<NativeStackNavigationProp<AadhaarStackParamList>>();

If you already have a central navigation types module (e.g., HomeStackParamList), use that instead of the local AadhaarStackParamList.

Also applies to: 25-28, 32-32


99-103: Guard goBack to avoid dead‑ends (deep links/first screen cases).

Without a guard, goBack() can no‑op and strand users.

-                // Navigate back to upload screen to try again
-                navigation.goBack();
+                // Navigate back safely
+                if (navigation.canGoBack()) {
+                  navigation.goBack();
+                } else {
+                  navigation.popToTop();
+                }

Please verify via a deep link directly into this screen that the fallback works.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d60335 and 12c3866.

📒 Files selected for processing (9)
  • .gitguardian.yml (2 hunks)
  • .gitleaks.toml (1 hunks)
  • app/src/providers/passportDataProvider.tsx (8 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (1 hunks)
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx (1 hunks)
  • app/src/screens/home/HomeScreen.tsx (2 hunks)
  • app/src/screens/home/IdDetailsScreen.tsx (2 hunks)
  • packages/mobile-sdk-alpha/src/constants/analytics.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .gitleaks.toml
  • app/src/screens/document/aadhaar/AadhaarUploadedSuccessScreen.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/technical-specification.mdc)

**/*.{ts,tsx}: Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')
Define DSCKeyCommitment with fields: publicKeyHash (Poseidon hash), certificateChain (hashes), revocationStatus (boolean), issuer (country code)
Define VerificationConfig with fields: circuitVersion (semver), complianceRules array, timeWindow (seconds, 24h), clockDrift (±5 min), trustAnchors, revocationRoots, timeSource (NTP), nullifierScope (domain separation)

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
  • app/src/screens/home/IdDetailsScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/providers/passportDataProvider.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/home/HomeScreen.tsx
packages/mobile-sdk-alpha/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/mobile-sdk-alpha/AGENTS.md)

packages/mobile-sdk-alpha/**/*.{ts,tsx}: Use strict TypeScript type checking across the codebase
Follow ESLint TypeScript-specific rules
Avoid introducing circular dependencies

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}: Review alpha mobile SDK code for:

  • API consistency with core SDK
  • Platform-neutral abstractions
  • Performance considerations
  • Clear experimental notes or TODOs

Files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/screens/home/IdDetailsScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
  • app/src/providers/passportDataProvider.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
  • app/src/screens/home/HomeScreen.tsx
🧠 Learnings (14)
📚 Learning: 2025-08-25T14:25:57.586Z
Learnt from: aaronmgdr
PR: selfxyz/self#951
File: app/src/providers/authProvider.web.tsx:17-18
Timestamp: 2025-08-25T14:25:57.586Z
Learning: The selfxyz/mobile-sdk-alpha/constants/analytics import path is properly configured with SDK exports, Metro aliases, and TypeScript resolution. Import changes from @/consts/analytics to this path are part of valid analytics migration, not TypeScript resolution issues.

Applied to files:

  • packages/mobile-sdk-alpha/src/constants/analytics.ts
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: Applies to **/*.{ts,tsx} : Define IdentityCommitment with fields: commitment (Poseidon hash), nullifier (domain-separated), timestamp (UTC number), version (circuit version), documentType ('passport' | 'eu_id_card')

Applied to files:

  • app/src/screens/home/IdDetailsScreen.tsx
  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-09-10T14:47:40.945Z
Learnt from: shazarre
PR: selfxyz/self#1041
File: app/src/providers/passportDataProvider.tsx:297-301
Timestamp: 2025-09-10T14:47:40.945Z
Learning: In app/src/providers/passportDataProvider.tsx: The deleteDocumentDirectlyFromKeychain function is a low-level utility used by the DocumentsAdapter and should not include error handling since callers like deleteDocument() already implement appropriate try/catch with logging for Keychain operations.

Applied to files:

  • app/src/screens/home/IdDetailsScreen.tsx
  • app/src/providers/passportDataProvider.tsx
📚 Learning: 2025-08-24T18:52:25.796Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursorrules:0-0
Timestamp: 2025-08-24T18:52:25.796Z
Learning: Applies to src/navigation/**/*.{ts,tsx} : Use react-navigation/native with createStaticNavigation for type-safe navigation

Applied to files:

  • app/src/screens/home/IdDetailsScreen.tsx
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Test isPassportDataValid() with realistic synthetic passport data (never real user data)

Applied to files:

  • app/src/screens/home/IdDetailsScreen.tsx
  • app/src/providers/passportDataProvider.tsx
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Do NOT mock selfxyz/mobile-sdk-alpha in tests (avoid jest.mock('selfxyz/mobile-sdk-alpha') and replacing real functions with mocks)

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Use actual imports from selfxyz/mobile-sdk-alpha in tests

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx
📚 Learning: 2025-08-29T15:30:12.210Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-08-29T15:30:12.210Z
Learning: Document complex native module changes for AI review

Applied to files:

  • app/src/providers/passportDataProvider.tsx
  • app/src/screens/home/HomeScreen.tsx
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Never log PII, credentials, or private keys (especially in production); redact sensitive fields consistently

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-29T15:30:12.210Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-08-29T15:30:12.210Z
Learning: Ensure no sensitive data (PII, credentials, tokens) appears in logs

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-24T18:55:07.940Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/technical-specification.mdc:0-0
Timestamp: 2025-08-24T18:55:07.940Z
Learning: No raw PII should appear in logs or network traffic

Applied to files:

  • app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Never use real user PII in tests; use only synthetic, anonymized, or approved test vectors

Applied to files:

  • app/src/screens/home/HomeScreen.tsx
📚 Learning: 2025-08-26T14:49:11.190Z
Learnt from: shazarre
PR: selfxyz/self#936
File: app/src/screens/passport/PassportNFCScanScreen.tsx:28-31
Timestamp: 2025-08-26T14:49:11.190Z
Learning: The main App.tsx file is located at app/App.tsx (not in app/src), and it properly wraps the entire app with SelfClientProvider at the top of the provider hierarchy, enabling useSelfClient() hook usage throughout all navigation screens.

Applied to files:

  • app/src/screens/home/HomeScreen.tsx
🧬 Code graph analysis (5)
app/src/screens/home/IdDetailsScreen.tsx (1)
common/src/utils/types.ts (1)
  • IDDocument (56-56)
app/src/screens/document/aadhaar/AadhaarUploadErrorScreen.tsx (7)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • black (8-8)
  • slate500 (43-43)
  • white (59-59)
app/src/components/typography/BodyText.ts (1)
  • BodyText (9-11)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/components/buttons/PrimaryButton.tsx (1)
  • PrimaryButton (12-32)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • AadhaarEvents (5-39)
app/src/components/buttons/SecondaryButton.tsx (1)
  • SecondaryButton (12-32)
app/src/providers/passportDataProvider.tsx (3)
common/src/utils/types.ts (5)
  • IDDocument (56-56)
  • DocumentMetadata (39-46)
  • PassportData (65-76)
  • AadhaarData (15-22)
  • isMRZDocument (168-174)
packages/mobile-sdk-alpha/src/documents/utils.ts (3)
  • getAllDocuments (40-58)
  • storeDocumentWithDeduplication (158-201)
  • storePassportData (203-205)
common/src/utils/passports/passport.ts (1)
  • inferDocumentCategory (318-327)
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx (11)
app/src/mocks/react-native-safe-area-context.js (1)
  • useSafeAreaInsets (44-46)
app/src/navigation/index.tsx (1)
  • RootStackParamList (49-49)
app/src/hooks/useModal.ts (1)
  • useModal (15-54)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • AadhaarEvents (5-39)
app/src/utils/qrScanner.ts (2)
  • isQRScannerPhotoLibraryAvailable (34-36)
  • scanQRCodeFromPhotoLibrary (42-48)
common/src/utils/aadhaar/utils.ts (2)
  • getAadharRegistrationWindow (382-398)
  • extractQRDataFields (245-326)
common/src/utils/types.ts (1)
  • AadhaarData (15-22)
app/src/providers/passportDataProvider.tsx (1)
  • storePassportData (803-807)
app/ios/QRScannerBridge.swift (1)
  • scanQRCodeFromPhotoLibrary (35-48)
app/src/utils/colors.ts (5)
  • slate100 (33-33)
  • slate200 (35-35)
  • slate500 (43-43)
  • slate400 (39-39)
  • white (59-59)
app/src/utils/constants.ts (1)
  • extraYPadding (5-5)
app/src/screens/home/HomeScreen.tsx (4)
packages/mobile-sdk-alpha/src/context.tsx (1)
  • useSelfClient (64-68)
app/src/providers/passportDataProvider.tsx (1)
  • usePassport (827-829)
common/src/utils/types.ts (1)
  • IDDocument (56-56)
packages/mobile-sdk-alpha/src/constants/analytics.ts (1)
  • DocumentEvents (85-98)
🪛 GitHub Check: build-deps
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 234-234:
Unexpected any. Specify a different type


[warning] 227-227:
Unexpected any. Specify a different type


[warning] 167-167:
Unexpected any. Specify a different type

app/src/screens/home/HomeScreen.tsx

[warning] 15-15:
'PassportData' is defined but never used

🪛 GitHub Check: workspace-lint
app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx

[warning] 234-234:
Unexpected any. Specify a different type


[warning] 227-227:
Unexpected any. Specify a different type


[warning] 167-167:
Unexpected any. Specify a different type

app/src/screens/home/HomeScreen.tsx

[warning] 15-15:
'PassportData' is defined but never used

⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-ios
  • GitHub Check: e2e-ios
🔇 Additional comments (2)
app/src/screens/home/IdDetailsScreen.tsx (1)

12-12: Type unification with IDDocument — LGTM

Switching to IDDocument and updating state typing aligns this screen with the unified document model and avoids future narrowing issues when Aadhaar is selected.

Also applies to: 32-32

packages/mobile-sdk-alpha/src/constants/analytics.ts (1)

5-39: Aadhaar analytics surface — LGTM

Event taxonomy looks comprehensive and non-identifying. No PII in keys or values by default.

Also applies to: 45-46, 88-89

Comment on lines +1 to +5
# GitGuardian configuration for ggshield
# This file configures which files and secrets to ignore during scanning

# Ignore specific file patterns (newer format)
ignore:
# Ignore specific file patterns
paths-ignore:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Fix ggshield schema: add version: 2 and move path ignores under secret.ignored-paths

Current keys look v1-ish; ggshield v2 expects version: 2 and secret.ignored-paths. As-is, the config risks being partially ignored, weakening secret scanning across the repo.

Apply this rewrite to align with ggshield v2 while preserving your intent:

-# GitGuardian configuration for ggshield
-# This file configures which files and secrets to ignore during scanning
-
-# Ignore specific file patterns
-paths-ignore:
+version: 2
+secret:
+  # Validate findings with providers when possible (helps reduce false positives)
+  validity: true
+  # Ignore specific file patterns (test/demo/mock-generated only)
+  ignored-paths:
     # Mock certificates for testing (these are intentionally committed test data)
     - "**/mock_certificates/**/*.key"
     - "**/mock_certificates/**/*.crt"
     - "**/mock_certificates/**/*.pem"
     - "**/constants/mockCertificates.ts"
-  - "common/src/mock_certificates/**"
-  - "common/src/mock_certificates/aadhaar/mockAadhaarCert.ts"
-  - "common/src/utils/passports/genMockIdDoc.ts"
+    - "common/src/mock_certificates/**"
+    - "common/src/mock_certificates/aadhaar/mockAadhaarCert.ts"
+    - "common/src/utils/passports/genMockIdDoc.ts"
 
     # Test data files
     - "**/test/**/*.key"
     - "**/test/**/*.crt"
     - "**/test/**/*.pem"
     - "**/tests/**/*.key"
     - "**/tests/**/*.crt"
     - "**/tests/**/*.pem"
 
     # Mock data files
     - "**/mock/**/*.key"
     - "**/mock/**/*.crt"
     - "**/mock/**/*.pem"
 
     # Demo app test data
     - "**/demo-app/**/mock/**"
     - "**/demo-app/**/test-data/**"
     - "**/test-data/**"
     - "**/mock-data/**"
 
     # Generated test files
     - "**/generated/**/*.key"
     - "**/generated/**/*.crt"
     - "**/generated/**/*.pem"

🌐 Web query:

GitGuardian ggshield YAML schema (v2): confirm required keys and where to place path ignores (e.g., "version: 2", "secret.ignored-paths", "secret.validity"). Are "paths-ignore" and "secrets-ignore" valid in v2?

💡 Result:

Short answer

  • .gitguardian.yaml v2 must start with version: 2 at top. Put scan-specific settings under the relevant top-level key (secret:, sca:, iac:, etc.). (docs.gitguardian.com)
  • For secrets, use the secret (or secrets) section keys shown in the docs: ignored_paths / ignored_paths entries (or the hyphenated form ignored-paths in some pages) for path excludes and ignored_matches (aka secrets.ignored_matches) for ignored secret matches. Example from the ggshield config sample: version: 2 then secret: ignored_paths: [...] ignored_matches: [...]. (docs.gitguardian.com)
  • secret.validity is controlled by the workspace/dashboard validity-check settings (and ggshield follows that); custom validity-check hosts are configured in the documentation for validity checks. There is no separate top-level key named secret.validity documented for v2 config beyond following dashboard settings / custom host configuration for validity checks. (docs.gitguardian.com)

About paths-ignore / secrets-ignore

  • The docs and examples for v2 use keys like ignored_paths, ignored-paths or ignored_matches (and paths-ignore / paths-ignore appear in older examples/packaging notes). Rely on ignored_paths / ignored_matches (or the hyphenated equivalent shown per-subcommand) — paths-ignore and secrets-ignore are not the documented v2 canonical keys. If you use an older example that shows paths-ignore it may still work in older releases, but follow the official v2 examples (ignored_paths / ignored-paths and secrets.ignored_matches) to be safe. (pypi.org)

If you want, paste your .gitguardian.yaml here and I’ll validate it against the docs.

Citations:


Fix ggshield config: set version: 2 and move ignore patterns under secret.ignored_paths

  • Problem: current file uses v1-style keys (paths-ignore); ggshield v2 requires a top-level version: 2 and secret-specific keys — leaving v1 keys risks ignores being skipped and weakens secret scanning.
  • Action (top of .gitguardian.yml): add version: 2; replace paths-ignore: with a secret: block and move patterns under secret.ignored_paths (or ignored-paths). Use secret.ignored_matches for ignored secret matches. Do NOT add secret.validity — validity checks are managed via the workspace/dashboard or custom validity-host settings.
  • File: .gitguardian.yml (top-level).
🤖 Prompt for AI Agents
In .gitguardian.yml around lines 1 to 5, the config uses v1-style keys
(paths-ignore) which ggshield v2 ignores; update the file by adding a top-level
"version: 2" and replace the "paths-ignore:" entry with a "secret:" block,
moving ignore patterns under "secret.ignored_paths" (or "secret.ignored-paths")
and, if needed, use "secret.ignored_matches" for specific secret patterns; do
not add "secret.validity" as validity is managed elsewhere.

Comment on lines 39 to 44
# Ignore specific secret types for mock files
ignore_secrets:
secrets-ignore:
- "Generic Private Key" # For mock certificate keys
- "Generic Certificate" # For mock certificates
- "RSA Private Key" # For mock RSA keys
- "EC Private Key" # For mock EC keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not globally ignore private-key detectors; remove secrets-ignore

Declaring "Generic Private Key", "RSA Private Key", and "EC Private Key" under a global ignore would allow real keys to slip through scans outside test paths. Also, secrets-ignore isn’t a recognized v2 key.

Apply this removal (the rewrite above already drops it):

-# Ignore specific secret types for mock files
-secrets-ignore:
-  - "Generic Private Key" # For mock certificate keys
-  - "Generic Certificate" # For mock certificates
-  - "RSA Private Key" # For mock RSA keys
-  - "EC Private Key" # For mock EC keys

If you must silence a specific false positive, prefer:

  • path-based ignores limited to test/mock folders (as above), or
  • per-finding allowlists via ignored-matches with match IDs, scoped and reviewable.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Ignore specific secret types for mock files
ignore_secrets:
secrets-ignore:
- "Generic Private Key" # For mock certificate keys
- "Generic Certificate" # For mock certificates
- "RSA Private Key" # For mock RSA keys
- "EC Private Key" # For mock EC keys
🤖 Prompt for AI Agents
In .gitguardian.yml around lines 39 to 44, the file currently uses the
unrecognized v2 key `secrets-ignore` and globally lists private-key detectors
(Generic Private Key, RSA Private Key, EC Private Key); remove that global
`secrets-ignore` block entirely and instead implement scoped ignores: either add
path-based ignores limited to your test/mock directories or use
`ignored-matches` entries with specific match IDs and clear scopes/review
metadata. Ensure the final YAML conforms to GitGuardian v2 schema (no
`secrets-ignore` key) and that any suppressed detectors are only disabled via
path-scoped rules or per-finding allowlists so real keys are not globally
ignored.

Comment on lines +803 to 807
export async function storePassportData(
passportData: PassportData | AadhaarData,
) {
await storeDocumentWithDeduplication(passportData);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Type surface inconsistency: some “direct” loaders still return PassportData

Several public/direct functions still use PassportData where IDDocument is now stored. This causes unsound casts and potential runtime errors with Aadhaar documents.

Update signatures and usages (outside this hunk), e.g.:

// Return types should be IDDocument
export async function loadDocumentByIdDirectlyFromKeychain(
  documentId: string,
): Promise<IDDocument | null> { /* ... */ }

export async function loadSelectedDocumentDirectlyFromKeychain(): Promise<{
  data: IDDocument;
  metadata: DocumentMetadata;
} | null> { /* ... */ }

export const getAllDocumentsDirectlyFromKeychain = async (): Promise<{
  [documentId: string]: { data: IDDocument; metadata: DocumentMetadata };
}> => { /* ... */ }

Also ensure DocumentsAdapter types in SDK accept IDDocument.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Searching for direct loader function names..."
rg -n --hidden -S "loadDocumentByIdDirectlyFromKeychain|loadSelectedDocumentDirectlyFromKeychain|getAllDocumentsDirectlyFromKeychain" -C3 || true

echo
echo "2) Searching for functions/exports that return PassportData..."
rg -n --hidden -S "Promise<\s*PassportData\b|:\s*PassportData\b|:\s*PassportData\s*\|" -C3 || true

echo
echo "3) Searching for PassportData, AadhaarData, IDDocument type/interface definitions and usages..."
rg -n --hidden -S "\b(type|interface)\s+(PassportData|AadhaarData|IDDocument)\b|\bIDDocument\b|\bPassportData\b|\bAadhaarData\b" -C3 || true

echo
echo "4) Searching for DocumentsAdapter symbol/usages..."
rg -n --hidden -S "DocumentsAdapter" -C3 || true

echo
echo "5) Show passportDataProvider.tsx around storePassportData (if present)"
rg -n --hidden -S "storePassportData" -C3 || true
if [ -f "app/src/providers/passportDataProvider.tsx" ]; then
  echo
  echo "----- app/src/providers/passportDataProvider.tsx (lines 760-840) -----"
  sed -n '760,840p' app/src/providers/passportDataProvider.tsx || true
fi

Length of output: 205717


Action: change public/direct loader APIs to return IDDocument (not PassportData).

Direct keychain/document loader APIs in the app are still typed to PassportData which is unsound when Aadhaar documents flow through them — update signatures and the provider surface to the IDDocument union and fix callsites.

  • Change in app/src/providers/passportDataProvider.tsx:

    • loadDocumentByIdDirectlyFromKeychain(documentId: string): Promise<IDDocument | null>
    • loadSelectedDocumentDirectlyFromKeychain(): Promise<{ data: IDDocument; metadata: DocumentMetadata } | null>
    • getAllDocumentsDirectlyFromKeychain(): Promise<{ [documentId: string]: { data: IDDocument; metadata: DocumentMetadata } }>
    • IPassportContext methods that currently use PassportData (getData, getSelectedData, setData, getAllData, getPassportDataAndSecret, etc.) → use IDDocument.
    • selfClientDocumentsAdapter entries must match DocumentsAdapter (IDDocument) types.
    • storePassportData(...) should accept IDDocument.
  • Fix callsites and tests that assume PassportData (examples found: app/src/utils/proving/validateDocument.ts, app/src/utils/proving/provingMachine.ts, numerous screens/components and tests). Use existing type guards isMRZDocument/isAadhaarDocument before accessing MRZ-specific fields (mrz, dsc, eContent) or Aadhaar-only fields (qrData, extractedFields).

  • Ensure packages/mobile-sdk-alpha DocumentsAdapter stays IDDocument; adapt any mocks/tests that use PassportData so types align.

Risk: leaving these as PassportData allows unsound casts and runtime failures in Aadhaar flows (e.g. MRZ-only logic running on Aadhaar). Addressing this is a mandatory refactor.

🤖 Prompt for AI Agents
In app/src/providers/passportDataProvider.tsx around lines 803-807, the
public/direct loader API and related provider surface currently use PassportData
which is unsound for Aadhaar documents; change storePassportData(...) to accept
IDDocument and update the exposed signatures to use IDDocument:
loadDocumentByIdDirectlyFromKeychain(documentId: string): Promise<IDDocument |
null>, loadSelectedDocumentDirectlyFromKeychain(): Promise<{ data: IDDocument;
metadata: DocumentMetadata } | null>, getAllDocumentsDirectlyFromKeychain():
Promise<{ [documentId: string]: { data: IDDocument; metadata: DocumentMetadata }
}>, and update all IPassportContext methods (getData, getSelectedData, setData,
getAllData, getPassportDataAndSecret, etc.) and selfClientDocumentsAdapter
entries to DocumentsAdapter(IDDocument) types; then update all callsites and
tests to use IDDocument and guard MRZ- or Aadhaar-specific access with
isMRZDocument/isAadhaarDocument before reading mrz/dsc/eContent or
qrData/extractedFields, and adjust mobile-sdk-alpha mocks/tests to ensure
DocumentsAdapter stays typed to IDDocument.

: 'general';

trackEvent(AadhaarEvents.ERROR_SCREEN_NAVIGATED, { errorType });
(navigation.navigate as any)('AadhaarUploadError', { errorType });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove any-casts on navigation; use typed routes

Casting to any defeats type-safety and risks bad params at runtime. You already typed navigation with RootStackParamList.

Apply:

-        (navigation.navigate as any)('AadhaarUploadError', { errorType });
+        navigation.navigate('AadhaarUploadError', { errorType });

-        (navigation.navigate as any)('AadhaarUploadError', {
+        navigation.navigate('AadhaarUploadError', {
           errorType: 'general' as const,
         });

-      (navigation.navigate as any)('AadhaarUploadError', {
+      navigation.navigate('AadhaarUploadError', {
         errorType: 'general' as const,
       });

Also applies to: 227-229, 234-236

🧰 Tools
🪛 GitHub Check: build-deps

[warning] 167-167:
Unexpected any. Specify a different type

🪛 GitHub Check: workspace-lint

[warning] 167-167:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx around lines 167
(and also update occurrences at 227-229 and 234-236), remove the
"(navigation.navigate as any)" casts and call navigation.navigate with the
properly typed route and params from RootStackParamList; ensure the component’s
navigation prop is typed (e.g. using NativeStackScreenProps or useNavigation
with the RootStackParamList) and then call navigation.navigate with the route
name and the typed { errorType } param so TypeScript enforces the correct param
shape instead of bypassing checks.

Comment on lines +185 to +206
trackEvent(AadhaarEvents.QR_UPLOAD_FAILED, {
error:
error instanceof Error
? error.message
: error?.toString() || 'Unknown error',
});

// Don't show error for user cancellation
if (error instanceof Error && error.message.includes('cancelled')) {
trackEvent(AadhaarEvents.USER_CANCELLED_SELECTION);
return;
}

// Handle permission errors specifically - check for exact message from native code
const errorMessage =
error instanceof Error ? error.message : String(error);

if (errorMessage.includes('Photo library access is required')) {
trackEvent(AadhaarEvents.PERMISSION_MODAL_OPENED);
showPermissionModal();
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Don’t count user cancellation as failure; reorder error tracking

Failure is tracked before cancellation/permission checks, inflating failure metrics and harming UX analytics.

Apply:

-    } catch (error) {
-      trackEvent(AadhaarEvents.QR_UPLOAD_FAILED, {
-        error:
-          error instanceof Error
-            ? error.message
-            : error?.toString() || 'Unknown error',
-      });
-
+    } catch (error) {
       // Don't show error for user cancellation
       if (error instanceof Error && error.message.includes('cancelled')) {
-        trackEvent(AadhaarEvents.USER_CANCELLED_SELECTION);
+        trackEvent(AadhaarEvents.USER_CANCELLED_SELECTION);
         return;
       }
@@
       if (errorMessage.includes('Photo library access is required')) {
         trackEvent(AadhaarEvents.PERMISSION_MODAL_OPENED);
         showPermissionModal();
         return;
       }
@@
       if (
         errorMessage.includes('permission') ||
         errorMessage.includes('access') ||
         errorMessage.includes('Settings') ||
         errorMessage.includes('enable access')
       ) {
         trackEvent(AadhaarEvents.PERMISSION_MODAL_OPENED);
         showPermissionModal();
         return;
       }
+      // Real failure paths below:
+      trackEvent(AadhaarEvents.QR_UPLOAD_FAILED, {
+        error: error instanceof Error ? error.message : String(error || 'Unknown error'),
+      });

Also applies to: 209-218

🤖 Prompt for AI Agents
In app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx around lines 185-206
(and similarly 209-218), the code tracks QR_UPLOAD_FAILED before checking for
user cancellation or permission errors; move the failure tracking after the
early returns for cancellation and permission modal so cancelled actions and
permission flows are not recorded as failures. Specifically, perform the
"cancelled" check first and return, then check for the permission error and
handle/show modal and return, and only after those checks call
trackEvent(AadhaarEvents.QR_UPLOAD_FAILED, ...) with the error details.

@transphorm transphorm merged commit 2df4dc4 into dev Sep 20, 2025
36 of 37 checks passed
@transphorm transphorm deleted the app/add-aadhaar-onboarding branch September 20, 2025 00:36
remicolin added a commit that referenced this pull request Sep 20, 2025
* chore: bump v2.6.5 rd2 (#1067)

* commit wip version bump

* remove from building

* chore: update tooling dependencies (#1069)

* chore: update tooling dependencies

* chore: align react typings and node types

* update lock

* chore: minor fixes across monorepo (#1068)

* small fixes

* fixes

* fix gesture handler error

* ci fixes

* fix yarn build; add workflow ci (#1075)

* add new workspace ci

* disable package version check for now

* build before checks

* format

* fix in future pr

* feat: add functions for disclosing aadhaar attributes (#1033)

* feat: add functions for disclosing aadhaar attributes

* format

* chore: update monorepo artifacts (#1079)

* remove unneeded artifacts, skip building circuits

* update md files

* cleans up unused parts of sdk interface, adds inline documentation, (#1078)

* cleans up unused parts of sdk interface, adds inline documentation,

* fix up build

* yolo

* Feat/aadhaar sdk (#1082)

* feat: add aadhaar support to the ts sdk

* feat: aadhaar support to go sdk

* chore: refactor

* move clearPassportData, markCurrentDocumentAsRegistered, reStorePassportDataWithRightCSCA to SDK (#1041)

* Move self app store to mobile sdk (#1040)

* chore(mobile-sdk-alpha): remove unused tslib dependency (#1053)

* remove tslib -- seems unused

* remove deps accidentally added to root

* build file

* remove unused imports (#1055)

* fix: sha256 signed attr tests (#1058)

* fix mock screen launch (#1059)

* Hotfix: Belgium ID cards (#1061)

* feat: parse belgium TD1 mrz android

* feat: Parse Belgium TD1 MRZ IOS

* fix: OFAC trees not found (#1060)

* fix: relax OFAC tree response validation

* test: cover OFAC tree edge cases

* fix stateless

* revert and fix types

* fix tests

* [SELF-723] feat: add structured NFC and Proof logging (#1048)

* feat: add structured NFC logging

* fix ci

* Fix: add deps

* logging fixes. use breadcrumbs

* fix android build

* update SeverityLevel

* [SELF-705] feat: add proof event logging (#1057)

* feat: add proof event logging

* refactor: unify sentry event logging

* fix types

* fix mock

* simplify

* code rabbit feedback

* fix tests

---------

Co-authored-by: seshanthS <[email protected]>

* skip on dev (#1063)

* don't get fancy just disable (#1064)

* saw it building so gonna try (#1065)

* chore: bump v2.6.5 rd2 (#1067)

* commit wip version bump

* remove from building

* chore: update tooling dependencies (#1069)

* chore: update tooling dependencies

* chore: align react typings and node types

* update lock

* chore: minor fixes across monorepo (#1068)

* small fixes

* fixes

* fix gesture handler error

* ci fixes

* fix yarn build; add workflow ci (#1075)

* add new workspace ci

* disable package version check for now

* build before checks

* format

* fix in future pr

* feat: add functions for disclosing aadhaar attributes (#1033)

* feat: add functions for disclosing aadhaar attributes

* format

* chore: update monorepo artifacts (#1079)

* remove unneeded artifacts, skip building circuits

* update md files

* chore: update hub contract address

* format

* fix: add aadhaar in AllIds

* chore: bump to v1.1.0-beta

---------

Co-authored-by: vishal <[email protected]>
Co-authored-by: Leszek Stachowski <[email protected]>
Co-authored-by: Aaron DeRuvo <[email protected]>
Co-authored-by: Justin Hernandez <[email protected]>
Co-authored-by: Seshanth.S🐺 <[email protected]>
Co-authored-by: seshanthS <[email protected]>

* feat: change to gcp attestation verification (#959)

* feat: change to gcp attestation verification

* lint

* fix e2e test

* chore: don't check PCR0 mapping if building the app locally

* fmt:fix

---------

Co-authored-by: Justin Hernandez <[email protected]>

* Mobile SDK: move provingMachine from the app (#1052)

* Mobile SDK: move provingMachine from the app

* lint, fixes

* fix web build?

* lint

* fix metro build, add deps

* update lock files

* move the status handlers and proving machine tests

* may it be

* fix up

* yolo

---------

Co-authored-by: Justin Hernandez <[email protected]>
Co-authored-by: Aaron DeRuvo <[email protected]>

* Revert "Mobile SDK: move provingMachine from the app (#1052)" (#1084)

This reverts commit 8983ac2.

* fix: sdk (#1085)

* bump sdk (#1086)

* chore update mobile app types (#1087)

* clean up types

* clean up additional types

* format

* fix types

* feat: add contract utils (#1088)

* Feat/contracts npm publish (#1089)

* chore: ci to publish contracts

* yarn fmt

* fix: use celo sepolia in common (#1091)

* chore: export selfappbuilder (#1092)

* [SELF-747] feat: clone android passport reader during setup (#1080)

* chore: remove android private modules doc

* private repo pull

* skip private modules

* remove unused circuits building

* save wip

* format

* restore tsconfig

* fix package install

* fix internal repo cloning

* unify logic and fix cloning

* git clone internal repos efficiently

* formatting

* run app yarn reinstall from root

* coderabbit feedback

* coderabbit suggestions

* remove skip private modules logic

* fix: ensure PAT is passed through yarn-install action and handle missing PAT gracefully

- Update yarn-install action to pass SELFXYZ_INTERNAL_REPO_PAT to yarn install
- Make setup-private-modules.cjs skip gracefully when PAT is unavailable in CI
- Fixes issue where setup script was throwing error instead of skipping for forks

* prettier

* fix clone ci

* clone ci fixes

* fix import export sorts

* fix instructions

* fix: remove SelfAppBuilder re-export to fix duplicate export error

- Remove SelfAppBuilder import/export from @selfxyz/qrcode
- Update README to import SelfAppBuilder directly from @selfxyz/common
- Fixes CI build failure with duplicate export error

* fix: unify eslint-plugin-sort-exports version across workspaces

- Update mobile-sdk-alpha from 0.8.0 to 0.9.1 to match other workspaces
- Removes yarn.lock version conflict causing CI/local behavior mismatch
- Fixes quality-checks workflow linting failure

* fix: bust qrcode SDK build cache to resolve stale SelfAppBuilder issue

- Increment GH_SDK_CACHE_VERSION from v1 to v2
- Forces CI to rebuild artifacts from scratch instead of using cached version
- Resolves quality-checks linter error showing removed SelfAppBuilder export

* skip job

* test yarn cache

* bump cache version to try and fix the issue

* revert cache version

* refactor: use direct re-exports for cleaner qrcode package structure

- Replace import-then-export pattern with direct re-exports
- Keep SelfAppBuilder export with proper alphabetical sorting (before SelfQRcode)
- Maintain API compatibility as documented in README
- Eliminates linter sorting issues while keeping clean code structure

* fix: separate type and value imports in README examples

- Import SelfApp as type since it's an interface
- Import SelfAppBuilder as value since it's a class
- Follows TypeScript best practices and improves tree shaking

* address version mismatches and package resolutions (#1081)

* fix package version mismatches and resolutions

* fixes

* update lock

* fix comma

* fixes

* fix packages

* update packages

* remove firebase analytics. not needed

* fix: aadhaar verifier abi (#1096)

* fix: aadhaar verifier abi

* bump: core

* fix: go-sdk (#1090)

* SELF-725: add iOS qrcode opener and aadhaar screen (#1038)

* add iOS qrcode opener and aadhaar screen

* format

* fix test

* add Image-picker android (#1077)

* add image-picker android

* fix validation

* feat: implement Aadhaar upload success and error screens, enhance AadhaarNavBar with dynamic progress indication

- Added AadhaarUploadedSuccessScreen and AadhaarUploadErrorScreen components for handling upload outcomes.
- Updated AadhaarNavBar to reflect current upload step with dynamic progress bar.
- Integrated new screens into navigation flow for Aadhaar upload process.
- Introduced blue check and warning SVG icons for visual feedback on success and error states.

* feat: generate mock aadhar (#1083)

* feat: generate mock aadhar

* add yarn.lock

* update yarn.lock

* update protocolStore, update types, start modifying provingMachine

* Register mock aadhar (#1093)

* Register mock aadhar

* fix ofac

* temp: generate name

* fix dob

* Add Aadhaar support to ID card component and screens

- Integrated Aadhaar icon and conditional rendering in IdCardLayout.
- Updated AadhaarUploadScreen to process QR codes and store Aadhaar data.
- Modified navigation and button text in AadhaarUploadedSuccessScreen.
- Added mock data generation for Aadhaar in the mobile SDK.
- Updated ManageDocumentsScreen to include Aadhaar document type.
- Enhanced error handling and validation for Aadhaar QR code processing.
- Added utility functions for Aadhaar data extraction and commitment processing.

* aadhaar disclose - wip (#1094)

* fix: timestamp cal of extractQRDataFields

* Feat/aadhar fixes (#1099)

* Fix - android aadhar qr scanner

* fixes

* update text

* yarn nice

* run prettier

* Add mock Aadhaar certificates for development

- Introduced hardcoded Aadhaar test certificates for development purposes.
- Moved Aadhaar mock private and public keys to a dedicated file for better organization.
- Updated the mock ID document generation utility to utilize the new Aadhaar mock certificates.

* prettier write

* add 'add-aadhaar' button (#1100)

* Update .gitleaks.toml to include path for mock certificates in the common/dist directory

* yarn nice

* Enhance Aadhaar error handling with specific error types

- Updated the AadhaarUploadErrorScreen to display different messages based on the error type (general or expired).
- Modified the AadhaarUploadScreen to pass the appropriate error type when navigating to the error screen.
- Set initial parameters for the home screen to include a default error type.

* Update passport handling in proving machine to support Aadhaar document category

- Modified the handling of country code in the useProvingStore to return 'IND' for Aadhaar documents.
- Ensured that the country code is only fetched from passport metadata for non-Aadhaar documents.

* tweak layout, text, change email to support, hide help button

* fix ci, remove aadhaar logging, add aadhaar events

* remove unused aadhaar tracking events

* update globs

* fix gitguardian config

* don't track id

---------

Co-authored-by: Justin Hernandez <[email protected]>
Co-authored-by: Seshanth.S🐺 <[email protected]>
Co-authored-by: vishal <[email protected]>

* fix aadhaar screen test (#1101)

* add iOS qrcode opener and aadhaar screen

* format

* fix test

* add Image-picker android (#1077)

* add image-picker android

* fix validation

* feat: implement Aadhaar upload success and error screens, enhance AadhaarNavBar with dynamic progress indication

- Added AadhaarUploadedSuccessScreen and AadhaarUploadErrorScreen components for handling upload outcomes.
- Updated AadhaarNavBar to reflect current upload step with dynamic progress bar.
- Integrated new screens into navigation flow for Aadhaar upload process.
- Introduced blue check and warning SVG icons for visual feedback on success and error states.

* feat: generate mock aadhar (#1083)

* feat: generate mock aadhar

* add yarn.lock

* update yarn.lock

* update protocolStore, update types, start modifying provingMachine

* Register mock aadhar (#1093)

* Register mock aadhar

* fix ofac

* temp: generate name

* fix dob

* Add Aadhaar support to ID card component and screens

- Integrated Aadhaar icon and conditional rendering in IdCardLayout.
- Updated AadhaarUploadScreen to process QR codes and store Aadhaar data.
- Modified navigation and button text in AadhaarUploadedSuccessScreen.
- Added mock data generation for Aadhaar in the mobile SDK.
- Updated ManageDocumentsScreen to include Aadhaar document type.
- Enhanced error handling and validation for Aadhaar QR code processing.
- Added utility functions for Aadhaar data extraction and commitment processing.

* aadhaar disclose - wip (#1094)

* fix: timestamp cal of extractQRDataFields

* Feat/aadhar fixes (#1099)

* Fix - android aadhar qr scanner

* fixes

* update text

* yarn nice

* run prettier

* Add mock Aadhaar certificates for development

- Introduced hardcoded Aadhaar test certificates for development purposes.
- Moved Aadhaar mock private and public keys to a dedicated file for better organization.
- Updated the mock ID document generation utility to utilize the new Aadhaar mock certificates.

* prettier write

* add 'add-aadhaar' button (#1100)

* Update .gitleaks.toml to include path for mock certificates in the common/dist directory

* yarn nice

* Enhance Aadhaar error handling with specific error types

- Updated the AadhaarUploadErrorScreen to display different messages based on the error type (general or expired).
- Modified the AadhaarUploadScreen to pass the appropriate error type when navigating to the error screen.
- Set initial parameters for the home screen to include a default error type.

* Update passport handling in proving machine to support Aadhaar document category

- Modified the handling of country code in the useProvingStore to return 'IND' for Aadhaar documents.
- Ensured that the country code is only fetched from passport metadata for non-Aadhaar documents.

* tweak layout, text, change email to support, hide help button

* fix ci, remove aadhaar logging, add aadhaar events

* remove unused aadhaar tracking events

* update globs

* fix gitguardian config

* don't track id

* fix test

---------

Co-authored-by: turnoffthiscomputer <[email protected]>
Co-authored-by: Seshanth.S🐺 <[email protected]>
Co-authored-by: vishal <[email protected]>

---------

Co-authored-by: Justin Hernandez <[email protected]>
Co-authored-by: Nesopie <[email protected]>
Co-authored-by: Aaron DeRuvo <[email protected]>
Co-authored-by: vishal <[email protected]>
Co-authored-by: Leszek Stachowski <[email protected]>
Co-authored-by: Seshanth.S🐺 <[email protected]>
Co-authored-by: seshanthS <[email protected]>
Co-authored-by: Justin Hernandez <[email protected]>
Co-authored-by: Vishalkulkarni45 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants