Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a credential type method accessor to check if a credential is def… #16

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/core/credential_format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ impl From<ClaimFormatDesignation> for String {
}
}

impl std::fmt::Display for ClaimFormatDesignation {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", String::from(self.clone()))
}
}

/// Credential types that may be requested in a credential request.
///
/// Credential types can be presented in a number of formats.
Expand Down Expand Up @@ -292,6 +298,6 @@ impl From<&CredentialType> for String {

impl std::fmt::Display for &CredentialType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
write!(f, "{}", String::from(*self))
}
}
82 changes: 70 additions & 12 deletions src/core/input_descriptor.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::collections::HashSet;

use super::{credential_format::*, presentation_submission::*};
use crate::utils::NonEmptyVec;

use anyhow::{bail, Context, Result};
use jsonschema::{JSONSchema, ValidationError};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use ssi_claims::jwt::VerifiablePresentation;
use ssi_dids::ssi_json_ld::syntax::from_value;

Expand Down Expand Up @@ -135,6 +138,16 @@ impl InputDescriptor {
self
}

/// Return the format of the input descriptor.
pub fn format(&self) -> Option<&ClaimFormatMap> {
self.format.as_ref()
}

/// Return the format designations of the input descriptor as a hash set.
pub fn format_designations(&self) -> Option<HashSet<&ClaimFormatDesignation>> {
self.format.as_ref().map(|f| f.keys().collect())
}

/// Set the group of the constraints field.
pub fn set_group(mut self, group: Vec<GroupId>) -> Self {
self.group = Some(group);
Expand Down Expand Up @@ -257,18 +270,6 @@ impl InputDescriptor {

Ok(())
}

/// Return the format of the input descriptor.
///
/// The Input Descriptor Object MAY contain a format property. If present,
/// its value MUST be an object with one or more properties matching the registered
/// Claim Format Designations (e.g., jwt, jwt_vc, jwt_vp, etc.).
///
/// This format property is identical in value signature to the top-level format object,
/// but can be used to specifically constrain submission of a single input to a subset of formats or algorithms.
pub fn format(&self) -> Option<&ClaimFormatMap> {
self.format.as_ref()
}
}

/// Constraints are objects used to describe the constraints that a [Holder](https://identity.foundation/presentation-exchange/spec/v2.0.0/#term:holder) must satisfy to fulfill an Input Descriptor.
Expand Down Expand Up @@ -329,6 +330,16 @@ impl Constraints {
.map(|fields| fields.iter().any(|field| field.is_required()))
.unwrap_or(false)
}

/// Intent to retain.
///
/// Returns whether any of the contraint fields have an intent
/// to retain the data by the verifier.
pub fn intend_to_retain(&self) -> bool {
self.fields()
.map(|fields| fields.iter().any(|field| field.intent_to_retain()))
.unwrap_or(false)
}
}

/// ConstraintsField objects are used to describe the constraints that a
Expand Down Expand Up @@ -600,6 +611,53 @@ impl ConstraintsField {
})
.collect()
}

/// Return the Credential Type of the constraints field
pub fn credential_type(&self) -> Option<CredentialType> {
// NOTE: There may be other ways to search for a valid the credential type
// that meets the input descriptor constraints.
//
// A more exhaustive search may require parsing each credential to
// check if it contains a certain field, e.g. `firstName`, `familyName`, etc.,
// and see if it will satisfy the constraints.
//
// For now, we explicity check the type of the credential if it is present
// in the credential `type` field.

if self
.path
.as_ref()
.iter()
// Check if any of the paths contain a reference to type.
// NOTE: I am not sure if this is normative to add a `type` field to the path
// for a verifiable credential.
.any(|path| path.contains(&"type".to_string()))
{
// Check the filter field to determine the `const`
// value for the credential type, e.g. `iso.org.18013.5.1.mDL`, etc.
if let Some(credential) = self.filter.as_ref().and_then(|filter| {
filter
.get("const")
.and_then(Value::as_str)
.map(CredentialType::from)
}) {
return Some(credential);
}

// The `type` field may be an array with a nested const value.
if let Some(credential) = self.filter.as_ref().and_then(|filter| {
filter
.get("contains")
.and_then(|value| value.get("const"))
.and_then(Value::as_str)
.map(CredentialType::from)
}) {
return Some(credential);
}
}

None
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion src/holder/verifiable_presentation_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl VerifiablePresentationBuilder {
pub fn as_base64_encoded_vp_token(self) -> Result<VpToken> {
let json_string = serde_json::to_string(&self.0).context("Failed to encode JSON string")?;

let token = BASE64_STANDARD.encode(&json_string);
let token = BASE64_STANDARD.encode(json_string);

Ok(VpToken(token))
}
Expand Down
Loading