Skip to main content

dpp_crypto/access/credential/
trust.rs

1use std::collections::HashSet;
2
3use dpp_domain::AccessTier;
4
5/// Registry of issuer DIDs authorised to grant each access tier.
6///
7/// For MVP single-tenant, this is a static allow-list loaded from operator
8/// configuration (see [`StaticTrustedIssuers`]). Use [`AllowAllIssuers`] only
9/// in tests or pre-configuration bootstrapping — never in production.
10pub trait TrustedIssuerRegistry: Send + Sync {
11    fn is_trusted_for_tier(&self, issuer_did: &str, tier: AccessTier) -> bool;
12}
13
14/// Configuration-driven allow-list implementation of [`TrustedIssuerRegistry`].
15///
16/// A DID in `confidential_dids` is implicitly also trusted for Professional-tier
17/// credentials — Confidential implies Professional.
18pub struct StaticTrustedIssuers {
19    professional_dids: HashSet<String>,
20    confidential_dids: HashSet<String>,
21}
22
23impl StaticTrustedIssuers {
24    pub fn new(
25        professional_dids: impl IntoIterator<Item = impl Into<String>>,
26        confidential_dids: impl IntoIterator<Item = impl Into<String>>,
27    ) -> Self {
28        Self {
29            professional_dids: professional_dids.into_iter().map(Into::into).collect(),
30            confidential_dids: confidential_dids.into_iter().map(Into::into).collect(),
31        }
32    }
33
34    /// Single DID trusted for all tiers (e.g. the operator's own issuer DID).
35    pub fn single(trusted_did: impl Into<String>) -> Self {
36        let did = trusted_did.into();
37        Self {
38            professional_dids: HashSet::from([did.clone()]),
39            confidential_dids: HashSet::from([did]),
40        }
41    }
42}
43
44impl TrustedIssuerRegistry for StaticTrustedIssuers {
45    fn is_trusted_for_tier(&self, issuer_did: &str, tier: AccessTier) -> bool {
46        match tier {
47            AccessTier::Public => true,
48            AccessTier::Professional => {
49                self.professional_dids.contains(issuer_did)
50                    || self.confidential_dids.contains(issuer_did)
51            }
52            AccessTier::Confidential => self.confidential_dids.contains(issuer_did),
53            // Fail-closed: an unmodelled (future, more-sensitive) tier trusts
54            // no issuer until it is explicitly handled.
55            _ => false,
56        }
57    }
58}
59
60/// Trust registry that accepts any issuer DID — use in tests or single-operator
61/// bootstrap only. In production, supply a [`StaticTrustedIssuers`] loaded from
62/// operator configuration.
63pub struct AllowAllIssuers;
64
65impl TrustedIssuerRegistry for AllowAllIssuers {
66    fn is_trusted_for_tier(&self, _issuer_did: &str, _tier: AccessTier) -> bool {
67        true
68    }
69}