Skip to main content

dpp_vc/credential/
types.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4/// Re-export the canonical access vocabulary from dpp-domain.
5pub use dpp_domain::Audience;
6
7// ─── Credential role ─────────────────────────────────────────────────────────
8
9/// The access role granted by a Verifiable Credential.
10///
11/// Maps an operator role to the [`Audience`] it may claim, alongside the
12/// specific operator roles defined in the transfer-of-responsibility model.
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum CredentialRole {
16    /// Authorised repairer — can access disassembly instructions, spare parts info.
17    AuthorisedRepairer,
18    /// Recycler — can access material composition, SVHC data, recycling instructions.
19    Recycler,
20    /// Remanufacturer — can access full technical specifications.
21    Remanufacturer,
22    /// Preparer for reuse — can access quality and safety data.
23    PreparerForReuse,
24    /// Distributor holding a legitimate interest.
25    Distributor,
26    /// Market surveillance authority — Annex XIII points 1, 2 and 3. Note this
27    /// does **not** include point 4 individual-item data.
28    MarketSurveillanceAuthority,
29    /// Customs authority — access for border control.
30    CustomsAuthority,
31    /// Notified body — conformity assessment.
32    NotifiedBody,
33    /// Custom role (extension point for sector-specific roles).
34    Custom(String),
35}
36
37impl CredentialRole {
38    /// The Art. 77(2) audience this role belongs to.
39    ///
40    /// Note the consequence of the lattice: an authority does **not** thereby
41    /// gain the individual-item data of Annex XIII point 4, which Art. 77(2)(b)
42    /// does not grant it. A market surveillance authority that also needs that
43    /// data needs a separate legitimate-interest basis for it.
44    #[must_use]
45    pub fn audience(&self) -> Audience {
46        match self {
47            Self::MarketSurveillanceAuthority | Self::CustomsAuthority | Self::NotifiedBody => {
48                Audience::Authority
49            }
50            _ => Audience::LegitimateInterest,
51        }
52    }
53}
54
55// ─── Credential subject ─────────────────────────────────────────────────────
56
57/// The claims inside a DPP access credential.
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
59#[serde(rename_all = "camelCase")]
60pub struct DppCredentialSubject {
61    /// DID of the credential holder (the entity being granted access).
62    pub id: String,
63    /// Legal name of the credential holder.
64    pub name: String,
65    /// The role being granted.
66    pub role: CredentialRole,
67    /// ISO 3166-1 alpha-2 country code of the holder's registration.
68    pub country: String,
69    /// Sector(s) this credential applies to (e.g., `["textile"]`).
70    /// Empty means all sectors.
71    #[serde(skip_serializing_if = "Vec::is_empty", default)]
72    pub sectors: Vec<String>,
73    /// Specific product categories this credential covers.
74    /// Empty means all categories within the sectors.
75    #[serde(skip_serializing_if = "Vec::is_empty", default)]
76    pub product_categories: Vec<String>,
77}
78
79// ─── Verifiable Credential envelope ─────────────────────────────────────────
80
81/// A W3C Verifiable Credential for DPP access.
82///
83/// Follows the VC Data Model v2.0 structure with DPP-specific extensions.
84#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
85#[serde(rename_all = "camelCase")]
86pub struct DppAccessCredential {
87    /// JSON-LD context (always includes the VC context).
88    #[serde(rename = "@context")]
89    pub context: Vec<String>,
90    /// Credential type (always includes "VerifiableCredential").
91    #[serde(rename = "type")]
92    pub credential_type: Vec<String>,
93    /// Unique credential ID (UUID-based URI).
94    pub id: String,
95    /// DID of the issuer (the authority granting access).
96    pub issuer: String,
97    /// When the credential was issued.
98    pub valid_from: DateTime<Utc>,
99    /// When the credential expires (mandatory for DPP credentials).
100    pub valid_until: DateTime<Utc>,
101    /// The access claims.
102    pub credential_subject: DppCredentialSubject,
103    /// Credential status for revocation checking.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub credential_status: Option<CredentialStatus>,
106}
107
108/// Credential status descriptor for revocation checking.
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
110#[serde(rename_all = "camelCase")]
111pub struct CredentialStatus {
112    /// URL to check revocation status.
113    pub id: String,
114    /// Status method type. Per W3C Bitstring Status List v1.0 this is
115    /// `"BitstringStatusListEntry"` (the older `"StatusList2021Entry"` is dated).
116    #[serde(rename = "type")]
117    pub status_type: String,
118    /// Index in the status list.
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub status_list_index: Option<String>,
121    /// URL of the status list credential.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub status_list_credential: Option<String>,
124}