Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
3 changes: 3 additions & 0 deletions rust/catalyst-signed-doc-spec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ license.workspace = true
workspace = true

[dependencies]
catalyst-types = { version = "0.0.11", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "catalyst-types/v0.0.11" }
cbork-cddl-parser = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cbork-cddl-parser/v0.0.3" }

serde_json = "1.0.142"
anyhow = "1.0.99"
serde = { version = "1.0.219", features = ["derive"] }
Expand Down
75 changes: 75 additions & 0 deletions rust/catalyst-signed-doc-spec/src/cddl_definitions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//! 'cddlDefinitions' field definition

use std::{collections::HashMap, fmt::Display};

use cbork_cddl_parser::validate_cddl;

#[derive(serde::Deserialize)]
pub struct CddlDefinitions(HashMap<CddlType, CddlDef>);

#[derive(Clone, serde::Deserialize, PartialEq, Eq, Hash)]
pub struct CddlType(String);

#[derive(serde::Deserialize)]
struct CddlDef {
def: String,
requires: Vec<CddlType>,
}

impl Display for CddlType {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
self.0.fmt(f)
}
}

impl CddlDef {
fn get_cddl_spec(
&self,
cddl_type: &CddlType,
) -> String {
format!("{cddl_type}={}\n", self.def)
}
}

impl CddlDefinitions {
fn find_cddl_def(
&self,
cddl_type: &CddlType,
) -> anyhow::Result<&CddlDef> {
self.0.get(cddl_type).ok_or(anyhow::anyhow!(
"Cannot find a cddl defition for the {cddl_type}"
))
}

/// Returns a full CDDL specification schema.
/// Performs
pub fn get_cddl_spec(
&self,
cddl_type: &CddlType,
) -> anyhow::Result<String> {
let def = self.find_cddl_def(cddl_type)?;

let spec = def.get_cddl_spec(&cddl_type);
let mut requires = def.requires.clone();

let mut imports = HashMap::new();
while let Some(req) = requires.pop() {
let req_def = self.find_cddl_def(&req)?;
let req_spec = req_def.get_cddl_spec(&req);
if imports.insert(req, req_spec).is_none() {
requires.extend(req_def.requires.clone());
}
}

let mut spec = imports.values().fold(spec, |mut spec, import_spec| {
spec.push_str(import_spec);
spec
});

validate_cddl(&mut spec, &cbork_cddl_parser::Extension::CDDL)?;
Ok(spec)
}
}
10 changes: 7 additions & 3 deletions rust/catalyst-signed-doc-spec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#![allow(missing_docs, clippy::missing_docs_in_private_items)]

pub mod copyright;
pub mod cddl_definitions;
mod copyright;
pub mod doc_types;
pub mod headers;
pub mod is_required;
Expand All @@ -15,16 +16,19 @@ use std::{collections::HashMap, fmt::Display, ops::Deref};
use build_info as build_info_lib;

use crate::{
copyright::Copyright, headers::Headers, metadata::Metadata, payload::Payload, signers::Signers,
cddl_definitions::CddlDefinitions, copyright::Copyright, headers::Headers, metadata::Metadata,
payload::Payload, signers::Signers,
};

build_info_lib::build_info!(pub(crate) fn build_info);

/// Catalyst Signed Document spec representation struct
#[derive(serde::Deserialize)]
pub struct CatalystSignedDocSpec {
pub docs: DocSpecs,
#[serde(rename = "cddlDefinitions")]
pub cddl_definitions: CddlDefinitions,
copyright: Copyright,
pub docs: DocSpecs,
}

#[derive(serde::Deserialize)]
Expand Down
33 changes: 32 additions & 1 deletion rust/catalyst-signed-doc-spec/src/payload.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
//! `signed_doc.json` "payload" field JSON definition

use catalyst_types::json_schema::JsonSchema;
use serde::Deserialize;

use crate::cddl_definitions::CddlType;

/// `signed_doc.json` "payload" field JSON object
#[derive(serde::Deserialize)]
#[allow(clippy::missing_docs_in_private_items)]
pub struct Payload {
pub nil: bool,
pub schema: Option<serde_json::Value>,
pub schema: Option<Schema>,
}

pub enum Schema {
Cddl(CddlType),
Json(JsonSchema),
}

impl<'de> Deserialize<'de> for Schema {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
#[derive(serde::Deserialize)]
#[serde(untagged)]
pub enum SchemaSerde {
Cddl(CddlType),
Json(serde_json::Value),
}

match SchemaSerde::deserialize(deserializer)? {
SchemaSerde::Json(json) => {
JsonSchema::try_from(&json)
.map(|v| Self::Json(v))
.map_err(|e| serde::de::Error::custom(e))
},
SchemaSerde::Cddl(cddl_type) => Ok(Self::Cddl(cddl_type)),
}
}
}
2 changes: 1 addition & 1 deletion rust/signed_doc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license.workspace = true
workspace = true

[dependencies]
catalyst-types = { version = "0.0.10", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "catalyst-types/v0.0.10" }
catalyst-types = { version = "0.0.11", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "catalyst-types/v0.0.11" }
cbork-utils = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cbork-utils-v0.0.2" }

catalyst-signed-doc-macro = { version = "0.0.1", path = "../catalyst-signed-doc-macro" }
Expand Down
139 changes: 0 additions & 139 deletions rust/signed_doc/src/validator/json_schema.rs

This file was deleted.

1 change: 0 additions & 1 deletion rust/signed_doc/src/validator/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Catalyst Signed Documents validation logic

pub(crate) mod json_schema;
pub(crate) mod rules;

use std::{collections::HashMap, sync::LazyLock};
Expand Down
39 changes: 25 additions & 14 deletions rust/signed_doc/src/validator/rules/content/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ mod tests;

use std::fmt::Debug;

use catalyst_signed_doc_spec::payload::Payload;
use catalyst_signed_doc_spec::{
cddl_definitions::CddlDefinitions,
payload::{Payload, Schema},
};
use catalyst_types::json_schema::JsonSchema;
use minicbor::Encode;

use crate::{
validator::{json_schema, rules::utils::content_json_schema_check},
CatalystSignedDocument,
};
use crate::{validator::rules::utils::content_json_schema_check, CatalystSignedDocument};

/// Enum represents different content schemas, against which documents content would be
/// validated.
pub(crate) enum ContentSchema {
/// Draft 7 JSON schema
Json(json_schema::JsonSchema),
Json(JsonSchema),
/// CDDL schema
Cddl,
}

impl Debug for ContentSchema {
Expand All @@ -27,6 +30,7 @@ impl Debug for ContentSchema {
) -> std::fmt::Result {
match self {
Self::Json(_) => writeln!(f, "JsonSchema"),
Self::Cddl => writeln!(f, "CddlSchema"),
}
}
}
Expand All @@ -44,7 +48,10 @@ pub(crate) enum ContentRule {

impl ContentRule {
/// Generating `ContentRule` from specs
pub(crate) fn new(spec: &Payload) -> anyhow::Result<Self> {
pub(crate) fn new(
cddl_def: &CddlDefinitions,
spec: &Payload,
) -> anyhow::Result<Self> {
if spec.nil {
anyhow::ensure!(
spec.schema.is_none(),
Expand All @@ -53,13 +60,16 @@ impl ContentRule {
return Ok(Self::Nil);
}

if let Some(schema) = &spec.schema {
let schema_str = schema.to_string();
Ok(Self::StaticSchema(ContentSchema::Json(
json_schema::JsonSchema::try_from(&serde_json::from_str(&schema_str)?)?,
)))
} else {
Ok(Self::NotNil)
match &spec.schema {
Some(Schema::Json(schema)) => {
Ok(Self::StaticSchema(ContentSchema::Json(schema.clone())))
},
Some(Schema::Cddl(cddl_type)) => {
cddl_def
.get_cddl_spec(cddl_type)
.map(|_| Self::StaticSchema(ContentSchema::Cddl))
},
None => Ok(Self::NotNil),
}
}

Expand All @@ -75,6 +85,7 @@ impl ContentRule {
ContentSchema::Json(json_schema) => {
return Ok(content_json_schema_check(doc, json_schema))
},
ContentSchema::Cddl => return Ok(true),
}
}
if let Self::NotNil = self {
Expand Down
Loading
Loading