- 
                Notifications
    You must be signed in to change notification settings 
- Fork 901
[PM-25423] Force LTR direction for password and sensitive fields #6090
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This commit introduces a `VisualTransformation` to enforce Left-To-Right (LTR) text direction in password fields and other sensitive inputs. This ensures consistent layout and prevents rendering issues, particularly in Right-To-Left (RTL) locales where characters like asterisks might otherwise appear incorrectly aligned. A `CompoundVisualTransformation` utility has also been added to allow chaining multiple `VisualTransformation`s together. Specific changes: - Created `ForceLtrVisualTransformation` to wrap text with LTR Unicode control characters. - Created `CompoundVisualTransformation` to combine multiple transformations, preserving correct offset mapping. - Applied `forceLtrVisualTransformation` to `BitwardenPasswordField` and `BitwardenHiddenPasswordField`, combining it with the existing `PasswordVisualTransformation` or `nonLetterColorVisualTransformation`. - Enforced LTR direction on generated passwords in the Password History screen. - Applied LTR transformation to sensitive fields in the "Identity" and "Login" item views, such as TOTP, URI, SSN, and passport number.
| Claude finished @SaintPatrck's task —— View job Review CompleteI've completed a comprehensive review of the LTR visual transformation implementation. Here's my detailed feedback: Summary of Changes Since Last ReviewThe PR has addressed several previous review comments: 
 Critical Issues1. Potential Offset Mapping Bug in CompoundVisualTransformationLocation:  The  override fun transformedToOriginal(offset: Int): Int {
    val resultOriginal = result.offsetMapping.transformedToOriginal(offset)
    return acc.offsetMapping.transformedToOriginal(resultOriginal)
}Issue: When  Example scenario: 
 Recommendation: Add bounds checking similar to  override fun transformedToOriginal(offset: Int): Int {
    val resultOriginal = result.offsetMapping.transformedToOriginal(offset)
    return acc.offsetMapping.transformedToOriginal(resultOriginal)
        .coerceIn(0, /* original text length */)
}However, getting the original text length requires refactoring. Consider capturing it in the fold operation. 2. Missing  | 
| 
 Great job! No new security vulnerabilities introduced in this pull request | 
        
          
                ui/src/main/kotlin/com/bitwarden/ui/platform/components/field/BitwardenPasswordField.kt
              
                Outdated
          
            Show resolved
            Hide resolved
        
      Simplifies password field visual transformations and adds comprehensive documentation to clarify usage patterns for future contributors. Changes: - Remove unnecessary CompoundVisualTransformation when password is obscured (bullets are directionally neutral) - Change ForceLtrVisualTransformation and CompoundVisualTransformation visibility from private to internal for testability - Add comprehensive KDoc explaining when to use LTR transformation: * Apply to technical identifiers (SSN, passport, license, etc.) * Do NOT apply to locale-dependent text (names, addresses, usernames) - Add usage examples to CompoundVisualTransformation - Create comprehensive test suites (39 test cases) to verify offset mapping correctness and edge case handling All tests pass and code compiles successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Objective Update test assertions to expect LTR-wrapped text in password and sensitive fields following the implementation of ForceLtrVisualTransformation. ## Changes - Made LRO and PDF constants public in ForceLtrVisualTransformation.kt to enable cross-module access from :app tests - Updated VaultAddEditScreenTest assertions (4 locations) to expect text wrapped with Unicode LTR control characters (LRO/PDF) - Updated VaultItemScreenTest assertions (3 locations) for password, card number, and security code fields - Added @Suppress("StringTemplate") annotations to maintain code clarity with wrapped text format ## Technical Details BitwardenPasswordField now applies ForceLtrVisualTransformation to visible, read-only fields, wrapping text with `\u202A` (LRO) prefix and `\u202C` (PDF) suffix to ensure left-to-right display in all locales. Tests now correctly expect this transformed output. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
d5198bd    to
    3c86dc3      
    Compare
  
    | Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@           Coverage Diff           @@
##             main    #6090   +/-   ##
=======================================
  Coverage   84.80%   84.81%           
=======================================
  Files         721      721           
  Lines       52811    52826   +15     
  Branches     7669     7670    +1     
=======================================
+ Hits        44789    44805   +16     
+ Misses       5332     5329    -3     
- Partials     2690     2692    +2     ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
 | 
| @codokie We've pivoted to a different approach for handling bidi text. Would you be willing to check behavior with these changes? I'm particularly curious if the Password fields handle manual RTL input correctly. | 
        
          
                .../com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreenTest.kt
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreenTest.kt
              
                Outdated
          
            Show resolved
            Hide resolved
        
      This commit removes several unnecessary `@Suppress("StringTemplate")` annotations from UI test files. These suppressions were added to handle string templates that are no longer present or are no longer flagged by the linter, making the annotation redundant.
    This commit corrects the order of visual transformations applied to the password history list item. The `forceLtrVisualTransformation` is moved after the `nonLetterColorVisualTransformation`. This ensures that the left-to-right transformation is applied correctly after the color transformation has processed the text, preventing potential rendering issues.
| } | ||
|  | ||
| composeTestRule.onNodeWithText(password.password).assertIsDisplayed() | ||
| composeTestRule.onNodeWithText("${LRO}${password.password}$PDF").assertIsDisplayed() | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one can just be "$LRO${password.password}$PDF"
| * recomposition. | ||
| */ | ||
| @Composable | ||
| fun forceLtrVisualTransformation(): VisualTransformation = remember { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the Remember do anything here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only to expose ForceLtrTransformation since it's internal and follow the existing pattern(s).

🎟️ Tracking
PM-25423
📔 Objective
This commit introduces a
VisualTransformationto enforce Left-To-Right (LTR) text direction in password fields and other sensitive inputs. This ensures consistent layout and prevents rendering issues, particularly in Right-To-Left (RTL) locales where characters like asterisks might otherwise appear incorrectly aligned.A
CompoundVisualTransformationutility has also been added to allow chaining multipleVisualTransformations together.Specific changes:
ForceLtrVisualTransformationto wrap text with LTR Unicode control characters.CompoundVisualTransformationto combine multiple transformations, preserving correct offset mapping.forceLtrVisualTransformationtoBitwardenPasswordFieldandBitwardenHiddenPasswordField, combining it with the existingPasswordVisualTransformationornonLetterColorVisualTransformation.📸 Screenshots
Coming soon!
⏰ Reminders before review
🦮 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