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#[allow(missing_docs)]
35#[derive(Debug)]
36#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
37#[allow(dead_code)]
38pub struct MasterPasswordPolicyOptions {
39 min_complexity: u8,
40 min_length: u8,
41 require_upper: bool,
42 require_lower: bool,
43 require_numbers: bool,
44 require_special: bool,
45
46 enforce_on_login: bool,
50}
51
52#[cfg(test)]
53mod tests {
54
55 use super::{satisfies_policy, MasterPasswordPolicyOptions};
56
57 #[test]
58 fn satisfies_policy_gives_success() {
59 let password = "lkasfo!icbb$2323ALKJCO22".to_string();
60 let options = MasterPasswordPolicyOptions {
61 min_complexity: 3,
62 min_length: 5,
63 require_upper: true,
64 require_lower: true,
65 require_numbers: true,
66 require_special: true,
67 enforce_on_login: false,
68 };
69
70 let result = satisfies_policy(password, 4, &options);
71 assert!(result);
72 }
73
74 #[test]
75 fn satisfies_policy_evaluates_strength() {
76 let password = "password123".to_string();
77 let options = MasterPasswordPolicyOptions {
78 min_complexity: 3,
79 min_length: 0,
80 require_upper: false,
81 require_lower: false,
82 require_numbers: false,
83 require_special: false,
84 enforce_on_login: false,
85 };
86
87 let result = satisfies_policy(password, 0, &options);
88 assert!(!result);
89 }
90
91 #[test]
92 fn satisfies_policy_evaluates_length() {
93 let password = "password123".to_string();
94 let options = MasterPasswordPolicyOptions {
95 min_complexity: 0,
96 min_length: 20,
97 require_upper: false,
98 require_lower: false,
99 require_numbers: false,
100 require_special: false,
101 enforce_on_login: false,
102 };
103
104 let result = satisfies_policy(password, 0, &options);
105 assert!(!result);
106 }
107
108 #[test]
109 fn satisfies_policy_evaluates_upper() {
110 let password = "password123".to_string();
111 let options = MasterPasswordPolicyOptions {
112 min_complexity: 0,
113 min_length: 0,
114 require_upper: true,
115 require_lower: false,
116 require_numbers: false,
117 require_special: false,
118 enforce_on_login: false,
119 };
120
121 let result = satisfies_policy(password, 0, &options);
122 assert!(!result);
123 }
124
125 #[test]
126 fn satisfies_policy_evaluates_lower() {
127 let password = "ABCDEFG123".to_string();
128 let options = MasterPasswordPolicyOptions {
129 min_complexity: 0,
130 min_length: 0,
131 require_upper: false,
132 require_lower: true,
133 require_numbers: false,
134 require_special: false,
135 enforce_on_login: false,
136 };
137
138 let result = satisfies_policy(password, 0, &options);
139 assert!(!result);
140 }
141
142 #[test]
143 fn satisfies_policy_evaluates_numbers() {
144 let password = "password".to_string();
145 let options = MasterPasswordPolicyOptions {
146 min_complexity: 0,
147 min_length: 0,
148 require_upper: false,
149 require_lower: false,
150 require_numbers: true,
151 require_special: false,
152 enforce_on_login: false,
153 };
154
155 let result = satisfies_policy(password, 0, &options);
156 assert!(!result);
157 }
158
159 #[test]
160 fn satisfies_policy_evaluates_special() {
161 let password = "Password123".to_string();
162 let options = MasterPasswordPolicyOptions {
163 min_complexity: 0,
164 min_length: 0,
165 require_upper: false,
166 require_lower: false,
167 require_numbers: false,
168 require_special: true,
169 enforce_on_login: false,
170 };
171
172 let result = satisfies_policy(password, 0, &options);
173 assert!(!result);
174 }
175}