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