1+ use std:: collections:: HashMap ;
2+
3+ use serde:: { Deserialize , Serialize } ;
4+
5+ use crate :: CipherId ;
6+ #[ cfg( feature = "wasm" ) ]
7+ use { tsify:: Tsify , wasm_bindgen:: prelude:: * } ;
8+
9+ /// Minimal login cipher data needed for risk evaluation
10+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
11+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
12+ #[ cfg_attr( feature = "wasm" , derive( Tsify ) , tsify( into_wasm_abi, from_wasm_abi) ) ]
13+ pub struct CipherLoginDetails {
14+ /// Cipher ID to identify which cipher in results
15+ pub id : Option < CipherId > ,
16+ /// The decrypted password to evaluate
17+ pub password : String ,
18+ /// Username or email (login ciphers only have one field)
19+ pub username : Option < String > ,
20+ }
21+
22+ /// Password reuse map wrapper for WASM compatibility
23+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
24+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
25+ #[ cfg_attr( feature = "wasm" , derive( Tsify ) , tsify( into_wasm_abi, from_wasm_abi) ) ]
26+ #[ serde( transparent) ]
27+ pub struct PasswordReuseMap {
28+ /// Map of passwords to their occurrence count
29+ #[ cfg_attr( feature = "wasm" , tsify( type = "Record<string, number>" ) ) ]
30+ pub map : HashMap < String , u32 > ,
31+ }
32+
33+ /// Options for configuring risk computation
34+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
35+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
36+ #[ cfg_attr( feature = "wasm" , derive( Tsify ) , tsify( into_wasm_abi, from_wasm_abi) ) ]
37+ #[ serde( rename_all = "camelCase" ) ]
38+ pub struct CipherRiskOptions {
39+ /// Pre-computed password reuse map (password → count)
40+ /// If provided, enables reuse detection across ciphers
41+ pub password_map : Option < PasswordReuseMap > ,
42+ /// Whether to check passwords against Have I Been Pwned API
43+ /// When true, makes network requests to check for exposed passwords
44+ pub check_exposed : bool ,
45+ }
46+
47+ impl Default for CipherRiskOptions {
48+ fn default ( ) -> Self {
49+ Self {
50+ password_map : None ,
51+ check_exposed : false ,
52+ }
53+ }
54+ }
55+
56+ /// Risk evaluation result for a single cipher
57+ #[ derive( Serialize , Deserialize , Debug , Clone , PartialEq ) ]
58+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
59+ #[ cfg_attr( feature = "wasm" , derive( Tsify ) , tsify( into_wasm_abi, from_wasm_abi) ) ]
60+ pub struct CipherRisk {
61+ /// Cipher ID matching the input CipherLoginDetails
62+ pub id : Option < CipherId > ,
63+ /// Password strength score from 0 (weakest) to 4 (strongest)
64+ /// Calculated using zxcvbn with cipher-specific context
65+ pub password_strength : u8 ,
66+ /// Number of times password appears in HIBP database
67+ /// None if check_exposed was false in options
68+ pub exposed_count : Option < u32 > ,
69+ /// Number of times this password appears in the provided cipher list
70+ /// Minimum value is 1 (the cipher itself)
71+ pub reuse_count : u32 ,
72+ }
73+
74+ #[ cfg( feature = "wasm" ) ]
75+ impl wasm_bindgen:: __rt:: VectorIntoJsValue for CipherRisk {
76+ fn vector_into_jsvalue (
77+ vector : wasm_bindgen:: __rt:: std:: boxed:: Box < [ Self ] > ,
78+ ) -> wasm_bindgen:: JsValue {
79+ wasm_bindgen:: __rt:: js_value_vector_into_jsvalue ( vector)
80+ }
81+ }
0 commit comments