1use baseid_crypto::jwt::{self, alg_to_str, JwtHeader};
4use baseid_crypto::signer::Signer;
5use serde_json::Value;
6
7use crate::disclosure::Disclosure;
8use crate::SdJwt;
9
10pub struct SdJwtIssuer<'a> {
12 signer: &'a dyn Signer,
13 kid: String,
14 plain_claims: serde_json::Map<String, Value>,
15 sd_claims: Vec<(String, Value)>,
16}
17
18impl<'a> SdJwtIssuer<'a> {
19 pub fn new(signer: &'a dyn Signer, kid: &str) -> Self {
21 Self {
22 signer,
23 kid: kid.to_string(),
24 plain_claims: serde_json::Map::new(),
25 sd_claims: Vec::new(),
26 }
27 }
28
29 pub fn add_plain_claim(mut self, name: &str, value: Value) -> Self {
31 self.plain_claims.insert(name.to_string(), value);
32 self
33 }
34
35 pub fn add_sd_claim(mut self, name: &str, value: Value) -> Self {
37 self.sd_claims.push((name.to_string(), value));
38 self
39 }
40
41 pub fn build(self) -> baseid_core::Result<SdJwt> {
43 let mut disclosures = Vec::new();
44 let mut sd_digests = Vec::new();
45
46 for (name, value) in &self.sd_claims {
48 let disclosure = Disclosure::new(Some(name.clone()), value.clone());
49 let encoded = disclosure.encode()?;
50 let digest = disclosure.digest()?;
51 disclosures.push(encoded);
52 sd_digests.push(Value::String(digest));
53 }
54
55 let mut claims = self.plain_claims;
57 if !sd_digests.is_empty() {
58 claims.insert("_sd".to_string(), Value::Array(sd_digests));
59 claims.insert("_sd_alg".to_string(), Value::String("sha-256".to_string()));
60 }
61
62 let header = JwtHeader {
63 alg: alg_to_str(self.signer.algorithm()).to_string(),
64 typ: Some("sd-jwt".to_string()),
65 kid: Some(self.kid),
66 additional: serde_json::Map::new(),
67 };
68
69 let jwt = jwt::encode_jwt(&header, &Value::Object(claims), self.signer)?;
70
71 Ok(SdJwt {
72 jwt,
73 disclosures,
74 key_binding_jwt: None,
75 })
76 }
77}