identity_credential/credential/
jwt.rs1use identity_core::common::Object;
5use identity_verification::jws::Decoder;
6use serde::Deserialize;
7use serde::Serialize;
8
9use crate::credential::CredentialV2;
10use crate::credential::EnvelopedVc;
11use crate::credential::VcDataUrl;
12
13#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
15pub struct Jwt(String);
16
17impl Jwt {
18 pub fn new(jwt_string: String) -> Self {
20 Self(jwt_string)
21 }
22
23 pub fn as_str(&self) -> &str {
25 &self.0
26 }
27}
28
29impl From<String> for Jwt {
30 fn from(jwt: String) -> Self {
31 Self::new(jwt)
32 }
33}
34
35impl From<Jwt> for String {
36 fn from(jwt: Jwt) -> Self {
37 jwt.0
38 }
39}
40
41impl AsRef<str> for Jwt {
42 fn as_ref(&self) -> &str {
43 &self.0
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
49pub struct JwtVcV2(Box<str>);
50
51impl AsRef<str> for JwtVcV2 {
52 fn as_ref(&self) -> &str {
53 &self.0
54 }
55}
56
57impl JwtVcV2 {
58 pub const fn as_str(&self) -> &str {
60 &self.0
61 }
62
63 pub fn into_enveloped_vc(self) -> EnvelopedVc {
66 let data_url = VcDataUrl::parse(&format!("data:application/vc+jwt,{}", self.as_str())).expect("valid data url");
67 EnvelopedVc::new(data_url)
68 }
69
70 pub fn parse(jwt: &str) -> Result<Self, JwtVcV2ParsingError> {
72 let decoded_jws = Decoder::new()
73 .decode_compact_serialization(jwt.as_bytes(), None)
74 .map_err(|e| JwtVcV2ParsingError { source: e.into() })?;
75
76 let _credential: CredentialV2<Object> =
78 serde_json::from_slice(decoded_jws.claims()).map_err(|e| JwtVcV2ParsingError { source: e.into() })?;
79
80 Ok(Self(jwt.to_owned().into_boxed_str()))
81 }
82}
83
84#[derive(Debug, thiserror::Error)]
86#[error("failed to parse a JWT-encoded Verifiable Credential v2.0")]
87#[non_exhaustive]
88pub struct JwtVcV2ParsingError {
89 source: Box<dyn std::error::Error + Send + Sync>,
90}
91
92impl TryFrom<EnvelopedVc> for JwtVcV2 {
93 type Error = JwtVcV2ParsingError;
94
95 fn try_from(enveloped_vc: EnvelopedVc) -> Result<Self, Self::Error> {
96 let data_url = &enveloped_vc.id;
97 if data_url.media_type() != "application/vc+jwt" {
98 return Err(JwtVcV2ParsingError {
99 source: format!(
100 "invalid media type: `{}`, expected `application/vc+jwt`",
101 data_url.media_type()
102 )
103 .into(),
104 });
105 }
106
107 let jwt_str = enveloped_vc.id.encoded_data();
108 Self::parse(jwt_str)
109 }
110}