bitwarden_policies/
policy_client.rs1use bitwarden_core::Client;
4#[cfg(feature = "wasm")]
5use wasm_bindgen::prelude::wasm_bindgen;
6
7use crate::{
8 OrganizationUserPolicyContext, PolicyType, PolicyView, policy_overrides::*,
9 registry::PolicyRegistry,
10};
11
12fn build_policy_registry() -> PolicyRegistry {
13 PolicyRegistry::builder()
14 .register(MasterPasswordPolicy)
15 .register(PasswordGeneratorPolicy)
16 .register(MaximumVaultTimeoutPolicy)
17 .register(FreeFamiliesSponsorshipPolicy)
18 .register(RemoveUnlockWithPinPolicy)
19 .register(RestrictedItemTypesPolicy)
20 .register(AutomaticUserConfirmationPolicy)
21 .build()
22}
23
24#[cfg_attr(feature = "wasm", wasm_bindgen)]
28pub struct PolicyClient {
29 registry: PolicyRegistry,
30}
31
32impl Default for PolicyClient {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl PolicyClient {
39 pub fn new() -> Self {
41 Self {
42 registry: build_policy_registry(),
43 }
44 }
45}
46
47#[cfg_attr(feature = "wasm", wasm_bindgen)]
48impl PolicyClient {
49 pub fn filter_by_type(
54 &self,
55 policies: Vec<PolicyView>,
56 organization_user_policy_contexts: Vec<OrganizationUserPolicyContext>,
57 policy_type: PolicyType,
58 ) -> Vec<PolicyView> {
59 self.registry
60 .filter_by_type(&policies, &organization_user_policy_contexts, policy_type)
61 .into_iter()
62 .cloned()
63 .collect()
64 }
65}
66
67pub trait PoliciesClientExt {
69 fn policies(&self) -> PolicyClient;
71}
72
73impl PoliciesClientExt for Client {
74 fn policies(&self) -> PolicyClient {
75 PolicyClient::new()
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use bitwarden_organizations::{OrganizationUserStatusType, OrganizationUserType};
82 use uuid::Uuid;
83
84 use super::*;
85 use crate::filter::Policy;
86
87 fn policy_view(organization_id: Uuid, policy_type: PolicyType, enabled: bool) -> PolicyView {
88 PolicyView {
89 id: Uuid::new_v4(),
90 organization_id,
91 r#type: policy_type,
92 data: None,
93 enabled,
94 revision_date: Default::default(),
95 }
96 }
97
98 fn organization(id: Uuid) -> OrganizationUserPolicyContext {
99 OrganizationUserPolicyContext {
100 id,
101 role: OrganizationUserType::User,
102 status: OrganizationUserStatusType::Confirmed,
103 enabled: true,
104 use_policies: true,
105 is_provider_user: false,
106 }
107 }
108
109 #[test]
110 fn filter_by_type_delegates_to_registry() {
111 let org_id = Uuid::new_v4();
112 let policies = vec![
113 policy_view(org_id, PolicyType::MasterPassword, true),
114 policy_view(org_id, PolicyType::PasswordGenerator, true),
115 ];
116 let orgs = vec![organization(org_id)];
117
118 let client = PolicyClient::new();
119 let result = client.filter_by_type(policies, orgs, PolicyType::MasterPassword);
120
121 assert_eq!(result.len(), 1);
122 assert_eq!(result[0].r#type, PolicyType::MasterPassword);
123 }
124
125 #[test]
126 fn filter_by_type_returns_empty_for_no_match() {
127 let org_id = Uuid::new_v4();
128 let policies = vec![policy_view(org_id, PolicyType::MasterPassword, true)];
129 let orgs = vec![organization(org_id)];
130
131 let client = PolicyClient::new();
132 let result = client.filter_by_type(policies, orgs, PolicyType::TwoFactorAuthentication);
133
134 assert!(result.is_empty());
135 }
136
137 #[test]
138 fn filter_by_type_uses_registered_policy_definition() {
139 struct NoExemptionPolicy;
140 impl Policy for NoExemptionPolicy {
141 fn policy_type(&self) -> PolicyType {
142 PolicyType::MasterPassword
143 }
144 fn exempt_roles(&self) -> &[OrganizationUserType] {
145 &[]
146 }
147 }
148
149 let org_id = Uuid::new_v4();
150 let policies = vec![policy_view(org_id, PolicyType::MasterPassword, true)];
152 let orgs = vec![OrganizationUserPolicyContext {
153 id: org_id,
154 role: OrganizationUserType::Owner,
155 status: OrganizationUserStatusType::Confirmed,
156 enabled: true,
157 use_policies: true,
158 is_provider_user: false,
159 }];
160
161 let registry = PolicyRegistry::builder()
162 .register(NoExemptionPolicy)
163 .build();
164 let client = PolicyClient { registry };
165 let result = client.filter_by_type(policies, orgs, PolicyType::MasterPassword);
166
167 assert_eq!(result.len(), 1);
168 }
169}