bitwarden_policies/policies/
password_generator.rs1use bitwarden_organizations::OrganizationUserType;
2use serde::{Deserialize, Serialize};
3
4use crate::{PolicyDefinition, PolicyType, policy_type::PolicyDataType};
5
6pub struct PasswordGeneratorPolicy;
8
9impl PolicyDefinition for PasswordGeneratorPolicy {
10 type Data = PasswordGeneratorPolicyData;
11
12 fn policy_type(&self) -> PolicyType {
13 PolicyType::PasswordGenerator
14 }
15
16 fn to_erased(&self, data: Self::Data) -> PolicyDataType {
17 PolicyDataType::PasswordGenerator(data)
18 }
19
20 fn exempt_roles(&self) -> &[OrganizationUserType] {
21 &[]
22 }
23}
24
25#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
28#[serde(rename_all = "camelCase")]
29#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
30#[bitwarden_ffi::wasm_record]
31pub enum PasswordGeneratorType {
32 Password,
34 Passphrase,
36}
37
38#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
41#[serde(rename_all = "camelCase")]
42#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
43#[bitwarden_ffi::wasm_record]
44pub struct PasswordGeneratorPolicyData {
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub override_password_type: Option<PasswordGeneratorType>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub min_length: Option<i32>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub use_upper: Option<bool>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub use_lower: Option<bool>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub use_numbers: Option<bool>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub use_special: Option<bool>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub min_numbers: Option<i32>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub min_special: Option<i32>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub min_number_words: Option<i32>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub capitalize: Option<bool>,
84
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub include_number: Option<bool>,
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn round_trips_full() {
96 let data = PasswordGeneratorPolicyData {
97 override_password_type: Some(PasswordGeneratorType::Passphrase),
98 min_length: Some(14),
99 use_upper: Some(true),
100 use_lower: Some(true),
101 use_numbers: Some(true),
102 use_special: Some(false),
103 min_numbers: Some(1),
104 min_special: Some(0),
105 min_number_words: Some(4),
106 capitalize: Some(true),
107 include_number: Some(true),
108 };
109 let json = serde_json::to_string(&data).unwrap();
110 assert!(json.contains(r#""overridePasswordType":"passphrase""#));
111 assert!(json.contains("minNumberWords"));
112 assert_eq!(
113 serde_json::from_str::<PasswordGeneratorPolicyData>(&json).unwrap(),
114 data
115 );
116 }
117
118 #[test]
119 fn override_password_type_serializes_as_camel_case_string() {
120 let json = serde_json::to_string(&PasswordGeneratorPolicyData {
121 override_password_type: Some(PasswordGeneratorType::Password),
122 ..Default::default()
123 })
124 .unwrap();
125 assert_eq!(json, r#"{"overridePasswordType":"password"}"#);
126 }
127
128 #[test]
129 fn empty_serializes_to_empty_object() {
130 assert_eq!(
131 serde_json::to_string(&PasswordGeneratorPolicyData::default()).unwrap(),
132 "{}"
133 );
134 }
135}