bitwarden_core/auth/password/
policy.rs1pub(crate) fn satisfies_policy(
3 password: String,
4 strength: u8,
5 policy: &MasterPasswordPolicyOptions,
6) -> bool {
7 if policy.min_complexity > 0 && policy.min_complexity > strength {
8 return false;
9 }
10
11 if policy.min_length > 0 && usize::from(policy.min_length) > password.len() {
12 return false;
13 }
14
15 if policy.require_upper && password.to_lowercase() == password {
16 return false;
17 }
18
19 if policy.require_lower && password.to_uppercase() == password {
20 return false;
21 }
22
23 if policy.require_numbers && !password.chars().any(|c| c.is_numeric()) {
24 return false;
25 }
26
27 if policy.require_special && !password.chars().any(|c| "!@#$%^&*".contains(c)) {
28 return false;
29 }
30
31 true
32}
33
34#[derive(Debug)]
35#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
36#[allow(dead_code)]
37pub struct MasterPasswordPolicyOptions {
38 min_complexity: u8,
39 min_length: u8,
40 require_upper: bool,
41 require_lower: bool,
42 require_numbers: bool,
43 require_special: bool,
44
45 enforce_on_login: bool,
49}
50
51#[cfg(test)]
52mod tests {
53
54 use super::{satisfies_policy, MasterPasswordPolicyOptions};
55
56 #[test]
57 fn satisfies_policy_gives_success() {
58 let password = "lkasfo!icbb$2323ALKJCO22".to_string();
59 let options = MasterPasswordPolicyOptions {
60 min_complexity: 3,
61 min_length: 5,
62 require_upper: true,
63 require_lower: true,
64 require_numbers: true,
65 require_special: true,
66 enforce_on_login: false,
67 };
68
69 let result = satisfies_policy(password, 4, &options);
70 assert!(result);
71 }
72
73 #[test]
74 fn satisfies_policy_evaluates_strength() {
75 let password = "password123".to_string();
76 let options = MasterPasswordPolicyOptions {
77 min_complexity: 3,
78 min_length: 0,
79 require_upper: false,
80 require_lower: false,
81 require_numbers: false,
82 require_special: false,
83 enforce_on_login: false,
84 };
85
86 let result = satisfies_policy(password, 0, &options);
87 assert!(!result);
88 }
89
90 #[test]
91 fn satisfies_policy_evaluates_length() {
92 let password = "password123".to_string();
93 let options = MasterPasswordPolicyOptions {
94 min_complexity: 0,
95 min_length: 20,
96 require_upper: false,
97 require_lower: false,
98 require_numbers: false,
99 require_special: false,
100 enforce_on_login: false,
101 };
102
103 let result = satisfies_policy(password, 0, &options);
104 assert!(!result);
105 }
106
107 #[test]
108 fn satisfies_policy_evaluates_upper() {
109 let password = "password123".to_string();
110 let options = MasterPasswordPolicyOptions {
111 min_complexity: 0,
112 min_length: 0,
113 require_upper: true,
114 require_lower: false,
115 require_numbers: false,
116 require_special: false,
117 enforce_on_login: false,
118 };
119
120 let result = satisfies_policy(password, 0, &options);
121 assert!(!result);
122 }
123
124 #[test]
125 fn satisfies_policy_evaluates_lower() {
126 let password = "ABCDEFG123".to_string();
127 let options = MasterPasswordPolicyOptions {
128 min_complexity: 0,
129 min_length: 0,
130 require_upper: false,
131 require_lower: true,
132 require_numbers: false,
133 require_special: false,
134 enforce_on_login: false,
135 };
136
137 let result = satisfies_policy(password, 0, &options);
138 assert!(!result);
139 }
140
141 #[test]
142 fn satisfies_policy_evaluates_numbers() {
143 let password = "password".to_string();
144 let options = MasterPasswordPolicyOptions {
145 min_complexity: 0,
146 min_length: 0,
147 require_upper: false,
148 require_lower: false,
149 require_numbers: true,
150 require_special: false,
151 enforce_on_login: false,
152 };
153
154 let result = satisfies_policy(password, 0, &options);
155 assert!(!result);
156 }
157
158 #[test]
159 fn satisfies_policy_evaluates_special() {
160 let password = "Password123".to_string();
161 let options = MasterPasswordPolicyOptions {
162 min_complexity: 0,
163 min_length: 0,
164 require_upper: false,
165 require_lower: false,
166 require_numbers: false,
167 require_special: true,
168 enforce_on_login: false,
169 };
170
171 let result = satisfies_policy(password, 0, &options);
172 assert!(!result);
173 }
174}