Skip to main content

dpp_vc/credential/
types.rs

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