-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add VCDM SD-JWT profile
- Loading branch information
Showing
10 changed files
with
586 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
pub mod profiles; | ||
|
||
pub mod metadata { | ||
use crate::metadata; | ||
|
||
use super::profiles::CustomProfilesCredentialConfiguration; | ||
|
||
pub type CredentialIssuerMetadata = | ||
metadata::CredentialIssuerMetadata<CustomProfilesCredentialConfiguration>; | ||
} | ||
|
||
pub mod credential { | ||
use crate::credential; | ||
|
||
use super::profiles::CustomProfilesCredentialRequest; | ||
|
||
pub type Request = credential::Request<CustomProfilesCredentialRequest>; | ||
pub type BatchRequest = credential::BatchRequest<CustomProfilesCredentialRequest>; | ||
} | ||
|
||
pub mod authorization { | ||
use crate::authorization; | ||
|
||
use super::profiles::CustomProfilesAuthorizationDetailsObject; | ||
|
||
pub type AuthorizationDetailsObject = | ||
authorization::AuthorizationDetailsObject<CustomProfilesAuthorizationDetailsObject>; | ||
} | ||
|
||
pub mod client { | ||
|
||
use crate::client; | ||
|
||
use super::profiles::CustomProfiles; | ||
|
||
pub type Client = client::Client<CustomProfiles>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
use std::{collections::HashMap, fmt::Debug}; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
use serde_json::Value; | ||
|
||
use crate::{ | ||
profiles::{ | ||
AuthorizationDetailsObjectProfile, CredentialConfigurationProfile, | ||
CredentialRequestProfile, CredentialResponseProfile, Profile, | ||
}, | ||
types::{ClaimValueType, CredentialConfigurationId, LanguageTag}, | ||
}; | ||
|
||
pub mod vc_sd_jwt; | ||
|
||
pub struct CustomProfiles; | ||
impl Profile for CustomProfiles { | ||
type CredentialConfiguration = CustomProfilesCredentialConfiguration; | ||
type AuthorizationDetailsObject = CustomProfilesAuthorizationDetailsObject; | ||
type CredentialRequest = CustomProfilesCredentialRequest; | ||
type CredentialResponse = CustomProfilesCredentialResponse; | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CustomProfilesCredentialConfiguration { | ||
VcSdJwt(vc_sd_jwt::CredentialConfiguration), | ||
} | ||
|
||
impl CredentialConfigurationProfile for CustomProfilesCredentialConfiguration {} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CustomProfilesAuthorizationDetailsObject { | ||
WithFormat { | ||
#[serde(flatten)] | ||
inner: AuthorizationDetailsObjectWithFormat, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "credential_identifier" | ||
)] | ||
_credential_identifier: (), | ||
}, | ||
WithIdAndUnresolvedProfile { | ||
credential_configuration_id: CredentialConfigurationId, | ||
#[serde(flatten)] | ||
inner: HashMap<String, Value>, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "format" | ||
)] | ||
_format: (), | ||
}, | ||
#[serde(skip_deserializing)] | ||
WithId { | ||
credential_configuration_id: CredentialConfigurationId, | ||
#[serde(flatten)] | ||
inner: AuthorizationDetailsObjectWithCredentialConfigurationId, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "format" | ||
)] | ||
_format: (), | ||
}, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum AuthorizationDetailsObjectWithFormat { | ||
VcSdJwt(vc_sd_jwt::AuthorizationDetailsObjectWithFormat), | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum AuthorizationDetailsObjectWithCredentialConfigurationId { | ||
VcSdJwt(vc_sd_jwt::AuthorizationDetailsObject), | ||
} | ||
|
||
impl AuthorizationDetailsObjectProfile for CustomProfilesAuthorizationDetailsObject {} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CustomProfilesCredentialRequest { | ||
WithFormat { | ||
#[serde(flatten)] | ||
inner: CredentialRequestWithFormat, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "credential_identifier" | ||
)] | ||
_credential_identifier: (), | ||
}, | ||
WithIdAndUnresolvedProfile { | ||
credential_identifier: CredentialConfigurationId, | ||
#[serde(flatten)] | ||
inner: HashMap<String, Value>, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "format" | ||
)] | ||
_format: (), | ||
}, | ||
#[serde(skip_deserializing)] | ||
WithId { | ||
credential_identifier: CredentialConfigurationId, | ||
#[serde(flatten)] | ||
inner: CredentialRequestWithCredentialIdentifier, | ||
#[serde( | ||
default, | ||
skip_serializing, | ||
deserialize_with = "crate::deny_field::deny_field", | ||
rename = "format" | ||
)] | ||
_format: (), | ||
}, | ||
} | ||
|
||
impl CredentialRequestProfile for CustomProfilesCredentialRequest { | ||
type Response = CustomProfilesCredentialResponse; | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CredentialRequestWithFormat { | ||
VcSdJwt(vc_sd_jwt::CredentialRequestWithFormat), | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CredentialRequestWithCredentialIdentifier { | ||
VcSdJwt(vc_sd_jwt::CredentialRequest), | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, Serialize)] | ||
pub struct CustomProfilesCredentialResponse; | ||
|
||
#[derive(Clone, Debug, Deserialize, Serialize)] | ||
#[serde(untagged)] | ||
pub enum CustomProfilesCredentialResponseType { | ||
VcSdJwt(<vc_sd_jwt::CredentialResponse as CredentialResponseProfile>::Type), | ||
} | ||
|
||
impl CredentialResponseProfile for CustomProfilesCredentialResponse { | ||
type Type = CustomProfilesCredentialResponseType; | ||
} | ||
|
||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | ||
pub struct AuthorizationDetailsObjectClaim { | ||
#[serde(default, skip_serializing_if = "is_false")] | ||
mandatory: bool, | ||
} | ||
|
||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | ||
pub struct CredentialConfigurationClaim { | ||
#[serde(default, skip_serializing_if = "is_false")] | ||
mandatory: bool, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
value_type: Option<ClaimValueType>, | ||
#[serde(default, skip_serializing_if = "Vec::is_empty")] | ||
display: Vec<ClaimDisplay>, | ||
} | ||
|
||
fn is_false(b: &bool) -> bool { | ||
!b | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct ClaimDisplay { | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
name: Option<String>, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
locale: Option<LanguageTag>, | ||
#[serde(flatten)] | ||
additional_fields: HashMap<String, Value>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::{ | ||
core::profiles::CredentialConfigurationClaim, profiles::AuthorizationDetailsObjectProfile, | ||
}; | ||
|
||
use super::{Claims, Format}; | ||
|
||
#[derive(Clone, Debug, Deserialize, Default, PartialEq, Serialize)] | ||
pub struct AuthorizationDetailsObjectWithFormat { | ||
format: Format, | ||
vct: String, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
claims: Option<Claims<CredentialConfigurationClaim>>, | ||
} | ||
|
||
impl AuthorizationDetailsObjectWithFormat { | ||
field_getters_setters![ | ||
pub self [self] ["VC SD-JWT authorization detail value"] { | ||
set_vct -> vct[String], | ||
set_claims -> claims[Option<Claims<CredentialConfigurationClaim>>], | ||
} | ||
]; | ||
} | ||
|
||
impl AuthorizationDetailsObjectProfile for AuthorizationDetailsObjectWithFormat {} | ||
|
||
#[derive(Clone, Debug, Deserialize, Default, PartialEq, Serialize)] | ||
pub struct AuthorizationDetailsObject { | ||
vct: String, | ||
claims: Option<Claims<CredentialConfigurationClaim>>, | ||
} | ||
|
||
impl AuthorizationDetailsObject { | ||
field_getters_setters![ | ||
pub self [self] ["VC SD-JWT authorization detail value"] { | ||
set_vct -> vct[String], | ||
set_claims -> claims[Option<Claims<CredentialConfigurationClaim>>], | ||
} | ||
]; | ||
} | ||
|
||
impl AuthorizationDetailsObjectProfile for AuthorizationDetailsObject {} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use serde_json::json; | ||
|
||
use crate::authorization::AuthorizationDetailsObject; | ||
|
||
#[test] | ||
fn roundtrip_with_format() { | ||
let expected_json = json!( | ||
{ | ||
"type": "openid_credential", | ||
"format": "spruce-vc+sd-jwt", | ||
"vct": "SD_JWT_VC_example_in_OpenID4VCI" | ||
} | ||
); | ||
|
||
let authorization_detail: AuthorizationDetailsObject< | ||
super::AuthorizationDetailsObjectWithFormat, | ||
> = serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_str( | ||
&serde_json::to_string(&expected_json).unwrap(), | ||
)) | ||
.unwrap(); | ||
|
||
let roundtripped = serde_json::to_value(authorization_detail).unwrap(); | ||
assert_json_diff::assert_json_eq!(expected_json, roundtripped) | ||
} | ||
} |
Oops, something went wrong.