Skip to content

[PM-34125] feat: Add card text analysis pipeline#6720

Merged
SaintPatrck merged 6 commits intomainfrom
card-scanner/2-text-analysis-pipeline
Apr 6, 2026
Merged

[PM-34125] feat: Add card text analysis pipeline#6720
SaintPatrck merged 6 commits intomainfrom
card-scanner/2-text-analysis-pipeline

Conversation

@SaintPatrck
Copy link
Copy Markdown
Contributor

@SaintPatrck SaintPatrck commented Mar 26, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-34125

📔 Objective

Add the complete text analysis pipeline for credit card scanning:

  • CardNumberUtils: Shared Luhn validation and card number sanitization (ui module)
  • CardDataParser: Interface and regex-based implementation for extracting card details from OCR text (number, expiry, CVV)
  • CardTextAnalyzer: ML Kit Text Recognition integration for camera frame analysis
  • CardScanOverlay: Camera overlay composable for scan UI
  • CardScanData: Data class for parsed card fields
  • CardNumberUtils in app: Brand detection (detectCardBrand) using VaultCardBrand

Includes full test coverage for parser logic, Luhn validation, and sanitization.

@SaintPatrck SaintPatrck added the ai-review-vnext Request a Claude code review using the vNext workflow label Mar 26, 2026
@github-actions github-actions Bot added app:password-manager Bitwarden Password Manager app context app:authenticator Bitwarden Authenticator app context t:deps Change Type - Dependencies t:feature Change Type - Feature Development labels Mar 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 26, 2026

Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR adds a complete text analysis pipeline for credit card scanning, including ML Kit text recognition integration, regex-based card data parsing with Luhn validation, a camera overlay composable, and card brand detection. The implementation follows established codebase patterns (mirroring the QrCodeAnalyzer architecture), includes comprehensive test coverage for parser and validation logic, and properly handles security concerns such as masking sensitive fields in CardScanData.toString().

Code Review Details

No findings to report. The code is well-structured and follows established patterns. Notable positives:

  • Thread safety in CardTextAnalyzerImpl uses AtomicBoolean with compareAndSet, which is an improvement over the plain boolean in QrCodeAnalyzerImpl
  • ImageProxy is properly closed on all code paths (skip, null image, and completion listener)
  • Sensitive data is masked in CardScanData.toString() for defense-in-depth logging safety
  • Previous review feedback has been thoroughly addressed

@SaintPatrck SaintPatrck removed the t:deps Change Type - Dependencies label Mar 26, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 26, 2026

Codecov Report

❌ Patch coverage is 66.99029% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.47%. Comparing base (99fb051) to head (8299421).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...m/x8bit/bitwarden/ui/vault/util/CardNumberUtils.kt 50.00% 0 Missing and 19 partials ⚠️
...orm/feature/cardscanner/util/CardDataParserImpl.kt 76.19% 0 Missing and 10 partials ⚠️
...itwarden/ui/platform/composition/LocalProviders.kt 33.33% 2 Missing ⚠️
.../platform/feature/cardscanner/util/CardScanData.kt 71.42% 2 Missing ⚠️
...atform/feature/cardscanner/util/CardNumberUtils.kt 92.30% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6720      +/-   ##
==========================================
- Coverage   85.54%   85.47%   -0.07%     
==========================================
  Files         949      956       +7     
  Lines       60571    60695     +124     
  Branches     8574     8634      +60     
==========================================
+ Hits        51817    51882      +65     
- Misses       5773     5800      +27     
- Partials     2981     3013      +32     
Flag Coverage Δ
app-data 17.82% <0.00%> (-0.03%) ⬇️
app-ui-auth-tools 20.80% <0.97%> (-0.04%) ⬇️
app-ui-platform 15.99% <0.97%> (-0.01%) ⬇️
app-ui-vault 26.38% <20.38%> (+<0.01%) ⬆️
authenticator 6.50% <0.97%> (-0.03%) ⬇️
lib-core-network-bridge 4.30% <0.00%> (-0.01%) ⬇️
lib-data-ui 1.02% <47.57%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 26, 2026

Logo
Checkmarx One – Scan Summary & Detailsff8b0ac8-78d7-4103-90da-03bbfeda6bf7


New Issues (128) Checkmarx found the following issues in this Pull Request
# Severity Issue Source File / Package Checkmarx Insight
1 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 154
detailsThe web application's `clearCookies should remove all stored cookie configs` method creates a cookie Cookie, at line 154 of /app/src/test/kotlin/...
Attack Vector
2 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 148
detailsThe web application's `clearCookies should remove all stored cookie configs` method creates a cookie Cookie, at line 148 of /app/src/test/kotlin/...
Attack Vector
3 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/network/NetworkCookieManagerTest.kt: 203
detailsThe web application's Lambda method creates a cookie Cookie, at line 203 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/network/...
Attack Vector
4 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/network/NetworkCookieManagerTest.kt: 229
detailsThe web application's Lambda method creates a cookie Cookie, at line 229 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/network/...
Attack Vector
5 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt: 46
detailsThe web application's `toNetworkCookieList should map multiple cookies correctly` method creates a cookie Cookie, at line 46 of /app/src/test/kot...
Attack Vector
6 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt: 62
detailsThe web application's `toNetworkCookie should map name and value correctly` method creates a cookie Cookie, at line 62 of /app/src/test/kotlin/co...
Attack Vector
7 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt: 45
detailsThe web application's `toNetworkCookieList should map multiple cookies correctly` method creates a cookie Cookie, at line 45 of /app/src/test/kot...
Attack Vector
8 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt: 31
detailsThe web application's `toNetworkCookieList should map single cookie correctly` method creates a cookie Cookie, at line 31 of /app/src/test/kotlin...
Attack Vector
9 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 129
detailsThe web application's `storeCookieConfig with null should not affect other hostnames` method creates a cookie Cookie, at line 129 of /app/src/tes...
Attack Vector
10 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 123
detailsThe web application's `storeCookieConfig with null should not affect other hostnames` method creates a cookie Cookie, at line 123 of /app/src/tes...
Attack Vector
11 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 103
detailsThe web application's `storeCookieConfig with null should remove stored config` method creates a cookie Cookie, at line 103 of /app/src/test/kotl...
Attack Vector
12 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/AcquiredCookieExtensionsTest.kt: 20
detailsThe web application's `toConfigurationCookie should map AcquiredCookie to CookieConfigurationData Cookie` method creates a cookie Cookie, at line...
Attack Vector
13 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/CookieConfigurationDataExtensionsTest.kt: 31
detailsThe web application's `toAcquiredCookiesList should map list of Cookie to list of AcquiredCookie` method creates a cookie Cookie, at line 31 of /...
Attack Vector
14 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/CookieConfigurationDataExtensionsTest.kt: 32
detailsThe web application's `toAcquiredCookiesList should map list of Cookie to list of AcquiredCookie` method creates a cookie Cookie, at line 32 of /...
Attack Vector
15 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/CookieConfigurationDataExtensionsTest.kt: 12
detailsThe web application's `toAcquiredCookie should map Cookie to AcquiredCookie` method creates a cookie Cookie, at line 12 of /app/src/test/kotlin/c...
Attack Vector
16 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/AcquiredCookieExtensionsTest.kt: 39
detailsThe web application's `toConfigurationDataCookies should map list of AcquiredCookie to list of Cookie` method creates a cookie Cookie, at line 39...
Attack Vector
17 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/util/AcquiredCookieExtensionsTest.kt: 40
detailsThe web application's `toConfigurationDataCookies should map list of AcquiredCookie to list of Cookie` method creates a cookie Cookie, at line 40...
Attack Vector
18 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/ServerCommunicationConfigRepositoryTest.kt: 156
detailsThe web application's Lambda method creates a cookie Cookie, at line 156 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/S...
Attack Vector
19 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/ServerCommunicationConfigRepositoryTest.kt: 71
detailsThe web application's Lambda method creates a cookie Cookie, at line 71 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/Se...
Attack Vector
20 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/ServerCommunicationConfigRepositoryTest.kt: 72
detailsThe web application's Lambda method creates a cookie Cookie, at line 72 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/Se...
Attack Vector
21 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/ServerCommunicationConfigRepositoryTest.kt: 157
detailsThe web application's Lambda method creates a cookie Cookie, at line 157 of /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/sdk/S...
Attack Vector
22 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 180
detailsThe web application's `storage should isolate configs by hostname` method creates a cookie Cookie, at line 180 of /app/src/test/kotlin/com/x8bit/...
Attack Vector
23 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 189
detailsThe web application's `storage should isolate configs by hostname` method creates a cookie Cookie, at line 189 of /app/src/test/kotlin/com/x8bit/...
Attack Vector
24 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 81
detailsThe web application's `storage should handle cookies with multiple values` method creates a cookie Cookie, at line 81 of /app/src/test/kotlin/com...
Attack Vector
25 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 85
detailsThe web application's `storage should handle cookies with multiple values` method creates a cookie Cookie, at line 85 of /app/src/test/kotlin/com...
Attack Vector
26 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 51
detailsThe web application's `storeCookieConfig should update existing config` method creates a cookie Cookie, at line 51 of /app/src/test/kotlin/com/x8...
Attack Vector
27 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 61
detailsThe web application's `storeCookieConfig should update existing config` method creates a cookie Cookie, at line 61 of /app/src/test/kotlin/com/x8...
Attack Vector
28 MEDIUM HttpOnly_Cookie_Flag_Not_Set /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/CookieDiskSourceTest.kt: 32
detailsThe web application's `storeCookieConfig should persist config and getCookieConfig should retrieve it` method creates a cookie Cookie, at line 32...
Attack Vector
29 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 98
detailsMethod createMockCipherView at line 98 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user in...
Attack Vector
30 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt: 203
detailsMethod Lambda at line 203 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt s...
Attack Vector
31 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt: 1202
detailsMethod Lambda at line 1202 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt sends user inform...
Attack Vector
32 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 429
detailsMethod Lambda at line 429 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
33 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 386
detailsMethod Lambda at line 386 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
34 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 402
detailsMethod Lambda at line 402 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
35 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 334
detailsMethod Lambda at line 334 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
36 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 305
detailsMethod Lambda at line 305 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
37 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 265
detailsMethod Lambda at line 265 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
38 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 237
detailsMethod Lambda at line 237 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
39 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 206
detailsMethod Lambda at line 206 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
40 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 170
detailsMethod Lambda at line 170 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
41 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 110
detailsMethod Lambda at line 110 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
Attack Vector
42 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 90
detailsMethod Lambda at line 90 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest....
Attack Vector
43 MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 70
detailsMethod Lambda at line 70 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest....
Attack Vector
44 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt: 482
detailsMethod Lambda at line 482 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt s...
Attack Vector
45 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 585
detailsMethod Lambda at line 585 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt se...
Attack Vector
46 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt: 796
detailsMethod `on UnlockClick for password unlock should display error dialog on AuthenticationError` at line 796 of /app/src/test/kotlin/com/x8bit/bitw...
Attack Vector
47 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewModelTest.kt: 175
detailsMethod Lambda at line 175 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewM...
Attack Vector
48 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 61
detailsMethod Lambda at line 61 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user information outs...
Attack Vector
49 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 61
detailsMethod Lambda at line 61 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user information outs...
Attack Vector
50 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 125
detailsMethod createMockLoginView at line 125 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user in...
Attack Vector
51 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/model/Fido2CredentialAssertionRequestUtil.kt: 12
detailsMethod createMockFido2CredentialAssertionRequest at line 12 of /app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/model/Fido2CredentialAsser...
Attack Vector
52 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt: 150
detailsMethod `on ApproveAccountChangeClick dialog state should be cleared, user should be switched, and getAuthRequestByIdFlow should be called` at lin...
Attack Vector
53 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt: 376
detailsMethod Lambda at line 376 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewM...
Attack Vector
54 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt: 307
detailsMethod Lambda at line 307 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewM...
Attack Vector
55 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 330
detailsMethod Lambda at line 330 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt se...
Attack Vector
56 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 675
detailsMethod at line 675 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt sends us...
Attack Vector
57 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 362
detailsMethod Lambda at line 362 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt se...
Attack Vector
58 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 687
detailsMethod at line 687 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt sends us...
Attack Vector
59 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt: 446
detailsMethod Lambda at line 446 of /app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/completeregistration/CompleteRegistrationViewModelTest.kt se...
Attack Vector
60 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 77
detailsMethod Lambda at line 77 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user information outs...
Attack Vector
61 MEDIUM Privacy_Violation /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt: 77
detailsMethod Lambda at line 77 of /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/CipherViewUtil.kt sends user information outs...
Attack Vector
62 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt: 596
detailsThe application uses the hard-coded password "mockId-1" for authentication purposes, either using it to verify users' identities, or to access an...
Attack Vector
63 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkCipherRepositoryTest.kt: 205
detailsThe application uses the hard-coded password "cipherId" for authentication purposes, either using it to verify users' identities, or to access ano...
Attack Vector
64 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt: 573
detailsThe application uses the hard-coded password "some-password" for authentication purposes, either using it to verify users' identities, or to acce...
Attack Vector
65 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt: 772
detailsThe application uses the hard-coded password "testPassword123" for authentication purposes, either using it to verify users' identities, or to acc...
Attack Vector
66 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt: 1955
detailsThe application uses the hard-coded password "mockValue" for authentication purposes, either using it to verify users' identities, or to access an...
Attack Vector
67 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt: 2011
detailsThe application uses the hard-coded password "mockValue" for authentication purposes, either using it to verify users' identities, or to access an...
Attack Vector
68 MEDIUM Use_of_Hardcoded_Password /app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt: 1252
detailsThe application uses the hard-coded password "mockValue" for authentication purposes, either using it to verify users' identities, or to access an...
Attack Vector

