dpp_crypto/access/credential/types.rs
1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4/// Re-export the canonical `AccessTier` from dpp-domain.
5pub use dpp_domain::AccessTier;
6
7// ─── Credential role ─────────────────────────────────────────────────────────
8
9/// The access role granted by a Verifiable Credential.
10///
11/// Maps to the ESPR access tiers and the specific operator roles
12/// 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 with professional access.
25 Distributor,
26 /// Market surveillance authority — full access to all tiers.
27 MarketSurveillanceAuthority,
28 /// Customs authority — access for border control.
29 CustomsAuthority,
30 /// Notified body — conformity assessment.
31 NotifiedBody,
32 /// Custom role (extension point for sector-specific roles).
33 Custom(String),
34}
35
36impl CredentialRole {
37 /// Returns the minimum access tier this role grants.
38 pub fn access_tier(&self) -> AccessTier {
39 match self {
40 Self::MarketSurveillanceAuthority | Self::CustomsAuthority | Self::NotifiedBody => {
41 AccessTier::Confidential
42 }
43 _ => AccessTier::Professional,
44 }
45 }
46}
47
48// ─── Credential subject ─────────────────────────────────────────────────────
49
50/// The claims inside a DPP access credential.
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
52#[serde(rename_all = "camelCase")]
53pub struct DppCredentialSubject {
54 /// DID of the credential holder (the entity being granted access).
55 pub id: String,
56 /// Legal name of the credential holder.
57 pub name: String,
58 /// The role being granted.
59 pub role: CredentialRole,
60 /// ISO 3166-1 alpha-2 country code of the holder's registration.
61 pub country: String,
62 /// Sector(s) this credential applies to (e.g., `["textile"]`).
63 /// Empty means all sectors.
64 #[serde(skip_serializing_if = "Vec::is_empty", default)]
65 pub sectors: Vec<String>,
66 /// Specific product categories this credential covers.
67 /// Empty means all categories within the sectors.
68 #[serde(skip_serializing_if = "Vec::is_empty", default)]
69 pub product_categories: Vec<String>,
70}
71
72// ─── Verifiable Credential envelope ─────────────────────────────────────────
73
74/// A W3C Verifiable Credential for DPP access.
75///
76/// Follows the VC Data Model v2.0 structure with DPP-specific extensions.
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78#[serde(rename_all = "camelCase")]
79pub struct DppAccessCredential {
80 /// JSON-LD context (always includes the VC context).
81 #[serde(rename = "@context")]
82 pub context: Vec<String>,
83 /// Credential type (always includes "VerifiableCredential").
84 #[serde(rename = "type")]
85 pub credential_type: Vec<String>,
86 /// Unique credential ID (UUID-based URI).
87 pub id: String,
88 /// DID of the issuer (the authority granting access).
89 pub issuer: String,
90 /// When the credential was issued.
91 pub valid_from: DateTime<Utc>,
92 /// When the credential expires (mandatory for DPP credentials).
93 pub valid_until: DateTime<Utc>,
94 /// The access claims.
95 pub credential_subject: DppCredentialSubject,
96 /// Credential status for revocation checking.
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub credential_status: Option<CredentialStatus>,
99}
100
101/// Credential status descriptor for revocation checking.
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103#[serde(rename_all = "camelCase")]
104pub struct CredentialStatus {
105 /// URL to check revocation status.
106 pub id: String,
107 /// Status method type. Per W3C Bitstring Status List v1.0 this is
108 /// `"BitstringStatusListEntry"` (the older `"StatusList2021Entry"` is dated).
109 #[serde(rename = "type")]
110 pub status_type: String,
111 /// Index in the status list.
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub status_list_index: Option<String>,
114 /// URL of the status list credential.
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub status_list_credential: Option<String>,
117}