sdjwt/
lib.rs

1#[cfg(target_arch = "wasm32")]
2use serde::{Deserialize, Serialize};
3#[cfg(target_arch = "wasm32")]
4use serde_json::Value;
5#[cfg(target_arch = "wasm32")]
6use serde_wasm_bindgen::to_value;
7#[cfg(target_arch = "wasm32")]
8use wasm_bindgen::prelude::*;
9
10// #[cfg(target_arch = "wasm32")]
11// #[wasm_bindgen]
12// extern "C" {
13//     #[wasm_bindgen(js_namespace = console)]
14//     fn log(value: &str);
15// }
16
17#[cfg(target_arch = "wasm32")]
18#[wasm_bindgen]
19pub struct SdJwtIssuer {}
20
21#[cfg(target_arch = "wasm32")]
22#[wasm_bindgen]
23impl SdJwtIssuer {
24    #[wasm_bindgen(constructor)]
25    pub fn new() -> SdJwtIssuer {
26        SdJwtIssuer {}
27    }
28
29    pub fn encode(
30        &self,
31        claims: &str,
32        signing_key: &str,
33        algorithm: &str,
34    ) -> Result<String, JsValue> {
35        let (claims, tagged_paths) = parse_yaml(claims)?;
36        let encoding_key = match algorithm {
37            "RS256" | "RS384" | "RS512" | "PS256" | "PS384" | "PS512" => {
38                KeyForEncoding::from_rsa_pem(signing_key.as_bytes())?
39            }
40            "ES256" | "ES384" | "ES512" => KeyForEncoding::from_ec_pem(signing_key.as_bytes())?,
41            _ => return Err(JsValue::from_str("Unsupported algorithm")),
42        };
43        let issuer_sd_jwt = crate::issuer::Issuer::new(claims.clone())?
44            .iter_disclosable(tagged_paths.iter())
45            .encode(&encoding_key)?;
46        Ok(issuer_sd_jwt)
47    }
48}
49
50#[cfg(target_arch = "wasm32")]
51impl Default for SdJwtIssuer {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57#[cfg(target_arch = "wasm32")]
58#[derive(Serialize, Deserialize)]
59pub struct DecodedIssuerJwt {
60    pub header: Value,
61    pub updated_claims: Value,
62    pub disclosure_paths: Vec<DisclosurePath>,
63}
64
65#[cfg(target_arch = "wasm32")]
66#[wasm_bindgen]
67pub struct SdJwtHolder {}
68
69#[cfg(target_arch = "wasm32")]
70#[wasm_bindgen]
71impl SdJwtHolder {
72    #[wasm_bindgen(constructor)]
73    pub fn new() -> Self {
74        SdJwtHolder {}
75    }
76
77    #[wasm_bindgen]
78    pub fn verify(
79        &self,
80        encoded_issuer_jwt: &str,
81        public_key: &str,
82        algorithm: &str,
83    ) -> Result<JsValue, JsValue> {
84        let decoding_key = match algorithm {
85            "RS256" | "RS384" | "RS512" => KeyForDecoding::from_rsa_pem(public_key.as_bytes())?,
86            "ES256" | "ES384" | "ES512" => KeyForDecoding::from_ec_pem(public_key.as_bytes())?,
87            _ => return Err(JsValue::from_str("Unsupported algorithm")),
88        };
89        let validation = Validation::default().without_expiry();
90        let (header, decoded_claims, disclosure_paths) =
91            Holder::verify(encoded_issuer_jwt, &decoding_key, &validation)?;
92        let decoded_issuer_jwt = DecodedIssuerJwt {
93            header,
94            updated_claims: decoded_claims,
95            disclosure_paths,
96        };
97        Ok(to_value(&decoded_issuer_jwt)?)
98    }
99
100    #[wasm_bindgen]
101    pub fn presentation(
102        &self,
103        encoded_issuer_jwt: &str,
104        redacted_paths: Vec<String>,
105    ) -> Result<String, JsValue> {
106        let mut presentation = Holder::presentation(encoded_issuer_jwt)?;
107        let _ = redacted_paths
108            .iter()
109            .try_for_each::<_, Result<(), Error>>(|path| {
110                presentation.redact(path)?;
111                Ok(())
112            });
113
114        Ok(presentation.build()?)
115    }
116}
117
118#[cfg(target_arch = "wasm32")]
119impl Default for SdJwtHolder {
120    fn default() -> Self {
121        Self::new()
122    }
123}
124
125#[cfg(target_arch = "wasm32")]
126#[derive(Debug, Serialize, Deserialize)]
127pub struct DecodedHolderJwt {
128    pub header: Value,
129    pub restored_claims: Value,
130}
131
132#[cfg(target_arch = "wasm32")]
133#[wasm_bindgen]
134pub struct SdJwtVerifier {}
135
136#[cfg(target_arch = "wasm32")]
137#[wasm_bindgen]
138impl SdJwtVerifier {
139    #[wasm_bindgen(constructor)]
140    pub fn new() -> Self {
141        SdJwtVerifier {}
142    }
143
144    #[wasm_bindgen]
145    pub fn verify(
146        &self,
147        holder_presentation_sdjwt: &str,
148        public_key: &str,
149        algorithm: &str,
150    ) -> Result<JsValue, JsValue> {
151        let decoding_key = match algorithm {
152            "RS256" | "RS384" | "RS512" => KeyForDecoding::from_rsa_pem(public_key.as_bytes())?,
153            "ES256" | "ES384" | "ES512" => KeyForDecoding::from_ec_pem(public_key.as_bytes())?,
154            _ => return Err(JsValue::from_str("Unsupported algorithm")),
155        };
156        let validation = Validation::default().without_expiry();
157        let (header, restored_claims) =
158            Verifier::verify(holder_presentation_sdjwt, &decoding_key, &validation, &None)?;
159        let decoded_holder_jwt = DecodedHolderJwt {
160            header,
161            restored_claims,
162        };
163        Ok(to_value(&decoded_holder_jwt)?)
164    }
165}
166
167#[cfg(target_arch = "wasm32")]
168impl Default for SdJwtVerifier {
169    fn default() -> Self {
170        Self::new()
171    }
172}
173
174pub mod algorithm;
175pub mod decoding;
176pub(crate) mod decoy;
177pub mod disclosure;
178pub mod disclosure_path;
179pub mod encoding;
180pub mod error;
181pub mod header;
182pub mod holder;
183pub mod issuer;
184pub mod jwk;
185mod parser;
186mod utils;
187pub mod validation;
188pub mod verifier;
189
190#[cfg(test)]
191mod test_utils;
192
193pub use algorithm::*;
194pub use decoding::*;
195pub use disclosure::Disclosure;
196pub use disclosure_path::*;
197pub use encoding::*;
198pub use error::*;
199pub use header::*;
200pub use holder::*;
201pub use issuer::*;
202pub use jwk::*;
203pub use parser::parse_yaml;
204pub use validation::*;
205pub use verifier::*;