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 salt = match array.next() {
96 Some(Value::String(salt)) => salt,
97 _ => return Err(invalid("the salt is not a string")),
98 };
99 let (name, value) = match (array.next(), array.next(), array.next()) {
100 (Some(value), None, None) => (None, value),
101 (Some(Value::String(name)), Some(value), None) => (Some(name), value),
102 (Some(_), Some(_), None) => return Err(invalid("the claim name is not a string")),
103 _ => return Err(invalid("not an array of two or three elements")),
104 };
105 Ok(Self {
106 encoded: encoded.to_owned(),
107 salt,
108 name,
109 value,
110 })
111 }
112
113 pub fn as_str(&self) -> &str {
115 &self.encoded
116 }
117
118 pub fn salt(&self) -> &str {
120 &self.salt
121 }
122
123 pub fn name(&self) -> Option<&str> {
125 self.name.as_deref()
126 }
127
128 pub fn value(&self) -> &Value {
130 &self.value
131 }
132
133 pub fn is_element(&self) -> bool {
135 self.name.is_none()
136 }
137
138 pub fn digest(&self, alg: HashAlgorithm) -> String {
140 alg.digest(self.encoded.as_bytes())
141 }
142}
143
144fn encode(array: &Value) -> String {
146 let json = serde_json::to_vec(array).expect("a JSON value serializes");
147 base64url::encode(&json)
148}
149
150impl fmt::Debug for Disclosure {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 f.debug_struct("Disclosure")
153 .field("salt", &self.salt)
154 .field("name", &self.name)
155 .field("value", &self.value)
156 .finish()
157 }
158}
159
160impl fmt::Display for Disclosure {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.write_str(&self.encoded)
163 }
164}
165
166impl AsRef<str> for Disclosure {
167 fn as_ref(&self) -> &str {
168 &self.encoded
169 }
170}
171
172impl FromStr for Disclosure {
173 type Err = SdJwtError;
174
175 fn from_str(s: &str) -> Result<Self, Self::Err> {
176 Self::parse(s)
177 }
178}
179
180impl Serialize for Disclosure {
181 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182 serializer.serialize_str(&self.encoded)
183 }
184}
185
186impl<'de> Deserialize<'de> for Disclosure {
187 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
188 let encoded = String::deserialize(deserializer)?;
189 Self::parse(&encoded).map_err(serde::de::Error::custom)
190 }
191}