identity_kit/sd_jwt_vc/
disclosure.rs1use core::fmt;
4use core::str::FromStr;
5
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde_json::Value;
8
9use super::{HashAlgorithm, SdJwtError};
10use crate::jose::base64url;
11
12#[derive(Clone, PartialEq, Eq)]
42pub struct Disclosure {
43 encoded: String,
44 salt: String,
45 name: Option<String>,
46 value: Value,
47}
48
49impl Disclosure {
50 pub fn property(salt: impl Into<String>, name: impl Into<String>, value: Value) -> Self {
52 let salt = salt.into();
53 let name = name.into();
54 let array = Value::Array(vec![
55 Value::String(salt.clone()),
56 Value::String(name.clone()),
57 value.clone(),
58 ]);
59 Self {
60 encoded: encode(&array),
61 salt,
62 name: Some(name),
63 value,
64 }
65 }
66
67 pub fn element(salt: impl Into<String>, value: Value) -> Self {
69 let salt = salt.into();
70 let array = Value::Array(vec![Value::String(salt.clone()), value.clone()]);
71 Self {
72 encoded: encode(&array),
73 salt,
74 name: None,
75 value,
76 }
77 }
78
79 pub fn parse(encoded: &str) -> Result<Self, SdJwtError> {
87 let invalid = |reason: &str| SdJwtError::InvalidDisclosure {
88 disclosure: encoded.to_owned(),
89 reason: reason.to_owned(),
90 };
91 let bytes = base64url::decode(encoded).map_err(|_| invalid("not base64url"))?;
92 let array: Vec<Value> =
93 serde_json::from_slice(&bytes).map_err(|_| invalid("not a JSON array"))?;
94 let mut array = array.into_iter();
95 let Some(Value::String(salt)) = array.next() else {
96 return Err(invalid("the salt is not a string"));
97 };
98 let (name, value) = match (array.next(), array.next(), array.next()) {
99 (Some(value), None, None) => (None, value),
100 (Some(Value::String(name)), Some(value), None) => (Some(name), value),
101 (Some(_), Some(_), None) => return Err(invalid("the claim name is not a string")),
102 _ => return Err(invalid("not an array of two or three elements")),
103 };
104 Ok(Self {
105 encoded: encoded.to_owned(),
106 salt,
107 name,
108 value,
109 })
110 }
111
112 pub fn as_str(&self) -> &str {
114 &self.encoded
115 }
116
117 pub fn salt(&self) -> &str {
119 &self.salt
120 }
121
122 pub fn name(&self) -> Option<&str> {
124 self.name.as_deref()
125 }
126
127 pub fn value(&self) -> &Value {
129 &self.value
130 }
131
132 pub fn is_element(&self) -> bool {
134 self.name.is_none()
135 }
136
137 pub fn digest(&self, alg: HashAlgorithm) -> String {
139 alg.digest(self.encoded.as_bytes())
140 }
141}
142
143fn encode(array: &Value) -> String {
145 let json = serde_json::to_vec(array).expect("a JSON value serializes");
146 base64url::encode(&json)
147}
148
149impl fmt::Debug for Disclosure {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 f.debug_struct("Disclosure")
152 .field("salt", &self.salt)
153 .field("name", &self.name)
154 .field("value", &self.value)
155 .finish_non_exhaustive()
156 }
157}
158
159impl fmt::Display for Disclosure {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 f.write_str(&self.encoded)
162 }
163}
164
165impl AsRef<str> for Disclosure {
166 fn as_ref(&self) -> &str {
167 &self.encoded
168 }
169}
170
171impl FromStr for Disclosure {
172 type Err = SdJwtError;
173
174 fn from_str(s: &str) -> Result<Self, Self::Err> {
175 Self::parse(s)
176 }
177}
178
179impl Serialize for Disclosure {
180 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
181 serializer.serialize_str(&self.encoded)
182 }
183}
184
185impl<'de> Deserialize<'de> for Disclosure {
186 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
187 let encoded = String::deserialize(deserializer)?;
188 Self::parse(&encoded).map_err(serde::de::Error::custom)
189 }
190}