-
Notifications
You must be signed in to change notification settings - Fork 907
[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 <[email protected]>
## 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 <[email protected]>
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).
The usage of unicode characters to force LTR direction on text does seem to fix the first and third regressions of the unicodeWrap() attempt (see this comment). However, the 2nd regression (wrong cursor position) is still very much an issue. As for manual RTL input in password fields, there seems to be a problem with that because LTR direction is being forced regardless of the directionality of the input. For example, the password Upon brief testing, I’ve noticed a few more quirks that occur when an RTL app language is selected:
It still seems to me that #5012 is a better approach than utilizing Unicode, mainly because the native Android implementation to set text direction takes care to align the text cursor correctly. The only downside is that it also aligns the text according to its direction, but it is easy to override this behavior with basically no side effects. Lastly, maintainability is also an important factor to consider. With the changes that this PR proposes, future PRs that add new types of vault items (for example) could be prone to omitting or misusing the new Thanks for dedicating time to find the best solution to this matter, issuing a fix could greatly improve the usability of the app for users of RTL languages. Please let me know if I could help with anything. |

🎟️ 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