Skip to content

Commit

Permalink
feat: impl formencoded for AuthorizationResponse
Browse files Browse the repository at this point in the history
  • Loading branch information
nanderstabel committed Jun 23, 2023
1 parent cc374a3 commit 641d48c
Showing 1 changed file with 95 additions and 1 deletion.
96 changes: 95 additions & 1 deletion siopv2/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,76 @@ pub struct AuthorizationResponse {
redirect_uri: String,
#[getset(get = "pub")]
id_token: Option<String>,
#[serde(flatten)]
#[serde(flatten, with = "serde_oid4vp_response")]
#[getset(get = "pub")]
oid4vp_response: Option<Oid4vpParams>,
state: Option<String>,
}

pub mod serde_oid4vp_response {
use super::*;
use serde::{
de,
ser::{self, SerializeMap},
};
use serde_json::Value;

pub fn serialize<S>(oid4vp_response: &Option<Oid4vpParams>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match oid4vp_response {
Some(Oid4vpParams::Jwt { response }) => response.serialize(serializer),
Some(Oid4vpParams::Params {
vp_token,
presentation_submission,
}) => {
let mut map = serializer.serialize_map(Some(2))?;
map.serialize_entry("vp_token", vp_token)?;
map.serialize_entry(
"presentation_submission",
&serde_json::to_string(&presentation_submission).map_err(ser::Error::custom)?,
)?;
map.end()
}
None => serializer.serialize_none(),
}
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Oid4vpParams>, D::Error>
where
D: serde::Deserializer<'de>,
{
let oid4vp_response = Option::<serde_json::Value>::deserialize(deserializer)?;
match oid4vp_response {
None => Ok(None),
Some(Value::Object(map)) if map.is_empty() => Ok(None),
Some(Value::String(response)) => Ok(Some(Oid4vpParams::Jwt { response })),
Some(Value::Object(map)) => {
let vp_token = map.get("vp_token").ok_or_else(|| {
de::Error::custom(
"`vp_token` parameter is required when using `presentation_submission` parameter.",
)
})?;
let presentation_submission = map.get("presentation_submission").ok_or_else(|| {
de::Error::custom(
"`presentation_submission` parameter is required when using `vp_token` parameter.",
)
})?;
let presentation_submission = presentation_submission
.as_str()
.ok_or_else(|| de::Error::custom("`presentation_submission` parameter must be a string."))?;
Ok(Some(Oid4vpParams::Params {
vp_token: serde_json::from_value(vp_token.clone()).map_err(de::Error::custom)?,
presentation_submission: serde_json::from_str(presentation_submission)
.map_err(de::Error::custom)?,
}))
}
_ => Err(de::Error::custom("Invalid `oid4vp_response` parameter.")),
}
}
}

impl AuthorizationResponse {
pub fn builder() -> ResponseBuilder {
ResponseBuilder::new()
Expand Down Expand Up @@ -103,6 +167,36 @@ impl ResponseBuilder {
#[cfg(test)]
mod tests {
use super::*;
use oid4vp::{InputDescriptorMappingObject, PathNested};

#[tokio::test]
async fn test_authorization_response_url_formencoded() {
let authorization_response = AuthorizationResponse::builder()
.redirect_uri("".to_string())
.id_token("id_token".to_string())
.vp_token("vp_token".to_string())
.presentation_submission(PresentationSubmission {
id: "id".to_string(),
definition_id: "definition_id".to_string(),
descriptor_map: vec![InputDescriptorMappingObject {
id: "id".to_string(),
path: "path".to_string(),
format: oid4vp::ClaimFormatDesignation::AcVc,
path_nested: Some(PathNested {
id: Some("id".to_string()),
format: oid4vp::ClaimFormatDesignation::AcVc,
path: "path".to_string(),
path_nested: None,
}),
}],
})
.build()
.unwrap();

let encoded = serde_urlencoded::to_string(&authorization_response).unwrap();

assert_eq!(authorization_response, serde_urlencoded::from_str(&encoded).unwrap());
}

#[test]
fn test_valid_response() {
Expand Down

0 comments on commit 641d48c

Please sign in to comment.