bitwarden_policies/
registry.rs1#![allow(dead_code)]
2
3use std::collections::HashMap;
10
11use bitwarden_organizations::ProfileOrganization;
12
13use crate::filter::{Policy, PolicyFilter, PolicyType, PolicyView};
14
15struct DefaultPolicy(PolicyType);
17
18impl Policy for DefaultPolicy {
19 fn policy_type(&self) -> PolicyType {
20 self.0
21 }
22}
23
24pub struct PolicyRegistry {
32 policies: HashMap<PolicyType, Box<dyn PolicyFilter>>,
33}
34
35impl PolicyRegistry {
36 pub fn builder() -> PolicyRegistryBuilder {
38 PolicyRegistryBuilder {
39 policies: HashMap::new(),
40 }
41 }
42
43 pub(crate) fn filter_by_type<'a>(
48 &self,
49 policies: &'a [PolicyView],
50 organizations: &[ProfileOrganization],
51 policy_type: PolicyType,
52 ) -> Vec<&'a PolicyView> {
53 match self.policies.get(&policy_type) {
54 Some(p) => p.filter(policies, organizations),
55 None => DefaultPolicy(policy_type).filter(policies, organizations),
56 }
57 }
58}
59
60pub struct PolicyRegistryBuilder {
62 policies: HashMap<PolicyType, Box<dyn PolicyFilter>>,
63}
64
65impl PolicyRegistryBuilder {
66 pub fn register<P: Policy>(mut self, policy: P) -> Self {
72 let policy_type = policy.policy_type();
73 if self.policies.contains_key(&policy_type) {
74 panic!("policy already registered for type {:?}", policy_type);
75 }
76 self.policies.insert(policy_type, Box::new(policy));
77 self
78 }
79
80 pub fn build(self) -> PolicyRegistry {
82 PolicyRegistry {
83 policies: self.policies,
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use bitwarden_organizations::{OrganizationUserStatusType, OrganizationUserType};
91 use uuid::Uuid;
92
93 use super::*;
94
95 fn policy_view(organization_id: Uuid, policy_type: u8, enabled: bool) -> PolicyView {
96 PolicyView {
97 id: Uuid::new_v4(),
98 organization_id,
99 r#type: PolicyType(policy_type),
100 data: None,
101 enabled,
102 }
103 }
104
105 fn organization(
106 id: Uuid,
107 user_type: OrganizationUserType,
108 status: OrganizationUserStatusType,
109 provider: bool,
110 ) -> ProfileOrganization {
111 ProfileOrganization {
112 id,
113 r#type: user_type,
114 status,
115 use_policies: true,
116 is_provider_user: provider,
117 ..Default::default()
118 }
119 }
120
121 #[test]
122 #[should_panic(expected = "policy already registered for type")]
123 fn registry_panics_on_duplicate_registration() {
124 struct AnyPolicy;
125 impl Policy for AnyPolicy {
126 fn policy_type(&self) -> PolicyType {
127 PolicyType(1)
128 }
129 }
130
131 PolicyRegistry::builder()
132 .register(AnyPolicy)
133 .register(AnyPolicy)
134 .build();
135 }
136
137 #[test]
138 fn registry_uses_registered_definition() {
139 let org_id = Uuid::new_v4();
140 let policies = [policy_view(org_id, 1, true)];
141 let orgs = [organization(
143 org_id,
144 OrganizationUserType::Owner,
145 OrganizationUserStatusType::Confirmed,
146 false,
147 )];
148
149 struct NoExemptionPolicy;
150 impl Policy for NoExemptionPolicy {
151 fn policy_type(&self) -> PolicyType {
152 PolicyType(1)
153 }
154 fn exempt_roles(&self) -> &[OrganizationUserType] {
155 &[]
156 }
157 }
158
159 let registry = PolicyRegistry::builder()
160 .register(NoExemptionPolicy)
161 .build();
162
163 let result = registry.filter_by_type(&policies, &orgs, PolicyType(1));
164
165 assert_eq!(result.len(), 1);
166 }
167
168 #[test]
169 fn registry_uses_default_policy_definition() {
170 let org_id = Uuid::new_v4();
171 let policies = [policy_view(org_id, 1, true)];
172 let orgs = [organization(
173 org_id,
174 OrganizationUserType::User,
175 OrganizationUserStatusType::Confirmed,
176 false,
177 )];
178
179 let registry = PolicyRegistry::builder().build();
181
182 let result = registry.filter_by_type(&policies, &orgs, PolicyType(1));
183
184 assert_eq!(result.len(), 1);
185 }
186}