Skip to content

Conversation

@david-livefront
Copy link
Collaborator

@david-livefront david-livefront commented Oct 27, 2025

🎟️ Tracking

PM-27597

📔 Objective

Update the TwoFactorLoginScreen to display a Yubi Key illustration instead of a raster image and standardize it with the rest of the 2-factor mechanisms.

Figme: https://www.figma.com/design/WjD06w9dFlA67Ba27d1OSu/Dev-Ready--Bitwarden-Android?node-id=40001448-10884&t=JYXtbE7zOvtmnzFh-4

📸 Screenshots

Before After

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@claude
Copy link
Contributor

claude bot commented Oct 27, 2025

Claude finished @david-livefront's task —— View job


Code Review Complete ✅

I've reviewed this PR which includes two main improvements:

  1. YubiKey Illustration Update (PM-27597)
  2. TOTP Parsing Consolidation (PM-27817)

Summary

This PR successfully modernizes the YubiKey illustration and eliminates significant code duplication through intelligent refactoring. The changes follow established patterns and improve both user experience and code maintainability.

Key Improvements

Vector Drawable Migration:

  • ✅ Replaced ~2MB of PNG assets with a 3KB vector drawable
  • ✅ Better scalability across screen densities
  • ✅ Consistent with other 2FA illustrations
  • ✅ Well-structured vector with semantic path naming

TOTP Parsing Consolidation:

  • ✅ Eliminated ~170 lines of duplicated code across modules
  • ✅ Created shared TotpUriUtils with proper validation
  • ✅ Improved maintainability with single source of truth
  • ✅ Consistent parsing logic between :app and :authenticator modules

String Updates:

  • ✅ More accurate: "Yubico OTP" instead of "YubiKey NEO"
  • ✅ Supports all YubiKey models (4, 5, NEO)
  • ⚠️ Minor inconsistency between title and instruction text

Architecture Compliance

  • MVVM Pattern: ViewModels simplified, business logic extracted to utilities
  • Module Organization: Shared utilities correctly placed in :ui module
  • Dependency Management: Both app modules properly use shared :ui utilities
  • Testing: All test coverage maintained, tests updated appropriately
  • Code Style: Follows Kotlin idioms, proper expression functions, clear naming

Recommendations

String Consistency (Minor):
Consider updating the title to include "OTP" for consistency:

  • Current: "Yubico security key" (title) vs "Yubico OTP security key" (instruction)
  • Suggested: "Yubico OTP security key" (both)
  • Benefit: Matches web vault naming and addresses user feedback from @pamperer562580892423

See inline comment on strings.xml:183 for details.

Test Results

  • Checkmarx: No new security vulnerabilities
  • Codecov: 97.22% patch coverage (1 partial line in TwoFactorLoginScreen.kt)
  • CI Builds: All passing

Code Quality

Strengths:

  • Clean refactoring that reduces complexity
  • Proper error handling with nullable types
  • Good separation of concerns
  • Maintains test coverage
  • Follows established naming conventions

Metrics:

  • 15 files changed: +205/-407 lines
  • Net reduction of 202 lines
  • Significant improvement in code reuse

Conclusion

This is a well-executed PR that improves both the visual presentation and code architecture. The YubiKey illustration update provides a modern, scalable asset while the TOTP parsing consolidation demonstrates excellent refactoring discipline. The only suggestion is the minor string consistency improvement mentioned above.

Recommendation: ✅ Approve (with optional string consistency improvement)


@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

Logo
Checkmarx One – Scan Summary & Detailsa44ac119-8011-42d9-9b50-88d66686801c

Great job! No new security vulnerabilities introduced in this pull request

@codecov
Copy link

codecov bot commented Oct 27, 2025

Codecov Report