More results are available on the CxOne platform

@SaintPatrck SaintPatrck force-pushed the card-scanner/2-text-analysis-pipeline branch from 2333a61 to d776756 Compare March 26, 2026 11:37
@github-actions github-actions Bot added the t:deps Change Type - Dependencies label Mar 26, 2026
@SaintPatrck SaintPatrck added innovation Feature work related to Innovation Sprint or BEEEP projects and removed t:deps Change Type - Dependencies labels Mar 27, 2026
Comment thread app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/util/CardNumberUtils.kt Outdated
) {
Canvas(modifier = modifier) {
val strokeWidthPx = strokeWidth.toPx()
val cornerRadiusPx = 12.dp.toPx()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should this be passed in as a param too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. The corner radius is a fixed visual property of the card shape, not something the callers should modify.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Fair enough

val number = panMatch
?.value
?.filter { it.isDigit() }
?.takeIf { it.isValidLuhn() }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we want to return null if there is no number.

I noticed that later on you have a check for the number here anyways.

So maybe just return null if it's not valid

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that couples the parser logic too tightly to the consumers use case. The purpose of this parser is to extract all of the card data it can. It's up to the consumer to decide whether the extracted data is sufficient for its needs. This feel like the correct separation of concerns boundary to me.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It just feels very weird to have a data class that has all nullable properties.

But I see your point, maybe that is OK in this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree. I'm not against a check to ensure at least some data is parsed, otherwise we return null. That would at least ensure callers don't receive an empty object.

@github-actions github-actions Bot added the t:deps Change Type - Dependencies label Mar 31, 2026
override lateinit var onCardScanned: (CardScanData) -> Unit

override fun close() {
recognizer.close()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am unsure how we will call this when it is provided via a LocalComposition

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. I don't actually think we need it, anyways. At least not until we see actual memory issues. If we need to, we might be able to leverage remember and DisposableEffect to make sure it's closed properly. I'll revert for now and we can come back if issues start showing up.

@SaintPatrck SaintPatrck removed t:deps Change Type - Dependencies labels Mar 31, 2026
@SaintPatrck
Copy link
Copy Markdown
Contributor Author

After discussion with Design team, cardholder name extraction will be omitted. It is too error prone, and comparable features in other applications also omit cardholder name when scanning with a camera.

@github-actions github-actions Bot added the t:deps Change Type - Dependencies label Apr 1, 2026
@SaintPatrck SaintPatrck added the hold do not merge yet label Apr 1, 2026
@SaintPatrck SaintPatrck marked this pull request as ready for review April 1, 2026 18:01
@SaintPatrck SaintPatrck requested a review from a team as a code owner April 1, 2026 18:01
david-livefront
david-livefront previously approved these changes Apr 2, 2026
Base automatically changed from card-scanner/1-generalize-camera-preview to main April 6, 2026 18:27
@SaintPatrck SaintPatrck dismissed david-livefront’s stale review April 6, 2026 18:27

The base branch was changed.

Add the complete text analysis pipeline for credit card scanning:
- CardNumberUtils: sanitize, Luhn validation, brand detection
- CardDataParser: interface and implementation for OCR text parsing
- CardTextAnalyzer: ML Kit-based camera frame analysis
- CardScanOverlay: camera overlay composable
- CardScanData: data class for parsed card fields
- FakeCardTextAnalyzer: test fixture
- LocalProviders: composition local for CardTextAnalyzer
- Move empty digits check into when block as first case
- Remove unnecessary @Suppress("MagicNumber") from parseCardData
- Remove unused default values from CardScanData
- Use @OptIn(ExperimentalGetImage::class) with androidx.annotation.OptIn
- Remove default CardDataParserImpl from CardTextAnalyzerImpl constructor
- Add Closeable to CardTextAnalyzerImpl to release ML Kit native resources
- Override toString on CardScanData to mask sensitive fields
- Add missing RuPay brand detection test coverage
Instead of returning a CardScanData with all null properties, return
null to avoid creating meaningless objects. Consolidate tests to assert
full objects rather than individual properties.
LocalComposition doesn't provide a lifecycle hook for cleanup,
so close() would never be invoked. Removes Closeable to stay
consistent with QrCodeAnalyzerImpl.
OCR-based name detection is unreliable and inconsistent per
Design team decision. Remove the field, regex, and related tests.
@SaintPatrck SaintPatrck force-pushed the card-scanner/2-text-analysis-pipeline branch from 35fa5f1 to 8299421 Compare April 6, 2026 18:29
@SaintPatrck SaintPatrck removed hold do not merge yet labels Apr 6, 2026
@SaintPatrck SaintPatrck enabled auto-merge April 6, 2026 18:31
}
}

@Suppress("MagicNumber")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this suppression needed?

@SaintPatrck SaintPatrck added this pull request to the merge queue Apr 6, 2026
Merged via the queue into main with commit 8c5c145 Apr 6, 2026
33 of 36 checks passed
@SaintPatrck SaintPatrck deleted the card-scanner/2-text-analysis-pipeline branch April 6, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review-vnext Request a Claude code review using the vNext workflow app:authenticator Bitwarden Authenticator app context app:password-manager Bitwarden Password Manager app context innovation Feature work related to Innovation Sprint or BEEEP projects t:deps Change Type - Dependencies t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants