- 
                Notifications
    You must be signed in to change notification settings 
- Fork 20
[PM-24468] Introduce CipherRiskClient #499
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
Conversation
| Claude finished @shane-melton's task —— View job Code Review Complete ✓I've completed a comprehensive review of the CipherRiskClient implementation. Overall, the code is well-structured with excellent test coverage and good documentation. The refactoring based on previous feedback has significantly improved the code organization. Summary of Changes Since Last ReviewThe PR has been significantly refactored since the initial reviews: 
 Critical Issues1. 🔴 Missing SHA-1 Algorithm Justification (BLOCKER per CLAUDE.md)Location:  Per CLAUDE.md guidelines on crypto algorithms, any crypto algorithm choice requires detailed justification. SHA-1 is cryptographically broken for security purposes, and while its use here is correct (HIBP API requirement + k-anonymity protection), this MUST be documented. Required comment/// Hash password with SHA-1 and split into prefix/suffix for k-anonymity.
///
/// **SHA-1 Algorithm Justification:**
/// SHA-1 is used here despite being cryptographically broken for the following reasons:
/// 1. HIBP API requires SHA-1 for backwards compatibility with their database
/// 2. The k-anonymity model (only sending 5-char prefix) protects the actual password
/// 3. This is used solely as a hash function for lookup, not for cryptographic security
/// 4. The privacy guarantee comes from k-anonymity, not from SHA-1's collision resistance
///
/// Returns a tuple of (prefix: first 5 chars, suffix: remaining chars).
fn hash_password_for_hibp(password: &str) -> (String, String) {Suggested Improvements2. 🎨 Document Concurrency Limit RationaleLocation:  The magic number  Suggested comment/// Maximum number of concurrent HIBP API requests.
///
/// This limit balances several factors:
/// - Performance: Allows efficient batch processing of multiple passwords
/// - API courtesy: Prevents overwhelming the HIBP service
/// - Client resources: Avoids exhausting connection pools (typical HTTP/2 limit is 100)
/// - Error handling: Limits blast radius if the API has issues
///
/// Value tuned based on typical HTTP/2 connection limits and HIBP API best practices.
const MAX_CONCURRENT_REQUESTS: usize = 100;3. 🎨 Add Documentation for Error Handling StrategyLocation:  The per-cipher error capture is an excellent design choice that deserves highlighting with a comment. // Capture errors per-cipher instead of propagating them to allow partial results.
// This ensures that if HIBP checks fail for some passwords (e.g., network issues),
// we still return strength and reuse data for all ciphers.
let exposed_result = if check_exposed {
    match hibp::check_password_exposed(&http_client, &details.password, &base_url).await {4. 🎨 Consider Adding User-Agent Header to HIBP RequestsLocation:  HIBP API best practices recommend identifying your application with a User-Agent header. This helps HIBP track usage patterns and contact developers if issues arise. let response = http_client
    .get(&url)
    .header("User-Agent", "Bitwarden-SDK/1.0") // Consider adding this
    .send()
    .await5. 💭 Potential Memory OptimizationLocation:  The  Potential enhancementpub struct PasswordReuseMap {
    pub map: HashMap<String, u32>,
    /// Count of ciphers with empty passwords (not included in map)
    pub empty_password_count: u32,
}This is non-blocking and depends on business requirements. 6. 📝 Minor: Test Naming Could Be More DescriptiveLocation:  Test name  Security Considerations ✅I've reviewed the implementation for security concerns: 
 Good Practices Observed ✨
 Action Items for Author
 ConclusionThis is a solid implementation with excellent test coverage (96.92%) and good architecture. The main blocker is the missing crypto algorithm justification required by CLAUDE.md. Once that's added, this will be ready to merge. The suggested improvements are mostly documentation enhancements that would help future maintainers. The refactoring based on previous reviews has resulted in a clean, maintainable implementation that follows Rust and Bitwarden SDK best practices. | 
| 
 Great job! No new security vulnerabilities introduced in this pull request | 
| Codecov Report❌ Patch coverage is  Additional details and impacted files@@            Coverage Diff             @@
##             main     #499      +/-   ##
==========================================
+ Coverage   78.31%   78.70%   +0.38%     
==========================================
  Files         292      296       +4     
  Lines       29883    30500     +617     
==========================================
+ Hits        23404    24005     +601     
- Misses       6479     6495      +16     ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
 | 
915fe76    to
    a10fef6      
    Compare
  
    Remove performance test
…er in exposed_count
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.
Looks good! A few minor suggestions.
| 
 | 
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.
A couple of non-blocking observations, but otherwise looks good!
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.
One blocker.
| wasm-bindgen-futures = "0.4.41" | ||
| wasm-bindgen-test = "0.3.45" | ||
| wiremock = ">=0.6.0, <0.7" | ||
| zxcvbn = ">=3.0.1, <4.0" | 
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.
issue (blocker): Please update bitwarden-core to reference the workspace version.
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.
Fixed 02f5614
| pub fn password_reuse_map(&self, login_details: Vec<CipherLoginDetails>) -> PasswordReuseMap { | ||
| PasswordReuseMap::new(login_details) | ||
| } | 
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.
observation (non-blocking): This is likely a pattern we will want to avoid in the future. Part of the reason for moving towards cipher list views is to decrease the amount of data available in the renderer. Sending a plain text list of passwords to JS is therefore undesired. (Decrypting multiple full ciphers on the renderer in order to get the passwords and sending them to the sdk, would likewise be undesired in the future).
You might be able to send a pointer which would keep the memory on the rust side and ensure the rust de-allocator zeroes the memory.
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.
Agreed! Once we have more of the Cipher domain (w/ repositories) migrated to the SDK, I anticipate we'll be able to deprecate this pattern and let the cipher risk client pull from the cipher repository internally. Perhaps accepting a list of CipherIds instead in case callers only wish to map a subset of ciphers (e.g. for AC and reporting)
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.
non-blocking: I generally prefer to keep the related data models close to where they are used, (which in this case is the cipher_risk_client.
        02f5614
      
    …uce CipherRiskClient (bitwarden/sdk-internal#499)




🎟️ Tracking
PM-24468
📔 Objective
Implement the cipher risk evaluation logic in the Vault SDK as a separate
CipherRiskClientso that it can be re-used in mobile and gain potential performance improvements.The
CipherRiskClientcontains logic to check if a multiple login ciphers' passwords are exposed (via HIBP), weak (via zxcvbn), or reused.⏰ Reminders before review
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 confirmedissue 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