❌ Patch coverage is 86.56716% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.96%. Comparing base (ed47ff4) to head (d9a1f8a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...nticator/feature/qrcodescan/QrCodeScanViewModel.kt 68.18% 7 Missing ⚠️
...uth/feature/twofactorlogin/TwoFactorLoginScreen.kt 96.96% 0 Missing and 1 partial ⚠️
...lin/com/bitwarden/ui/platform/util/TotpUriUtils.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6087      +/-   ##
==========================================
+ Coverage   84.91%   84.96%   +0.04%     
==========================================
  Files         724      724              
  Lines       52820    52758      -62     
  Branches     7679     7659      -20     
==========================================
- Hits        44853    44826      -27     
+ Misses       5274     5249      -25     
+ Partials     2693     2683      -10     

☔ 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.

@pamperer562580892423
Copy link

pamperer562580892423 commented Oct 27, 2025

Hey, I know, PRs are no discussion board... so I'll just throw it in shortly:

  1. I like the new naming in the Help Sites more as just "Yubikey Security Key" (as many users confuse this with the FIDO2-2FA option) - the Help Sites now call it "YubiKey OTP" (https://bitwarden.com/help/setup-two-step-login-yubikey/ - BTW, actually, the correct name would be "Yubico OTP" - that's how Yubico calls it themselves: https://www.yubico.com/resources/glossary/yubico-otp/ ...):
2025-10-27--23-49-33-vivaldi_SW8RYjcxd1

 

  1. I was already confused many times - also on Crowdin - why only YubiKey NEO is mentioned, while you can also use Yubikeys 4 and 5 for this 2FA option. (--> actually, I think this is a mistake in the Crowdin source string, but as there are also some questions unanswered for years - some even for 5-7 years unanswered - , I'm not confident it will change there of it's own...)
2025-10-27--23-54-14-vivaldi_5vpGC54FpN

 

BTW, the web vault not only shows all YubiKey options (4, 5 and NEO) but also the correct name "Yubico OTP":

2025-10-27--23-51-19-vivaldi_8KeLbrdr7r

 

PS: Overall, it would be good to have one common name for the same thing in all places... currently:

  • Web vault: Yubico OTP security key
  • Help Sites: YubiKey OTP
  • Mobile App: YubiKey security key

(--> the web vault's version "Yubico OTP security key" would be my - and probably also Yubico's - favorite, as it's closest to their product name...)

@david-livefront david-livefront added the hold do not merge yet label Oct 28, 2025
@david-livefront
Copy link
Collaborator Author

@pamperer562580892423 I have forwarded your concerns to our design team and am awaiting their feedback.

@SaintPatrck SaintPatrck mentioned this pull request Oct 29, 2025
6 tasks
@david-livefront david-livefront force-pushed the standardize-yubikey-illustration branch from 1c00e9d to 736fe3d Compare November 4, 2025 20:38
<string name="verification_email_sent">Verification email sent</string>
<string name="yubi_key_instruction">To continue, hold your YubiKey NEO against the back of the device or insert your YubiKey into your device’s USB port, then touch its button.</string>
<string name="yubi_key_title">YubiKey security key</string>
<string name="yubi_key_instruction">To continue, hold your Yubico OTP security key against the back of the device or insert it into your device’s USB port, then touch its button.</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

📝 String Update Analysis

The instruction text has been updated from mentioning "YubiKey NEO" specifically to "Yubico OTP security key". This is more accurate since:

  1. YubiKey 4 and 5 also support Yubico OTP (not just NEO)
  2. It correctly identifies the 2FA method as "Yubico OTP" rather than just "YubiKey"

However, there's a minor inconsistency worth noting:

  • The title uses "Yubico security key" (line 183)
  • The instruction uses "Yubico OTP security key" (line 182)

For consistency with the web vault (which uses "Yubico OTP security key") and clarity for users, consider updating line 183 to also include "OTP":

Suggested change
<string name="yubi_key_instruction">To continue, hold your Yubico OTP security key against the back of the device or insert it into your device’s USB port, then touch its button.</string>
<string name="yubi_key_title">Yubico OTP security key</string>

This would align with:

  • Web vault naming convention
  • The more specific instruction text
  • Industry-standard terminology from Yubico

contentDescription = null,
modifier = Modifier
.standardHorizontalMargin()
.size(124.dp),
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Good Improvement

The migration from painterResource (used for raster images) to using it with the new vector drawable is correct. The image is now properly sized at 124.dp, which matches the vector drawable's viewport dimensions and provides consistent sizing with other 2FA method illustrations like the authenticator app icon.

The removal of unnecessary layout complexity (previous version had more nested layouts) also improves performance.

val TwoFactorAuthMethod.imageRes: Int?
get() = when (this) {
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.img_yubi_key
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.ill_yubi_key
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Correct Resource Update

The reference has been properly updated from the raster image resources (img_yubi_key) to the new vector drawable (ill_yubi_key). This follows the established naming convention in the codebase:

  • img_* prefix for raster images
  • ill_* prefix for illustration vector drawables

The vector drawable provides:

  • Better scalability across different screen densities
  • Smaller binary size (single XML file vs 5 PNG files)
  • Consistency with other 2FA illustrations

@@ -0,0 +1,85 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Well-Designed Vector Drawable

The new vector illustration is well-structured:

  • Proper viewport dimensions (124x124) matching the design specifications
  • Clear semantic naming for paths (primary, secondary, accent, outline, tertiary)
  • Follows Material Design color palette conventions
  • Uses the established color scheme from the app's design system

The illustration effectively represents a YubiKey device with:

  • A key/USB device representation
  • Clear visual hierarchy with multiple color layers
  • Consistent style with other 2FA illustrations in the app

This replaces ~2MB of PNG assets across 5 density buckets with a single ~3KB XML file.

TwoFactorAuthMethod.EMAIL to BitwardenDrawable.ill_new_device_verification,
TwoFactorAuthMethod.DUO to null,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.img_yubi_key,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.ill_yubi_key,
Copy link
Contributor

Choose a reason for hiding this comment

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

Test Coverage Updated

The test has been correctly updated to verify that TwoFactorAuthMethod.YUBI_KEY returns BitwardenDrawable.ill_yubi_key instead of the old raster image resource. This ensures:

  1. The extension property returns the correct drawable resource
  2. Test coverage is maintained at the same level
  3. Future refactoring won't break the image association

All tests are passing according to CI, confirming the changes work as expected.

@david-livefront david-livefront changed the title Update Yubikey illustration to match the rest of the app PM-27597: Update Yubikey illustration to match the rest of the app Nov 4, 2025
@david-livefront david-livefront force-pushed the standardize-yubikey-illustration branch from 736fe3d to d9a1f8a Compare November 4, 2025 21:43
<string name="yubi_key_instruction">To continue, hold your YubiKey NEO against the back of the device or insert your YubiKey into your device’s USB port, then touch its button.</string>
<string name="yubi_key_title">YubiKey security key</string>
<string name="yubi_key_instruction">To continue, hold your Yubico security key against the back of the device or insert it into your device’s USB port, then touch its button.</string>
<string name="yubi_key_title">Yubico security key</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

📝 String Consistency Suggestion

The title uses "Yubico security key" while the instruction text (line 182) uses "Yubico OTP security key". For consistency with:

  • The web vault (which uses "Yubico OTP security key")
  • The more specific instruction text
  • Industry-standard terminology from Yubico

Consider updating to:

Suggested change
<string name="yubi_key_title">Yubico security key</string>
<string name="yubi_key_title">Yubico OTP security key</string>

This would also address the user feedback from @pamperer562580892423 about naming consistency across platforms.

<string name="verification_email_sent">Verification email sent</string>
<string name="yubi_key_instruction">To continue, hold your YubiKey NEO against the back of the device or insert your YubiKey into your device’s USB port, then touch its button.</string>
<string name="yubi_key_title">YubiKey security key</string>
<string name="yubi_key_instruction">To continue, hold your Yubico security key against the back of the device or insert it into your device’s USB port, then touch its button.</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Improved Accuracy

Good update from "YubiKey NEO" to "Yubico OTP security key". This is more accurate because:

  1. YubiKey 4 and 5 also support Yubico OTP (not just NEO)
  2. It correctly identifies the 2FA method as "Yubico OTP" rather than just "YubiKey"

This addresses the concern raised by @pamperer562580892423 about the NEO-specific language.

@@ -0,0 +1,85 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Excellent Vector Drawable Implementation

This new vector illustration is well-designed:

  • ✅ Proper viewport dimensions (124x124) matching design specs
  • ✅ Clear semantic naming for paths (primary, secondary, accent, outline, tertiary)
  • ✅ Follows Material Design color palette conventions
  • ✅ Consistent with app's design system

Benefits:

  • Replaces ~2MB of PNG assets across 5 density buckets with a single ~3KB XML file
  • Better scalability across different screen densities
  • Consistency with other 2FA illustrations in the codebase

The illustration effectively represents a YubiKey device with clear visual hierarchy.

contentDescription = null,
modifier = Modifier
.standardHorizontalMargin()
.size(124.dp),
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Improved Image Rendering

Good migration from raster to vector drawable:

  • painterResource now used with vector drawable
  • ✅ Proper sizing at 124.dp matching viewport dimensions
  • ✅ Consistent with other 2FA illustrations (authenticator app icon)
  • ✅ Simplified layout complexity (removed unnecessary nesting)

The streamlined implementation improves both performance and maintainability.

val TwoFactorAuthMethod.imageRes: Int?
get() = when (this) {
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.img_yubi_key
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.ill_yubi_key
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Correct Resource Update

Properly updated from raster (img_yubi_key) to vector drawable (ill_yubi_key). Follows established naming conventions:

  • img_* prefix for raster images
  • ill_* prefix for illustration vector drawables

The vector approach provides better scalability and smaller binary size.

vaultRepository.emitTotpCodeResult(result)
val qrCode = action.qrCode
qrCode
.getTotpDataOrNull()
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Simplified ViewModel Logic

Excellent refactoring using the new TotpUriUtils.getTotpDataOrNull() extension:

Before: ~80 lines of URI parsing logic duplicated in this ViewModel
After: Single line delegation to shared utility

This aligns with MVVM architecture guidelines:

  • ViewModels should focus on UI logic, not parsing utilities
  • Shared parsing logic belongs in utility modules (:ui)
  • Reduces cyclomatic complexity and improves testability

The error handling remains clear with the elvis operator handling invalid TOTP data.

import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
import com.bitwarden.ui.platform.base.BaseViewModel
import com.bitwarden.ui.platform.base.util.isBase32
import com.bitwarden.ui.platform.util.getTotpDataOrNull
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Consistent TOTP Parsing Across Modules

Good use of the shared getTotpDataOrNull() utility from :ui module. This ensures:

  • Consistency: Both :app and :authenticator modules use identical TOTP parsing logic
  • Module Architecture: Authenticator module correctly depends on :ui for shared utilities
  • Code Reuse: Eliminates ~80 lines of duplicated parsing code from this module

This follows the project's multi-module architecture where :ui provides common utilities for both application modules.

TwoFactorAuthMethod.EMAIL to BitwardenDrawable.ill_new_device_verification,
TwoFactorAuthMethod.DUO to null,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.img_yubi_key,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.ill_yubi_key,
Copy link
Contributor

Choose a reason for hiding this comment

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

✅ Test Coverage Maintained

Test correctly updated to verify TwoFactorAuthMethod.YUBI_KEY returns the new ill_yubi_key drawable resource. This ensures:

  • ✅ Extension property returns correct drawable
  • ✅ Test coverage maintained at same level
  • ✅ Future refactoring won't break the image association

All tests passing per CI confirms the changes work as expected.

@david-livefront
Copy link
Collaborator Author

Thanks @SaintPatrck

@david-livefront
Copy link
Collaborator Author

@pamperer562580892423 We've updated the app copy, it does not match the web exactly but it no longer mentions NEO or any specific model since we should have the capability to support all of them.

@david-livefront david-livefront added this pull request to the merge queue Nov 4, 2025
@pamperer562580892423
Copy link

pamperer562580892423 commented Nov 4, 2025

@david-livefront I would have preferred "Yubico OTP security key" in the title also... but hey, thanks for hearing me out and addressing some of it! 🙂

Merged via the queue into main with commit bfbe47f Nov 4, 2025
21 of 41 checks passed
@david-livefront david-livefront deleted the standardize-yubikey-illustration branch November 4, 2025 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold do not merge yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants