diff --git a/Cargo.lock b/Cargo.lock index 3760ea3076ed8933035009417ead039d331c50e8..801e0864f7d4280911b83fc09235c1b93e77305a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,14 @@ name = "base58" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "base64" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "base64" version = "0.9.2" @@ -230,13 +238,13 @@ 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.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 0.1.0-a0.1", "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)", "pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustbreak 2.0.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustbreak 2.0.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -250,7 +258,7 @@ dependencies = [ "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "duniter-documents 0.9.0-b1", "duniter-module 0.1.0-a0.1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", "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)", @@ -267,7 +275,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.3.0-b2", + "dup-crypto 0.3.0-b3", + "durs-network-documents 0.1.0-a0.1", "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)", @@ -285,11 +294,10 @@ dependencies = [ "duniter-documents 0.9.0-b1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-wot 0.8.0-a0.9", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustbreak 2.0.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustbreak 2.0.0-rc3 (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)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -302,12 +310,13 @@ 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.3.0-b2", + "dup-crypto 0.3.0-b3", "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)", - "rust-crypto 0.2.36 (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)", "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)", ] [[package]] @@ -318,7 +327,8 @@ dependencies = [ "duniter-documents 0.9.0-b1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", + "durs-network-documents 0.1.0-a0.1", "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)", @@ -329,7 +339,8 @@ name = "duniter-module" version = "0.1.0-a0.1" dependencies = [ "duniter-documents 0.9.0-b1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", + "durs-network-documents 0.1.0-a0.1", "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)", @@ -342,7 +353,7 @@ version = "0.1.0-a0.1" dependencies = [ "duniter-documents 0.9.0-b1", "duniter-module 0.1.0-a0.1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 0.1.0-a0.1", "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)", @@ -359,7 +370,7 @@ 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.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 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)", @@ -371,13 +382,13 @@ dependencies = [ [[package]] name = "dup-crypto" -version = "0.3.0-b2" +version = "0.3.0-b3" 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)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto-wasm 0.3.1 (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)", ] @@ -400,7 +411,8 @@ 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)", "duniter-documents 0.9.0-b1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", + "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)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -424,11 +436,13 @@ dependencies = [ name = "durs-ws2p" version = "0.1.0-a0.1" dependencies = [ + "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "duniter-conf 0.1.0-a0.1", + "duniter-documents 0.9.0-b1", "duniter-message 0.1.0-a0.1", "duniter-module 0.1.0-a0.1", "duniter-network 0.1.0-a0.1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 0.1.0-a0.1", "durs-ws2p-messages 0.1.0-a0.1", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -444,11 +458,10 @@ 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)", "duniter-documents 0.9.0-b1", - "dup-crypto 0.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 0.1.0-a0.1", "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)", - "rust-crypto 0.2.36 (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)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -465,12 +478,11 @@ 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.3.0-b2", + "dup-crypto 0.3.0-b3", "durs-network-documents 0.1.0-a0.1", "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)", - "rust-crypto 0.2.36 (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)", "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -486,21 +498,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "failure" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -548,6 +561,16 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "httparse" version = "1.3.0" @@ -772,7 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -803,23 +826,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.4.6" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -902,25 +920,26 @@ dependencies = [ ] [[package]] -name = "rust-crypto" -version = "0.2.36" +name = "rust-crypto-wasm" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustbreak" -version = "2.0.0-rc2" +version = "2.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -929,11 +948,6 @@ name = "rustc-demangle" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "safemem" version = "0.2.0" @@ -954,7 +968,7 @@ name = "serde_derive" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1051,46 +1065,40 @@ name = "structopt-derive" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "synom" -version = "0.11.3" +name = "syn" +version = "0.15.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.6.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1166,11 +1174,6 @@ name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -1262,6 +1265,7 @@ dependencies = [ "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2" +"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" @@ -1283,8 +1287,8 @@ dependencies = [ "checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" -"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" +"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" +"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" @@ -1292,6 +1296,8 @@ dependencies = [ "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum httparse 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "422d5a93b40dbfbd8c8c24d1b4b5ef455973ef3afffc172487429fecd05bde42" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -1323,8 +1329,7 @@ dependencies = [ "checksum pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221" "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" -"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ab2fc21ba78ac73e4ff6b3818ece00be4e175ffbef4d0a717d978b48b24150c4" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" @@ -1335,10 +1340,9 @@ dependencies = [ "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -"checksum rustbreak 2.0.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)" = "676cb04876f4391d5d2f2c9029d10cfe5fe28ad625ad8460531bed1191477083" +"checksum rust-crypto-wasm 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9dcf11edbc9a0effb4a99ddbe909dd26fb2e71459064879218c27b0add1cb6ec" +"checksum rustbreak 2.0.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c185a2ede13fcb28feb6864ee9412a20f57bd83b4be18dc81fde4d6e786982" "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)" = "92ec94e2754699adddbbc4f555791bd3acc2a2f5574cba16c93a4a9cf4a04415" @@ -1355,10 +1359,9 @@ dependencies = [ "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8e9ad6a11096cbecdcca0cc6aa403fdfdbaeda2fb3323a39c98e6a166a1e45a" "checksum structopt-derive 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4cbce8ccdc62166bd594c14396a3242bf94c337a51dbfa9be1076dd74b3db2af" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" +"checksum syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)" = "90c39a061e2f412a9f869540471ab679e85e50c6b05604daf28bc3060f75c430" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" @@ -1369,7 +1372,6 @@ dependencies = [ "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474" diff --git a/blockchain/Cargo.toml b/blockchain/Cargo.toml index 218ff6b2665bc19edc73a2ff9c98bcb8c136f601..ea020681ce68abb27c2362846dbdefc0e34179d3 100644 --- a/blockchain/Cargo.toml +++ b/blockchain/Cargo.toml @@ -22,7 +22,7 @@ durs-wot = { path = "../wot" } log = "0.4.*" num_cpus = "1.8.*" pbr = "1.0.*" -rustbreak = {version = "2.0.0-rc2", features = ["bin_enc"]} +rustbreak = {version = "2.0.0-rc3", features = ["bin_enc"]} serde = "1.0.*" serde_json = "1.0.*" sqlite = "0.23.*" diff --git a/blockchain/lib.rs b/blockchain/lib.rs index a01dd2df2418c20b6195031e3b977a55e07e3148..67d300e88539ea12eee48f7202e26ee5651999a3 100644 --- a/blockchain/lib.rs +++ b/blockchain/lib.rs @@ -444,7 +444,7 @@ impl BlockchainModule { wot: &BinDB<W>, ) -> Blockstamp { debug!("BlockchainModule : receive_blocks()"); - let blocks: Vec<&NetworkBlock> = blocks_in_box.into_iter().map(|b| b.deref()).collect(); + let blocks: Vec<&NetworkBlock> = blocks_in_box.iter().map(|b| b.deref()).collect(); let mut current_blockstamp = *current_blockstamp; let mut save_blocks_dbs = false; let mut save_wots_dbs = false; diff --git a/core/Cargo.toml b/core/Cargo.toml index fe81eec107eab6d1e93c58fece27862c20642a4b..37d43e959dcb3c3620116efae31c34d6ff6dd48c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -16,6 +16,7 @@ dup-crypto = { path = "../crypto" } duniter-message = { path = "../message" } duniter-module = { path = "../module" } duniter-network = { path = "../network" } +durs-network-documents = { path = "../network-documents" } log = "0.4.*" log-panics = "2.0.*" serde = "1.0.*" diff --git a/core/lib.rs b/core/lib.rs index bca1a77c35b1b383dbb3e1491d6d2f2926b69fa4..ba7b2c047f2d96223a3ed69433800bfbf49aaeaa 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -40,6 +40,7 @@ extern crate duniter_message; extern crate duniter_module; extern crate duniter_network; extern crate dup_crypto; +extern crate durs_network_documents; extern crate log_panics; extern crate serde_json; extern crate simplelog; @@ -206,7 +207,7 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> { keypairs: None, run_duration_in_secs, rooter_sender: None, - modules_count: 0, + modules_count: 1, // Count blockchain module network_modules_count: 0, thread_pool: ThreadPool::new(*THREAD_POOL_SIZE), } @@ -441,15 +442,22 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> { panic!("Try to start core without rooter_sender !"); }; - // Send blockchain sender to rooter thread + // Send expected modules count to rooter thread rooter_sender - .send(RooterThreadMessage::ModuleSender( + .send(RooterThreadMessage::ModulesCount(self.modules_count)) + .expect("Fatal error: fail to send expected modules count to rooter thread !"); + + // Send blockchain module registration to rooter thread + rooter_sender + .send(RooterThreadMessage::ModuleRegistration( BlockchainModule::name(), blockchain_sender, vec![ModuleRole::BlockchainDatas, ModuleRole::BlockValidation], vec![ModuleEvent::NewBlockFromNetwork], + vec![], + vec![], )) - .expect("Fatal error: fail to send blockchain sender to rooter thread !"); + .expect("Fatal error: fail to send blockchain registration to rooter thread !"); // Instantiate blockchain module and load is conf let mut blockchain_module = BlockchainModule::load_blockchain_conf( diff --git a/core/rooter.rs b/core/rooter.rs index e12801b739b11706aece03d78815908840d3e9ea..1dce12f5578f4450a9617700c031d7c51839bb9b 100644 --- a/core/rooter.rs +++ b/core/rooter.rs @@ -19,6 +19,7 @@ use duniter_conf; use duniter_conf::DuRsConf; use duniter_message::*; use duniter_module::*; +use durs_network_documents::network_endpoint::EndpointEnum; use std::collections::HashMap; use std::sync::mpsc; use std::sync::mpsc::RecvTimeoutError; @@ -26,6 +27,8 @@ use std::thread; use std::time::Duration; use std::time::SystemTime; +static MAX_REGISTRATION_DELAY: &'static u64 = &20; + /// Start broadcasting thread fn start_broadcasting_thread( start_time: SystemTime, @@ -38,17 +41,27 @@ fn start_broadcasting_thread( let mut pool_msgs: HashMap<DursMsgReceiver, Vec<DursMsgContent>> = HashMap::new(); let mut events_subscriptions: HashMap<ModuleEvent, Vec<ModuleStaticName>> = HashMap::new(); let mut roles: HashMap<ModuleRole, Vec<ModuleStaticName>> = HashMap::new(); + let mut registrations_count = 0; + let mut expected_registrations_count = None; + let mut local_node_endpoints: Vec<EndpointEnum> = Vec::new(); + let mut reserved_apis_name: HashMap<ModuleStaticName, Vec<String>> = HashMap::new(); loop { match receiver.recv_timeout(Duration::from_secs(1)) { Ok(mess) => { match mess { - RooterThreadMessage::ModuleSender( + RooterThreadMessage::ModulesCount(modules_count) => { + expected_registrations_count = Some(modules_count) + } + RooterThreadMessage::ModuleRegistration( module_static_name, module_sender, sender_roles, events_subscription, + module_reserved_apis_name, + mut module_endpoints, ) => { + registrations_count += 1; // For all events for event in events_subscription { // Send pending message of this event @@ -93,6 +106,41 @@ fn start_broadcasting_thread( .or_insert_with(Vec::new) .push(module_static_name); } + // For all endpoints + for ep in &module_endpoints { + let ep_api = ep.api(); + if !module_reserved_apis_name.contains(&ep_api.0) { + panic!("Fatal error : Module {} try to declare endpoint with undeclared api name: {} !", module_static_name.0, ep_api.0); + } + for other_module_ep in &local_node_endpoints { + if ep_api == other_module_ep.api() { + panic!("Fatal error : two modules try to declare endpoint of same api : {} !", ep_api.0); + } + } + } + // Store reserved APIs name + reserved_apis_name.insert(module_static_name, module_reserved_apis_name); + // Add module endpoints to local node endpoints + local_node_endpoints.append(&mut module_endpoints); + // Send endpoints to network module + if expected_registrations_count.is_some() + && registrations_count == expected_registrations_count.unwrap() + { + // Get list of InterNodesNetwork modules + let receivers = roles + .get(&ModuleRole::InterNodesNetwork) + .expect("Fatal error : no module with role InterNodesNetwork !") + .to_vec(); + // Send endpoints to receivers + send_msg_to_several_receivers( + DursMsg( + DursMsgReceiver::Role(ModuleRole::InterNodesNetwork), + DursMsgContent::Endpoints(local_node_endpoints.clone()), + ), + &receivers, + &modules_senders, + ); + } // Add this sender to modules_senders modules_senders.insert(module_static_name, module_sender); } @@ -175,6 +223,20 @@ fn start_broadcasting_thread( } }, } + if (expected_registrations_count.is_none() + || registrations_count < expected_registrations_count.unwrap()) + && SystemTime::now() + .duration_since(start_time) + .expect("Duration error !") + .as_secs() + > *MAX_REGISTRATION_DELAY + { + panic!( + "{} modules have registered, but expected {} !", + registrations_count, + expected_registrations_count.unwrap_or(0) + ); + } } } @@ -303,11 +365,23 @@ pub fn start_rooter( match rooter_receiver.recv_timeout(Duration::from_secs(1)) { Ok(mess) => { match mess { - RooterThreadMessage::ModuleSender( + RooterThreadMessage::ModulesCount(expected_registrations_count) => { + // Relay to broadcasting thread + broadcasting_sender + .send(RooterThreadMessage::ModulesCount( + expected_registrations_count, + )) + .expect( + "Fail to relay ModulesCount message to broadcasting thread !", + ); + } + RooterThreadMessage::ModuleRegistration( module_static_name, module_sender, events_subscription, sender_roles, + _module_reserved_apis_name, + _module_endpoints, ) => { // Send pending messages destined specifically to this module if let Some(msgs) = pool_msgs.remove(&module_static_name) { @@ -329,13 +403,17 @@ pub fn start_rooter( modules_senders.insert(module_static_name, module_sender.clone()); // Relay to broadcasting thread broadcasting_sender - .send(RooterThreadMessage::ModuleSender( + .send(RooterThreadMessage::ModuleRegistration( module_static_name, module_sender, events_subscription, sender_roles, + vec![], + vec![], )) - .expect("Fail to relay message to broadcasting thread !"); + .expect( + "Fail to relay module registration to broadcasting thread !", + ); // Log the number of modules_senders received info!( "Rooter thread receive {} module senders", @@ -369,13 +447,13 @@ pub fn start_rooter( broadcasting_sender .send(RooterThreadMessage::ModuleMessage(msg)) .expect( - "Fail to relay message to broadcasting thread !", + "Fail to relay specific role message to broadcasting thread !", ); } } DursMsgReceiver::Event(_module_event) => broadcasting_sender .send(RooterThreadMessage::ModuleMessage(msg)) - .expect("Fail to relay message to broadcasting thread !"), + .expect("Fail to relay specific event message to broadcasting thread !"), DursMsgReceiver::One(module_static_name) => { if let Some(module_sender) = modules_senders.get(&module_static_name) diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 9927beb5b62f9b4a692388dcd04c4260ac8cd379..def563d3cbe91ae1b8fb04b4f59e19b0df294d15 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dup-crypto" -version = "0.3.0-b2" +version = "0.3.0-b3" 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" @@ -16,10 +16,12 @@ base58 = "0.1.*" base64 = "0.10.*" bincode = "1.0.*" rand = "0.5.*" -rust-crypto = "0.2.*" +rust-crypto-wasm = "0.3.1" serde = "1.0.*" serde_derive = "1.0.*" + + [features] # Treat warnings as a build error. strict = [] \ No newline at end of file diff --git a/crypto/src/hashs/mod.rs b/crypto/src/hashs/mod.rs index da51bdcea51e87d1ec59c3224e0c55a10c0bc813..8b2c580a100d7b1aee8a12fce2d5f7d1fbb8cf84 100644 --- a/crypto/src/hashs/mod.rs +++ b/crypto/src/hashs/mod.rs @@ -70,6 +70,13 @@ impl Hash { Hash(hash_buffer) } + /// Compute hash of a string + pub fn compute_str(str_datas: &str) -> Hash { + let mut sha256 = Sha256::new(); + sha256.input_str(&str_datas); + Hash::from_hex(&sha256.result_str()).expect("Sha256 result must be an hexa string !") + } + /// Convert Hash into bytes vector pub fn to_bytes_vector(&self) -> Vec<u8> { self.0.to_vec() diff --git a/crypto/src/keys/mod.rs b/crypto/src/keys/mod.rs index 46a7ff9dbc5b07ee4ff35413e11fc611b78a8c18..051dd974d03e870089242685c11851210259eb70 100644 --- a/crypto/src/keys/mod.rs +++ b/crypto/src/keys/mod.rs @@ -58,6 +58,7 @@ use std::hash::Hash; pub mod bin_signable; pub mod ed25519; +pub mod text_signable; /// Cryptographic keys algorithms list #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)] diff --git a/crypto/src/keys/text_signable.rs b/crypto/src/keys/text_signable.rs new file mode 100644 index 0000000000000000000000000000000000000000..43c02f062a63a9c65c10ad028dafd0cd597aa17e --- /dev/null +++ b/crypto/src/keys/text_signable.rs @@ -0,0 +1,69 @@ +// Copyright (C) 2018 The Durs Project Developers. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Generic code for signing data in text format + +use super::*; + +/// Signatureable in text format +pub trait TextSignable: Debug + Clone { + /// Return signable text + fn as_signable_text(&self) -> String; + /// Return message issuer pubkey + fn issuer_pubkey(&self) -> PubKey; + /// Return message signature + fn signature(&self) -> Option<Sig>; + /// Change signature + fn set_signature(&mut self, _signature: Sig); + /// Sign text message + fn sign(&mut self, priv_key: PrivKey) -> Result<String, SignError> { + if self.signature().is_some() { + return Err(SignError::AlreadySign()); + } + let text = self.as_signable_text(); + match self.issuer_pubkey() { + PubKey::Ed25519(_) => match priv_key { + PrivKey::Ed25519(priv_key) => { + let sig = priv_key.sign(&text.as_bytes()); + self.set_signature(Sig::Ed25519(sig)); + let str_sig = sig.to_base64(); + Ok(format!("{}{}", text, str_sig)) + } + _ => Err(SignError::WrongAlgo()), + }, + _ => Err(SignError::WrongAlgo()), + } + } + /// Check signature of text message + fn verify(&self) -> Result<(), SigError> { + if let Some(signature) = self.signature() { + match self.issuer_pubkey() { + PubKey::Ed25519(pubkey) => match signature { + Sig::Ed25519(sig) => { + if pubkey.verify(&self.as_signable_text().as_bytes(), &sig) { + Ok(()) + } else { + Err(SigError::InvalidSig()) + } + } + _ => Err(SigError::NotSameAlgo()), + }, + _ => Err(SigError::NotSameAlgo()), + } + } else { + Err(SigError::NotSig()) + } + } +} diff --git a/dal/Cargo.toml b/dal/Cargo.toml index dd16c4e68660cdc2f131ee8101145657bc4a0912..ea6bbd619378f99a30a764a7025113db4d47a8cb 100644 --- a/dal/Cargo.toml +++ b/dal/Cargo.toml @@ -15,8 +15,7 @@ duniter-module = { path = "../module" } duniter-network = { path = "../network" } durs-wot = { path = "../wot" } log = "0.4.*" -rustbreak = {version = "2.0.0-rc2", features = ["bin_enc"]} -rust-crypto = "0.2.*" +rustbreak = {version = "2.0.0-rc3", features = ["bin_enc"]} serde = "1.0.*" serde_derive = "1.0.*" serde_json = "1.0.*" diff --git a/documents/Cargo.toml b/documents/Cargo.toml index 8b887f77d5e098b0b485df066480aeee63315120..042065c0a3fa54f60e1dbe7dada6e6ea8e4aaa3e 100644 --- a/documents/Cargo.toml +++ b/documents/Cargo.toml @@ -18,9 +18,12 @@ byteorder = "1.2.3" dup-crypto = { path = "../crypto" } pest = "2.0" pest_derive = "2.0" -rust-crypto = "0.2.*" serde = "1.0.*" serde_derive = "1.0.*" +serde_json = "1.0.*" + +[dev-dependencies] +pretty_assertions = "0.5.1" [features] # Treat warnings as a build error. diff --git a/documents/src/documents_grammar.pest b/documents/src/documents_grammar.pest index aba4de05ba21ae2a0b0a1a1352b74f79a101280f..695f6e262c9b875cf694333a59e786338a2debe3 100644 --- a/documents/src/documents_grammar.pest +++ b/documents/src/documents_grammar.pest @@ -6,15 +6,17 @@ nl = _{ "\n" } // Only one way to break a line is accepted hexa_upper = { ASCII_DIGIT | 'A'..'F' } base58 = { !("O" | "I" | "l") ~ ASCII_ALPHANUMERIC } base64 = { ASCII_ALPHANUMERIC | "+" | "/" } -integer = @{ "0" | ('1'..'9' ~ ASCII_DIGIT*) } +no_zero_u_int = @{ '1'..'9' ~ ASCII_DIGIT* } +u_int = @{ "0" | no_zero_u_int } hash = @{ hexa_upper{64} } currency = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* } pubkey = @{ base58{43,44} } -uid = @{ ASCII_ALPHA+ } -block_id = @{ integer } +uid = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* } +block_id = @{ u_int } blockstamp = ${ block_id ~ "-" ~ hash } -ed25519_sig = @{ base64{86,88} ~ "="{0,2} } +ed25519_sig = @{ base64{88} | (base64{87} ~ "=") | (base64{86} ~ "==") } +//^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$ v10 = _{ "Version: 10" } @@ -87,16 +89,16 @@ revoc = ${ (&(SOI ~ v10 ~ nl) ~ revoc_v10) } -tx_locktime = @{ integer } -tx_amount = @{ integer } -tx_amount_base = @{ integer } -du_block_id = @{ integer } -tx_index = @{ integer } -input_index = @{ integer } -issuer_index = @{ integer } +tx_locktime = @{ u_int } +tx_amount = @{ u_int } +tx_amount_base = @{ u_int } +du_block_id = @{ u_int } +tx_index = @{ u_int } +input_index = @{ u_int } +issuer_index = @{ u_int } xhx_secret = @ { ASCII_ALPHANUMERIC+ } -csv_duration = @{ integer } -cltv_timestamp = @{ integer } +csv_duration = @{ u_int } +cltv_timestamp = @{ u_int } tx_input = ${ tx_input_du | tx_input_tx } tx_input_du = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id } diff --git a/documents/src/lib.rs b/documents/src/lib.rs index 5202225d080cd4ae825ed655e872d1b0d0a396dc..586f5d41f7889685eae9de7f8846cfe15f5150e6 100644 --- a/documents/src/lib.rs +++ b/documents/src/lib.rs @@ -29,14 +29,17 @@ extern crate base58; extern crate base64; extern crate byteorder; -extern crate crypto; extern crate dup_crypto; extern crate pest; #[macro_use] extern crate pest_derive; +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate serde_json; pub mod blockstamp; mod currencies_codes; @@ -48,6 +51,7 @@ use dup_crypto::hashs::Hash; use dup_crypto::keys::*; use pest::iterators::Pair; use pest::Parser; +use serde::Serialize; use std::cmp::Ordering; use std::fmt::{Debug, Display, Error, Formatter}; use std::io::Cursor; @@ -313,3 +317,19 @@ pub trait DocumentParser<S, D, E> { /// Parse a source and return a document or an error. 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; + + /// Convert to JSON String + fn to_json_string(&self) -> Result<String, serde_json::Error> { + Ok(serde_json::to_string(&self.to_json_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())?) + } +} diff --git a/documents/src/v10/block.rs b/documents/src/v10/block.rs index f9b417d23e89b585ba02eddcf208dc0ec0f59052..2a53d4ea79bcb3f7a22d4927d24af1fbbf81a32a 100644 --- a/documents/src/v10/block.rs +++ b/documents/src/v10/block.rs @@ -15,8 +15,6 @@ //! Wrappers around Block document. -use crypto::digest::Digest; -use crypto::sha2::Sha256; use dup_crypto::hashs::Hash; use dup_crypto::keys::*; use std::ops::Deref; @@ -277,10 +275,7 @@ impl BlockDocument { } /// Compute inner hash pub fn compute_inner_hash(&mut self) { - let mut sha256 = Sha256::new(); - let inner_text = self.generate_compact_inner_text(); - sha256.input_str(&inner_text); - self.inner_hash = Some(Hash::from_hex(&sha256.result_str()).unwrap()); + self.inner_hash = Some(Hash::compute_str(&self.generate_compact_inner_text())); } /// Fill inner_hash_and_nonce_str pub fn fill_inner_hash_and_nonce_str(&mut self, new_nonce: Option<u64>) { @@ -302,16 +297,14 @@ impl BlockDocument { } /// Compute hash pub fn compute_hash(&mut self) { - let mut sha256 = Sha256::new(); - sha256.input_str(&format!( + self.hash = Some(BlockHash(Hash::compute_str(&format!( "InnerHash: {}\nNonce: {}\n{}\n", self.inner_hash .expect("Try to get inner_hash of an uncompleted or reduce block !") .to_hex(), self.nonce, self.signatures[0] - )); - self.hash = Some(BlockHash(Hash::from_hex(&sha256.result_str()).unwrap())); + )))); } /// Lightens the block (for example to store it while minimizing the space required) pub fn reduce(&mut self) { @@ -718,4 +711,144 @@ Nonce: " "000004F8B84A3590243BA562E5F2BA379F55A0B387C5D6FAC1022DFF7FFE6014" ); } + + #[test] + fn generate_and_verify_block_2() { + let ms1 = MembershipDocumentParser::parse( + "Version: 10 +Type: Membership +Currency: g1 +Issuer: 4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969 +Block: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2 +Membership: IN +UserID: piaaf31 +CertTS: 74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6 +gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==", + ) + .expect("Fail to parse ms1"); + + let tx1 = TransactionDocumentParser::parse( + "Version: 10 +Type: Transaction +Currency: g1 +Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2 +Locktime: 0 +Issuers: +51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2 +Inputs: +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118 +1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389 +Unlocks: +0:SIG(0) +1:SIG(0) +2:SIG(0) +3:SIG(0) +4:SIG(0) +5:SIG(0) +6:SIG(0) +Outputs: +7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant) +28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2) +Comment: Panier mixte plus 40 pommes merci +7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==", + ) + .expect("Fail to parse tx1"); + + let tx2 = TransactionDocumentParser::parse( + "Version: 10 +Type: Transaction +Currency: g1 +Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2 +Locktime: 0 +Issuers: +3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX +Inputs: +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827 +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100 +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370 +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664 +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943 +1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222 +Unlocks: +0:SIG(0) +1:SIG(0) +2:SIG(0) +3:SIG(0) +4:SIG(0) +5:SIG(0) +Outputs: +6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD) +12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX) +Comment: En reglement de tes bons bocaux de fruits et legumes +nxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg== +", + ) + .expect("Fail to parse tx2"); + + let mut block = BlockDocument { + nonce: 0, + number: BlockId(165_647), + pow_min: 90, + time: 1_540_633_175, + median_time: 1_540_627_811, + members_count: 1402, + monetary_mass: 386_008_811, + unit_base: 0, + issuers_count: 37, + issuers_frame: 186, + issuers_frame_var: 0, + currency: CurrencyName(String::from("g1")), + issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq").unwrap())], + signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("2Z/+9ADdZvHXs19YR8+qDzgfl8WJlBG5PcbFvBG9TOuUJbjAdxhcgxrFrSRIABGWcCrIgLkB805fZVLP8jOjBA==").unwrap())], + hash: None, + parameters: None, + previous_hash: Hash::from_hex("000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51").expect("fail to parse previous_hash"), + previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65").unwrap())), + inner_hash: None,//Some(Hash::from_hex("3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846").expect("fail to parse inner_hash")), + dividend: None, + identities: vec![], + joiners: vec![], + actives: vec![ms1], + leavers: vec![], + revoked: vec![], + excluded: vec![], + certifications: vec![], + transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))], + inner_hash_and_nonce_str: String::new(), + }; + // test inner_hash computation + block.compute_inner_hash(); + println!("{}", block.generate_compact_text()); + assert_eq!( + block + .inner_hash + .expect("Try to get inner_hash of an uncompleted or reduce block !") + .to_hex(), + "3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846" + ); + // test generate_compact_text() + let block_compact_text = block.generate_compact_text(); + assert_eq!( + block_compact_text, + "Version: 10\nType: Block\nCurrency: g1\nNumber: 165647\nPoWMin: 90\nTime: 1540633175\nMedianTime: 1540627811\nUnitBase: 0\nIssuer: A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq\nIssuersFrame: 186\nIssuersFrameVar: 0\nDifferentIssuersCount: 37\nPreviousHash: 000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51\nPreviousIssuer: 8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65\nMembersCount: 1402\nIdentities:\nJoiners:\nActives:\n4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969:gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==:165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2:74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6:piaaf31\nLeavers:\nRevoked:\nExcluded:\nCertifications:\nTransactions:\nTX:10:1:7:7:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6:SIG(0)\n7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant)\n28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2)\nPanier mixte plus 40 pommes merci\n7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==\nTX:10:1:6:6:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD)\n12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX)\nEn reglement de tes bons bocaux de fruits et legumes\nnxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg==\nInnerHash: 3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846\nNonce: " + ); + // Test signature validity + block.fill_inner_hash_and_nonce_str(Some(10_300_000_090_296)); + assert_eq!(block.verify_signatures(), VerificationResult::Valid()); + // Test hash computation + block.compute_hash(); + assert_eq!( + block + .hash + .expect("Try to get hash of an uncompleted or reduce block !") + .0 + .to_hex(), + "000002026E32A3D649B34968AAF9D03C4F19A5954229C54A801BBB1CD216B230" + ); + } } diff --git a/documents/src/v10/mod.rs b/documents/src/v10/mod.rs index 6c6653fa7457ccc4829fdbe79ebe9adabb06928d..bcad4ff71c566f938edf84cb9a83e5c574a66701 100644 --- a/documents/src/v10/mod.rs +++ b/documents/src/v10/mod.rs @@ -22,7 +22,6 @@ pub mod membership; pub mod revocation; pub mod transaction; -use crypto::digest::Digest; use dup_crypto::keys::PrivateKey; use pest::Parser; @@ -149,12 +148,6 @@ pub trait TextDocument: Document<PublicKey = PubKey, CurrencyType = str> { &text[0..(text.len() - sigs_str_len)] } - /// Return sha256 hash of text document - fn hash<H: Digest>(&self, digest: &mut H) -> String { - digest.input_str(self.as_text()); - digest.result_str() - } - /*/// Return document as text with leading signatures. fn as_text_with_signatures(&self) -> String { let mut text = self.as_text().to_string(); diff --git a/documents/src/v10/transaction.rs b/documents/src/v10/transaction.rs index c0729efc4dbb638155fd653d52ff0129bd9f254c..a3878a290579e4214dce47c417e4daa384ac8f45 100644 --- a/documents/src/v10/transaction.rs +++ b/documents/src/v10/transaction.rs @@ -15,8 +15,7 @@ //! Wrappers around Transaction documents. -use crypto::digest::Digest; -use crypto::sha2::Sha256; +use dup_crypto::hashs::*; use pest::iterators::Pair; use pest::iterators::Pairs; use pest::Parser; @@ -513,7 +512,6 @@ pub struct TransactionDocument { impl TransactionDocument { /// Compute transaction hash pub fn compute_hash(&mut self) -> Hash { - let mut sha256 = Sha256::new(); let mut hashing_text = if let Some(ref text) = self.text { text.clone() } else { @@ -522,8 +520,7 @@ impl TransactionDocument { hashing_text.push_str(&self.signatures[0].to_string()); hashing_text.push_str("\n"); //println!("tx_text_hasing={}", hashing_text); - sha256.input_str(&hashing_text); - self.hash = Some(Hash::from_hex(&sha256.result_str()).unwrap()); + self.hash = Some(Hash::compute_str(&hashing_text)); self.hash.expect("Try to get hash of a reduce tx !") } /// get transaction hash option diff --git a/message/Cargo.toml b/message/Cargo.toml index c6ec17a1bec33c514a1806ed3486c34924e9b00e..79c4e074f2d503a1dc6b2abb02e18deb25929e47 100644 --- a/message/Cargo.toml +++ b/message/Cargo.toml @@ -14,6 +14,7 @@ duniter-dal = { path = "../dal" } duniter-documents = { path = "../documents" } duniter-module = { path = "../module" } duniter-network = { path = "../network" } +durs-network-documents = { path = "../network-documents" } serde = "1.0.*" serde_derive = "1.0.*" serde_json = "1.0.*" diff --git a/message/lib.rs b/message/lib.rs index 2e0f2ade4212c08965a140c57d6f6a8173bdfe1a..d2d1e2e59ae18d2462ac849229dd801009b67d46 100644 --- a/message/lib.rs +++ b/message/lib.rs @@ -34,6 +34,7 @@ extern crate duniter_documents; extern crate duniter_module; extern crate duniter_network; extern crate dup_crypto; +extern crate durs_network_documents; extern crate serde; extern crate serde_json; @@ -45,6 +46,7 @@ use duniter_module::*; use duniter_network::{NetworkEvent, NetworkResponse, OldNetworkRequest}; use dup_crypto::hashs::Hash; use dup_crypto::keys::Sig; +use durs_network_documents::network_endpoint::EndpointEnum; #[derive(Debug, Clone)] /// Message exchanged between Durs modules @@ -76,6 +78,8 @@ pub enum DursMsgContent { Binary(Vec<u8>), /// New configuration of a module to save SaveNewModuleConf(ModuleStaticName, serde_json::Value), + /// List of local node endpoints + Endpoints(Vec<EndpointEnum>), /// Response of DALRequest DALResponse(Box<DALResponse>), /// Blockchain event diff --git a/module/Cargo.toml b/module/Cargo.toml index 97a06dd068e5afcb41f5b081be086f7d35efc519..a49bd6d9b50d2ebbddd23493e80a75cea58c1185 100644 --- a/module/Cargo.toml +++ b/module/Cargo.toml @@ -11,6 +11,7 @@ path = "lib.rs" [dependencies] dup-crypto = { path = "../crypto" } duniter-documents = { path = "../documents" } +durs-network-documents = { path = "../network-documents" } serde = "1.0.*" serde_derive = "1.0.*" serde_json = "1.0.*" diff --git a/module/lib.rs b/module/lib.rs index 5f0f39ef3047dbff6e6499f6d67bbc6b3dae4dbf..a2834f43a01f781cd34bac7336e80216be4e4a74 100644 --- a/module/lib.rs +++ b/module/lib.rs @@ -34,12 +34,14 @@ extern crate serde_derive; extern crate duniter_documents; extern crate dup_crypto; +extern crate durs_network_documents; extern crate serde; extern crate serde_json; extern crate structopt; use duniter_documents::CurrencyName; use dup_crypto::keys::{KeyPair, KeyPairEnum}; +use durs_network_documents::network_endpoint::EndpointEnum; use serde::de::DeserializeOwned; use serde::ser::{Serialize, Serializer}; use std::collections::HashSet; @@ -213,12 +215,16 @@ pub enum ModuleInitError { #[derive(Debug, Clone)] /// Type sent by each module to the rooter during initialization pub enum RooterThreadMessage<M: ModuleMessage> { - /// Channel on which the module listens - ModuleSender( + /// Number of expected modules + ModulesCount(usize), + /// Registration of the module at the rooter + ModuleRegistration( ModuleStaticName, mpsc::Sender<M>, Vec<ModuleRole>, Vec<ModuleEvent>, + Vec<String>, + Vec<EndpointEnum>, ), /// Module message ModuleMessage(M), diff --git a/network-documents/Cargo.toml b/network-documents/Cargo.toml index be4f452368f614bfe47734ded628fd8ac2476cd3..9785dbd526e7856d24b6ce57fe35e941a62be669 100644 --- a/network-documents/Cargo.toml +++ b/network-documents/Cargo.toml @@ -12,6 +12,7 @@ path = "src/lib.rs" base58 = "0.1.*" dup-crypto = { path = "../crypto" } duniter-documents = { path = "../documents" } +hex = "0.3.*" pest = "2.0" pest_derive = "2.0" serde = "1.0.*" diff --git a/network-documents/src/lib.rs b/network-documents/src/lib.rs index 784fac492a0db57fe60cb27519136493d97a5065..e2fc967a0009ea9fc11454ade98f78a058dd28ef 100644 --- a/network-documents/src/lib.rs +++ b/network-documents/src/lib.rs @@ -29,6 +29,7 @@ extern crate base58; extern crate duniter_documents; extern crate dup_crypto; +extern crate hex; extern crate pest; #[macro_use] extern crate pest_derive; @@ -55,6 +56,12 @@ use std::fmt::{Display, Error, Formatter}; /// Parser for network documents struct NetworkDocsParser; +#[derive(Debug, Clone, PartialEq, Eq)] +/// ParseError +pub enum ParseError { + /// Pest grammar error + PestError(String), +} #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Random identifier with which several Duniter nodes with the same network keypair can be differentiated pub struct NodeId(pub u32); @@ -134,9 +141,8 @@ mod tests { let node_id = NodeId(u32::from_str_radix("c1c39a0a", 16).unwrap()); let full_id = NodeFullId(node_id, issuer); assert_eq!( - EndpointEnum::parse_from_raw("WS2P c1c39a0a i3.ifee.fr 80 /ws2p", issuer, 0, 0, 1), - Ok(EndpointEnum::V1(EndpointEnumV1 { - version: 1, + EndpointV1::parse_from_raw("WS2P c1c39a0a i3.ifee.fr 80 /ws2p", issuer, 0, 0), + Ok(EndpointV1 { issuer, api: NetworkEndpointApi(String::from("WS2P")), node_id: Some(node_id), @@ -147,7 +153,7 @@ mod tests { raw_endpoint: String::from("WS2P c1c39a0a i3.ifee.fr 80 /ws2p"), last_check: 0, status: 0, - },)) + }) ); } @@ -160,9 +166,8 @@ mod tests { let node_id = NodeId(u32::from_str_radix("cb06a19b", 16).unwrap()); let full_id = NodeFullId(node_id, issuer); assert_eq!( - EndpointEnum::parse_from_raw("WS2P cb06a19b g1.imirhil.fr 53012 /", issuer, 0, 0, 1), - Ok(EndpointEnum::V1(EndpointEnumV1 { - version: 1, + EndpointV1::parse_from_raw("WS2P cb06a19b g1.imirhil.fr 53012", issuer, 0, 0), + Ok(EndpointV1 { issuer, api: NetworkEndpointApi(String::from("WS2P")), node_id: Some(node_id), @@ -170,10 +175,10 @@ mod tests { host: String::from("g1.imirhil.fr"), port: 53012, path: None, - raw_endpoint: String::from("WS2P cb06a19b g1.imirhil.fr 53012 /"), + raw_endpoint: String::from("WS2P cb06a19b g1.imirhil.fr 53012"), last_check: 0, status: 0, - },)) + }) ); } } diff --git a/network-documents/src/network_documents.pest b/network-documents/src/network_documents.pest index 44b3b35d42af28a4b4cb46c1d7f10e7cf77994d2..5461807299b8949616d2d5c7312cd65de0d80761 100644 --- a/network-documents/src/network_documents.pest +++ b/network-documents/src/network_documents.pest @@ -1,16 +1,99 @@ //r"^(?P<api>[A-Z0-9_]+) (?P<version>[1-9][0-9]*)? ?(?P<uuid>[a-f0-9]{6,8})? ?(?P<host>[a-z_][a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+) (?P<port>[0-9]+)(?: /?(?P<path>.+)?)? *$" +WHITESPACE = _{ "" } +// Single character rules +nl = _{ "\n" } +no_zero_hexa_lower = @{ '1'..'9' | 'a'..'f' } +hexa_lower = @{ ASCII_DIGIT | 'a'..'f' } +hexa_upper = @{ ASCII_DIGIT | 'A'..'F' } +base58 = { !("O" | "I" | "l") ~ ASCII_ALPHANUMERIC } +base64 = { ASCII_ALPHANUMERIC | "+" | "/" } + +// Numbers rules +tens = @{ '1'..'9' ~ ASCII_DIGIT } +u8_hundreds = @{ ("2" ~ ('0'..'4' ~ ASCII_DIGIT | ('0'..'5'){2})) | ("1" ~ ASCII_DIGIT{2}) } +u8 = @{ u8_hundreds | tens | ASCII_DIGIT } no_zero_u_int = @{ '1'..'9' ~ ASCII_DIGIT* } u_int = @{ "0" | no_zero_u_int } -api_name = @{ (ASCII_ALPHA_UPPER | ASCII_DIGIT)+ } -version = @{ u_int } -node_id = @{ ASCII_HEX_DIGIT{6,8} } +// Usefull types rules +currency = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_"){,255} } +block_id = @{ u_int } +hash = @{ hexa_upper{64} } +pubkey = @{ base58{43,44} } +blockstamp = ${ block_id ~ "-" ~ hash } +ed25519_sig = @{ base64{88} | (base64{87} ~ "=") | (base64{86} ~ "==") } + +// Endpoint v1 rules +api_name = @{ (ASCII_ALPHA_UPPER | ASCII_DIGIT | "_")+ } +node_id = @{ hexa_lower{1,8} } host = @{ ASCII_ALPHA_LOWER ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT | "-" | "_" | ".")* } port = @{ u_int } path_inner = @{ (ASCII_ALPHANUMERIC | "-" | "_" | ".")+ } -path = _{ "/"? ~ path_inner } -endpoint_v1 = { api_name ~ version? ~ node_id? ~ host ~ port ~ path? } +endpoint_v1 = ${ api_name ~ (" " ~ node_id)? ~ " " ~ host ~ " " ~ port ~ (" " ~ "/"? ~ path_inner)? ~ " "? } + +// IP v6 rules +ip6_seg = _{ hexa_lower{1,4} } +ip6_full = _{ (ip6_seg ~ ":"){7} ~ ip6_seg } +ip6_no_full = @{ + ip6_seg? ~ + (":" ~ ip6_seg){0,6} ~ + "::" ~ + (ip6_seg ~ ":"){0,6} ~ + ip6_seg? + // (IPV6SEG:){7,7}IPV6SEG| # 1:2:3:4:5:6:7:8 + // (IPV6SEG:){1,7}:| # 1:: 1:2:3:4:5:6:7:: + // (IPV6SEG:){1,6}:IPV6SEG| # 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + // (IPV6SEG:){1,5}(:IPV6SEG){1,2}| # 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + // (IPV6SEG:){1,4}(:IPV6SEG){1,3}| # 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + // (IPV6SEG:){1,3}(:IPV6SEG){1,4}| # 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + // (IPV6SEG:){1,2}(:IPV6SEG){1,5}| # 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + // IPV6SEG:((:IPV6SEG){1,6})| # 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + // :((:IPV6SEG){1,7}|:)| # ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + +} +ip6_inner = @{ ip6_full | ip6_no_full } +ip6 = _{ "[" ~ ip6_inner ~ "] " } + +// Endpoint v2 rules +api_version_inner = @{ no_zero_u_int } +api_version = _{ "V" ~ api_version_inner ~ " " } +tls = @{ "S " } +tor = @{ "TOR " } +network_features = _{ tls? ~ tor? } +api_features_inner = @{ (hexa_lower{2})+ | no_zero_hexa_lower } +api_features = _{ api_features_inner ~ " " } +host_v2_inner = @{ ASCII_ALPHA_LOWER ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT | "-" | "_" | ".")* } +host_v2 = _{ host_v2_inner ~ " " } +ip4_inner = { u8 ~ "." ~ u8 ~ "." ~ u8 ~ "." ~ u8 } +ip4 = _{ ip4_inner ~ " " } +path = _{ " " ~ path_inner } +endpoint_v2 = ${ api_name ~ " " ~ (api_version)? ~ (network_features)? ~ (api_features)? ~ host_v2? ~ ip4? ~ ip6? ~ port ~ path? } + +// Peer v11 rules +peer_v11 = ${ "11:" ~ currency ~ ":" ~ node_id ~ ":" ~ pubkey ~ ":" ~ blockstamp ~ nl ~ (endpoint_v2 ~ nl)+ ~ ed25519_sig? } + +// HEADv3 rules +api_outgoing_conf = @{ u8 } +api_incoming_conf = @{ u8 } +free_member_rooms = @{ u8 } +free_mirror_rooms = @{ u8 } +software = @{ ASCII_ALPHA ~ ASCII_ALPHANUMERIC* } +soft_version = @{ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ ("-" ~ ("a" | "b" | "rc") ~ ASCII_DIGIT ~ ("." ~ ASCII_DIGIT){0,2})? } +step = @{ u_int } -WHITESPACE = _{ " " } \ No newline at end of file +head_v3 = ${ + "3:" ~ currency ~ ":" ~ + api_outgoing_conf ~ ":" ~ + api_incoming_conf ~ ":" ~ + free_member_rooms ~ ":" ~ + free_mirror_rooms ~ ":" ~ + node_id ~ ":" ~ + pubkey ~ ":" ~ + blockstamp ~ ":" ~ + software ~ ":" ~ + soft_version ~ nl ~ + ed25519_sig? ~ + (nl ~ step)? +} diff --git a/network-documents/src/network_endpoint.rs b/network-documents/src/network_endpoint.rs index 62c7feaf40fda5337efe76e60dcb9cd930a9eeb7..479c8c3e09a0722b9ad3d572448996bbf2f0573e 100644 --- a/network-documents/src/network_endpoint.rs +++ b/network-documents/src/network_endpoint.rs @@ -21,9 +21,10 @@ extern crate serde; use dup_crypto::hashs::Hash; use dup_crypto::keys::PubKey; +use hex; +use pest::iterators::Pair; use pest::Parser; -use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr}; -use std::num::ParseIntError; +use std::net::{Ipv4Addr, Ipv6Addr}; use std::str::FromStr; use *; @@ -39,100 +40,26 @@ pub static MAX_API_FEATURES_COUNT: &'static usize = &2040; pub struct ApiFeatures(pub Vec<u8>); impl ApiFeatures { - fn to_string_for_api(&self, api: &NetworkEndpointApi) -> String { - match api.0.as_str() { - "WS2P" => { - let mut af_count = 0; - let def = if self.0[0] | 0b_1111_1110 == 255u8 { - af_count += 1; - " DEF" - } else { - "" - }; - let low = if self.0[0] | 0b_1111_1101 == 255u8 { - af_count += 1; - " LOW" - } else { - "" - }; - let abf = if self.0[0] | 0b_1111_1011 == 255u8 { - af_count += 1; - " ABF" - } else { - "" - }; - format!("{}{}{}{}", af_count, def, low, abf) + fn is_empty(&self) -> bool { + for byte in &self.0 { + if *byte > 0u8 { + return false; } - _ => String::from(""), } + true } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -/// ParseEndpointError -pub enum ParseEndpointError { - /// VersionNotSupported - VersionNotSupported(), - /// WrongV1Format - WrongV1Format(String), - /// WrongV2Format (human-readable explanation) - WrongV2Format(&'static str), - /// ApiNameTooLong - ApiNameTooLong(), - /// ParseIntError - ParseIntError(ParseIntError), - /// UnknowNetworkFeature (feature name) - UnknowNetworkFeature(String), - /// Maximum number of network features exceeded - MaxNetworkFeatures(), - /// Maximum number of api features exceeded - MaxApiFeatures(), - /// UnknowApiFeature (feature name) - UnknowApiFeature(String), - /// TooHighApiFeature - TooHighApiFeature(), - /// IP Parse error - AddrParseError(AddrParseError), -} -impl From<ParseIntError> for ParseEndpointError { - fn from(e: ParseIntError) -> Self { - ParseEndpointError::ParseIntError(e) - } -} - -impl From<AddrParseError> for ParseEndpointError { - fn from(e: AddrParseError) -> Self { - ParseEndpointError::AddrParseError(e) - } -} - -#[derive(Debug)] -/// Error when converting a byte vector to Endpoint -pub enum EndpointReadBytesError { - /// Bytes vector is too short - TooShort(), - /// Bytes vector is too long - TooLong(), - /// Wrong api datas Length - WrongApiDatasLen(), - /// Unknow api name - UnknowApiName(), - /// IoError - IoError(::std::io::Error), - /// FromUtf8Error - FromUtf8Error(::std::string::FromUtf8Error), -} - -impl From<::std::io::Error> for EndpointReadBytesError { - fn from(e: ::std::io::Error) -> Self { - EndpointReadBytesError::IoError(e) - } -} - -impl From<::std::string::FromUtf8Error> for EndpointReadBytesError { - fn from(e: ::std::string::FromUtf8Error) -> Self { - EndpointReadBytesError::FromUtf8Error(e) + fn to_string(&self) -> String { + if self.is_empty() { + String::from("") + } else { + let hex_str = hex::encode(self.0.clone()); + if hex_str.len() == 2 { + format!("{} ", &hex_str[1..]) + } else { + format!("{} ", hex_str) + } + } } } @@ -142,9 +69,7 @@ pub struct NetworkEndpointApi(pub String); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Endpoint v1 -pub struct EndpointEnumV1 { - /// API version - pub version: usize, +pub struct EndpointV1 { /// API Name pub api: NetworkEndpointApi, /// Node unique identifier @@ -167,42 +92,129 @@ pub struct EndpointEnumV1 { pub last_check: u64, } +impl EndpointV1 { + /// Accessors providing node full identifier + pub fn node_full_id(&self) -> Option<NodeFullId> { + match self.node_id { + Some(node_id) => Some(NodeFullId(node_id, self.issuer)), + None => None, + } + } + /// Generate endpoint url + pub fn get_url(&self, get_protocol: bool, _supported_ip_v6: bool) -> Option<String> { + let protocol = match &self.api.0[..] { + "WS2P" | "WS2PTOR" => "ws", + _ => "http", + }; + let tls = match self.port { + 443 => "s", + _ => "", + }; + let path = match self.path { + Some(ref path_string) => path_string.clone(), + None => String::new(), + }; + if get_protocol { + Some(format!( + "{}{}://{}:{}/{}", + protocol, tls, self.host, self.port, path + )) + } else { + Some(format!("{}:{}/{}", self.host, self.port, path)) + } + } + /// Generate from pest pair + fn from_pest_pair( + pair: Pair<Rule>, + issuer: PubKey, + status: u32, + last_check: u64, + ) -> EndpointV1 { + let raw_endpoint = String::from(pair.as_str()); + let mut api_name = ""; + let mut node_id = None; + let mut hash_full_id = None; + let mut host_str = ""; + let mut port = 0; + let mut path = None; + + for ep_pair in pair.into_inner() { + match ep_pair.as_rule() { + Rule::api_name => api_name = ep_pair.as_str(), + Rule::node_id => { + node_id = Some(NodeId(u32::from_str_radix(ep_pair.as_str(), 16).unwrap())); + hash_full_id = match node_id { + Some(node_id_) => Some(NodeFullId(node_id_, issuer).sha256()), + None => None, + }; + } + Rule::host => host_str = ep_pair.as_str(), + Rule::port => port = ep_pair.as_str().parse().unwrap(), + Rule::path_inner => path = Some(String::from(ep_pair.as_str())), + _ => panic!("unexpected rule: {:?}", ep_pair.as_rule()), // Grammar ensures that we never reach this line + } + } + EndpointV1 { + issuer, + api: NetworkEndpointApi(String::from(api_name)), + node_id, + hash_full_id, + host: String::from(host_str), + port, + path, + raw_endpoint, + status, + last_check, + } + } + + /// parse from ut8 format + pub fn parse_from_raw( + raw_endpoint: &str, + issuer: PubKey, + status: u32, + last_check: u64, + ) -> Result<EndpointV1, ParseError> { + match NetworkDocsParser::parse(Rule::endpoint_v1, raw_endpoint) { + Ok(mut ep_v1_pairs) => Ok(EndpointV1::from_pest_pair( + ep_v1_pairs.next().unwrap(), + issuer, + status, + last_check, + )), + Err(pest_error) => Err(ParseError::PestError(format!("{}", pest_error))), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Network features pub struct EndpointV2NetworkFeatures(pub Vec<u8>); impl ToString for EndpointV2NetworkFeatures { fn to_string(&self) -> String { + if self.is_empty() { + return "".to_owned(); + } + let mut features_str = Vec::with_capacity(2); if self.tls() { - String::from("1 TLS") - } else if self.tor() { - String::from("1 TOR") - } else { - String::from("") + features_str.push("S"); + } + if self.tor() { + features_str.push("TOR"); } + format!("{} ", features_str.join(" ")) } } impl EndpointV2NetworkFeatures { - /// Parse network features from utf8 string's array - pub fn from_str_array( - str_array: &[&str], - ) -> Result<EndpointV2NetworkFeatures, ParseEndpointError> { - let mut network_features = 0u8; - for nf_str in str_array { - match *nf_str { - "IP4" => network_features += 1u8, - "IP6" => network_features += 2u8, - "TLS" => network_features += 4u8, - "TOR" => network_features += 8u8, - &_ => { - return Err(ParseEndpointError::UnknowNetworkFeature(String::from( - *nf_str, - ))) - } + fn is_empty(&self) -> bool { + for byte in &self.0 { + if *byte > 0u8 { + return false; } } - Ok(EndpointV2NetworkFeatures(vec![network_features])) + true } /// Network features size pub fn size(&self) -> u8 { @@ -212,21 +224,13 @@ impl EndpointV2NetworkFeatures { pub fn to_bytes_slice(&self) -> &[u8] { &self.0 } - /// network feature ip_v4 is enable ? - pub fn ip_v4(&self) -> bool { - self.0[0] & 0b0000_0001 == 1u8 - } - /// network feature ip_v6 is enable ? - pub fn ip_v6(&self) -> bool { - self.0[0] & 0b0000_0010 == 2u8 - } /// TLS feature is enable ? pub fn tls(&self) -> bool { - self.0[0] & 0b0000_0100 == 4u8 + self.0[0] & 0b0000_0001 == 1u8 } /// TOR feature is enable ? pub fn tor(&self) -> bool { - self.0[0] & 0b0000_1000 == 8u8 + self.0[0] & 0b0000_0010 == 2u8 } } @@ -281,17 +285,21 @@ impl ToString for EndpointV2 { } else { String::from("") }; - let path: &str = if let Some(ref path) = self.path { - path + let path = if let Some(ref path) = self.path { + format!(" {}", path) } else { - "" + "".to_owned() }; format!( - "{api} {version} {nf} {af} {port} {host}{ip4}{ip6}{path}", + "{api} {version}{nf}{af}{host}{ip4}{ip6}{port}{path}", api = self.api.0, - version = self.api_version, + version = if self.api_version > 0 { + format!("V{} ", self.api_version) + } else { + "".to_owned() + }, nf = self.network_features.to_string(), - af = self.api_features.to_string_for_api(&self.api), + af = self.api_features.to_string(), port = self.port, host = host, ip4 = ip4, @@ -301,47 +309,6 @@ impl ToString for EndpointV2 { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -/// Size informations of Endpoint v2 -pub struct EndpointV2Size { - /// Api nalme size - pub api_size: u8, - /// Hostname size - pub host_size: u8, - /// Optional path size - pub path_size: u8, - /// Network features size - pub nf_size: u8, - /// Network feature ip_v4 - pub ip_v4: bool, - /// Network feature ip_v6 - pub ip_v6: bool, - /// Api features size - pub af_size: u8, -} - -impl EndpointV2Size { - /// Compute total size of endpoint in binary format - pub fn total_size(self) -> usize { - let mut total_size = self.api_size as usize - + self.host_size as usize - + self.path_size as usize - + self.nf_size as usize - + self.af_size as usize - + ENDPOINTV2_FIXED_SIZE; - if self.api_size == 0u8 { - total_size += 1; - } - if self.ip_v4 { - total_size += 4; - } - if self.ip_v6 { - total_size += 16; - } - total_size - } -} - impl EndpointV2 { /// Generate endpoint url pub fn get_url(&self, get_protocol: bool, supported_ip_v6: bool) -> Option<String> { @@ -375,232 +342,60 @@ impl EndpointV2 { Some(format!("{}:{}/{}", host, self.port, path)) } } - /// parse from ut8 format - pub fn parse_from_raw( - raw_endpoint: &str, - _status: u32, - _last_check: u64, - ) -> Result<EndpointEnum, ParseEndpointError> { - let raw_ep_elements: Vec<&str> = raw_endpoint.split(' ').collect(); - if raw_ep_elements.len() >= 6 { - let api = NetworkEndpointApi(String::from(raw_ep_elements[0])); - let api_version: u16 = raw_ep_elements[1].parse()?; - let network_features_count: usize = raw_ep_elements[2].parse()?; - if network_features_count > *MAX_NETWORK_FEATURES_COUNT { - Err(ParseEndpointError::MaxNetworkFeatures()) - } else if raw_ep_elements.len() >= 6 + network_features_count { - let network_features = EndpointV2NetworkFeatures::from_str_array( - &raw_ep_elements[3..(3 + network_features_count)], - )?; - let api_features_count: usize = - raw_ep_elements[3 + network_features_count].parse()?; - if network_features_count > *MAX_API_FEATURES_COUNT { - Err(ParseEndpointError::MaxApiFeatures()) - } else { - let mut af_bytes_count = network_features_count / 8; - if network_features_count % 8 != 0 { - af_bytes_count += 1; - } - let mut api_features = vec![0u8; af_bytes_count]; - if raw_ep_elements.len() < 4 + network_features_count + api_features_count { - return Err(ParseEndpointError::WrongV2Format( - "All api features must be declared !", - )); - } - for str_feature in raw_ep_elements - .iter() - .take(4 + network_features_count + api_features_count) - .skip(4 + network_features_count) - { - if let Ok(feature) = str_feature.parse::<usize>() { - if feature > *MAX_API_FEATURES_COUNT { - return Err(ParseEndpointError::TooHighApiFeature()); - } - let byte_index = feature / 8; - let feature = (feature % 8) as u8; - api_features[byte_index] += feature.pow(2); - } else if &api.0 == "WS2P" { - match *str_feature { - "DEF" => api_features[0] += 1u8, - "LOW" => api_features[0] += 2u8, - "ABF" => api_features[0] += 4u8, - _ => { - return Err(ParseEndpointError::UnknowApiFeature(String::from( - *str_feature, - ))) - } - } - } else { - return Err(ParseEndpointError::UnknowApiFeature(String::from( - *str_feature, - ))); - } - } - let mut index = 4 + network_features_count + api_features_count; - let port = if let Ok(port) = raw_ep_elements[index].parse::<u16>() { - index += 1; - port - } else { - return Err(ParseEndpointError::WrongV2Format( - "Missing port or is not integer !", - )); - }; - // HOST IP4 [IP6] PATH - let (host, ip_v4, ip_v6, path) = if raw_ep_elements.len() == index + 4 { - // HOST IP4 [IP6] PATH - let len2 = raw_ep_elements[index + 2].len(); - ( - Some(String::from(raw_ep_elements[index])), - Some(Ipv4Addr::from_str(raw_ep_elements[index + 1])?), - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 2][1..len2 - 1], - )?), - Some(String::from(raw_ep_elements[index + 3])), - ) - } else if raw_ep_elements.len() == index + 3 { - // IP4 [IP6] PATH - if let Ok(ip_v4) = Ipv4Addr::from_str(raw_ep_elements[index]) { - let len1 = raw_ep_elements[index + 1].len(); - ( - None, - Some(ip_v4), - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 1][1..len1 - 1], - )?), - Some(String::from(raw_ep_elements[index + 2])), - ) - } else { - let len1 = raw_ep_elements[index + 1].len(); - let len2 = raw_ep_elements[index + 2].len(); - if let Some('[') = raw_ep_elements[index + 1].chars().next() { - // HOST [IP6] PATH - ( - Some(String::from(raw_ep_elements[index])), - None, - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 1][1..len1 - 1], - )?), - Some(String::from(raw_ep_elements[index + 2])), - ) - } else if let Some('[') = raw_ep_elements[index + 2].chars().next() { - // HOST IP4 [IP6] - ( - Some(String::from(raw_ep_elements[index])), - Some(Ipv4Addr::from_str(raw_ep_elements[index + 1])?), - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 2][1..len2 - 1], - )?), - None, - ) - } else { - // HOST IP4 PATH - ( - Some(String::from(raw_ep_elements[index])), - Some(Ipv4Addr::from_str(raw_ep_elements[index + 1])?), - None, - Some(String::from(raw_ep_elements[index + 2])), - ) - } - } - } else if raw_ep_elements.len() == index + 2 { - let len0 = raw_ep_elements[index].len(); - let len1 = raw_ep_elements[index + 1].len(); - if let Ok(ip_v4) = Ipv4Addr::from_str(raw_ep_elements[index]) { - if let Some('[') = raw_ep_elements[index + 1].chars().next() { - // IP4 [IP6] - ( - None, - Some(ip_v4), - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 1][1..len1 - 1], - )?), - None, - ) - } else { - // IP4 PATH - ( - None, - Some(ip_v4), - None, - Some(String::from(raw_ep_elements[index + 1])), - ) - } - } else if let Some('[') = raw_ep_elements[index].chars().next() { - // [IP6] PATH - ( - None, - None, - Some(Ipv6Addr::from_str(&raw_ep_elements[index][1..len0 - 1])?), - Some(String::from(raw_ep_elements[index + 1])), - ) - } else if let Ok(ip_v4) = Ipv4Addr::from_str(raw_ep_elements[index + 1]) { - // HOST IP4 - ( - Some(String::from(raw_ep_elements[index])), - Some(ip_v4), - None, - None, - ) - } else if let Some('[') = raw_ep_elements[index + 1].chars().next() { - // HOST [IP6] - ( - Some(String::from(raw_ep_elements[index])), - None, - Some(Ipv6Addr::from_str( - &raw_ep_elements[index + 1][1..len1 - 1], - )?), - None, - ) - } else { - // HOST PATH - ( - Some(String::from(raw_ep_elements[index])), - None, - None, - Some(String::from(raw_ep_elements[index + 1])), - ) - } - } else if raw_ep_elements.len() == index + 1 { - let len0 = raw_ep_elements[index].len(); - if let Some('[') = raw_ep_elements[index].chars().next() { - // IP6 - ( - None, - None, - Some(Ipv6Addr::from_str(&raw_ep_elements[index][1..len0])?), - None, - ) - } else if let Ok(ip_v4) = Ipv4Addr::from_str(raw_ep_elements[index]) { - // IP4 - (None, Some(ip_v4), None, None) - } else { - // HOST - (Some(String::from(raw_ep_elements[index])), None, None, None) - } + /// Generate from pest pair + pub fn from_pest_pair(pair: Pair<Rule>) -> EndpointV2 { + let mut api_str = ""; + let mut api_version = 0; + let mut network_features = EndpointV2NetworkFeatures(vec![0u8]); + let mut api_features = ApiFeatures(vec![]); + let mut ip_v4 = None; + let mut ip_v6 = None; + let mut host = None; + let mut port = 0; + let mut path = None; + for field in pair.into_inner() { + match field.as_rule() { + Rule::api_name => api_str = field.as_str(), + Rule::api_version_inner => api_version = field.as_str().parse().unwrap(), + Rule::tls => network_features.0[0] |= 0b_0000_0001, + Rule::tor => network_features.0[0] |= 0b_0000_0010, + Rule::api_features_inner => { + api_features = if field.as_str().len() == 1 { + ApiFeatures(hex::decode(&format!("0{}", field.as_str())).unwrap()) } else { - return Err(ParseEndpointError::WrongV2Format("Invalid fields count !")); + ApiFeatures(hex::decode(field.as_str()).unwrap()) }; - Ok(EndpointEnum::V2(EndpointV2 { - api, - api_version, - network_features, - api_features: ApiFeatures(api_features.to_vec()), - ip_v4, - ip_v6, - host, - port, - path, - })) } - } else { - Err(ParseEndpointError::WrongV2Format( - "All network features must be declared !", - )) + Rule::port => port = field.as_str().parse().unwrap(), + Rule::host_v2_inner => host = Some(String::from(field.as_str())), + Rule::ip4_inner => ip_v4 = Some(Ipv4Addr::from_str(field.as_str()).unwrap()), + Rule::ip6_inner => ip_v6 = Some(Ipv6Addr::from_str(field.as_str()).unwrap()), + Rule::path_inner => path = Some(String::from(field.as_str())), + _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line } - } else { - Err(ParseEndpointError::WrongV2Format( - "An endpoint must contain at least 6 elements", - )) + } + if network_features.is_empty() { + network_features = EndpointV2NetworkFeatures(vec![]); + } + EndpointV2 { + api: NetworkEndpointApi(String::from(api_str)), + api_version, + network_features, + api_features, + ip_v4, + ip_v6, + host, + port, + path, + } + } + /// parse from raw ascii format + pub fn parse_from_raw(raw_endpoint: &str) -> Result<EndpointEnum, ParseError> { + match NetworkDocsParser::parse(Rule::endpoint_v2, raw_endpoint) { + Ok(mut ep_v2_pairs) => Ok(EndpointEnum::V2(EndpointV2::from_pest_pair( + ep_v2_pairs.next().unwrap(), + ))), + Err(pest_error) => Err(ParseError::PestError(format!("{}", pest_error))), } } } @@ -609,7 +404,7 @@ impl EndpointV2 { /// Endpoint pub enum EndpointEnum { /// Endpoint v1 - V1(EndpointEnumV1), + V1(EndpointV1), /// Endpoint v2 V2(EndpointV2), } @@ -645,13 +440,6 @@ impl EndpointEnum { EndpointEnum::V2(ref _ep) => unreachable!(), } } - /// Accessors providing node full identifier - pub fn node_full_id(&self) -> Option<NodeFullId> { - match self.node_uuid() { - Some(node_id) => Some(NodeFullId(node_id, self.pubkey())), - None => None, - } - } /// Accessors providing port number pub fn port(&self) -> usize { match *self { @@ -715,103 +503,6 @@ impl EndpointEnum { EndpointEnum::V2(ref ep_v2) => ep_v2.get_url(get_protocol, supported_ip_v6), } } - /// Parse Endpoint from raw format - pub fn parse_from_raw( - raw_endpoint: &str, - issuer: PubKey, - status: u32, - last_check: u64, - endpoint_version: u16, - ) -> Result<EndpointEnum, ParseEndpointError> { - match endpoint_version { - 1 => match NetworkDocsParser::parse(Rule::endpoint_v1, raw_endpoint) { - Ok(mut ep_ast) => { - let ep_pairs = ep_ast.next().unwrap().into_inner(); // get and unwrap the `envpoint_v1` rule; never fails - - let mut api_name = ""; - let mut node_id = None; - let mut hash_full_id = None; - let mut host_str = ""; - let mut port = 0; - let mut path = None; - - for ep_pair in ep_pairs { - match ep_pair.as_rule() { - Rule::api_name => api_name = ep_pair.as_str(), - Rule::node_id => { - node_id = match u32::from_str_radix(ep_pair.as_str(), 16) { - Ok(node_id) => Some(NodeId(node_id)), - Err(_) => { - return Err(ParseEndpointError::WrongV1Format( - "NodeId must be an hexadecimal string !".to_owned(), - )) - } - }; - hash_full_id = match node_id { - Some(node_id_) => Some(NodeFullId(node_id_, issuer).sha256()), - None => None, - }; - } - Rule::host => host_str = ep_pair.as_str(), - Rule::port => port = ep_pair.as_str().parse().unwrap(), - Rule::path_inner => path = Some(String::from(ep_pair.as_str())), - _ => panic!("unexpected rule: {:?}", ep_pair.as_rule()), // Grammar ensures that we never reach this line - } - } - Ok(EndpointEnum::V1(EndpointEnumV1 { - version: 1, - issuer, - api: NetworkEndpointApi(String::from(api_name)), - node_id, - hash_full_id, - host: String::from(host_str), - port, - path, - raw_endpoint: String::from(raw_endpoint), - status, - last_check, - })) - } - Err(e) => Err(ParseEndpointError::WrongV1Format(format!("{}", e))), - }, - /*match ENDPOINT_V1_REGEX.captures(raw_endpoint) { - Some(caps) => { - let node_id = match caps.name("uuid") { - Some(caps_node_id) => { - match u32::from_str_radix(caps_node_id.as_str(), 16) { - Ok(node_id) => Some(NodeId(node_id)), - Err(_) => None, - } - } - None => None, - }; - let hash_full_id = match node_id { - Some(node_id_) => Some(NodeFullId(node_id_, issuer).sha256()), - None => None, - }; - Ok(EndpointEnum::V1(EndpointEnumV1 { - version: 1, - issuer, - api: NetworkEndpointApi(String::from(&caps["api"])), - node_id, - hash_full_id, - host: String::from(&caps["host"]), - port: caps["port"].parse().unwrap_or(80), - path: match caps.name("path") { - Some(m) => Some(m.as_str().to_string()), - None => None, - }, - raw_endpoint: String::from(raw_endpoint), - status, - last_check, - })) - } - None => Err(ParseEndpointError::WrongV1Format()), - },*/ - 2 => EndpointV2::parse_from_raw(raw_endpoint, status, last_check), - _ => Err(ParseEndpointError::VersionNotSupported()), - } - } } #[cfg(test)] @@ -819,9 +510,31 @@ mod tests { use super::*; use tests::bincode::{deserialize, serialize}; + #[test] + fn test_network_features() { + assert_eq!(EndpointV2NetworkFeatures(vec![1u8]).tls(), true); + assert_eq!(EndpointV2NetworkFeatures(vec![1u8]).tor(), false); + assert_eq!(EndpointV2NetworkFeatures(vec![2u8]).tls(), false); + assert_eq!(EndpointV2NetworkFeatures(vec![2u8]).tor(), true); + assert_eq!(EndpointV2NetworkFeatures(vec![3u8]).tls(), true); + assert_eq!(EndpointV2NetworkFeatures(vec![3u8]).tor(), true); + + assert_eq!( + EndpointV2NetworkFeatures(vec![1u8]).to_string().as_str(), + "S " + ); + assert_eq!( + EndpointV2NetworkFeatures(vec![2u8]).to_string().as_str(), + "TOR " + ); + assert_eq!( + EndpointV2NetworkFeatures(vec![3u8]).to_string().as_str(), + "S TOR " + ); + } fn test_parse_and_read_endpoint(str_endpoint: &str, endpoint: EndpointV2) { assert_eq!( - EndpointV2::parse_from_raw(str_endpoint, 0, 0), + EndpointV2::parse_from_raw(str_endpoint), Ok(EndpointEnum::V2(endpoint.clone())), ); let binary_endpoint = serialize(&endpoint).expect("Fail to serialize endpoint !"); @@ -831,13 +544,47 @@ mod tests { assert_eq!(str_endpoint, endpoint.to_string()); } + #[test] + fn test_parse_and_read_minimal_endpoint() { + let str_endpoint = "UNKNOWN_API 8080"; + let endpoint = EndpointV2 { + api: NetworkEndpointApi(String::from("UNKNOWN_API")), + api_version: 0, + network_features: EndpointV2NetworkFeatures(vec![]), + api_features: ApiFeatures(vec![]), + ip_v4: None, + ip_v6: None, + host: None, + port: 8080u16, + path: None, + }; + test_parse_and_read_endpoint(str_endpoint, endpoint); + } + + #[test] + fn test_parse_and_read_classic_v1_endpoint() { + let str_endpoint = "ES_CORE_API g1.data.duniter.fr 443"; + let endpoint = EndpointV2 { + api: NetworkEndpointApi(String::from("ES_CORE_API")), + api_version: 0, + network_features: EndpointV2NetworkFeatures(vec![]), + api_features: ApiFeatures(vec![]), + ip_v4: None, + ip_v6: None, + host: Some(String::from("g1.data.duniter.fr")), + port: 443u16, + path: None, + }; + test_parse_and_read_endpoint(str_endpoint, endpoint); + } + #[test] fn test_parse_and_read_endpoint_with_host() { - let str_endpoint = "WS2P 2 1 TLS 3 DEF LOW ABF 443 g1.durs.ifee.fr ws2p"; + let str_endpoint = "WS2P V2 S 7 g1.durs.ifee.fr 443 ws2p"; let endpoint = EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: None, ip_v6: None, @@ -850,11 +597,11 @@ mod tests { #[test] fn test_parse_and_read_endpoint_with_ipv4() { - let str_endpoint = "WS2P 2 1 TLS 3 DEF LOW ABF 443 84.16.72.210 ws2p"; + let str_endpoint = "WS2P V2 S 7 84.16.72.210 443 ws2p"; let endpoint = EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: Some(Ipv4Addr::from_str("84.16.72.210").unwrap()), ip_v6: None, @@ -867,11 +614,11 @@ mod tests { #[test] fn test_parse_and_read_endpoint_with_ipv6() { - let str_endpoint = "WS2P 2 1 TLS 3 DEF LOW ABF 443 [2001:41d0:8:c5aa::1] ws2p"; + let str_endpoint = "WS2P V2 S 7 [2001:41d0:8:c5aa::1] 443 ws2p"; let endpoint = EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: None, ip_v6: Some(Ipv6Addr::from_str("2001:41d0:8:c5aa::1").unwrap()), @@ -884,12 +631,11 @@ mod tests { #[test] fn test_parse_and_read_endpoint_with_ipv4_and_ip_v6() { - let str_endpoint = - "WS2P 2 1 TLS 3 DEF LOW ABF 443 5.135.188.170 [2001:41d0:8:c5aa::1] ws2p"; + let str_endpoint = "WS2P V2 S 7 5.135.188.170 [2001:41d0:8:c5aa::1] 443 ws2p"; let endpoint = EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: Some(Ipv4Addr::from_str("5.135.188.170").unwrap()), ip_v6: Some(Ipv6Addr::from_str("2001:41d0:8:c5aa::1").unwrap()), @@ -899,4 +645,21 @@ mod tests { }; test_parse_and_read_endpoint(str_endpoint, endpoint); } + + #[test] + fn test_parse_and_read_endpoint_with_all_fields() { + let str_endpoint = "WS2P V2 S 7 g1.durs.info 5.135.188.170 [2001:41d0:8:c5aa::1] 443 ws2p"; + let endpoint = EndpointV2 { + api: NetworkEndpointApi(String::from("WS2P")), + api_version: 2, + network_features: EndpointV2NetworkFeatures(vec![1u8]), + api_features: ApiFeatures(vec![7u8]), + ip_v4: Some(Ipv4Addr::from_str("5.135.188.170").unwrap()), + ip_v6: Some(Ipv6Addr::from_str("2001:41d0:8:c5aa::1").unwrap()), + host: Some(String::from("g1.durs.info")), + port: 443u16, + path: Some(String::from("ws2p")), + }; + test_parse_and_read_endpoint(str_endpoint, endpoint); + } } diff --git a/network-documents/src/network_head.rs b/network-documents/src/network_head.rs index 5f6d2979299109836ba086004bad7243efd54622..396e977ce73795786dafd2920957ef0d5ce06ce0 100644 --- a/network-documents/src/network_head.rs +++ b/network-documents/src/network_head.rs @@ -32,7 +32,7 @@ pub enum NetworkHead { /// Head V2 V2(Box<NetworkHeadV2>), /// head V3 - V3(Box<NetworkHeadV3Container>), + V3(Box<NetworkHeadV3>), } impl ToString for NetworkHead { diff --git a/network-documents/src/network_head_v3.rs b/network-documents/src/network_head_v3.rs index 25251ff5334093f41bcf449b13db563c6f62c27e..e9998fe2db72f1a68f5e5ac0ed7828dc92b7c15d 100644 --- a/network-documents/src/network_head_v3.rs +++ b/network-documents/src/network_head_v3.rs @@ -17,68 +17,27 @@ use base58::ToBase58; use duniter_documents::blockstamp::Blockstamp; -use dup_crypto::keys::bin_signable::BinSignable; +use duniter_documents::{BlockHash, BlockId, CurrencyName, ToJsonObject}; +use dup_crypto::keys::text_signable::TextSignable; use dup_crypto::keys::*; -use serde_json; +use pest::iterators::Pair; +use pest::Parser; use std::cmp::Ordering; -use NodeId; - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -/// Head V3 -pub struct NetworkHeadV3Container { - /// Head step - pub step: u8, - /// head body - pub body: NetworkHeadV3, -} - -impl PartialOrd for NetworkHeadV3Container { - fn partial_cmp(&self, other: &NetworkHeadV3Container) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for NetworkHeadV3Container { - fn cmp(&self, other: &NetworkHeadV3Container) -> Ordering { - self.body.cmp(&other.body) - } -} - -impl NetworkHeadV3Container { - /// Convert to JSON String - pub fn to_json_head(&self) -> Result<String, serde_json::Error> { - Ok(serde_json::to_string_pretty(&JsonHeadV3 { - api_outgoing_conf: self.body.api_outgoing_conf, - api_incoming_conf: self.body.api_incoming_conf, - free_mirror_rooms: self.body.free_mirror_rooms, - low_priority_rooms: self.body.low_priority_rooms, - node_id: self.body.node_id, - algorithm: self.body.pubkey.algo(), - pubkey: self.body.pubkey.to_base58(), - blockstamp: self.body.blockstamp.to_string(), - software: &self.body.software, - soft_version: &self.body.soft_version, - signature: if let Some(sig) = self.body.signature { - Some(sig.to_base64()) - } else { - None - }, - step: self.step, - })?) - } -} +use *; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Head V3 pub struct NetworkHeadV3 { + /// Currency name + pub currency_name: CurrencyName, /// 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 free "low priority" rooms - pub low_priority_rooms: u8, /// Issuer node id pub node_id: NodeId, /// Issuer pubkey @@ -91,6 +50,8 @@ pub struct NetworkHeadV3 { pub soft_version: String, /// Issuer signature pub signature: Option<Sig>, + /// Head step + pub step: u8, } impl PartialOrd for NetworkHeadV3 { @@ -105,7 +66,7 @@ impl Ord for NetworkHeadV3 { } } -impl<'de> BinSignable<'de> for NetworkHeadV3 { +/*impl<'de> BinSignable<'de> for NetworkHeadV3 { fn issuer_pubkey(&self) -> PubKey { self.pubkey } @@ -115,19 +76,122 @@ impl<'de> BinSignable<'de> for NetworkHeadV3 { fn set_signature(&mut self, signature: Sig) { self.signature = Some(signature); } +}*/ + +impl TextSignable for NetworkHeadV3 { + fn as_signable_text(&self) -> String { + format!( +"3:{currency}:{api_outgoing_conf}:{api_incoming_conf}:{free_member_rooms}:{free_mirror_rooms}:{node_id}:{pubkey}:{blockstamp}:{software}:{soft_version}\n", + currency = self.currency_name, + 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 = format!("{}", self.node_id), + pubkey = self.pubkey.to_base58(), + blockstamp = self.blockstamp.to_string(), + software = self.software, + soft_version = self.soft_version, + ) + } + fn issuer_pubkey(&self) -> PubKey { + self.pubkey + } + fn signature(&self) -> Option<Sig> { + self.signature + } + fn set_signature(&mut self, signature: Sig) { + self.signature = Some(signature); + } +} + +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) { + Ok(mut head_v3_pairs) => { + Ok(NetworkHeadV3::from_pest_pair(head_v3_pairs.next().unwrap())) + } + Err(pest_error) => Err(ParseError::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; + let mut api_incoming_conf = 0; + let mut free_member_rooms = 0; + let mut free_mirror_rooms = 0; + let mut node_id = NodeId(0); + let mut pubkey = None; + let mut blockstamp = None; + let mut software = ""; + let mut soft_version = ""; + let mut signature = None; + let mut step = 0; + for field in pair.into_inner() { + match field.as_rule() { + Rule::currency => currency_str = field.as_str(), + Rule::api_outgoing_conf => api_outgoing_conf = field.as_str().parse().unwrap(), + Rule::api_incoming_conf => api_incoming_conf = field.as_str().parse().unwrap(), + Rule::free_member_rooms => free_member_rooms = field.as_str().parse().unwrap(), + Rule::free_mirror_rooms => free_mirror_rooms = field.as_str().parse().unwrap(), + Rule::node_id => node_id = NodeId(field.as_str().parse().unwrap()), + Rule::pubkey => { + pubkey = Some(PubKey::Ed25519( + ed25519::PublicKey::from_base58(field.as_str()).unwrap(), + )) + } + Rule::blockstamp => { + let mut inner_rules = field.into_inner(); // { block_id ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamp = Some(Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }); + } + Rule::software => software = field.as_str(), + Rule::soft_version => soft_version = field.as_str(), + Rule::ed25519_sig => { + signature = Some(Sig::Ed25519( + ed25519::Signature::from_base64(field.as_str()).unwrap(), + )) + } + Rule::step => step = field.as_str().parse().unwrap(), + _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line + } + } + NetworkHeadV3 { + currency_name: CurrencyName(currency_str.to_owned()), + api_outgoing_conf, + api_incoming_conf, + free_member_rooms, + free_mirror_rooms, + node_id, + pubkey: pubkey.expect("Grammar must ensure that head v3 have valid issuer pubkey !"), + blockstamp: blockstamp + .expect("Grammar must ensure that head v3 have valid blockstamp!"), + software: software.to_owned(), + soft_version: soft_version.to_owned(), + signature, + step, + } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Head V3 for json serializer -pub struct JsonHeadV3<'a> { +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 free "low priority" rooms - pub low_priority_rooms: u8, /// Issuer node id pub node_id: NodeId, /// Issuer key algorithm @@ -137,57 +201,77 @@ pub struct JsonHeadV3<'a> { /// Head blockstamp pub blockstamp: String, /// Issuer node software - pub software: &'a str, + pub software: String, /// Issuer node soft version - pub soft_version: &'a str, + pub soft_version: String, /// Issuer signature pub signature: Option<String>, /// Head step pub step: u8, } +impl<'a> ToJsonObject for NetworkHeadV3 { + type JsonObject = JsonHeadV3; + + 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(), + signature: if let Some(sig) = self.signature { + Some(sig.to_base64()) + } else { + None + }, + step: self.step, + } + } +} + #[cfg(test)] mod tests { use super::*; - use dup_crypto::keys::bin_signable::BinSignable; - use tests::bincode::deserialize; use tests::keypair1; #[test] fn head_v3_sign_and_verify() { - let mut head_v3 = NetworkHeadV3Container { + let keypair = keypair1(); + let mut head_v3 = NetworkHeadV3 { + currency_name: CurrencyName("g1".to_owned()), + api_outgoing_conf: 0u8, + api_incoming_conf: 0u8, + free_mirror_rooms: 0u8, + free_member_rooms: 0u8, + node_id: NodeId(0), + pubkey: PubKey::Ed25519(keypair.public_key()), + blockstamp: Blockstamp::from_string( + "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370", + ) + .unwrap(), + software: String::from("durs"), + soft_version: String::from("0.1.0-a0.1"), + signature: None, step: 0, - body: NetworkHeadV3 { - api_outgoing_conf: 0u8, - api_incoming_conf: 0u8, - free_mirror_rooms: 0u8, - low_priority_rooms: 0u8, - node_id: NodeId(0), - pubkey: PubKey::Ed25519(keypair1().public_key()), - blockstamp: Blockstamp::from_string( - "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370", - ) - .unwrap(), - software: String::from("durs"), - soft_version: String::from("0.1.0-a0.1"), - signature: None, - }, }; // Sign - let sign_result = head_v3 - .body - .sign(PrivKey::Ed25519(keypair1().private_key())); - if let Ok(head_v3_body_bytes) = sign_result { - let deser_head_v3_body: NetworkHeadV3 = - deserialize(&head_v3_body_bytes).expect("Fail to deserialize PeerCardV11 !"); - assert_eq!(head_v3.body, deser_head_v3_body,) + let sign_result = head_v3.sign(PrivKey::Ed25519(keypair.private_key())); + if let Ok(head_v3_raw) = sign_result { + println!("{}", head_v3_raw); + assert_eq!( + head_v3, + NetworkHeadV3::parse_from_raw(&head_v3_raw).expect("Fail to parse head v3 !") + ) } else { - panic!("failt to sign head v3 : {:?}", sign_result.err().unwrap()) + panic!("fail to sign head v3 : {:?}", sign_result.err().unwrap()) } // Verify signature - head_v3.body.verify().expect("HEADv3 : Invalid signature !"); - //let json_head_v3 = head_v3.to_json_head().expect("Fail to serialize HEAD v3 !"); - //println!("{}", json_head_v3); - //panic!(); + head_v3.verify().expect("HEADv3 : Invalid signature !"); } } diff --git a/network-documents/src/network_peer.rs b/network-documents/src/network_peer.rs index bcd71b161328212b0b05d31fd7d567d8a9393ce0..c80a23e4d241d5e95656443d825aaaecf0b123c7 100644 --- a/network-documents/src/network_peer.rs +++ b/network-documents/src/network_peer.rs @@ -21,9 +21,12 @@ extern crate serde; use base58::ToBase58; use duniter_documents::{blockstamp::Blockstamp, CurrencyName}; -use dup_crypto::keys::bin_signable::BinSignable; +use duniter_documents::{BlockHash, BlockId}; +use dup_crypto::keys::text_signable::TextSignable; use dup_crypto::keys::*; use network_endpoint::*; +use pest::iterators::Pair; +use pest::Parser; use *; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -48,34 +51,105 @@ pub struct PeerCardV11 { pub node_id: NodeId, /// Peer card Blockstamp pub blockstamp: Blockstamp, - /// Peer card endpoints list - pub endpoints: Vec<EndpointEnum>, + /// Peer card binary endpoints + pub endpoints: Vec<EndpointV2>, + /// Peer card string endpoints + pub endpoints_str: Vec<String>, /// Signature pub sig: Option<Sig>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -/// Peer card V11 for JSON Serializer -pub struct JsonPeerCardV11<'a> { - /// PeerCard version - pub version: usize, - /// Currency Name - pub currency_name: &'a str, - /// Issuer node id - pub node_id: NodeId, - /// Issuer pubkey alogirithm - pub algorithm: KeysAlgo, - /// Issuer pubkey - pub pubkey: String, - /// Peer card creation blockstamp - pub blockstamp: String, - /// Endpoints - pub endpoints: Vec<String>, - /// Signature - pub signature: Option<String>, +impl TextSignable for PeerCardV11 { + fn as_signable_text(&self) -> String { + format!( + "11:{currency}:{node_id}:{pubkey}:{blockstamp}\n{endpoinds}\n{endpoints_str}{nl}", + currency = self.currency_name.0, + node_id = format!("{}", self.node_id), + pubkey = self.issuer.to_base58(), + blockstamp = self.blockstamp.to_string(), + endpoinds = self + .endpoints + .iter() + .map(EndpointV2::to_string) + .collect::<Vec<String>>() + .join("\n"), + endpoints_str = self.endpoints_str.join("\n"), + nl = if self.endpoints_str.is_empty() { + "" + } else { + "\n" + }, + ) + } + fn issuer_pubkey(&self) -> PubKey { + self.issuer + } + fn signature(&self) -> Option<Sig> { + self.sig + } + fn set_signature(&mut self, signature: Sig) { + self.sig = Some(signature); + } } 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) { + Ok(mut peer_v11_pairs) => { + Ok(PeerCardV11::from_pest_pair(peer_v11_pairs.next().unwrap())) + } + Err(pest_error) => Err(ParseError::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); + let mut issuer = None; + let mut blockstamp = None; + let mut endpoints = Vec::new(); + let mut sig = None; + for field in pair.into_inner() { + match field.as_rule() { + Rule::currency => currency_str = field.as_str(), + Rule::node_id => node_id = NodeId(field.as_str().parse().unwrap()), + Rule::pubkey => { + issuer = Some(PubKey::Ed25519( + ed25519::PublicKey::from_base58(field.as_str()).unwrap(), + )) + } + Rule::blockstamp => { + let mut inner_rules = field.into_inner(); // { block_id ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamp = Some(Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }); + } + Rule::endpoint_v2 => endpoints.push(EndpointV2::from_pest_pair(field)), + Rule::ed25519_sig => { + sig = Some(Sig::Ed25519( + ed25519::Signature::from_base64(field.as_str()).unwrap(), + )) + } + _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line + } + } + let endpoints_len = endpoints.len(); + PeerCardV11 { + currency_name: CurrencyName(currency_str.to_owned()), + issuer: issuer.expect("Grammar must ensure that peer v11 have valid issuer pubkey !"), + node_id, + blockstamp: blockstamp + .expect("Grammar must ensure that peer v11 have valid blockstamp!"), + endpoints, + endpoints_str: Vec::with_capacity(endpoints_len), + sig, + } + } /// Convert to JSON String pub fn to_json_peer(&self) -> Result<String, serde_json::Error> { Ok(serde_json::to_string_pretty(&JsonPeerCardV11 { @@ -95,16 +169,25 @@ impl PeerCardV11 { } } -impl<'de> BinSignable<'de> for PeerCardV11 { - fn issuer_pubkey(&self) -> PubKey { - self.issuer - } - fn signature(&self) -> Option<Sig> { - self.sig - } - fn set_signature(&mut self, signature: Sig) { - self.sig = Some(signature) - } +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +/// Peer card V11 for JSON Serializer +pub struct JsonPeerCardV11<'a> { + /// PeerCard version + pub version: usize, + /// Currency Name + pub currency_name: &'a str, + /// Issuer node id + pub node_id: NodeId, + /// Issuer pubkey alogirithm + pub algorithm: KeysAlgo, + /// Issuer pubkey + pub pubkey: String, + /// Peer card creation blockstamp + pub blockstamp: String, + /// Endpoints + pub endpoints: Vec<String>, + /// Signature + pub signature: Option<String>, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -128,24 +211,18 @@ impl PeerCard { pub fn blockstamp(&self) -> Blockstamp { match *self { PeerCard::V10(ref peer_v10) => peer_v10.blockstamp, - _ => panic!("Peer version is not supported !"), + PeerCard::V11(ref peer_v11) => peer_v11.blockstamp, + //_ => panic!("Peer version is not supported !"), } } /// Get peer card issuer pub fn issuer(&self) -> PubKey { match *self { PeerCard::V10(ref peer_v10) => peer_v10.issuer, - _ => panic!("Peer version is not supported !"), + PeerCard::V11(ref peer_v11) => peer_v11.issuer, + //_ => panic!("Peer version is not supported !"), } } - /// Verify validity of peer card signature - pub fn verify(&self) -> bool { - false - } - /// Get peer card endpoint - pub fn get_endpoints(&self) -> Vec<EndpointEnum> { - Vec::with_capacity(0) - } } #[cfg(test)] @@ -153,14 +230,13 @@ mod tests { use super::*; use std::net::Ipv4Addr; use std::str::FromStr; - use tests::bincode::deserialize; use tests::keypair1; fn create_endpoint_v2() -> EndpointV2 { EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: None, ip_v6: None, @@ -173,7 +249,7 @@ mod tests { EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![5u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: Some(Ipv4Addr::from_str("84.16.72.210").unwrap()), ip_v6: None, @@ -194,20 +270,21 @@ mod tests { "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370", ) .unwrap(), - endpoints: vec![ - EndpointEnum::V2(create_endpoint_v2()), - EndpointEnum::V2(create_second_endpoint_v2()), - ], + endpoints: vec![create_endpoint_v2(), create_second_endpoint_v2()], + endpoints_str: vec![], sig: None, }; // Sign let sign_result = peer_card_v11.sign(PrivKey::Ed25519(keypair1.private_key())); - if let Ok(peer_card_v11_bytes) = sign_result { - let deser_peer_card_v11: PeerCardV11 = - deserialize(&peer_card_v11_bytes).expect("Fail to deserialize PeerCardV11 !"); - assert_eq!(peer_card_v11, deser_peer_card_v11,) + if let Ok(peer_card_v11_raw) = sign_result { + 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 !") + ) } else { - panic!("failt to sign peer card : {:?}", sign_result.err().unwrap()) + panic!("fail to sign peer card : {:?}", sign_result.err().unwrap()) } // Verify signature peer_card_v11 diff --git a/tui/lib.rs b/tui/lib.rs index e31369b328cd71f564e393933af6d60b9f05f184..eda016905c0084fcdb4f7cfc721ff52b4788d4a7 100644 --- a/tui/lib.rs +++ b/tui/lib.rs @@ -467,7 +467,7 @@ impl DuniterModule<DuRsConf, DursMsg> for TuiModule { thread::spawn(move || { // Send proxy sender to main main_sender - .send(RooterThreadMessage::ModuleSender( + .send(RooterThreadMessage::ModuleRegistration( TuiModule::name(), proxy_sender, vec![ModuleRole::UserInterface], @@ -477,6 +477,8 @@ impl DuniterModule<DuRsConf, DursMsg> for TuiModule { ModuleEvent::NewValidHeadFromNetwork, ModuleEvent::NewValidPeerFromNodeNetwork, ], + vec![], + vec![], )) .expect("Fatal error : tui module fail to send is sender channel !"); debug!("Send tui sender to main thread."); diff --git a/ws2p-messages/Cargo.toml b/ws2p-messages/Cargo.toml index fa0e7d6a3b23e82603a94eecd5ca620991670047..ea73afd5e54633c93344cb2f088da9e75bac7bb9 100644 --- a/ws2p-messages/Cargo.toml +++ b/ws2p-messages/Cargo.toml @@ -15,7 +15,6 @@ dup-crypto = { path = "../crypto" } duniter-documents = { path = "../documents" } durs-network-documents = { path = "../network-documents" } log = "0.4.*" -rust-crypto = "0.2.*" serde = "1.0.*" serde_derive = "1.0.*" serde_json = "1.0.*" diff --git a/ws2p-messages/lib.rs b/ws2p-messages/lib.rs index 17746468d0b2013b80f42006ccc8056c724b42f3..63e50c1c282cbd1adb65c50ec7bc8e0aecc5edaf 100644 --- a/ws2p-messages/lib.rs +++ b/ws2p-messages/lib.rs @@ -75,31 +75,31 @@ mod tests { ) } - pub fn create_endpoint_v11() -> EndpointEnum { - EndpointEnum::V2(EndpointV2 { + pub fn create_endpoint_v11() -> EndpointV2 { + EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![4u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: None, ip_v6: None, host: Some(String::from("g1.durs.ifee.fr")), port: 443u16, path: Some(String::from("ws2p")), - }) + } } - pub fn create_second_endpoint_v11() -> EndpointEnum { - EndpointEnum::V2(EndpointV2 { + pub fn create_second_endpoint_v11() -> EndpointV2 { + EndpointV2 { api: NetworkEndpointApi(String::from("WS2P")), api_version: 2, - network_features: EndpointV2NetworkFeatures(vec![5u8]), + network_features: EndpointV2NetworkFeatures(vec![1u8]), api_features: ApiFeatures(vec![7u8]), ip_v4: Some(Ipv4Addr::from_str("84.16.72.210").unwrap()), ip_v6: None, host: None, port: 443u16, path: Some(String::from("ws2p")), - }) + } } pub fn create_peer_card_v11() -> PeerCardV11 { @@ -112,6 +112,7 @@ mod tests { ) .unwrap(), endpoints: vec![create_endpoint_v11(), create_second_endpoint_v11()], + endpoints_str: vec![], sig: None, } } diff --git a/ws2p-messages/v2/connect.rs b/ws2p-messages/v2/connect.rs index 19426fb017ef69d4c25975b4be488f1428026d03..37d70705089424fbd0fcdf2988524f770d1af3d2 100644 --- a/ws2p-messages/v2/connect.rs +++ b/ws2p-messages/v2/connect.rs @@ -87,6 +87,7 @@ mod tests { use super::super::*; use super::*; use duniter_documents::Blockstamp; + use dup_crypto::keys::text_signable::TextSignable; use tests::*; #[test] diff --git a/ws2p-messages/v2/mod.rs b/ws2p-messages/v2/mod.rs index b0c4aabd9d1a1c1372f4a77aadcd952d96996006..af7d32e9768b722f238d8afc3501db30d54bc665 100644 --- a/ws2p-messages/v2/mod.rs +++ b/ws2p-messages/v2/mod.rs @@ -84,6 +84,7 @@ impl<'de> BinSignable<'de> for WS2Pv0Message { #[cfg(test)] mod tests { use super::*; + use dup_crypto::keys::text_signable::TextSignable; use tests::*; #[test] diff --git a/ws2p-messages/v2/payload_container.rs b/ws2p-messages/v2/payload_container.rs index af62ee4d93eb5a9158bbbffe6d03e80d8ca11cf9..8bf5cfd89778dfb5a8a5a9477edb8d6686ab80f8 100644 --- a/ws2p-messages/v2/payload_container.rs +++ b/ws2p-messages/v2/payload_container.rs @@ -26,7 +26,7 @@ use duniter_documents::v10::revocation::RevocationDocument; use duniter_documents::v10::transaction::TransactionDocument; use dup_crypto::hashs::Hash; use durs_network_documents::network_head_v2::NetworkHeadV2; -use durs_network_documents::network_head_v3::NetworkHeadV3Container; +use durs_network_documents::network_head_v3::NetworkHeadV3; use durs_network_documents::network_peer::PeerCardV11; /// WS2P v2 message payload metadata size @@ -54,7 +54,7 @@ pub enum WS2Pv0MessagePayload { /// HEADS_V2 Message Headsv2(Vec<NetworkHeadV2>), /// HEADS_V3 Message - Heads3(Vec<NetworkHeadV3Container>), + Heads3(Vec<NetworkHeadV3>), /// BLOCKS Message Blocks(Vec<BlockDocument>), /// PENDING_IDENTITIES Message diff --git a/ws2p-v1-legacy/Cargo.toml b/ws2p-v1-legacy/Cargo.toml index 0350c5e73c4327cabd96d92c743535f2e86e18ac..0d80b8d94ed2c251b2b7cd0740be7e8b039c7247 100644 --- a/ws2p-v1-legacy/Cargo.toml +++ b/ws2p-v1-legacy/Cargo.toml @@ -21,7 +21,6 @@ duniter-network = { path = "../network" } durs-wot = { path = "../wot" } log = "0.4.*" rand = "0.4.*" -rust-crypto = "0.2.*" sqlite = "0.23.*" serde = "1.0.*" serde_derive = "1.0.*" diff --git a/ws2p-v1-legacy/datas.rs b/ws2p-v1-legacy/datas.rs index 7e2ea17e9b06af9fbc89ec53f53b9564dfcfdf76..a73937d4a33df9749d4396abf478d86ef5a8039a 100644 --- a/ws2p-v1-legacy/datas.rs +++ b/ws2p-v1-legacy/datas.rs @@ -37,7 +37,7 @@ pub struct WS2PModuleDatas { mpsc::Sender<WS2PThreadSignal>, mpsc::Receiver<WS2PThreadSignal>, ), - pub ws2p_endpoints: HashMap<NodeFullId, (EndpointEnum, WS2PConnectionState)>, + pub ws2p_endpoints: HashMap<NodeFullId, (EndpointV1, WS2PConnectionState)>, pub websockets: HashMap<NodeFullId, WsSender>, pub requests_awaiting_response: HashMap<ModuleReqId, (OldNetworkRequest, NodeFullId, SystemTime)>, @@ -169,18 +169,17 @@ impl WS2PModuleDatas { let mut reachable_endpoints = Vec::new(); let mut unreachable_endpoints = Vec::new(); for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() { - if ep.pubkey() == self.key_pair.unwrap().public_key() || !pubkeys.contains(&ep.pubkey()) - { + if ep.issuer == self.key_pair.unwrap().public_key() || !pubkeys.contains(&ep.issuer) { match state { WS2PConnectionState::Established => count_established_connections += 1, WS2PConnectionState::NeverTry | WS2PConnectionState::Close | WS2PConnectionState::Denial => { - pubkeys.insert(ep.pubkey()); + pubkeys.insert(ep.issuer); reachable_endpoints.push(ep); } _ => { - pubkeys.insert(ep.pubkey()); + pubkeys.insert(ep.issuer); unreachable_endpoints.push(ep); } } @@ -200,13 +199,13 @@ impl WS2PModuleDatas { } else { break; }; - if cfg!(feature = "ssl") || ep.port() != 443 { + if cfg!(feature = "ssl") || ep.port != 443 { self.connect_to_without_checking_quotas(&ep); free_outcoming_rooms -= 1; } } } - pub fn connect_to(&mut self, endpoint: &EndpointEnum) { + pub fn connect_to(&mut self, endpoint: &EndpointV1) { // Add endpoint to endpoints list (if there isn't already) match self.ws2p_endpoints.get( &endpoint @@ -529,7 +528,7 @@ impl WS2PModuleDatas { Ok(()) } - fn connect_to_without_checking_quotas(&mut self, endpoint: &EndpointEnum) { + fn connect_to_without_checking_quotas(&mut self, endpoint: &EndpointV1) { let endpoint_copy = endpoint.clone(); let conductor_sender_copy = self.main_thread_channel.0.clone(); let currency_copy = self.currency.clone(); diff --git a/ws2p-v1-legacy/lib.rs b/ws2p-v1-legacy/lib.rs index ad5732f0972755715680100791a71ddbe7fa9088..520ef3559cae83ce37bb801b26eefb50dda34a9a 100644 --- a/ws2p-v1-legacy/lib.rs +++ b/ws2p-v1-legacy/lib.rs @@ -94,7 +94,7 @@ pub struct WS2PConf { /// Limit of outcoming connections pub outcoming_quota: usize, /// Default WS2P endpoints provides by configuration file - pub sync_endpoints: Vec<EndpointEnum>, + pub sync_endpoints: Vec<EndpointV1>, } impl Default for WS2PConf { @@ -102,7 +102,7 @@ impl Default for WS2PConf { WS2PConf { outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA, sync_endpoints: vec![ - EndpointEnum::parse_from_raw( + EndpointV1::parse_from_raw( "WS2P c1c39a0a g1-monit.librelois.fr 443 /ws2p", PubKey::Ed25519( ed25519::PublicKey::from_base58( @@ -112,10 +112,9 @@ impl Default for WS2PConf { ), 0, 0, - 1u16, ) .unwrap(), - EndpointEnum::parse_from_raw( + EndpointV1::parse_from_raw( "WS2P b48824f0 g1.monnaielibreoccitanie.org 443 /ws2p", PubKey::Ed25519( ed25519::PublicKey::from_base58( @@ -125,7 +124,6 @@ impl Default for WS2PConf { ), 0, 0, - 1u16, ) .unwrap(), ], @@ -143,7 +141,7 @@ pub enum WS2PSignal { NegociationTimeout(NodeFullId), Timeout(NodeFullId), DalRequest(NodeFullId, ModuleReqId, serde_json::Value), - PeerCard(NodeFullId, serde_json::Value, Vec<EndpointEnum>), + PeerCard(NodeFullId, serde_json::Value, Vec<EndpointV1>), Heads(NodeFullId, Vec<NetworkHead>), Document(NodeFullId, BlockchainDocument), ReqResponse( @@ -307,7 +305,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { .expect("Fail to get endpoint node_full_id"), (ep.clone(), WS2PConnectionState::Close), ); - info!("Load sync endpoint {}", ep.raw()); + info!("Load sync endpoint {}", ep.raw_endpoint); } ws2p_module.key_pair = Some(key_pair); ws2p_module.currency = Some(soft_meta_datas.conf.currency().to_string()); @@ -327,7 +325,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { thread::spawn(move || { // Send proxy sender to main rooter_sender - .send(RooterThreadMessage::ModuleSender( + .send(RooterThreadMessage::ModuleRegistration( WS2PModule::name(), proxy_sender_clone, vec![ModuleRole::InterNodesNetwork], @@ -336,6 +334,8 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { ModuleEvent::NewWotDocInPool, ModuleEvent::NewTxinPool, ], + vec![], + vec![], )) .expect("Fatal error : ws2p module fail to send is sender channel !"); debug!("Send ws2p sender to main thread."); @@ -372,14 +372,14 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { let dal_enpoints = ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P"))); for ep in dal_enpoints { - if ep.api() == NetworkEndpointApi(String::from("WS2P")) - && (cfg!(feature = "ssl") || ep.port() != 443) + if ep.api == NetworkEndpointApi(String::from("WS2P")) + && (cfg!(feature = "ssl") || ep.port != 443) { count += 1; ws2p_module.ws2p_endpoints.insert( ep.node_full_id() .expect("WS2P: Fail to get ep.node_full_id() !"), - (ep.clone(), WS2PConnectionState::from(ep.status())), + (ep.clone(), WS2PConnectionState::from(ep.status)), ); } } @@ -675,7 +675,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { Some(_) => {} None => { if let Some(_api) = - ws2p_db::string_to_api(&ep.api().0.clone()) + ws2p_db::string_to_api(&ep.api.0.clone()) { endpoints_to_update_status.insert( ep.node_full_id().expect( @@ -684,7 +684,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule { SystemTime::now(), ); } - if cfg!(feature = "ssl") || ep.port() != 443 { + if cfg!(feature = "ssl") || ep.port != 443 { ws2p_module.connect_to(&ep); } } @@ -1117,7 +1117,7 @@ mod tests { let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let mut endpoint = EndpointEnum::parse_from_raw( + let mut endpoint = EndpointV1::parse_from_raw( "WS2P cb06a19b g1.imirhil.fr 53012 /", PubKey::Ed25519( ed25519::PublicKey::from_base58("5gJYnQp8v7bWwk7EWRoL8vCLof1r3y9c6VDdnGSM1GLv") @@ -1125,7 +1125,6 @@ mod tests { ), 1, current_time.as_secs(), - 1, ) .expect("Failt to parse test endpoint !"); @@ -1135,7 +1134,7 @@ mod tests { assert_eq!(endpoint, written_endpoints.pop().unwrap()); // Test status update - endpoint.set_status(3); + endpoint.status = 3; ws2p_db::write_endpoint(&db, &endpoint, 3, current_time.as_secs()); let mut written_endpoints = ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P"))); diff --git a/ws2p-v1-legacy/ws2p_connection.rs b/ws2p-v1-legacy/ws2p_connection.rs index 1b66ebb0459bbbaf47d5dc44fdc7c900f310a4c0..721b9f02a758f40a5e42dc1c14bd80ac7535c194 100644 --- a/ws2p-v1-legacy/ws2p_connection.rs +++ b/ws2p-v1-legacy/ws2p_connection.rs @@ -2,7 +2,7 @@ use constants::*; use duniter_module::ModuleReqId; use duniter_network::BlockchainDocument; use dup_crypto::keys::*; -use durs_network_documents::network_endpoint::{EndpointEnum, NetworkEndpointApi}; +use durs_network_documents::network_endpoint::{EndpointV1, NetworkEndpointApi}; use durs_network_documents::NodeId; use parsers::blocks::parse_json_block; use rand::Rng; @@ -271,7 +271,7 @@ pub enum WS2PConnectionMessagePayload { ValidAckMessage(String, WS2PConnectionState), ValidOk(WS2PConnectionState), DalRequest(ModuleReqId, serde_json::Value), - PeerCard(serde_json::Value, Vec<EndpointEnum>), + PeerCard(serde_json::Value, Vec<EndpointV1>), Heads(Vec<serde_json::Value>), Document(BlockchainDocument), ReqResponse(ModuleReqId, serde_json::Value), @@ -544,19 +544,18 @@ impl WS2PConnectionMetaDatas { Some(raw_pubkey) => { match ed25519::PublicKey::from_base58(raw_pubkey.as_str().unwrap_or("")) { Ok(pubkey) => { - let mut ws2p_endpoints: Vec<EndpointEnum> = Vec::new(); + let mut ws2p_endpoints: Vec<EndpointV1> = Vec::new(); match peer.get("endpoints") { Some(endpoints) => match endpoints.as_array() { Some(array_endpoints) => { for endpoint in array_endpoints { - if let Ok(ep) = EndpointEnum::parse_from_raw( + if let Ok(ep) = EndpointV1::parse_from_raw( endpoint.as_str().unwrap_or(""), PubKey::Ed25519(pubkey), 0, 0, - 1u16, ) { - if ep.api() + if ep.api == NetworkEndpointApi(String::from("WS2P")) { ws2p_endpoints.push(ep); @@ -584,7 +583,7 @@ impl WS2PConnectionMetaDatas { } pub fn get_random_connection<S: ::std::hash::BuildHasher>( - connections: &HashMap<NodeFullId, (EndpointEnum, WS2PConnectionState), S>, + connections: &HashMap<NodeFullId, (EndpointV1, WS2PConnectionState), S>, ) -> NodeFullId { let mut rng = rand::thread_rng(); let mut loop_count = 0; @@ -604,7 +603,7 @@ pub fn get_random_connection<S: ::std::hash::BuildHasher>( } pub fn connect_to_ws2p_endpoint( - endpoint: &EndpointEnum, + endpoint: &EndpointV1, conductor_sender: &mpsc::Sender<WS2PThreadSignal>, currency: &str, key_pair: KeyPairEnum, @@ -616,10 +615,10 @@ pub fn connect_to_ws2p_endpoint( let mut conn_meta_datas = WS2PConnectionMetaDatas::new( "b60a14fd-0826-4ae0-83eb-1a92cd59fd5308535fd3-78f2-4678-9315-cd6e3b7871b1".to_string(), ); - conn_meta_datas.remote_pubkey = Some(endpoint.pubkey()); + conn_meta_datas.remote_pubkey = Some(endpoint.issuer); conn_meta_datas.remote_uuid = Some( endpoint - .node_uuid() + .node_id .expect("WS2P: Fail to get ep.node_uuid() !"), ); diff --git a/ws2p-v1-legacy/ws2p_db.rs b/ws2p-v1-legacy/ws2p_db.rs index 6166fc4abca713608b406aa3bf8928b3e7d13f55..c23229dced15baccab7ec2c2358005e90ee9404f 100644 --- a/ws2p-v1-legacy/ws2p_db.rs +++ b/ws2p-v1-legacy/ws2p_db.rs @@ -1,5 +1,5 @@ use dup_crypto::keys::*; -use durs_network_documents::network_endpoint::{EndpointEnum, NetworkEndpointApi}; +use durs_network_documents::network_endpoint::{EndpointV1, NetworkEndpointApi}; use sqlite::*; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -44,7 +44,7 @@ pub fn api_to_integer(api: &NetworkEndpointApi) -> i64 { } } -pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<EndpointEnum> { +pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<EndpointV1> { let mut cursor: Cursor = db .prepare("SELECT hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check FROM endpoints WHERE api=? ORDER BY status DESC;") .expect("get_endpoints_for_api() : Error in SQL request !") @@ -61,12 +61,11 @@ pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<E let raw_ep = row[6].as_string().unwrap().to_string(); let ep_issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(row[3].as_string().unwrap()).unwrap()); - let mut ep = match EndpointEnum::parse_from_raw( + let mut ep = match EndpointV1::parse_from_raw( &raw_ep, ep_issuer, row[1].as_integer().unwrap() as u32, row[7].as_integer().unwrap() as u64, - 1u16, ) { Ok(ep) => ep, Err(e) => panic!(format!( @@ -74,8 +73,8 @@ pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<E raw_ep, e )), }; - ep.set_status(row[1].as_integer().unwrap() as u32); - ep.set_last_check(row[7].as_integer().unwrap() as u64); + ep.status = row[1].as_integer().unwrap() as u32; + ep.last_check = row[7].as_integer().unwrap() as u64; endpoints.push(ep); } @@ -84,7 +83,7 @@ pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<E pub fn write_endpoint( db: &Connection, - endpoint: &EndpointEnum, + endpoint: &EndpointV1, new_status: u32, new_last_check: u64, ) { @@ -106,26 +105,24 @@ pub fn write_endpoint( .next() .expect("write_endpoint() : Error in cursor.next()") { - if row[0].as_integer().expect("fail to read ep status !") as u32 != endpoint.status() { + if row[0].as_integer().expect("fail to read ep status !") as u32 != endpoint.status { db.execute(format!( "UPDATE endpoints SET status={} WHERE hash_full_id='{}'", - endpoint.status(), - hash_full_id + endpoint.status, hash_full_id )) .expect("Fail to parse SQL request update endpoint status !"); } - } else if let EndpointEnum::V1(ref ep_v10) = *endpoint { + } else { + let ep_v10 = endpoint; db .execute( format!( "INSERT INTO endpoints (hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check) VALUES ('{}', {}, {}, '{}', {}, {}, '{}', {});", ep_v10.hash_full_id.expect("ep_v10.hash_full_id = None"), new_status, ep_v10.node_id.expect("ep_v10.node_id = None").0, ep_v10.issuer.to_string(), api_to_integer(&ep_v10.api), - ep_v10.version, ep_v10.raw_endpoint, new_last_check + 1, ep_v10.raw_endpoint, new_last_check ) ) .expect("Fail to parse SQL request INSERT endpoint !"); - } else { - panic!("write_endpoint() : Endpoint version is not supported !") } } diff --git a/ws2p/Cargo.toml b/ws2p/Cargo.toml index dbd5d5b9ec1b1e5bd01bdbfa9f514c88a96b61ac..e9d05a0301ab14a3a257163541b7c27e2d1e0f1d 100644 --- a/ws2p/Cargo.toml +++ b/ws2p/Cargo.toml @@ -9,8 +9,10 @@ license = "AGPL-3.0" path = "lib.rs" [dependencies] -duniter-conf = { path = "../conf" } +bincode = "1.0.*" +duniter-conf= { path = "../conf" } dup-crypto = { path = "../crypto" } +duniter-documents = { path = "../documents" } durs-network-documents = { path = "../network-documents" } durs-ws2p-messages = { path = "../ws2p-messages" } duniter-message= { path = "../message" } diff --git a/ws2p/generate_peer.rs b/ws2p/generate_peer.rs new file mode 100644 index 0000000000000000000000000000000000000000..65340f644086e6f2d43600a66b50b0c5826bfa90 --- /dev/null +++ b/ws2p/generate_peer.rs @@ -0,0 +1,124 @@ +// Copyright (C) 2018 The Durs Project Developers. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Generate self peer card + +use bincode; +use duniter_documents::{Blockstamp, CurrencyName}; +use dup_crypto::keys::PubKey; +use durs_network_documents::network_endpoint::*; +use durs_network_documents::network_peer::*; +use durs_network_documents::*; + +pub fn _self_peer_update_endpoints( + self_peer: PeerCardV11, + blockstamp: Blockstamp, + new_endpoints: Vec<EndpointEnum>, +) -> PeerCardV11 { + let max_eps = self_peer.endpoints.len() + self_peer.endpoints_str.len() + new_endpoints.len(); + let apis: Vec<NetworkEndpointApi> = new_endpoints + .iter() + .filter(|ep| { + if let EndpointEnum::V2(_) = ep { + true + } else { + false + } + }) + .map(|ep| ep.api()) + .collect(); + let mut new_endpoints_bin = Vec::with_capacity(max_eps); + let mut new_endpoints_str = Vec::with_capacity(max_eps); + for ep in self_peer.endpoints { + if !apis.contains(&ep.api) { + new_endpoints_bin.push(ep); + } + } + for ep in self_peer.endpoints_str { + let ep_clone = ep.clone(); + let ep_fields: Vec<&str> = ep_clone.split(' ').collect(); + if !apis.contains(&NetworkEndpointApi(ep_fields[0].to_owned())) { + new_endpoints_str.push(ep); + } + } + for ep in new_endpoints { + if let EndpointEnum::V2(ep_v2) = ep { + let bin_len = bincode::serialize(&ep_v2) + .unwrap_or_else(|_| { + panic!( + "Fail to update self peer : invalid endpoint : {:?} !", + ep_v2 + ) + }) + .len(); + let str_ep = ep_v2.to_string(); + if str_ep.len() < bin_len { + new_endpoints_str.push(str_ep); + } else { + new_endpoints_bin.push(ep_v2); + } + } + } + + PeerCardV11 { + currency_name: self_peer.currency_name, + issuer: self_peer.issuer, + node_id: self_peer.node_id, + blockstamp, + endpoints: new_endpoints_bin, + endpoints_str: new_endpoints_str, + sig: None, + } +} + +pub fn _generate_self_peer( + currency_name: CurrencyName, + issuer: PubKey, + node_id: NodeId, + blockstamp: Blockstamp, + endpoints: Vec<EndpointEnum>, +) -> PeerCardV11 { + let mut endpoints_bin = Vec::with_capacity(endpoints.len()); + let mut endpoints_str = Vec::with_capacity(endpoints.len()); + + for ep in endpoints { + if let EndpointEnum::V2(ep_v2) = ep { + let bin_len = bincode::serialize(&ep_v2) + .unwrap_or_else(|_| { + panic!( + "Fail to generate self peer : invalid endpoint : {:?} !", + ep_v2 + ) + }) + .len(); + let str_ep = ep_v2.to_string(); + if str_ep.len() < bin_len { + endpoints_str.push(str_ep); + } else { + endpoints_bin.push(ep_v2); + } + } + } + + PeerCardV11 { + currency_name, + issuer, + node_id, + blockstamp, + endpoints: endpoints_bin, + endpoints_str, + sig: None, + } +} diff --git a/ws2p/lib.rs b/ws2p/lib.rs index c6c5aadbf08da3b670a8089c015ccadf795ceeaf..b3c808309bdb7835635569748fa5c9ea680607fa 100644 --- a/ws2p/lib.rs +++ b/ws2p/lib.rs @@ -34,7 +34,9 @@ extern crate serde_derive; #[macro_use] extern crate structopt; +extern crate bincode; extern crate duniter_conf; +extern crate duniter_documents; extern crate duniter_message; extern crate duniter_module; extern crate duniter_network; @@ -43,13 +45,13 @@ extern crate durs_network_documents; extern crate durs_ws2p_messages; mod constants; +mod generate_peer; use constants::*; use duniter_conf::DuRsConf; use duniter_message::DursMsg; use duniter_module::*; use duniter_network::*; -use dup_crypto::keys::*; use durs_network_documents::network_endpoint::*; use std::sync::mpsc; @@ -67,32 +69,8 @@ impl Default for WS2PConf { WS2PConf { outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA, sync_endpoints: vec![ - EndpointEnum::parse_from_raw( - "WS2P c1c39a0a g1-monit.librelois.fr 443 /ws2p", - PubKey::Ed25519( - ed25519::PublicKey::from_base58( - "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx", - ) - .unwrap(), - ), - 0, - 0, - 1u16, - ) - .unwrap(), - EndpointEnum::parse_from_raw( - "WS2P b48824f0 g1.monnaielibreoccitanie.org 443 /ws2p", - PubKey::Ed25519( - ed25519::PublicKey::from_base58( - "7v2J4badvfWQ6qwRdCwhhJfAsmKwoxRUNpJHiJHj7zef", - ) - .unwrap(), - ), - 0, - 0, - 1u16, - ) - .unwrap(), + EndpointV2::parse_from_raw("WS2P g1-monit.librelois.fr 443 ws2p").unwrap(), + EndpointV2::parse_from_raw("WS2P g1.monnaielibreoccitanie.org 443 ws2p").unwrap(), ], } }