diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index 7463a94cb..48c35afe0 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -259,6 +259,8 @@ upnp ureq userid utimensat +uuidv4 +uuidv7 UTXO vitss Vkey diff --git a/rust/signed_doc/Cargo.toml b/rust/signed_doc/Cargo.toml index b1c2b8430..db525033e 100644 --- a/rust/signed_doc/Cargo.toml +++ b/rust/signed_doc/Cargo.toml @@ -11,9 +11,6 @@ license.workspace = true workspace = true [dependencies] - -[dev-dependencies] -clap = { version = "4.5.19", features = ["derive", "env"] } anyhow = "1.0.89" serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0" @@ -22,3 +19,6 @@ coset = "0.3.7" brotli = "7.0.0" ed25519-dalek = { version = "2.1.1", features = ["pem"] } uuid = { version = "1.10.0", features = ["v4", "v7", "serde"] } + +[dev-dependencies] +clap = { version = "4.5.19", features = ["derive", "env"] } diff --git a/rust/signed_doc/examples/mk_signed_doc.rs b/rust/signed_doc/examples/mk_signed_doc.rs index 1ed47ed04..c891fac3e 100644 --- a/rust/signed_doc/examples/mk_signed_doc.rs +++ b/rust/signed_doc/examples/mk_signed_doc.rs @@ -14,6 +14,7 @@ use ed25519_dalek::{ ed25519::signature::Signer, pkcs8::{DecodePrivateKey, DecodePublicKey}, }; +use signed_doc::{DocumentRef, Metadata}; fn main() { if let Err(err) = Cli::parse().exec() { @@ -60,26 +61,6 @@ const CONTENT_ENCODING_KEY: &str = "content encoding"; const CONTENT_ENCODING_VALUE: &str = "br"; const UUID_CBOR_TAG: u64 = 37; -#[derive(Debug, serde::Deserialize)] -struct Metadata { - r#type: uuid::Uuid, - id: uuid::Uuid, - ver: uuid::Uuid, - r#ref: Option, - template: Option, - reply: Option, - section: Option, -} - -#[derive(Debug, serde::Deserialize)] -#[serde(untagged)] -enum DocumentRef { - /// Reference to the latest document - Latest { id: uuid::Uuid }, - /// Reference to the specific document version - WithVer { id: uuid::Uuid, ver: uuid::Uuid }, -} - fn encode_cbor_uuid(uuid: &uuid::Uuid) -> coset::cbor::Value { coset::cbor::Value::Tag( UUID_CBOR_TAG, diff --git a/rust/signed_doc/src/lib.rs b/rust/signed_doc/src/lib.rs index 8ed8e7868..34330464e 100644 --- a/rust/signed_doc/src/lib.rs +++ b/rust/signed_doc/src/lib.rs @@ -1 +1,89 @@ //! Catalyst documents signing crate +use std::{convert::TryFrom, sync::Arc}; + +/// Keep all the contents private. +/// Better even to use a structure like this. Wrapping in an Arc means we don't have to +/// manage the Arc anywhere else. These are likely to be large, best to have the Arc be +/// non-optional. +pub struct CatalystSignedDocument { + /// Catalyst Signed Document metadata, raw doc, with content errors. + inner: Arc, + /// Content Errors found when parsing the Document + content_errors: Vec, +} + +/// Inner type that holds the Catalyst Signed Document with parsing errors. +struct InnerCatalystSignedDocument { + /// Document Metadata + _metadata: Metadata, + /// Raw payload + _raw_doc: Vec, +} + +/// Document Metadata. +#[derive(Debug, serde::Deserialize)] +pub struct Metadata { + /// Document Type `UUIDv7`. + pub r#type: uuid::Uuid, + /// Document ID `UUIDv7`. + pub id: uuid::Uuid, + /// Document Version `UUIDv7`. + pub ver: uuid::Uuid, + /// Reference to the latest document. + pub r#ref: Option, + /// Reference to the document template. + pub template: Option, + /// Reference to the document reply. + pub reply: Option, + /// Reference to the document section. + pub section: Option, +} + +/// Reference to a Document. +#[derive(Debug, serde::Deserialize)] +#[serde(untagged)] +pub enum DocumentRef { + /// Reference to the latest document + Latest { + /// Document ID UUID + id: uuid::Uuid, + }, + /// Reference to the specific document version + WithVer { + /// Document ID UUID + id: uuid::Uuid, + /// Document Version UUID + ver: uuid::Uuid, + }, +} + +// Do this instead of `new` if we are converting a single parameter into a struct/type we +// should use either `From` or `TryFrom` and reserve `new` for cases where we need +// multiple parameters to actually create the type. This is much more elegant to use this +// way, in code. +impl TryFrom> for CatalystSignedDocument { + type Error = &'static str; + + fn try_from(value: Vec) -> Result { + todo!(); + } +} + +impl CatalystSignedDocument { + /// Invalid Doc Type UUID + const INVALID_UUID: uuid::Uuid = uuid::Uuid::from_bytes([0x00; 16]); + + // A bunch of getters to access the contents, or reason through the document, such as. + + /// Are there any validation errors (as opposed to structural errors. + #[must_use] + pub fn has_error(&self) -> bool { + !self.content_errors.is_empty() + } + + /// Return Document Type UUID. + #[must_use] + pub fn doc_type(&self) -> uuid::Uuid { + INVALID_UUID + } // Can compare it against INVALID_DOC_TYPE to see if its valid or not. +}