From 2917fdb6f72dfeae4ca2814b72e5ac6acba1605d Mon Sep 17 00:00:00 2001 From: Arnaud Mimart <33665250+amimart@users.noreply.github.com> Date: Tue, 26 Mar 2024 14:13:52 +0100 Subject: [PATCH] fix(dataverse): prevent vc to contain reserved predicates --- contracts/okp4-dataverse/src/registrar/rdf.rs | 89 ++++++++++++++----- .../okp4-dataverse/src/registrar/registry.rs | 3 +- .../testdata/vc-unsupported-4.nq | 3 +- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/contracts/okp4-dataverse/src/registrar/rdf.rs b/contracts/okp4-dataverse/src/registrar/rdf.rs index 4854a40c..cdeddf2e 100644 --- a/contracts/okp4-dataverse/src/registrar/rdf.rs +++ b/contracts/okp4-dataverse/src/registrar/rdf.rs @@ -2,10 +2,22 @@ use crate::credential::rdf_marker::RDF_DATE_TYPE; use crate::registrar::credential::DataverseCredential; use crate::ContractError; use cosmwasm_std::{Binary, StdError}; +use okp4_rdf::dataset::QuadIterator; use okp4_rdf::normalize::IdentifierIssuer; use okp4_rdf::serde::{DataFormat, TripleWriter}; use rio_api::model::{BlankNode, Literal, NamedNode, Subject, Term, Triple}; +pub const VC_RESERVED_PREDICATES: &[NamedNode<'_>] = &[ + VC_SUBMITTER_ADDRESS, + VC_TYPE, + VC_ISSUER, + VC_VALID_FROM, + VC_VALID_UNTIL, + VC_SUBJECT, + VC_CLAIM, + VC_CLAIM_ORIGINAL_NODE, +]; + pub const VC_SUBMITTER_ADDRESS: NamedNode<'_> = NamedNode { iri: "dataverse:credential#submitterAddress", }; @@ -28,7 +40,37 @@ pub const VC_CLAIM: NamedNode<'_> = NamedNode { iri: "dataverse:credential#claim", }; +/// Used when a claim triple contains a named node as object to establish a hierarchy, we replace this hierarchical link +/// with a blank node, and this predicate is used to allow the reconciliation with the original named node. +pub const VC_CLAIM_ORIGINAL_NODE: NamedNode<'_> = NamedNode { + iri: "dataverse:claim#original-node", +}; + impl<'a> DataverseCredential<'a> { + pub fn serialize(&self, format: DataFormat) -> Result { + if self.contains_reserved_predicates() { + Err(ContractError::UnsupportedCredential( + "Claim contains reserved predicates.".to_string(), + ))?; + } + + let claim_node = BlankNode { id: "c0" }; + // Used to rename all blank nodes to avoid conflict with the forged claim node `c0` + let mut id_issuer = IdentifierIssuer::new("b", 0u128); + let triples: Vec> = self.as_triples(claim_node, &mut id_issuer)?; + let out: Vec = Vec::default(); + let mut writer = TripleWriter::new(&format, out); + for triple in triples { + writer.write(&triple).map_err(|e| { + StdError::serialize_err("triple", format!("Error writing triple: {e}")) + })?; + } + + Ok(Binary::from(writer.finish().map_err(|e| { + StdError::serialize_err("triple", format!("Error writing triple: {e}")) + })?)) + } + fn as_triples( &'a self, claim_node: BlankNode<'a>, @@ -152,27 +194,14 @@ impl<'a> DataverseCredential<'a> { Ok(triples) } -} -pub fn serialize( - credential: &DataverseCredential<'_>, - format: DataFormat, -) -> Result { - let claim_node = BlankNode { id: "c0" }; - // Used to rename all blank nodes to avoid conflict with the forged claim node `c0` - let mut id_issuer = IdentifierIssuer::new("b", 0u128); - let triples: Vec> = credential.as_triples(claim_node, &mut id_issuer)?; - let out: Vec = Vec::default(); - let mut writer = TripleWriter::new(&format, out); - for triple in triples { - writer - .write(&triple) - .map_err(|e| StdError::serialize_err("triple", format!("Error writing triple: {e}")))?; + fn contains_reserved_predicates(&self) -> bool { + self.claim + .content + .iter() + .predicates() + .any(|p| VC_RESERVED_PREDICATES.contains(&p)) } - - Ok(Binary::from(writer.finish().map_err(|e| { - StdError::serialize_err("triple", format!("Error writing triple: {e}")) - })?)) } #[cfg(test)] @@ -204,7 +233,7 @@ _:c0 _:c0 . \"2025-01-22T00:00:00\"^^ .\n"; - let serialization_res = serialize(&dc, DataFormat::NQuads); + let serialization_res = dc.serialize(DataFormat::NQuads); assert!(serialization_res.is_ok()); assert_eq!( @@ -212,4 +241,24 @@ _:c0 . "Cloud" . - . - "yes I am" . + "this shall not be allowed" . . . .