diff --git a/Cargo.lock b/Cargo.lock index 63f1899d9c834631838369629c9b9d5fd7154e99..178d543d7e8199397d27ee2d277da01c625d5640 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,12 +229,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "dubp-documents" -version = "0.10.0-b1" +version = "0.11.0" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dup-crypto 0.4.0-b1", + "dup-crypto 0.5.0", "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,14 +248,14 @@ name = "duniter-blockchain" version = "0.1.0-a0.1" dependencies = [ "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-conf 0.1.0-a0.1", "duniter-dal 0.1.0-a0.1", "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "durs-wot 0.8.0-a0.9", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -272,9 +272,9 @@ name = "duniter-conf" version = "0.1.0-a0.1" dependencies = [ "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-module 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", + "dup-crypto 0.5.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -291,8 +291,8 @@ dependencies = [ "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -307,10 +307,10 @@ dependencies = [ name = "duniter-dal" version = "0.1.0-a0.1" dependencies = [ - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", + "dup-crypto 0.5.0", "durs-wot 0.8.0-a0.9", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustbreak 2.0.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -323,12 +323,12 @@ dependencies = [ name = "duniter-message" version = "0.1.0-a0.1" dependencies = [ - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-dal 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,9 +338,9 @@ dependencies = [ name = "duniter-module" version = "0.1.0-a0.1" dependencies = [ - "dubp-documents 0.10.0-b1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dubp-documents 0.11.0", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -351,10 +351,10 @@ dependencies = [ name = "duniter-network" version = "0.1.0-a0.1" dependencies = [ - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-module 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -364,14 +364,14 @@ dependencies = [ name = "duniter-tui" version = "0.1.0-a0.1" dependencies = [ - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-conf 0.1.0-a0.1", "duniter-dal 0.1.0-a0.1", "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -382,7 +382,7 @@ dependencies = [ [[package]] name = "dup-crypto" -version = "0.4.0-b1" +version = "0.5.0" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -406,12 +406,12 @@ dependencies = [ [[package]] name = "durs-network-documents" -version = "0.2.0-b1" +version = "0.3.0" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", - "dup-crypto 0.4.0-b1", + "dubp-documents 0.11.0", + "dup-crypto 0.5.0", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -437,13 +437,13 @@ name = "durs-ws2p" version = "0.1.0-a0.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-conf 0.1.0-a0.1", "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "durs-ws2p-messages 0.1.0-a0.1", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -457,9 +457,9 @@ version = "0.1.0-a0.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dubp-documents 0.11.0", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -472,14 +472,14 @@ name = "durs-ws2p-v1-legacy" version = "0.1.0-a0.1" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dubp-documents 0.10.0-b1", + "dubp-documents 0.11.0", "duniter-conf 0.1.0-a0.1", "duniter-dal 0.1.0-a0.1", "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.4.0-b1", - "durs-network-documents 0.2.0-b1", + "dup-crypto 0.5.0", + "durs-network-documents 0.3.0", "durs-wot 0.8.0-a0.9", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 983a3cf007b815a89135b602b74a19f5e240fda1..6347d17cb5f78b56617fc3330820e8b9601bc4b5 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dup-crypto" -version = "0.4.0-b1" +version = "0.5.0" authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"] description = "Manage cryptographic operations for the DUP (DUniter Protocol)." repository = "https://git.duniter.org/nodes/rust/duniter-rs" diff --git a/documents/Cargo.toml b/documents/Cargo.toml index 7ef7055d8961ab67583a225b410f37db2f45dba5..405cf08300de293bc9576ff2ad85a1ebfb8ed05f 100644 --- a/documents/Cargo.toml +++ b/documents/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dubp-documents" -version = "0.10.0-b1" +version = "0.11.0" authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@ifee.fr>"] description = "Handles DUBP documents (DUBP: DUniter Blockhain Protocol)" repository = "https://git.duniter.org/nodes/rust/duniter-rs" diff --git a/documents/src/documents_grammar.pest b/documents/src/documents_grammar.pest index 695f6e262c9b875cf694333a59e786338a2debe3..12f7d49706b9a4e91ffc4ae4f3e6e96c49a273fa 100644 --- a/documents/src/documents_grammar.pest +++ b/documents/src/documents_grammar.pest @@ -147,11 +147,11 @@ tx = ${ document_v10 = ${ &(SOI ~ v10 ~ nl) ~ - (&"Type: Identity" ~ idty_v10) | - (&"Type: Membership" ~ membership_v10) | - (&"Type: Certification" ~ cert_v10) | - (&"Type: Revocation" ~ revoc_v10) | - (&"Type: Transaction" ~ tx_v10) + idty_v10 | + membership_v10 | + cert_v10 | + revoc_v10 | + tx_v10 } document = ${ diff --git a/documents/src/lib.rs b/documents/src/lib.rs index 586f5d41f7889685eae9de7f8846cfe15f5150e6..dbb8d5f675e470ffe27947bc40e128e4147556ad 100644 --- a/documents/src/lib.rs +++ b/documents/src/lib.rs @@ -50,7 +50,7 @@ use currencies_codes::*; use dup_crypto::hashs::Hash; use dup_crypto::keys::*; use pest::iterators::Pair; -use pest::Parser; +use pest::{Parser, RuleType}; use serde::Serialize; use std::cmp::Ordering; use std::fmt::{Debug, Display, Error, Formatter}; @@ -64,14 +64,14 @@ pub use blockstamp::{Blockstamp, PreviousBlockstamp}; /// Parser for Documents struct DocumentsParser; -trait TextDocumentParser { +pub trait TextDocumentParser<R: RuleType> { /// Type of document generated by the parser type DocumentType; /// Parse text document from raw format fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError>; /// Parse text document from pest pairs - fn from_pest_pair(pairs: Pair<Rule>) -> Self::DocumentType; + fn from_pest_pair(pairs: Pair<R>) -> Self::DocumentType; } /// List of possible errors while parsing. @@ -79,18 +79,16 @@ trait TextDocumentParser { pub enum TextDocumentParseError { /// The given source don't have a valid specific document format (document type). InvalidInnerFormat(&'static str), - /// Type fields contains an unknown document type. - UnknownDocumentType(String), /// Error with pest parser PestError(String), - /// Invalid currency - InvalidCurrency(), /// UnexpectedVersion UnexpectedVersion(String), + /// Unknown type + UnknownType, } /// Document of DUBP (DUniter Blockhain Protocol) -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum DUBPDocument { /// Version 10. V10(Box<v10::V10Document>), @@ -98,12 +96,12 @@ pub enum DUBPDocument { V11(), } -impl TextDocumentParser for DUBPDocument { +impl TextDocumentParser<Rule> for DUBPDocument { type DocumentType = DUBPDocument; fn parse(doc: &str) -> Result<DUBPDocument, TextDocumentParseError> { match DocumentsParser::parse(Rule::document, doc) { - Ok(mut root_ast) => Ok(DUBPDocument::from_pest_pair(root_ast.next().unwrap())), // get and unwrap the `document` rule; never fails + Ok(mut doc_pairs) => Ok(DUBPDocument::from_pest_pair(doc_pairs.next().unwrap())), // get and unwrap the `document` rule; never fails Err(pest_error) => Err(TextDocumentParseError::PestError(format!("{}", pest_error))), } } @@ -318,18 +316,43 @@ pub trait DocumentParser<S, D, E> { fn parse(source: S) -> Result<D, E>; } -/// Jsonify a document -pub trait ToJsonObject { - type JsonObject: Serialize; - /// Transforms an object into a json object - fn to_json_object(&self) -> Self::JsonObject; +/// Stringify a document +pub trait ToStringObject { + type StringObject: Serialize; + /// Transforms object fields into string + fn to_string_object(&self) -> Self::StringObject; +} +/// Jsonify a document +pub trait ToJsonObject: ToStringObject { /// Convert to JSON String fn to_json_string(&self) -> Result<String, serde_json::Error> { - Ok(serde_json::to_string(&self.to_json_object())?) + Ok(serde_json::to_string(&self.to_string_object())?) } /// Convert to JSON String pretty fn to_json_string_pretty(&self) -> Result<String, serde_json::Error> { - Ok(serde_json::to_string_pretty(&self.to_json_object())?) + Ok(serde_json::to_string_pretty(&self.to_string_object())?) + } +} + +impl<T: ToStringObject> ToJsonObject for T {} + +#[cfg(test)] +mod tests { + use super::*; + //use dup_crypto::keys::*; + + #[test] + fn parse_dubp_document() { + let text = "Version: 10 +Type: Identity +Currency: g1 +Issuer: D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx +UniqueID: elois +Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 +Ydnclvw76/JHcKSmU9kl9Ie0ne5/X8NYOqPqbGnufIK3eEPRYYdEYaQh+zffuFhbtIRjv6m/DkVLH5cLy/IyAg=="; + + let doc = DUBPDocument::parse(text).expect("Fail to parse DUBPDocument !"); + println!("Doc : {:?}", doc); } } diff --git a/documents/src/v10/certification.rs b/documents/src/v10/certification.rs index 419b18d18924e81969126b7109fcb98ce2bd05f4..bb81effb764d2bf1b8ce4f4ee01331a08ee36aa0 100644 --- a/documents/src/v10/certification.rs +++ b/documents/src/v10/certification.rs @@ -75,6 +75,44 @@ pub struct CertificationDocument { signatures: Vec<Sig>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// identity document for jsonification +pub struct CertificationStringDocument { + /// Name of the currency. + currency: String, + /// Document issuer + issuer: String, + /// issuer of target identity. + target: String, + /// Username of target identity + identity_username: String, + /// Target Identity document blockstamp. + identity_blockstamp: String, + /// Target Identity document signature. + identity_sig: String, + /// Blockstamp + blockstamp: String, + /// Document signature + signature: String, +} + +impl ToStringObject for CertificationDocument { + type StringObject = CertificationStringDocument; + /// Transforms an object into a json object + fn to_string_object(&self) -> CertificationStringDocument { + CertificationStringDocument { + currency: self.currency.clone(), + issuer: format!("{}", self.issuers[0]), + target: format!("{}", self.target), + identity_username: self.identity_username.clone(), + identity_blockstamp: format!("{}", self.identity_blockstamp), + blockstamp: format!("{}", self.blockstamp), + identity_sig: format!("{}", self.identity_sig), + signature: format!("{}", self.signatures[0]), + } + } +} + impl CertificationDocument { /// Username of target identity pub fn identity_username(&self) -> &str { @@ -221,7 +259,7 @@ CertTimestamp: {blockstamp} #[derive(Debug, Clone, Copy)] pub struct CertificationDocumentParser; -impl TextDocumentParser for CertificationDocumentParser { +impl TextDocumentParser<Rule> for CertificationDocumentParser { type DocumentType = CertificationDocument; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { diff --git a/documents/src/v10/identity.rs b/documents/src/v10/identity.rs index 03bef1bee587266a954d24395a169940aee0dc00..ff28eb7e93c5eafc6fac15bd15cdfd57f48fdb24 100644 --- a/documents/src/v10/identity.rs +++ b/documents/src/v10/identity.rs @@ -44,6 +44,35 @@ pub struct IdentityDocument { signatures: Vec<Sig>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// identity document for jsonification +pub struct IdentityStringDocument { + /// Currency. + currency: String, + /// Unique ID + username: String, + /// Blockstamp + blockstamp: String, + /// Document issuer + issuer: String, + /// Document signature + signature: String, +} + +impl ToStringObject for IdentityDocument { + type StringObject = IdentityStringDocument; + /// Transforms an object into a json object + fn to_string_object(&self) -> IdentityStringDocument { + IdentityStringDocument { + currency: self.currency.clone(), + username: self.username.clone(), + blockstamp: format!("{}", self.blockstamp), + issuer: format!("{}", self.issuers[0]), + signature: format!("{}", self.signatures[0]), + } + } +} + impl IdentityDocument { /// Unique ID pub fn username(&self) -> &str { @@ -199,7 +228,7 @@ Timestamp: {blockstamp} #[derive(Debug, Clone, Copy)] pub struct IdentityDocumentParser; -impl TextDocumentParser for IdentityDocumentParser { +impl TextDocumentParser<Rule> for IdentityDocumentParser { type DocumentType = IdentityDocument; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { diff --git a/documents/src/v10/membership.rs b/documents/src/v10/membership.rs index 66154b79ce81e6964df455c451e73a0dbca76858..1c44b0cd1a1443033bda2f7bb1f6c63349c0b445 100644 --- a/documents/src/v10/membership.rs +++ b/documents/src/v10/membership.rs @@ -57,6 +57,44 @@ pub struct MembershipDocument { signatures: Vec<Sig>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// identity document for jsonification +pub struct MembershipStringDocument { + /// Currency. + currency: String, + /// Document issuer + issuer: String, + /// Blockstamp + blockstamp: String, + /// Membership message. + membership: String, + /// Unique ID + username: String, + /// Identity document blockstamp. + identity_blockstamp: String, + /// Document signature + signature: String, +} + +impl ToStringObject for MembershipDocument { + type StringObject = MembershipStringDocument; + /// Transforms an object into a json object + fn to_string_object(&self) -> MembershipStringDocument { + MembershipStringDocument { + currency: self.currency.clone(), + issuer: format!("{}", self.issuers[0]), + blockstamp: format!("{}", self.blockstamp), + membership: match self.membership { + MembershipType::In() => "IN".to_owned(), + MembershipType::Out() => "OUT".to_owned(), + }, + username: self.identity_username.clone(), + identity_blockstamp: format!("{}", self.identity_blockstamp), + signature: format!("{}", self.signatures[0]), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Hash, Deserialize, Serialize)] /// Membership event type (blockchain event) pub enum MembershipEventType { @@ -248,7 +286,7 @@ CertTS: {ity_blockstamp} #[derive(Debug, Clone, Copy)] pub struct MembershipDocumentParser; -impl TextDocumentParser for MembershipDocumentParser { +impl TextDocumentParser<Rule> for MembershipDocumentParser { type DocumentType = MembershipDocument; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { diff --git a/documents/src/v10/mod.rs b/documents/src/v10/mod.rs index bcad4ff71c566f938edf84cb9a83e5c574a66701..505510dad00142e5bec7659f5eaf2b37e5ba98a2 100644 --- a/documents/src/v10/mod.rs +++ b/documents/src/v10/mod.rs @@ -31,6 +31,7 @@ use v10::identity::*; use v10::membership::*; use v10::revocation::*; use v10::transaction::*; +use ToStringObject; use *; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -53,7 +54,7 @@ impl<D: TextDocument> TextDocumentFormat<D> { } /// List of wrapped document types. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum V10Document { /// Block document. Block(Box<BlockDocument>), @@ -74,7 +75,52 @@ pub enum V10Document { Revocation(Box<RevocationDocument>), } -impl TextDocumentParser for V10Document { +/// List of stringified document types. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum V10DocumentString { + /// Block document (not yet implemented) + Block(), + + /// Transaction document. + Transaction(Box<TransactionDocumentStringified>), + + /// Identity document. + Identity(IdentityStringDocument), + + /// Membership document. + Membership(MembershipStringDocument), + + /// Certification document. + Certification(Box<CertificationStringDocument>), + + /// Revocation document. + Revocation(Box<RevocationStringDocument>), +} + +impl ToStringObject for V10Document { + type StringObject = V10DocumentString; + /// Transforms an object into a json object + fn to_string_object(&self) -> Self::StringObject { + match *self { + V10Document::Block(_) => unimplemented!(), + V10Document::Identity(ref doc) => V10DocumentString::Identity(doc.to_string_object()), + V10Document::Membership(ref doc) => { + V10DocumentString::Membership(doc.to_string_object()) + } + V10Document::Certification(ref doc) => { + V10DocumentString::Certification(Box::new(doc.to_string_object())) + } + V10Document::Revocation(ref doc) => { + V10DocumentString::Revocation(Box::new(doc.to_string_object())) + } + V10Document::Transaction(ref doc) => { + V10DocumentString::Transaction(Box::new(doc.to_string_object())) + } + } + } +} + +impl TextDocumentParser<Rule> for V10Document { type DocumentType = V10Document; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { @@ -216,49 +262,6 @@ pub struct V10DocumentParts { pub signatures: Vec<Sig>, } -/*/// A V10 document parser. -#[derive(Debug, Clone, Copy)] -pub struct V10DocumentParser; - -impl<'a> DocumentParser<&'a str, V10Document, TextDocumentParseError> for V10DocumentParser { - fn parse(source: &'a str) -> Result<V10Document, TextDocumentParseError> { - /*match DocumentsParser::parse(Rule::document_v10, source) { - Ok(mut source_ast) => { - let doc_v10_ast = source_ast.next().unwrap(); // get and unwrap the `document_v10` rule; never fails - let doc_type_v10_ast = doc_v10_ast.into_inner().next().unwrap(); // get and unwrap the `{DOC_TYPE}_v10` rule; never fails - - match doc_type_v10_ast.as_rule() { - Rule::idty_v10 => IdentityDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), - Rule::membership_v10 => MembershipDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), - Rule::cert_v10 => CertificationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), - Rule::revoc_v10 => RevocationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), - Rule::tx_v10 => TransactionDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), - } - } - Err(_) => Err(TextDocumentParseError::InvalidWrapperFormat()), - }*/ -if let Some(caps) = DOCUMENT_REGEX.captures(source) { -let doctype = &caps["type"]; -let currency = &caps["currency"]; - -// TODO : Improve error handling of Signature::from_base64 failure - -match doctype { -"Identity" => IdentityDocumentParser::parse_standard(source, currency), -"Membership" => MembershipDocumentParser::parse_standard(source, currency), -"Certification" => CertificationDocumentParser::parse_standard(source, currency), -"Revocation" => RevocationDocumentParser::parse_standard(source, currency), -"Transaction" => TransactionDocumentParser::parse_standard(source, currency), -_ => Err(TextDocumentParseError::UnknownDocumentType( -doctype.to_string(), -)), -} -} else { -Err(TextDocumentParseError::InvalidWrapperFormat()) -} -} -}*/ - #[cfg(test)] mod tests { use super::certification::CertificationDocumentParser; diff --git a/documents/src/v10/revocation.rs b/documents/src/v10/revocation.rs index 26137d661ec1fa8114861e926e386c3b7e153d82..c070a49c424d4c3321feb738343a231da2542b94 100644 --- a/documents/src/v10/revocation.rs +++ b/documents/src/v10/revocation.rs @@ -65,6 +65,38 @@ pub struct RevocationDocument { signatures: Vec<Sig>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// Revocation document for jsonification +pub struct RevocationStringDocument { + /// Name of the currency. + currency: String, + /// Document issuer + issuer: String, + /// Username of target identity + identity_username: String, + /// Target Identity document blockstamp. + identity_blockstamp: String, + /// Target Identity document signature. + identity_sig: String, + /// Document signature + signature: String, +} + +impl ToStringObject for RevocationDocument { + type StringObject = RevocationStringDocument; + /// Transforms an object into a json object + fn to_string_object(&self) -> RevocationStringDocument { + RevocationStringDocument { + currency: self.currency.clone(), + issuer: format!("{}", self.issuers[0]), + identity_username: self.identity_username.clone(), + identity_blockstamp: format!("{}", self.identity_blockstamp), + identity_sig: format!("{}", self.identity_sig), + signature: format!("{}", self.signatures[0]), + } + } +} + impl RevocationDocument { /// Username of target identity pub fn identity_username(&self) -> &str { @@ -189,7 +221,7 @@ IdtySignature: {idty_sig} #[derive(Debug, Clone, Copy)] pub struct RevocationDocumentParser; -impl TextDocumentParser for RevocationDocumentParser { +impl TextDocumentParser<Rule> for RevocationDocumentParser { type DocumentType = RevocationDocument; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { diff --git a/documents/src/v10/transaction.rs b/documents/src/v10/transaction.rs index a3878a290579e4214dce47c417e4daa384ac8f45..fe61bca114fc66c542507d6fd0ce57a21ead75ef 100644 --- a/documents/src/v10/transaction.rs +++ b/documents/src/v10/transaction.rs @@ -509,6 +509,66 @@ pub struct TransactionDocument { hash: Option<Hash>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// Transaction document stringifed +pub struct TransactionDocumentStringified { + /// Currency. + currency: String, + /// Blockstamp + blockstamp: String, + /// Locktime + locktime: u64, + /// Document issuer (there should be only one). + issuers: Vec<String>, + /// Transaction inputs. + inputs: Vec<String>, + /// Inputs unlocks. + unlocks: Vec<String>, + /// Transaction outputs. + outputs: Vec<String>, + /// Transaction comment + comment: String, + /// Document signature (there should be only one). + signatures: Vec<String>, + /// Transaction hash + hash: Option<String>, +} + +impl ToStringObject for TransactionDocument { + type StringObject = TransactionDocumentStringified; + /// Transforms an object into a json object + fn to_string_object(&self) -> TransactionDocumentStringified { + TransactionDocumentStringified { + currency: self.currency.clone(), + blockstamp: format!("{}", self.blockstamp), + locktime: self.locktime, + issuers: self.issuers.iter().map(|p| format!("{}", p)).collect(), + inputs: self + .inputs + .iter() + .map(TransactionInput::to_string) + .collect(), + unlocks: self + .unlocks + .iter() + .map(TransactionInputUnlocks::to_string) + .collect(), + outputs: self + .outputs + .iter() + .map(TransactionOutput::to_string) + .collect(), + comment: self.comment.clone(), + signatures: self.signatures.iter().map(|s| format!("{}", s)).collect(), + hash: if let Some(hash) = self.hash { + Some(hash.to_string()) + } else { + None + }, + } + } +} + impl TransactionDocument { /// Compute transaction hash pub fn compute_hash(&mut self) -> Hash { @@ -758,7 +818,7 @@ Issuers: #[derive(Debug, Clone, Copy)] pub struct TransactionDocumentParser; -impl TextDocumentParser for TransactionDocumentParser { +impl TextDocumentParser<Rule> for TransactionDocumentParser { type DocumentType = TransactionDocument; fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { diff --git a/network-documents/Cargo.toml b/network-documents/Cargo.toml index f0699f1f316730ab8b49ef059dbdf90e31091f4a..9149de41c496be9ebb3f78f67ae5b93356c2d00d 100644 --- a/network-documents/Cargo.toml +++ b/network-documents/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "durs-network-documents" -version = "0.2.0-b1" +version = "0.3.0" authors = ["librelois <elois@duniter.org>"] description = "Network documents for DUNP (DUniter Network Protocol)" license = "AGPL-3.0" diff --git a/network-documents/src/lib.rs b/network-documents/src/lib.rs index ab80b8b3ab3718999a59c0c934ca4f961c600667..d9a0440114da23ebaac187aa80a5e2baed8d2e44 100644 --- a/network-documents/src/lib.rs +++ b/network-documents/src/lib.rs @@ -47,8 +47,15 @@ pub mod network_head_v2; pub mod network_head_v3; pub mod network_peer; +use dubp_documents::{TextDocumentParseError, TextDocumentParser}; use dup_crypto::hashs::*; use dup_crypto::keys::*; +use network_head::NetworkHead; +use network_head_v3::NetworkHeadV3; +use network_peer::PeerCard; +use network_peer::PeerCardV11; +use pest::iterators::Pair; +use pest::Parser; use std::fmt::{Display, Error, Formatter}; #[derive(Parser)] @@ -56,6 +63,39 @@ use std::fmt::{Display, Error, Formatter}; /// Parser for network documents struct NetworkDocsParser; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// Network document +pub enum NetworkDocument { + /// Peer + Peer(Box<PeerCard>), + /// Head + Head(NetworkHead), +} + +impl TextDocumentParser<Rule> for NetworkDocument { + type DocumentType = NetworkDocument; + + fn parse(doc: &str) -> Result<NetworkDocument, TextDocumentParseError> { + match NetworkDocsParser::parse(Rule::network_document, doc) { + Ok(mut net_doc_pairs) => Ok(NetworkDocument::from_pest_pair( + net_doc_pairs.next().unwrap().into_inner().next().unwrap(), + )), // get and unwrap the `network_document` rule; never fails + Err(pest_error) => Err(TextDocumentParseError::PestError(format!("{}", pest_error))), + } + } + fn from_pest_pair(pair: Pair<Rule>) -> NetworkDocument { + match pair.as_rule() { + Rule::peer_v11 => { + NetworkDocument::Peer(Box::new(PeerCard::V11(PeerCardV11::from_pest_pair(pair)))) + } + Rule::head_v3 => NetworkDocument::Head(NetworkHead::V3(Box::new( + NetworkHeadV3::from_pest_pair(pair), + ))), + _ => panic!("unexpected rule: {:?}", pair.as_rule()), // Grammar ensures that we never reach this line + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] /// ParseError pub enum ParseError { diff --git a/network-documents/src/network_documents.pest b/network-documents/src/network_documents.pest index 5461807299b8949616d2d5c7312cd65de0d80761..112af2fda22cb587a07c4a0b515b82889c9a42c6 100644 --- a/network-documents/src/network_documents.pest +++ b/network-documents/src/network_documents.pest @@ -97,3 +97,7 @@ head_v3 = ${ ed25519_sig? ~ (nl ~ step)? } + +// Network document rule +network_document_inner = _{ head_v3 | peer_v11 } +network_document = ${ SOI ~ network_document_inner ~ EOI } \ No newline at end of file diff --git a/network-documents/src/network_head_v3.rs b/network-documents/src/network_head_v3.rs index 04be52130e7dfb3d732dcbb83aa485a05a7fa673..bb8be85b4a9435a4b3c523b249b358f34164b4cc 100644 --- a/network-documents/src/network_head_v3.rs +++ b/network-documents/src/network_head_v3.rs @@ -17,7 +17,7 @@ use base58::ToBase58; use dubp_documents::blockstamp::Blockstamp; -use dubp_documents::{BlockHash, BlockId, CurrencyName, ToJsonObject}; +use dubp_documents::{BlockHash, BlockId, CurrencyName, ToStringObject}; use dup_crypto::keys::text_signable::TextSignable; use dup_crypto::keys::*; use pest::iterators::Pair; @@ -105,17 +105,19 @@ impl TextSignable for NetworkHeadV3 { } } -impl NetworkHeadV3 { - /// parse from raw ascii format - pub fn parse_from_raw(raw_peer: &str) -> Result<NetworkHeadV3, ParseError> { - match NetworkDocsParser::parse(Rule::head_v3, raw_peer) { +impl TextDocumentParser<Rule> for NetworkHeadV3 { + /// Type of document generated by the parser + type DocumentType = NetworkHeadV3; + + fn parse(doc: &str) -> Result<NetworkHeadV3, TextDocumentParseError> { + match NetworkDocsParser::parse(Rule::head_v3, doc) { Ok(mut head_v3_pairs) => { Ok(NetworkHeadV3::from_pest_pair(head_v3_pairs.next().unwrap())) } - Err(pest_error) => Err(ParseError::PestError(format!("{}", pest_error))), + Err(pest_error) => Err(TextDocumentParseError::PestError(format!("{}", pest_error))), } } - /// Generate from pest pair + fn from_pest_pair(pair: Pair<Rule>) -> NetworkHeadV3 { let mut currency_str = ""; let mut api_outgoing_conf = 0; @@ -183,48 +185,23 @@ impl NetworkHeadV3 { #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Head V3 for json serializer -pub struct JsonHeadV3 { - /// WS2P Private configuration - pub api_outgoing_conf: u8, - /// WS2P Public configuration - pub api_incoming_conf: u8, - /// Issuer node free member rooms - pub free_member_rooms: u8, - /// Issuer node free mirror rooms - pub free_mirror_rooms: u8, - /// Issuer node id - pub node_id: NodeId, - /// Issuer key algorithm - pub algorithm: KeysAlgo, - /// Issuer pubkey - pub pubkey: String, - /// Head blockstamp - pub blockstamp: String, - /// Issuer node software - pub software: String, - /// Issuer node soft version - pub soft_version: String, +pub struct HeadV3Stringified { + /// Head body + pub body: String, /// Issuer signature pub signature: Option<String>, /// Head step pub step: u8, } -impl<'a> ToJsonObject for NetworkHeadV3 { - type JsonObject = JsonHeadV3; +impl<'a> ToStringObject for NetworkHeadV3 { + type StringObject = HeadV3Stringified; - fn to_json_object(&self) -> Self::JsonObject { - JsonHeadV3 { - api_outgoing_conf: self.api_outgoing_conf, - api_incoming_conf: self.api_incoming_conf, - free_member_rooms: self.free_member_rooms, - free_mirror_rooms: self.free_mirror_rooms, - node_id: self.node_id, - algorithm: self.pubkey.algo(), - pubkey: self.pubkey.to_base58(), - blockstamp: self.blockstamp.to_string(), - software: self.software.clone(), - soft_version: self.soft_version.clone(), + fn to_string_object(&self) -> Self::StringObject { + let body = self.as_signable_text(); + let body_len = body.len(); + HeadV3Stringified { + body: body.chars().take(body_len - 1).collect(), signature: if let Some(sig) = self.signature { Some(sig.to_base64()) } else { @@ -266,7 +243,7 @@ mod tests { println!("{}", head_v3_raw); assert_eq!( head_v3, - NetworkHeadV3::parse_from_raw(&head_v3_raw).expect("Fail to parse head v3 !") + NetworkHeadV3::parse(&head_v3_raw).expect("Fail to parse head v3 !") ) } else { panic!("fail to sign head v3 : {:?}", sign_result.err().unwrap()) diff --git a/network-documents/src/network_peer.rs b/network-documents/src/network_peer.rs index 134ef7e74a356b8dd63fabc22550097ec27963bf..c4b93afa8f918ebe59a44126e8b15777e34ba181 100644 --- a/network-documents/src/network_peer.rs +++ b/network-documents/src/network_peer.rs @@ -20,6 +20,7 @@ extern crate dup_crypto; extern crate serde; use base58::ToBase58; +use dubp_documents::ToStringObject; use dubp_documents::{blockstamp::Blockstamp, CurrencyName}; use dubp_documents::{BlockHash, BlockId}; use dup_crypto::keys::text_signable::TextSignable; @@ -29,7 +30,7 @@ use pest::iterators::Pair; use pest::Parser; use *; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Peer card V10 pub struct PeerCardV10 { /// Peer card Blockstamp @@ -59,6 +60,45 @@ pub struct PeerCardV11 { pub sig: Option<Sig>, } +#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)] +/// identity document for jsonification +pub struct PeerCardV11Stringified { + /// Currency name + pub currency_name: String, + /// Peer card issuer + pub issuer: String, + /// Issuer node id + pub node_id: String, + /// Peer card Blockstamp + pub blockstamp: String, + /// Peer card string endpoints + pub endpoints: Vec<String>, + /// Signature + pub sig: String, +} + +impl ToStringObject for PeerCardV11 { + type StringObject = PeerCardV11Stringified; + /// Transforms an object into a json object + fn to_string_object(&self) -> PeerCardV11Stringified { + let mut endpoints: Vec<String> = self.endpoints.iter().map(EndpointV2::to_string).collect(); + endpoints.extend_from_slice(&self.endpoints_str); + + PeerCardV11Stringified { + currency_name: self.currency_name.0.clone(), + issuer: format!("{}", self.issuer), + node_id: format!("{}", self.node_id), + blockstamp: format!("{}", self.blockstamp), + endpoints, + sig: if let Some(sig) = self.sig { + format!("{}", sig) + } else { + "".to_owned() + }, + } + } +} + impl TextSignable for PeerCardV11 { fn as_signable_text(&self) -> String { format!( @@ -92,17 +132,18 @@ impl TextSignable for PeerCardV11 { } } -impl PeerCardV11 { - /// parse from raw ascii format - pub fn parse_from_raw(raw_peer: &str) -> Result<PeerCardV11, ParseError> { - match NetworkDocsParser::parse(Rule::peer_v11, raw_peer) { +impl TextDocumentParser<Rule> for PeerCardV11 { + type DocumentType = PeerCardV11; + + fn parse(doc: &str) -> Result<Self::DocumentType, TextDocumentParseError> { + match NetworkDocsParser::parse(Rule::peer_v11, doc) { Ok(mut peer_v11_pairs) => { Ok(PeerCardV11::from_pest_pair(peer_v11_pairs.next().unwrap())) } - Err(pest_error) => Err(ParseError::PestError(format!("{}", pest_error))), + Err(pest_error) => Err(TextDocumentParseError::PestError(format!("{}", pest_error))), } } - /// Generate from pest pair + fn from_pest_pair(pair: Pair<Rule>) -> PeerCardV11 { let mut currency_str = ""; let mut node_id = NodeId(0); @@ -150,6 +191,9 @@ impl PeerCardV11 { sig, } } +} + +impl PeerCardV11 { /// Convert to JSON String pub fn to_json_peer(&self) -> Result<String, serde_json::Error> { Ok(serde_json::to_string_pretty(&JsonPeerCardV11 { @@ -190,7 +234,7 @@ pub struct JsonPeerCardV11<'a> { pub signature: Option<String>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Peer card pub enum PeerCard { /// Peer card V10 @@ -280,8 +324,7 @@ mod tests { println!("{}", peer_card_v11_raw); assert_eq!( peer_card_v11, - PeerCardV11::parse_from_raw(&peer_card_v11_raw) - .expect("Fail to parse peer card v11 !") + PeerCardV11::parse(&peer_card_v11_raw).expect("Fail to parse peer card v11 !") ) } else { panic!("fail to sign peer card : {:?}", sign_result.err().unwrap())