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