Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c697a3a4d | |||
| 21f0c3e2ac | |||
| 42ab21c133 | |||
| a39eed123e | |||
| 1954895e16 | |||
| 234bf7d0a0 | |||
| ef82d4327c | |||
| 8da639cd11 | |||
| 65aa1ba29d | |||
| c71f494974 | |||
| ae25f335f4 | |||
| 21834fde41 | |||
| b6db1bf1af | |||
| f262b2924b | |||
| 724af12e03 | |||
| 3a59f3cef9 | |||
| 6aba3f08f1 | |||
| 8cd2be7edc | |||
| d768eff303 | |||
| ddf0d762d7 | |||
| aa207e2c13 | |||
| c192afe9eb | |||
| 29e1488714 | |||
| 37a493439d | |||
| ab02eec824 | |||
| efb900a538 | |||
| 9d969904f2 | |||
| 2b5b61ea26 | |||
| 287d2b31a5 | |||
| de63fff1a1 | |||
| 265ef22838 | |||
| f0cf92b542 | |||
| ec849cfc0c | |||
| 233dc5ce9d | |||
| e4cfab537e | |||
| 842c0b10b9 | |||
| f10a403045 | |||
| 0b41badab0 | |||
| 1633f54f4f | |||
| 86d27b06df | |||
| 07bb0a69fa | |||
| 138814f26c | |||
| 06540f5ce1 | |||
| 4feadb6352 | |||
| fdf49ff804 | |||
| eb49ef1013 | |||
| 17deec7720 | |||
| 76c2eac3bd | |||
| f095dd114e | |||
| b5c5ea3193 | |||
| 1371b94599 | |||
| 9b8b0bff1d | |||
| cd94ecde19 | |||
| 0b4f10cfe6 | |||
| 31d0aa7fe4 | |||
| 256afa3be9 | |||
| 777c40bd97 | |||
| 9deaad8a2a | |||
| 1ad60582ba | |||
| 2aaf2465e4 | |||
| 0fb9c352d6 | |||
| ad289e531b | |||
| 2fbf2456ec | |||
| 2c2ecfb785 | |||
| 9478460893 | |||
| e8472e07f9 | |||
| 2c0a4b11db | |||
| d7ed6b5a13 | |||
| f4a62fd64c |
+1
-1
@@ -1,3 +1,3 @@
|
||||
.idea
|
||||
/target
|
||||
**/*.rs.bk
|
||||
/.idea/
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# nym-client Changelog
|
||||
|
||||
* removed the `--local` flag
|
||||
* introduced `--directory` argument to support arbitrary directory servers. Leaving it out will point the node at the "https://directory.nymtech.net" alpha testnet server
|
||||
* IPv6 support
|
||||
* client version number is now shown at node start
|
||||
* directory server location is now shown at node start
|
||||
* decrease default delays
|
||||
|
||||
## 0.1.0 - Initial Release
|
||||
|
||||
* The bare minimum set of features required by a Nym Client
|
||||
Generated
+64
-201
@@ -67,21 +67,12 @@ name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "assert-json-diff"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -97,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -106,8 +97,8 @@ name = "backtrace-sys"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -176,17 +167,6 @@ dependencies = [
|
||||
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
@@ -222,12 +202,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.48"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -243,16 +219,6 @@ dependencies = [
|
||||
"keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
@@ -272,7 +238,7 @@ name = "clear_on_drop"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -283,16 +249,6 @@ dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.4"
|
||||
@@ -330,7 +286,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -425,11 +381,6 @@ dependencies = [
|
||||
"subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
@@ -453,7 +404,7 @@ version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -500,7 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -516,7 +467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -622,7 +573,7 @@ dependencies = [
|
||||
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -667,22 +618,10 @@ version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libgit2-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.1.26"
|
||||
@@ -705,7 +644,7 @@ name = "hermit-abi"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -839,7 +778,7 @@ name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -847,16 +786,6 @@ name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
@@ -878,31 +807,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
version = "0.2.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lioness"
|
||||
version = "0.1.2"
|
||||
@@ -985,7 +892,7 @@ dependencies = [
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1010,7 +917,7 @@ version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1034,30 +941,13 @@ dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockito"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"assert-json-diff 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1074,61 +964,55 @@ version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "0.2.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"built 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockito 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pem 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sfw-provider-requests 0.1.0",
|
||||
"sphinx 0.1.0",
|
||||
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tungstenite 0.10.0 (git+https://github.com/dbcfd/tokio-tungstenite?rev=6dc2018cbfe8fe7ddd75ff977343086503135b38)",
|
||||
"tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nym-client 0.1.0",
|
||||
"sphinx 0.1.0",
|
||||
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
@@ -1143,7 +1027,7 @@ dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1158,8 +1042,8 @@ version = "0.9.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1181,7 +1065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1223,7 +1107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1253,7 +1137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1295,7 +1179,7 @@ version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1313,7 +1197,7 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1395,7 +1279,7 @@ name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1407,7 +1291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1480,7 +1364,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.9.22"
|
||||
version = "0.9.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1560,7 +1444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1600,7 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1659,7 +1543,7 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1686,7 +1570,7 @@ version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1743,7 +1627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.11"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1758,7 +1642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1768,7 +1652,7 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1796,7 +1680,7 @@ name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1821,14 +1705,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.2.4"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1885,7 +1769,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1963,18 +1847,10 @@ dependencies = [
|
||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.2"
|
||||
@@ -2170,7 +2046,6 @@ dependencies = [
|
||||
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum assert-json-diff 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9881d306dee755eccf052d652b774a6b2861e86b4772f555262130e58e4f81d2"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
@@ -2183,20 +2058,17 @@ dependencies = [
|
||||
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
"checksum built 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2315cfb416f86e05360edc950b1d7d25ecfb00f7f8eba60dbd7882a0f2e944"
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
|
||||
"checksum bytes 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c85319f157e4e26c703678e68e26ab71a46c0199286fa670b21cc9fec13d895"
|
||||
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
|
||||
"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862"
|
||||
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5"
|
||||
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
|
||||
"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
|
||||
"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
|
||||
@@ -2211,7 +2083,6 @@ dependencies = [
|
||||
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
||||
"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736"
|
||||
"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
@@ -2242,7 +2113,6 @@ dependencies = [
|
||||
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
|
||||
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
|
||||
"checksum git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c1af51ea8a906616af45a4ce78eacf25860f7a13ae7bf8a814693f0f4037a26"
|
||||
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
|
||||
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
|
||||
"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
|
||||
@@ -2259,13 +2129,10 @@ dependencies = [
|
||||
"checksum input_buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e1b822cc844905551931d6f81608ed5f50a79c1078a4e2b4d42dbc7c1eedfbf"
|
||||
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum libgit2-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4870c781f6063efb83150cd22c1ddf6ecf58531419e7570cdcced46970f64a16"
|
||||
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
|
||||
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
|
||||
"checksum lioness 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9"
|
||||
"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
@@ -2281,11 +2148,8 @@ dependencies = [
|
||||
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
|
||||
"checksum mockito 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e524e85ea7c80559354217a6470c14abc2411802a9996aed1821559b9e28e3c"
|
||||
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
|
||||
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585"
|
||||
@@ -2328,7 +2192,7 @@ dependencies = [
|
||||
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
|
||||
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
|
||||
"checksum reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab"
|
||||
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
@@ -2355,14 +2219,14 @@ dependencies = [
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||
"checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941"
|
||||
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
|
||||
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
|
||||
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
|
||||
"checksum tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bcced6bb623d4bff3739c176c415f13c418f426395c169c9c3cd9a492c715b16"
|
||||
"checksum tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "beeef686ef92a222de07e089f455d9f8478bbba9651718f9e4b276babe829082"
|
||||
"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
|
||||
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
|
||||
"checksum tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ca6df436c42b0c3330a82d855d2ef017cd793090ad550a6bc2184f4b933532ab"
|
||||
@@ -2374,7 +2238,6 @@ dependencies = [
|
||||
"checksum tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c32ffea4827978e9aa392d2f743d973c1dfa3730a2ed3f22ce1e6984da848c"
|
||||
"checksum tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1739638e364e558128461fc1ad84d997702c8e31c2e6b18fb99842268199e827"
|
||||
"checksum tokio-tungstenite 0.10.0 (git+https://github.com/dbcfd/tokio-tungstenite?rev=6dc2018cbfe8fe7ddd75ff977343086503135b38)" = "<none>"
|
||||
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
|
||||
"checksum tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0c2bd5aeb7dcd2bb32e472c8872759308495e5eccc942e929a513cd8d36110"
|
||||
|
||||
+4
-27
@@ -1,39 +1,16 @@
|
||||
[package]
|
||||
build = "build.rs"
|
||||
name = "nym-client"
|
||||
version = "0.2.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
name = "nym-mixnode"
|
||||
version = "0.1.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "nym_client"
|
||||
path = "src/lib.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.11.0"
|
||||
clap = "2.33.0"
|
||||
curve25519-dalek = "1.2.3"
|
||||
dirs = "2.0.2"
|
||||
futures = "0.3.1"
|
||||
hex = "0.4.0"
|
||||
pem = "0.7.0"
|
||||
rand = "0.7.2"
|
||||
rand_distr = "0.2.2"
|
||||
reqwest = "0.9.22"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde_json = "1.0.44"
|
||||
nym-client = { path = "../nym-client" }
|
||||
sphinx = { path = "../sphinx" }
|
||||
sfw-provider-requests = { path = "../nym-sfw-provider/sfw-provider-requests" }
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
tungstenite = "0.9.2"
|
||||
|
||||
# putting this explicitly below everything and most likely, the next time we look into it, it will already have a proper release
|
||||
tokio-tungstenite = { git = "https://github.com/dbcfd/tokio-tungstenite", rev="6dc2018cbfe8fe7ddd75ff977343086503135b38" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.3.2"
|
||||
|
||||
[dev-dependencies]
|
||||
mockito = "0.22.0"
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
# Nym Client
|
||||
# Nym Mixnode
|
||||
|
||||
The Nym Client communicates with the remote, decentralised nodes which make up the Nym system as a whole.
|
||||
A Rust mixnode implementation.
|
||||
|
||||
It needs to handle communication with 3 types of remote nodes. Here's the development status of each:
|
||||
## Building
|
||||
|
||||
- [ ] Directory nodes
|
||||
- [ ] Mix nodes
|
||||
- [ ] Validator nodes
|
||||
* check out the code
|
||||
* [install rust](https://www.rust-lang.org/tools/install) (stable)
|
||||
* `cargo build --release` (for a production build)
|
||||
|
||||
The built binary can be found at `target/release/nym-mixnode`
|
||||
|
||||
## Usage
|
||||
|
||||
* `nym-mixnode` prints a help message showing usage options
|
||||
* `nym-mixnode run --help` prints a help message showing usage options for the run command
|
||||
* `nym-mixnode run --layer 1` will start the mixnode in layer 1 (coordinate with other people to find out which layer you need to start yours in)
|
||||
|
||||
By default, the Nym Mixnode will start on port 1789. If desired, you can change the port using the `--port` option.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
use built;
|
||||
|
||||
fn main() {
|
||||
built::write_built_file().expect("Failed to acquire build-time information");
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PersistedMixMetric {
|
||||
pub pub_key: String,
|
||||
pub received: u64,
|
||||
pub sent: HashMap<String, u64>,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixMetric {
|
||||
pub pub_key: String,
|
||||
pub received: u64,
|
||||
pub sent: HashMap<String, u64>,
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
use crate::clients::directory::requests::health_check_get::{
|
||||
HealthCheckRequester, Request as HealthCheckRequest,
|
||||
};
|
||||
use crate::clients::directory::requests::metrics_mixes_get::{
|
||||
MetricsMixRequester, Request as MetricsMixRequest,
|
||||
};
|
||||
use crate::clients::directory::requests::metrics_mixes_post::{
|
||||
MetricsMixPoster, Request as MetricsMixPost,
|
||||
};
|
||||
use crate::clients::directory::requests::presence_coconodes_post::{
|
||||
PresenceCocoNodesPoster, Request as PresenceCocoNodesPost,
|
||||
};
|
||||
use crate::clients::directory::requests::presence_mixnodes_post::{
|
||||
PresenceMixNodesPoster, Request as PresenceMixNodesPost,
|
||||
};
|
||||
use crate::clients::directory::requests::presence_providers_post::{
|
||||
PresenceMixProviderPoster, Request as PresenceProvidersPost,
|
||||
};
|
||||
use crate::clients::directory::requests::presence_topology_get::{
|
||||
PresenceTopologyGetRequester, Request as PresenceTopologyRequest,
|
||||
};
|
||||
|
||||
pub mod metrics;
|
||||
pub mod presence;
|
||||
pub mod requests;
|
||||
|
||||
pub struct Config {
|
||||
pub base_url: String,
|
||||
}
|
||||
|
||||
pub trait DirectoryClient {
|
||||
fn new(config: Config) -> Self;
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
pub health_check: HealthCheckRequest,
|
||||
pub metrics_mixes: MetricsMixRequest,
|
||||
pub metrics_post: MetricsMixPost,
|
||||
pub presence_coconodes_post: PresenceCocoNodesPost,
|
||||
pub presence_mix_nodes_post: PresenceMixNodesPost,
|
||||
pub presence_providers_post: PresenceProvidersPost,
|
||||
pub presence_topology: PresenceTopologyRequest,
|
||||
}
|
||||
|
||||
impl DirectoryClient for Client {
|
||||
fn new(config: Config) -> Client {
|
||||
let health_check: HealthCheckRequest = HealthCheckRequest::new(config.base_url.clone());
|
||||
let metrics_mixes: MetricsMixRequest = MetricsMixRequest::new(config.base_url.clone());
|
||||
let metrics_post: MetricsMixPost = MetricsMixPost::new(config.base_url.clone());
|
||||
let presence_topology: PresenceTopologyRequest =
|
||||
PresenceTopologyRequest::new(config.base_url.clone());
|
||||
let presence_coconodes_post: PresenceCocoNodesPost =
|
||||
PresenceCocoNodesPost::new(config.base_url.clone());
|
||||
let presence_mix_nodes_post: PresenceMixNodesPost =
|
||||
PresenceMixNodesPost::new(config.base_url.clone());
|
||||
let presence_providers_post: PresenceProvidersPost =
|
||||
PresenceProvidersPost::new(config.base_url.clone());
|
||||
Client {
|
||||
health_check,
|
||||
metrics_mixes,
|
||||
metrics_post,
|
||||
presence_coconodes_post,
|
||||
presence_mix_nodes_post,
|
||||
presence_providers_post,
|
||||
presence_topology,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CocoPresence {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub last_seen: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixNodePresence {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub layer: u64,
|
||||
pub last_seen: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixProviderPresence {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub registered_clients: Vec<MixProviderClient>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixProviderClient {
|
||||
pub pub_key: String,
|
||||
}
|
||||
|
||||
// Topology shows us the current state of the overall Nym network
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Topology {
|
||||
pub coco_nodes: Vec<CocoPresence>,
|
||||
pub mix_nodes: Vec<MixNodePresence>,
|
||||
pub mix_provider_nodes: Vec<MixProviderPresence>,
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
use reqwest::Response;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait HealthCheckRequester {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn get(&self) -> Result<Response, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl HealthCheckRequester for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/healthcheck".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> Result<Response, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
reqwest::get(&url)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod healthcheck_requests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("GET", "/api/healthcheck").with_status(400).create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
assert!(req.get().is_err());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_a_response_with_200_status() {
|
||||
let _m = mock("GET", "/api/healthcheck").with_status(200).create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
assert!(req.get().is_ok());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
use crate::clients::directory::metrics::PersistedMixMetric;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait MetricsMixRequester {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn get(&self) -> Result<Vec<PersistedMixMetric>, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl MetricsMixRequester for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/metrics/mixes".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> Result<Vec<PersistedMixMetric>, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let mix_metric_vec = reqwest::get(&url)?.json()?;
|
||||
Ok(mix_metric_vec)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metrics_get_request {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("GET", "/api/metrics/mixes").with_status(400).create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
req.get().unwrap();
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_200_status_and_a_correct_topology() {
|
||||
let json = fixtures::mix_metrics_response_json();
|
||||
let _m = mock("GET", "/api/metrics/mixes")
|
||||
.with_status(200)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let result = req.get();
|
||||
assert_eq!(true, result.is_ok());
|
||||
assert_eq!(
|
||||
1576061080635800000,
|
||||
result.unwrap().first().unwrap().timestamp
|
||||
);
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fixtures {
|
||||
#[cfg(test)]
|
||||
pub fn mix_metrics_response_json() -> String {
|
||||
r#"[
|
||||
{
|
||||
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 1,
|
||||
"52.56.99.196:1789": 2
|
||||
},
|
||||
"received": 10,
|
||||
"timestamp": 1576061080635800000
|
||||
},
|
||||
{
|
||||
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 2,
|
||||
"35.178.212.193:1789": 2
|
||||
},
|
||||
"received": 4,
|
||||
"timestamp": 1576061080806225700
|
||||
},
|
||||
{
|
||||
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 3
|
||||
},
|
||||
"received": 3,
|
||||
"timestamp": 1576061080894667300
|
||||
},
|
||||
{
|
||||
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 5,
|
||||
"35.176.155.107:1789": 3
|
||||
},
|
||||
"received": 8,
|
||||
"timestamp": 1576061081254846500
|
||||
},
|
||||
{
|
||||
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 4,
|
||||
"52.56.99.196:1789": 6
|
||||
},
|
||||
"received": 19,
|
||||
"timestamp": 1576061081371549000
|
||||
},
|
||||
{
|
||||
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 4,
|
||||
"35.178.212.193:1789": 2
|
||||
},
|
||||
"received": 6,
|
||||
"timestamp": 1576061081498404900
|
||||
},
|
||||
{
|
||||
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 2,
|
||||
"52.56.99.196:1789": 3
|
||||
},
|
||||
"received": 6,
|
||||
"timestamp": 1576061081637625000
|
||||
},
|
||||
{
|
||||
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 5,
|
||||
"35.178.212.193:1789": 4
|
||||
},
|
||||
"received": 9,
|
||||
"timestamp": 1576061081805484800
|
||||
},
|
||||
{
|
||||
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 4,
|
||||
"35.176.155.107:1789": 4
|
||||
},
|
||||
"received": 8,
|
||||
"timestamp": 1576061081896562400
|
||||
},
|
||||
{
|
||||
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 2,
|
||||
"35.176.155.107:1789": 4
|
||||
},
|
||||
"received": 6,
|
||||
"timestamp": 1576061079255938600
|
||||
},
|
||||
{
|
||||
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 6
|
||||
},
|
||||
"received": 10,
|
||||
"timestamp": 1576061079370829300
|
||||
},
|
||||
{
|
||||
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 2,
|
||||
"35.178.212.193:1789": 5
|
||||
},
|
||||
"received": 7,
|
||||
"timestamp": 1576061079497993200
|
||||
},
|
||||
{
|
||||
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 5,
|
||||
"52.56.99.196:1789": 2
|
||||
},
|
||||
"received": 13,
|
||||
"timestamp": 1576061079637208600
|
||||
},
|
||||
{
|
||||
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 5,
|
||||
"35.178.212.193:1789": 4
|
||||
},
|
||||
"received": 9,
|
||||
"timestamp": 1576061079806557200
|
||||
},
|
||||
{
|
||||
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 2,
|
||||
"35.176.155.107:1789": 7
|
||||
},
|
||||
"received": 9,
|
||||
"timestamp": 1576061079895988000
|
||||
},
|
||||
{
|
||||
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
|
||||
"sent": {
|
||||
"3.9.12.238:1789": 3,
|
||||
"35.176.155.107:1789": 2
|
||||
},
|
||||
"received": 5,
|
||||
"timestamp": 1576061080255701500
|
||||
},
|
||||
{
|
||||
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 3,
|
||||
"52.56.99.196:1789": 3
|
||||
},
|
||||
"received": 7,
|
||||
"timestamp": 1576061080370956300
|
||||
},
|
||||
{
|
||||
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
|
||||
"sent": {
|
||||
"3.8.176.11:1789": 5,
|
||||
"35.178.212.193:1789": 1
|
||||
},
|
||||
"received": 6,
|
||||
"timestamp": 1576061080501732900
|
||||
}
|
||||
]"#
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
use crate::clients::directory::metrics::MixMetric;
|
||||
use reqwest::Response;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait MetricsMixPoster {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn post(&self, metric: &MixMetric) -> Result<Response, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl MetricsMixPoster for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/metrics/mixes".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn post(&self, metric: &MixMetric) -> Result<Response, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let client = reqwest::Client::new();
|
||||
let mix_metric_vec = client.post(&url).json(&metric).send()?;
|
||||
Ok(mix_metric_vec)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metrics_get_request {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("POST", "/api/metrics/mixes").with_status(400).create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let metric = fixtures::new_metric();
|
||||
let result = req.post(&metric);
|
||||
assert_eq!(400, result.unwrap().status());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_200() {
|
||||
let json = fixtures::mix_metrics_response_json();
|
||||
let _m = mock("POST", "/api/metrics/mixes")
|
||||
.with_status(201)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let metric = fixtures::new_metric();
|
||||
let result = req.post(&metric);
|
||||
assert_eq!(true, result.is_ok());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fixtures {
|
||||
use crate::clients::directory::metrics::MixMetric;
|
||||
|
||||
pub fn new_metric() -> MixMetric {
|
||||
MixMetric {
|
||||
pub_key: "abc".to_string(),
|
||||
received: 666,
|
||||
sent: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn mix_metrics_response_json() -> String {
|
||||
r#"
|
||||
{
|
||||
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
|
||||
"sent": {
|
||||
"35.178.213.77:1789": 1,
|
||||
"52.56.99.196:1789": 2
|
||||
},
|
||||
"received": 10,
|
||||
"timestamp": 1576061080635800000
|
||||
}
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
pub mod health_check_get;
|
||||
pub mod metrics_mixes_get;
|
||||
pub mod metrics_mixes_post;
|
||||
pub mod presence_coconodes_post;
|
||||
pub mod presence_mixnodes_post;
|
||||
pub mod presence_providers_post;
|
||||
pub mod presence_topology_get;
|
||||
@@ -1,86 +0,0 @@
|
||||
use crate::clients::directory::presence::CocoPresence;
|
||||
use reqwest::Response;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait PresenceCocoNodesPoster {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn post(&self, presence: &CocoPresence) -> Result<Response, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl PresenceCocoNodesPoster for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/presence/coconodes".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn post(&self, presence: &CocoPresence) -> Result<Response, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let client = reqwest::Client::new();
|
||||
let p = client.post(&url).json(&presence).send()?;
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metrics_get_request {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("POST", "/api/presence/coconodes")
|
||||
.with_status(400)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(400, result.unwrap().status());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_201() {
|
||||
let json = r#"{
|
||||
"ok": true
|
||||
}"#;
|
||||
let _m = mock("POST", "/api/presence/coconodes")
|
||||
.with_status(201)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(true, result.is_ok());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fixtures {
|
||||
use crate::clients::directory::presence::CocoPresence;
|
||||
|
||||
pub fn new_presence() -> CocoPresence {
|
||||
CocoPresence {
|
||||
host: "foo.com".to_string(),
|
||||
pub_key: "abc".to_string(),
|
||||
last_seen: 666,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use crate::clients::directory::presence::MixNodePresence;
|
||||
use reqwest::Response;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait PresenceMixNodesPoster {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn post(&self, presence: &MixNodePresence) -> Result<Response, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl PresenceMixNodesPoster for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/presence/mixnodes".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn post(&self, presence: &MixNodePresence) -> Result<Response, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let client = reqwest::Client::new();
|
||||
let p = client.post(&url).json(&presence).send()?;
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metrics_get_request {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("POST", "/api/presence/mixnodes")
|
||||
.with_status(400)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(400, result.unwrap().status());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_201() {
|
||||
let json = r#"{
|
||||
"ok": true
|
||||
}"#;
|
||||
let _m = mock("POST", "/api/presence/mixnodes")
|
||||
.with_status(201)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(true, result.is_ok());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fixtures {
|
||||
use crate::clients::directory::presence::MixNodePresence;
|
||||
|
||||
pub fn new_presence() -> MixNodePresence {
|
||||
MixNodePresence {
|
||||
host: "foo.com".to_string(),
|
||||
pub_key: "abc".to_string(),
|
||||
layer: 1,
|
||||
last_seen: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
use crate::clients::directory::presence::MixProviderPresence;
|
||||
use reqwest::Response;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait PresenceMixProviderPoster {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn post(&self, presence: &MixProviderPresence) -> Result<Response, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl PresenceMixProviderPoster for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/presence/mixproviders".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn post(&self, presence: &MixProviderPresence) -> Result<Response, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let client = reqwest::Client::new();
|
||||
let p = client.post(&url).json(&presence).send()?;
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metrics_get_request {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error() {
|
||||
let _m = mock("POST", "/api/presence/mixproviders")
|
||||
.with_status(400)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(400, result.unwrap().status());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_201() {
|
||||
let json = r#"{
|
||||
"ok": true
|
||||
}"#;
|
||||
let _m = mock("POST", "/api/presence/mixproviders")
|
||||
.with_status(201)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let presence = fixtures::new_presence();
|
||||
let result = req.post(&presence);
|
||||
assert_eq!(true, result.is_ok());
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod fixtures {
|
||||
use crate::clients::directory::presence::MixProviderPresence;
|
||||
|
||||
pub fn new_presence() -> MixProviderPresence {
|
||||
MixProviderPresence {
|
||||
host: "foo.com".to_string(),
|
||||
pub_key: "abc".to_string(),
|
||||
registered_clients: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
use crate::clients::directory::presence::Topology;
|
||||
|
||||
pub struct Request {
|
||||
base_url: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub trait PresenceTopologyGetRequester {
|
||||
fn new(base_url: String) -> Self;
|
||||
fn get(&self) -> Result<Topology, reqwest::Error>;
|
||||
}
|
||||
|
||||
impl PresenceTopologyGetRequester for Request {
|
||||
fn new(base_url: String) -> Self {
|
||||
Request {
|
||||
base_url,
|
||||
path: "/api/presence/topology".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> Result<Topology, reqwest::Error> {
|
||||
let url = format!("{}{}", self.base_url, self.path);
|
||||
let topology: Topology = reqwest::get(&url)?.json()?;
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod topology_requests {
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use mockito::mock;
|
||||
#[cfg(test)]
|
||||
mod on_a_400_status {
|
||||
use super::*;
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn it_panics() {
|
||||
let _m = mock("GET", "/api/presence/topology")
|
||||
.with_status(400)
|
||||
.with_body("bad body")
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
req.get().unwrap();
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod on_a_200 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_a_response_with_200_status_and_a_correct_topology() {
|
||||
let json = fixtures::topology_response_json();
|
||||
let _m = mock("GET", "/api/presence/topology")
|
||||
.with_status(200)
|
||||
.with_body(json)
|
||||
.create();
|
||||
let req = Request::new(mockito::server_url());
|
||||
let result = req.get();
|
||||
assert_eq!(true, result.is_ok());
|
||||
assert_eq!(
|
||||
1575915097085539300,
|
||||
result.unwrap().coco_nodes.first().unwrap().last_seen
|
||||
);
|
||||
_m.assert();
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
pub mod fixtures {
|
||||
#[cfg(test)]
|
||||
pub fn topology_response_json() -> String {
|
||||
r#"{
|
||||
"cocoNodes": [
|
||||
{
|
||||
"host": "3.8.244.109:4000",
|
||||
"pubKey": "AAAAAAAAAAEKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEFuhRpy4HfcuxwcRI9sIWMo_LVmbk19g1gfMRlBrmZqoEQL6rDApVLZ9eMp-5IQK8WLlZpWf4Zjy7kZolARAyp_rHUQkH4PrDjgoPrKbm6qK_iejYpL7qx28Q3VeInMpwMIMaSbbW9y36sEVtGc2I0Iu5vS0sp8ESiVlQ5NaBz72deZ8oKJJ4IEPPHP99-b0UQX80fVIrNM88mMzKy0bHri9NFlmIG-e0G1cqmw_ry3XWGQkcr1M5RuNa6oX50w5QawAEVxd5FP5bE8bS4x54Csof11sQWUTwMp6Q7_3H7ZCTSlKSqujlOhmfqSHfGPO2sDIYPHDhDzjakZpKAZWWhn_hiR6DfPpomQ01ZYUhVKKSMxz7_VPjsQplP0bZXA2gfnkADUN8UQ0N9g_usIw73r4aZsOviMsRM8oByvsjVfUWc4_HTLSdnQyImFkHz9CiCmrIYL2dYQRePRatWggvBAyeRzntxI4jDqLKiBdi54ZlAKgV6MCRaJ7Bu7BtmLXrtK4sawAED3QYxuvOSZrbZdUr4yG-U9yVvJ9Klkf-5Mo4EYp3qTL2KBB6_LrZepjAQqp486YkZ03mTIezcsZ48EboXVTWKBZ3QnTI5tX-j4gGxQb7klOJc97qJkDxsvpz4F0ChgCUIZhpIItWHia7_R3Gi-b5siLIdQdUho9isn3kiDGm6t0NED2Bgy3ZxxQwzqsBZm4kPr2_fPX4YyvIoP9895YcGjZyE5iiRC_TE41RJmB1GZYdxegTMq3lNDllKgiqaiPgawAEJASDkmZHTwlg9YOev5OWpQD-FnhPkqVNo_QcDyRu9eoGcWSGFp2sYqjG2SpmiXq0VNnAO7AcKxRzDFu7TjfhlU3Kt0uTKIcrWVU1zFNbJNMjYEq90pp50nowwx8INz20IXET2ZNX6kIXYFCsEvPLZFlG2OoL6xg3uQS1qMl3lIS_VxdO_JfVe0rT65WsJ_P4Nkc1jYiuNPHY6d_iFO0BVYqX0sOCX73GC_TT13BR0jnPwDAVw0rGtYHsXBb8TKOsawAEZIClauuT1V3qOZnb7uRZhFXO-PKTxgc1LCzJt2ChOrMZaBpjlkf3IPpJ2UF4JH4kGaDeBf2k_S-FLAs3drK21efbi5P6_a4QTxAiiRimXGoQIyvOg462s6kP_ZRFufo8YYQHS4olaOeqU4564dNskg_uBPsFMz_2GNOhmn_15cJqP1jfkyD49Z16GTS5YLHgVl9bJKqyvLuypsToLbt1BJzipEP0L2OohuRm-_MvqvwwWKyjNQsubgee1K728d9AawAEBkGggcNVCtXyhoSqi3_w0tVxtkAYeud8sBeAtZHGs06me_QL8co0MFLlO-zdkUb4ZBq08rFEbgLOma8_3whleM8NIPaHNISp1q3IsIhB5zdXcZoGsqLixODBFHtID3YEHAlr4f9T_yh11yJ95xGCl_6Y37hpwLQVGyrfSfccM24mVFqnV3TT5Wdq3ile-jesUx1Q2G1yK_xVqc6itmk-kDuBjyZgzYi1-jsIXAjnhM9G7t8J_Bv5yGGZhLK2dCzM=",
|
||||
"type": "validator",
|
||||
"lastSeen": 1575915097085539300
|
||||
},
|
||||
{
|
||||
"host": "3.9.129.61:4000",
|
||||
"pubKey": "AAAAAAAAAAMKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEEv6RMevAQmLGkeK0uJKnMPPAtm8GgXjWSQijYdnxlPh5SJSNeJUbPZKWFFWdk8yIFXKa8jnzETtdGFKgUUt5AVUDpTBmEdwaHCzlFhXrttshy0V5OhPUlV8cGABmxbagMYm0bFPg0r-snSkrB9YG6wqJYQVeIMOCGYCPbHmDA8R_0-h8VkRKWs1d9KvQOK4kShqgZtYN71KJW8uDE4q2jsGDVvxFt1AgmU9b93xsXF17KrpZy5WxlLZ73HtnTD_oawAED4vd_rK-Kx_n8x_OdDiiEOPUlYDlDCQUqenU9XHKH3B6ijfkJ368wd3LDDVStjDwNORrAyUSw_VlSNUpd1XLC8d17gTaIq5ZI2fWuwwZaoN1JCsYU8fQ6USgtIehQX7IPP8EkFuNmuCBCmpr4schtYniGe9J8Q4dsV-TYPr2uLJkdx1r7luzF--I22k7NfQQM14QDci_0kgrgmZ54CJGkjXyOhCppBXg3fqLC6aFvT3ZocfiiXBJt0huGgPMDtYsawAECLh8KUdNsDolERwJ8v04bS5jI_KKf7uUnCHWuCELwbJSUI3OK1ufS1qSpauvSzVQSbrhEzrEfwQn4VtxQxJlX4UdDU-R-hafiZvVC6DLLAbuORBAC3FScn9W58CnezH4DvCp_w7nftDfdxeuungbZT9XaxS3iNC6PnFsWF6WM3DxMwrzOrFe6wEEoTSPe1mcUDrtwM5UksIvJr6MBRAXrdl0IdBTQr7cLwKe_KYi4siwdjfJEJtOh7oxQBxBg2UkawAEJAPZK2Gg2MQwpxdDT24lNQHF7FVfkO_LuhJwn0RbwNDSVeA4P6-tWL5TkCpqr8xYHfwQ6Z3ILfpGCZr8PspwIoRzqZHQ16f8Pq9xnr0hLEI9BOQU0FS2EtuyPgju5iwsAJAfehUzu6kNLphuLGsXoIZdXDG5mbylwh9JzAVXTwgaR0hNqyXVJxgbt7jcYaSEBFcMGV-hjXyVVNzBleE-G9o_noI_KWU4Ce7K-qOMcewMKfy_VEw-gVaD6dHz6AMoawAEE9XuOLwRttvKybAssZ9gsK-_YRUwuFOeRDIr3NX___9bx6pCc18adCIlH_8EJWFwXZ05ZpNNE88mYx7ZQ3aqaArZJRoWeZeKhqH_s05V10xbzkYX71G5cqz--8vr9ZlQRb2BeETF_Tdq_PLk7qbT8WTGIoq7ZwyDRQTgzvkCgyzj_hBLh2o7sSVNgUo38SFUTMn7YtvVFYlSrTDE3WKE-T-nh5SWdDBxgDTc3Bw8JpzNH-WkoJ4Lim7sB4Op1gEUawAEW4-kenlffwsNr_3b3aV0YuusLpxB03sxPzQ5B0CWNiVtbja1Z4tWhKGUUrdq_eUgMV0y5Of-BqNi5FspAQnhJBFSSxtOzRGV1h3qyUTksfZyed9z8zPI-ZPP9XXm7hYgJgDz_kxte-NfS9UG9q5AZetHUN4kGxXutjjzfUQZ9yTvhBKgKgTI2Dp_R_jZrWQ8F1BoWzIJzjddT1K2MvCQEkARYw08isbOeFmCwgVUcjxYZO45WyOmLQA7QJRL9WvA=",
|
||||
"type": "validator",
|
||||
"lastSeen": 1575915097388409000
|
||||
},
|
||||
{
|
||||
"host": "3.9.222.1:4000",
|
||||
"pubKey": "AAAAAAAAAAQKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAECh9xcxpjOp1r7kiNIgrI9GgAlvXwgHkTchOxUiyOzTq6FDWdGN64KiC3NDeyGTg8FmzvGzS3jREeJqOdr4G9ZGtWkauAITgLFiH62t-YntRslhr8_1shxlmzKiNKJN_QFflEq79pZIlWtp3N8LIHMvXRtl-zt2DMze4s02XDmEkviyVE4CkQUDtCc-2MfPT4JcmEFqtFIxjrXn18SbYg3c6XUQHsGIkuDrKuCTRlpC8kvmM0uVoIeWdmwDlZk4jUawAEJhRwK5ozjqIWRP1bFzBPS9VhaJnfKU9PeFYtN5beiAHrYr2ylIB3yDfmAQUdKDowDUm5nfJATejEjEnrTGxh70QtfoNV391rSns3F71tBwY62KLaNr8qnVfeSFHV3FcQTMHHF_8mDb5_11Rj6aiMvW0y6eetHo7CDPMdEyDPmok_U2ZM5BzOUnwjT21HtnvcKxKKwHJ_QGfnAHPyDIhNOMgxJCrVazOidLCHeYGpyCLw1ipeTyKOQX0_ByB8dH6AawAEGV1GuF5SSlT67B1ityPJK2ZwXjeeKB4gGdCG3qRtWxLTZfGhVm7YAYm2f5tw_wrsJAZ9FubVhateGg0ZN67NxZtsvOOejXz6743f7ijnQopPgd_8pH-iVf6BEcSO8ZdcHxNRUTayzjVLs99bwMo2zaPevW4X4G_bN4mh---aPkdGYHwaiklzUhqJ-eqycrYAFyjyEXaPBXLQm1rpczqluNvnKbd8Q9LZWukgm7_uWv_HxufIvdWgoq8bAt78UU3oawAEP9VDehhqrQG5-WHMB66XVxo1TgMM8aVV0SwAq3lCRkpiFBz_9kw8T1F9Hx2AiNrEGT1QLbdMkpms1cG_5gBBahQofdt_NmUs1jfTFXY9iyMy1Q7A6ZYaLP8Z6q-orc1cKqySY-BJZQ_CpGFfXS0OVniFDQ6v78ytPK7K-yRgT1PxFgm3rZqrG0Tjbrpsg2PUL5S5fuXfMhUosP0uoLj0D1guWAR9Y7kfFBIXaTSFMoa8fghVBUTRNhK9f72a8SxQawAEOiv71taLjKqaaWQ_QjcDhWbvjG1EnsCyI0toNjGkcF19x4Vk-5NC96_4ioUGz404IC0XN03roRnibRT_78D9vZFVCWCqve9EjdF5TcApx03zIP4JT2g2q0MKIGgGrwt4Pz6LO6yOfMm7B8Yraps8IV-nP1w7K1m9XKP_FvH8egl5GHJe-_omlC2YyL_b28jMLENbxDFD-3KPjZFBhSLrRukX2PlayYTwEiTtokA2R9_11vQvJgP8KFEjGHg6zsAMawAEBn2H_hz2knb8ltnpEA5YSKVcV3nUtojkCNi_WUz7xUKd7efw1oI_lbnKrS7HkyC0JkQUZ1pCWUlSXNmgjMEhsn823a1LFzpV7rOv4vayYvvFX61hB9R78VjpyxJiYpDwRZLiUY3AK4WY8NqFDbjXR7rT4CkFHEf-VhSQQ8ZNvlpod1nmeVQVizHH9e7Tq7wsWz-LWEk3Hx6LmcrgDsL79LZYG9JXU5IdvG8RvLNx9cSwEI8yxcchpISAaot7UoYQ=",
|
||||
"type": "validator",
|
||||
"lastSeen": 1575915094734973000
|
||||
},
|
||||
{
|
||||
"host": "3.9.102.214:4000",
|
||||
"pubKey": "AAAAAAAAAAIKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEOVCUN3EwiVroS5-TOq2o7hYSxphK9X0G23N-IBZ0Tr1Rl8XEiJ-OEy0rqnAKwmhAZJWnx3u8oXqbZtOWIZmzQSpcoxhgwfhdmTZJCqT2RVzZyeFItX4sVeilEP3z2xdsJs8-a1kg6UZnx1s1BNLBo7eZrreZygWojPCIDBn03fSAflXoVc5PpY2CGy5MA_IgWgSYBHDdoZEtigp_amjqK7Us44Db20XpLxMXfbahiqa7WKNnMgi6Ca2H67VtaaD8awAEF3zbE1nZRAa7a8vbU25c80YBYJBaW8P6FwXQI-K0Xk5MakwYeMMnIrm6w6IS_0XAO5YlD453GLqnxY8H1BEnRpfOnT7PE4el9mJ8MuYQMo6R2up0lGCmYM0YA9FORjroM3ng69SEPfJPCReG7LfJkERl_m2U403ertDRBYrlqCDagDfyI500srBcMrjSvV3oNouyyx3yZUrjLQfbHhDteQFsYdmakJs8Y-Q9-5MXCcrz6Qa4xwv522Euv0CCxkHcawAEYjfsU_zDhUZA1ey1aquWXlFOnx-iEALqxW1slDYHwQ1M2SILc-v_E6i1doa5e_bAZHVezBHFAlaNAVedNyHFFJxYAqAK3hbzbvl2glw3Q6h_rTXElymloqtaqVFIJ-oUWWOHsZBmu8EDA-HzvGCiBa_GbRaVfh2lE4ObeMXoJrEm_5dbxxeEic2l3IYeIz40N9ooQQOkQcOZdY4AXWYCavIAwWEJBjLtptJgCLu9a_zM1S5GsiyJHpdDs46WbP0EawAEWZ-95Sf0YAHujxRNLdXgpqe0ZF8loVwzZfvyMvqaxF1Ug274BqHuY_c5NdPAzuqoTwjfEn8NKEoaNqlumM75FUYbaTd7mXvk4WVYWjVnkO40dfQjRB7DYhvj0LBlbndAJ4wJIA2ilPYgjZsXVbNNh3e2j3u9eABd0VaFMbSb8Sz5_31r8HzoWmPJs3HiyuyANGFUA6CvAnMN6K3b-D8BhFZU_nPUTgu80o8_n6LQt-XWbaC_mTHzsnOjzBiPJxlYawAEW3bmOEtStH2T8q7vMkhchImp2-hg9MFYGBmEe9sSByTn3NUf8eksqXOC1dUjHkXoZm298FgUYLkNdnlxWpf993j5mEDoFxjcTB7scBD7k6nu6Nrs_wK0-seS8gsHrx9UK7GwAsi10q82Cm4PFyAtrWjmy_d9WLHuZt6VIOKunTs8cf0FwNUiMcvZsruqIFJcP7iWxdiFdUkh65P_iCz1ZEjJcj2GEZoq4v3a3by1aizGPaaiKc1jd_T-XJg_YpncawAEWnstu5b9WiZv0x8xfsiMk6YRlU0Cnj5svxLLXz_8drvwAa--GBY5yH0ke2EM6udMEi2EPeFcGTe6Sjs0YEhSbY7Uad_8suD2J4tIWJSWBbiyvh7rSqzv57m7BlsVcHfQJn_wNH-UlC9xkx8vg-LwfN8_FlxvHNPTc7XZG3lKYbwpUWlZxAziOYT1VQ-2K2bQQBBMdix-ht_SjccL1Dc2dP5kDazQ8yZV_8xnyeheazEedWe63uutfkHlZRg9YwP8=",
|
||||
"type": "validator",
|
||||
"lastSeen": 1575915094967382800
|
||||
}
|
||||
],
|
||||
"mixNodes": [
|
||||
{
|
||||
"host": "35.176.155.107:1789",
|
||||
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
|
||||
"layer": 3,
|
||||
"lastSeen": 1575915096805374500
|
||||
},
|
||||
{
|
||||
"host": "18.130.86.190:1789",
|
||||
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
|
||||
"layer": 1,
|
||||
"lastSeen": 1575915097370376000
|
||||
},
|
||||
{
|
||||
"host": "3.10.22.152:1789",
|
||||
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
|
||||
"layer": 1,
|
||||
"lastSeen": 1575915097639423500
|
||||
},
|
||||
{
|
||||
"host": "35.178.213.77:1789",
|
||||
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
|
||||
"layer": 2,
|
||||
"lastSeen": 1575915097895166500
|
||||
},
|
||||
{
|
||||
"host": "52.56.99.196:1789",
|
||||
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
|
||||
"layer": 2,
|
||||
"lastSeen": 1575915096255174700
|
||||
},
|
||||
{
|
||||
"host": "3.9.12.238:1789",
|
||||
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
|
||||
"layer": 3,
|
||||
"lastSeen": 1575915096497827600
|
||||
}
|
||||
],
|
||||
"mixProviderNodes": [
|
||||
{
|
||||
"host": "3.8.176.11:1789",
|
||||
"pubKey": "54U6krAr-j9nQXFlsHk3io04_p0tctuqH71t7w_usgI=",
|
||||
"registeredClients": [
|
||||
{
|
||||
"pubKey": "zOqdJFH49HcgGSCRnmbXGzovnwRLEPN0YGN1SCafTyo="
|
||||
},
|
||||
{
|
||||
"pubKey": "fy9xo69hZ2UJ9uxhIS1YzKHZsH8saV-02AiyCNXPNUc="
|
||||
},
|
||||
{
|
||||
"pubKey": "6hFCz42d5AODAoMXqcBWtoOoZh-7hPMDXbLKKhS7x3I="
|
||||
},
|
||||
{
|
||||
"pubKey": "pPZMDzw0FyZ-LBAhwCvjlPGj1p2bO_vaWbRBc7Ojq3Q="
|
||||
},
|
||||
{
|
||||
"pubKey": "kjl5poXt2GdIrHLuMBjmTBSChV-zMqsXFBhKZoIREVI="
|
||||
},
|
||||
{
|
||||
"pubKey": "T1jMGuk7-rcIUWnVopAsdGzhAJ7ZVymwON2LzjuOfnY="
|
||||
},
|
||||
{
|
||||
"pubKey": "3X0eKPkflx5Vzok0Gk0jm5-YEfvPAuWP55ovyBUOtXA="
|
||||
},
|
||||
{
|
||||
"pubKey": "5wC3i8rCZolLKbWJ9U6eLieXNGLKM21dtL6lR30u_hE="
|
||||
},
|
||||
{
|
||||
"pubKey": "1P6p7fgjwjlEepD9JgbN1V-rk9n36-hCmPN5P6y62n4="
|
||||
},
|
||||
{
|
||||
"pubKey": "aBjlLQKKFroqhX_kvYLnMm1uq3FJdQWqVy9Q35zzERA="
|
||||
},
|
||||
{
|
||||
"pubKey": "I0gVOPj6lv9ha60xPYKeAgbeUU8pdyMD-Y7Nb1nS9EQ="
|
||||
},
|
||||
{
|
||||
"pubKey": "WgdvQ74QH1uFDWDL2YeApvv7oniNGh9BQJ_HZam20QA="
|
||||
},
|
||||
{
|
||||
"pubKey": "Mlw23KaSL2hyrIjEZM76bZStt2iMzxVAqXwO5clJfxg="
|
||||
},
|
||||
{
|
||||
"pubKey": "F9xzbjnMQVN4ZidcqN2ip9kVnI9wbS39aVayZGiMihY="
|
||||
},
|
||||
{
|
||||
"pubKey": "s6pfVkZrUG--RNjfzS55N2oPvFkMdvgb1LUut6gqRy4="
|
||||
},
|
||||
{
|
||||
"pubKey": "bSi-9k0jJNKc8PGx8M3SWFaNpORFjYw-NkWXRZVRWGU="
|
||||
},
|
||||
{
|
||||
"pubKey": "pz6ahQcGOQcZBFx1tGmzRngqk6BecXB_wFd4WVdOQDU="
|
||||
},
|
||||
{
|
||||
"pubKey": "5sfwIMcG2zRCxhDh4D9Evw1WPI5bfKZAShM_6o9Pu1I="
|
||||
},
|
||||
{
|
||||
"pubKey": "9fZnxXy9onGPpZ3Ygckqw0okqCw3di02sLr-NTBr4SE="
|
||||
},
|
||||
{
|
||||
"pubKey": "Q0TbbggOwzZjalUdi5eEHVFi9VMv-rMm5mJPUZZs12A="
|
||||
},
|
||||
{
|
||||
"pubKey": "aPNyox_qAIGFB2-wZ0lc9iAWDN6jzLojApSiWVFjCks="
|
||||
},
|
||||
{
|
||||
"pubKey": "DUKLEsIGMw-ucs3DjS7Ag9qCb5-C_A84DuIsZuLkdwI="
|
||||
},
|
||||
{
|
||||
"pubKey": "YV84vPoSrLf1p9Sw6FnnrcCpS3kvpJUfKyKpnwk8z0Q="
|
||||
},
|
||||
{
|
||||
"pubKey": "_IYEzZQoBAYeTxqzpEe_ez1-7pn7aId8AKliazy0qlE="
|
||||
},
|
||||
{
|
||||
"pubKey": "srkOAoVU-a02lnEsoH_wOLLw7HFx_xHIZUSbnhjFwDw="
|
||||
},
|
||||
{
|
||||
"pubKey": "LxSCBn_OEQq-hI2xDi6bfGoioRO_lSTIq6AQ9l1k5jg="
|
||||
},
|
||||
{
|
||||
"pubKey": "OC0OOqtGfAytgZjthpjoKeYNa0VrtzfgZ0iO5Fag5y8="
|
||||
},
|
||||
{
|
||||
"pubKey": "ImVEch2focRhm1ial1gA6YJPr6WDyW3oh-OgYcO5Ll4="
|
||||
},
|
||||
{
|
||||
"pubKey": "yTDnzLvEaSq0mC9xNrtyjpAKtsIU6yRuBepCuWQMBm4="
|
||||
},
|
||||
{
|
||||
"pubKey": "-LCUUc46HuL7iUEOMkrlVAkvvulRiQ7dR1QYh7bkKxw="
|
||||
},
|
||||
{
|
||||
"pubKey": "Bx1MGpISig25rqe7mhoX68EROUPPzmF7yGLYah9DPgM="
|
||||
},
|
||||
{
|
||||
"pubKey": "Z4Nu6iwLmgJ93yoIFTbTEBeDAHRwS-vo1T_K2Kv1FQo="
|
||||
},
|
||||
{
|
||||
"pubKey": "cKFAGxllwAmEXCtDxG_T1iEm3-lKWUVQxxpDBje6mQU="
|
||||
},
|
||||
{
|
||||
"pubKey": "pQV40whlQWUSXtrNTTePzO6sdq3zr1JUIWZWvD443nY="
|
||||
},
|
||||
{
|
||||
"pubKey": "6Bb5HwnVqJPy5wcNsaHY-0y__coZCE7XC80kUkesnRU="
|
||||
},
|
||||
{
|
||||
"pubKey": "COGdpfhmzNGR6YX820GqJIkjOihL8mr6-h-d3JlTDFA="
|
||||
}
|
||||
],
|
||||
"lastSeen": 1575915097358694100
|
||||
},
|
||||
{
|
||||
"host": "35.178.212.193:1789",
|
||||
"pubKey": "sA-sxi038pEbGy4lgZWG-RdHHDkA6kZzu44G0LUxFSc=",
|
||||
"registeredClients": [
|
||||
{
|
||||
"pubKey": "UE-7r6-bpw0b4T3GxOBVxlg02psx23DF2p5Tuf-OBSE="
|
||||
},
|
||||
{
|
||||
"pubKey": "UnZuLpzq64_EPtIcr1Fd-5AESBCBLFnDMDsjUaOqrUA="
|
||||
},
|
||||
{
|
||||
"pubKey": "4ExXPrW5w0nZIQ5ravBRT6H9r0RH0MXuOcGIF8HzUhg="
|
||||
},
|
||||
{
|
||||
"pubKey": "wPsRpJPi1e2sjItyRKDkFACbxwu3Cw5GlYVPmdYxk2U="
|
||||
},
|
||||
{
|
||||
"pubKey": "UfK5UvT3HUkT1SGbv1QGafy3in3uQ9a6NSy5EOT6k0k="
|
||||
},
|
||||
{
|
||||
"pubKey": "5Giu-tJpGXU0S9Av75iAv5qDO0k6l8v_k9-UCcRUCl4="
|
||||
},
|
||||
{
|
||||
"pubKey": "MnQxlmmKDybku4CfxsQQxfftilsaphF9Gq1w3MB1ZCE="
|
||||
},
|
||||
{
|
||||
"pubKey": "GdP1fHVs2R65EkuWVWKZSz6WPDh0MgThyuBOv6_xsmQ="
|
||||
},
|
||||
{
|
||||
"pubKey": "4JEtSrKsonmBuDvxJ9nITSu7iC4f8reutXRAVugPgS4="
|
||||
},
|
||||
{
|
||||
"pubKey": "q4XyuUJbSGJaoRb3SmWzeX88V2dKB7sPTf72BAtQp3k="
|
||||
},
|
||||
{
|
||||
"pubKey": "gTzKd1Ph5bpUw-JxTZiCe8RBfO-FsZiVYDYioQ-6dVg="
|
||||
},
|
||||
{
|
||||
"pubKey": "NX4oaDLYEOmMUP_9pcEaZv5MJHJ4ZYAoxPQDxov7tRs="
|
||||
},
|
||||
{
|
||||
"pubKey": "7fbk4oGQNlTW-tnWjVz8rWtKrtAicTsiNWgO98sqMyk="
|
||||
},
|
||||
{
|
||||
"pubKey": "w1bfLpnd3rWu5JczB0nQfnE2S6nUCbx2AA7HDE48DQo="
|
||||
}
|
||||
],
|
||||
"lastSeen": 1575915097869025000
|
||||
}
|
||||
]
|
||||
}"#.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
use sphinx::route::NodeAddressBytes;
|
||||
use sphinx::SphinxPacket;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::prelude::*;
|
||||
|
||||
pub struct MixClient {}
|
||||
|
||||
impl MixClient {
|
||||
pub fn new() -> MixClient {
|
||||
MixClient {}
|
||||
}
|
||||
|
||||
// Sends a Sphinx packet to a mixnode.
|
||||
pub async fn send(
|
||||
&self,
|
||||
packet: SphinxPacket,
|
||||
mix_addr: SocketAddr,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let bytes = packet.to_bytes();
|
||||
|
||||
println!("socket addr: {:?}", mix_addr);
|
||||
|
||||
let mut stream = tokio::net::TcpStream::connect(mix_addr).await?;
|
||||
stream.write_all(&bytes[..]).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sending_a_sphinx_packet {
|
||||
// use super::*;
|
||||
// use sphinx::SphinxPacket;
|
||||
|
||||
#[test]
|
||||
fn works() {
|
||||
// arrange
|
||||
// let directory = Client::new();
|
||||
// let message = "Hello, Sphinx!".as_bytes().to_vec();
|
||||
// let mixes = directory.get_mixes();
|
||||
// let destination = directory.get_destination();
|
||||
// let delays = sphinx::header::delays::generate(2);
|
||||
// let packet = SphinxPacket::new(message, &mixes, &destination, &delays).unwrap();
|
||||
// let mix_client = MixClient::new();
|
||||
// let first_hop = mixes.first().unwrap();
|
||||
//
|
||||
// // act
|
||||
// mix_client.send(packet, first_hop);
|
||||
|
||||
// assert
|
||||
// wtf are we supposed to assert here?
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
use crate::clients::directory::presence::Topology;
|
||||
use crate::clients::mix::MixClient;
|
||||
use crate::clients::provider::ProviderClient;
|
||||
use crate::sockets::tcp;
|
||||
use crate::sockets::ws;
|
||||
use crate::utils;
|
||||
use crate::utils::topology::get_topology;
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use futures::join;
|
||||
use futures::lock::Mutex as FMutex;
|
||||
use futures::select;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use sfw_provider_requests::AuthToken;
|
||||
use sphinx::route::{Destination, DestinationAddressBytes};
|
||||
use sphinx::SphinxPacket;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
pub mod directory;
|
||||
pub mod mix;
|
||||
pub mod provider;
|
||||
pub mod validator;
|
||||
|
||||
const LOOP_COVER_AVERAGE_DELAY: f64 = 0.5;
|
||||
// seconds
|
||||
const MESSAGE_SENDING_AVERAGE_DELAY: f64 = 0.5;
|
||||
// seconds;
|
||||
const FETCH_MESSAGES_DELAY: f64 = 1.0; // seconds;
|
||||
|
||||
// provider-poller sends polls service provider; receives messages
|
||||
// provider-poller sends (TX) to ReceivedBufferController (RX)
|
||||
// ReceivedBufferController sends (TX) to ... ??Client??
|
||||
// outQueueController sends (TX) to TrafficStreamController (RX)
|
||||
// TrafficStreamController sends messages to mixnet
|
||||
// ... ??Client?? sends (TX) to outQueueController (RX)
|
||||
// Loop cover traffic stream just sends messages to mixnet without any channel communication
|
||||
|
||||
struct MixMessage(SocketAddr, SphinxPacket);
|
||||
|
||||
struct MixTrafficController;
|
||||
|
||||
impl MixTrafficController {
|
||||
// this was way more difficult to implement than what this code may suggest...
|
||||
async fn run(mut rx: mpsc::UnboundedReceiver<MixMessage>) {
|
||||
let mix_client = MixClient::new();
|
||||
while let Some(mix_message) = rx.next().await {
|
||||
println!(
|
||||
"[MIX TRAFFIC CONTROL] - got a mix_message for {:?}",
|
||||
mix_message.0
|
||||
);
|
||||
let send_res = mix_client.send(mix_message.1, mix_message.0).await;
|
||||
match send_res {
|
||||
Ok(_) => println!("We successfully sent the message!"),
|
||||
Err(e) => eprintln!("We failed to send the message :( - {:?}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type BufferResponse = oneshot::Sender<Vec<Vec<u8>>>;
|
||||
|
||||
struct ReceivedMessagesBuffer {
|
||||
messages: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl ReceivedMessagesBuffer {
|
||||
fn add_arc_futures_mutex(self) -> Arc<FMutex<Self>> {
|
||||
Arc::new(FMutex::new(self))
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
ReceivedMessagesBuffer {
|
||||
messages: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn add_new_messages(buf: Arc<FMutex<Self>>, msgs: Vec<Vec<u8>>) {
|
||||
println!("Adding new messages to the buffer! {:?}", msgs);
|
||||
let mut unlocked = buf.lock().await;
|
||||
unlocked.messages.extend(msgs);
|
||||
}
|
||||
|
||||
async fn run_poller_input_controller(
|
||||
buf: Arc<FMutex<Self>>,
|
||||
mut poller_rx: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
||||
) {
|
||||
while let Some(new_messages) = poller_rx.next().await {
|
||||
ReceivedMessagesBuffer::add_new_messages(buf.clone(), new_messages).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn acquire_and_empty(buf: Arc<FMutex<Self>>) -> Vec<Vec<u8>> {
|
||||
let mut unlocked = buf.lock().await;
|
||||
std::mem::replace(&mut unlocked.messages, Vec::new())
|
||||
}
|
||||
|
||||
async fn run_query_output_controller(
|
||||
buf: Arc<FMutex<Self>>,
|
||||
mut query_receiver: mpsc::UnboundedReceiver<BufferResponse>,
|
||||
) {
|
||||
while let Some(request) = query_receiver.next().await {
|
||||
let messages = ReceivedMessagesBuffer::acquire_and_empty(buf.clone()).await;
|
||||
// if this fails, the whole application needs to blow
|
||||
// because currently only this thread would fail
|
||||
request.send(messages).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SocketType {
|
||||
TCP,
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct NymClient {
|
||||
// to be replaced by something else I guess
|
||||
address: DestinationAddressBytes,
|
||||
pub input_tx: mpsc::UnboundedSender<InputMessage>,
|
||||
// to be used by "send" function or socket, etc
|
||||
input_rx: mpsc::UnboundedReceiver<InputMessage>,
|
||||
socket_listening_address: SocketAddr,
|
||||
directory: String,
|
||||
auth_token: Option<AuthToken>,
|
||||
socket_type: SocketType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InputMessage(pub Destination, pub Vec<u8>);
|
||||
|
||||
impl NymClient {
|
||||
pub fn new(
|
||||
address: DestinationAddressBytes,
|
||||
socket_listening_address: SocketAddr,
|
||||
directory: String,
|
||||
auth_token: Option<AuthToken>,
|
||||
socket_type: SocketType,
|
||||
) -> Self {
|
||||
let (input_tx, input_rx) = mpsc::unbounded::<InputMessage>();
|
||||
|
||||
NymClient {
|
||||
address,
|
||||
input_tx,
|
||||
input_rx,
|
||||
socket_listening_address,
|
||||
directory,
|
||||
auth_token,
|
||||
socket_type,
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_loop_cover_traffic_stream(
|
||||
mut tx: mpsc::UnboundedSender<MixMessage>,
|
||||
our_info: Destination,
|
||||
topology: Topology,
|
||||
) {
|
||||
loop {
|
||||
println!("[LOOP COVER TRAFFIC STREAM] - next cover message!");
|
||||
let delay = utils::poisson::sample(LOOP_COVER_AVERAGE_DELAY);
|
||||
let delay_duration = Duration::from_secs_f64(delay);
|
||||
tokio::time::delay_for(delay_duration).await;
|
||||
let cover_message =
|
||||
utils::sphinx::loop_cover_message(our_info.address, our_info.identifier, &topology);
|
||||
tx.send(MixMessage(cover_message.0, cover_message.1))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn control_out_queue(
|
||||
mut mix_tx: mpsc::UnboundedSender<MixMessage>,
|
||||
mut input_rx: mpsc::UnboundedReceiver<InputMessage>,
|
||||
our_info: Destination,
|
||||
topology: Topology,
|
||||
) {
|
||||
loop {
|
||||
println!("[OUT QUEUE] here I will be sending real traffic (or loop cover if nothing is available)");
|
||||
select! {
|
||||
real_message = input_rx.next() => {
|
||||
println!("[OUT QUEUE] - we got a real message!");
|
||||
let real_message = real_message.expect("The channel must have closed! - if the client hasn't crashed, it should have!");
|
||||
println!("real: {:?}", real_message);
|
||||
let encapsulated_message = utils::sphinx::encapsulate_message(real_message.0, real_message.1, &topology);
|
||||
mix_tx.send(MixMessage(encapsulated_message.0, encapsulated_message.1)).await.unwrap();
|
||||
},
|
||||
|
||||
default => {
|
||||
println!("[OUT QUEUE] - no real message - going to send extra loop cover");
|
||||
let cover_message = utils::sphinx::loop_cover_message(our_info.address, our_info.identifier, &topology);
|
||||
mix_tx.send(MixMessage(cover_message.0, cover_message.1)).await.unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
let delay_duration = Duration::from_secs_f64(MESSAGE_SENDING_AVERAGE_DELAY);
|
||||
tokio::time::delay_for(delay_duration).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_provider_polling(
|
||||
provider_client: ProviderClient,
|
||||
mut poller_tx: mpsc::UnboundedSender<Vec<Vec<u8>>>,
|
||||
) {
|
||||
let loop_message = &utils::sphinx::LOOP_COVER_MESSAGE_PAYLOAD.to_vec();
|
||||
let dummy_message = &sfw_provider_requests::DUMMY_MESSAGE_CONTENT.to_vec();
|
||||
loop {
|
||||
let delay_duration = Duration::from_secs_f64(FETCH_MESSAGES_DELAY);
|
||||
tokio::time::delay_for(delay_duration).await;
|
||||
println!("[FETCH MSG] - Polling provider...");
|
||||
let messages = provider_client.retrieve_messages().await.unwrap();
|
||||
let good_messages = messages
|
||||
.into_iter()
|
||||
.filter(|message| message != loop_message && message != dummy_message)
|
||||
.collect();
|
||||
// if any of those fails, whole application should blow...
|
||||
poller_tx.send(good_messages).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Starting nym client");
|
||||
let mut rt = Runtime::new()?;
|
||||
|
||||
let topology = get_topology(self.directory.clone());
|
||||
// this is temporary and assumes there exists only a single provider.
|
||||
let provider_address: SocketAddr = topology
|
||||
.mix_provider_nodes
|
||||
.first()
|
||||
.unwrap()
|
||||
.host
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
||||
let mut provider_client =
|
||||
ProviderClient::new(provider_address, self.address, self.auth_token);
|
||||
|
||||
// registration
|
||||
rt.block_on(async {
|
||||
match self.auth_token {
|
||||
None => {
|
||||
let auth_token = provider_client.register().await.unwrap();
|
||||
provider_client.update_token(auth_token);
|
||||
println!("Obtained new token! - {:?}", auth_token);
|
||||
}
|
||||
Some(token) => println!("Already got the token! - {:?}", token),
|
||||
}
|
||||
});
|
||||
|
||||
// channels for intercomponent communication
|
||||
let (mix_tx, mix_rx) = mpsc::unbounded();
|
||||
let (poller_input_tx, poller_input_rx) = mpsc::unbounded();
|
||||
let (received_messages_buffer_output_tx, received_messages_buffer_output_rx) =
|
||||
mpsc::unbounded();
|
||||
|
||||
let received_messages_buffer = ReceivedMessagesBuffer::new().add_arc_futures_mutex();
|
||||
|
||||
let received_messages_buffer_input_controller_future =
|
||||
rt.spawn(ReceivedMessagesBuffer::run_poller_input_controller(
|
||||
received_messages_buffer.clone(),
|
||||
poller_input_rx,
|
||||
));
|
||||
let received_messages_buffer_output_controller_future =
|
||||
rt.spawn(ReceivedMessagesBuffer::run_query_output_controller(
|
||||
received_messages_buffer,
|
||||
received_messages_buffer_output_rx,
|
||||
));
|
||||
|
||||
let mix_traffic_future = rt.spawn(MixTrafficController::run(mix_rx));
|
||||
let loop_cover_traffic_future = rt.spawn(NymClient::start_loop_cover_traffic_stream(
|
||||
mix_tx.clone(),
|
||||
Destination::new(self.address, Default::default()),
|
||||
topology.clone(),
|
||||
));
|
||||
|
||||
let out_queue_control_future = rt.spawn(NymClient::control_out_queue(
|
||||
mix_tx,
|
||||
self.input_rx,
|
||||
Destination::new(self.address, Default::default()),
|
||||
topology.clone(),
|
||||
));
|
||||
|
||||
let provider_polling_future = rt.spawn(NymClient::start_provider_polling(
|
||||
provider_client,
|
||||
poller_input_tx,
|
||||
));
|
||||
|
||||
match self.socket_type {
|
||||
SocketType::WebSocket => {
|
||||
rt.spawn(ws::start_websocket(
|
||||
self.socket_listening_address,
|
||||
self.input_tx,
|
||||
received_messages_buffer_output_tx,
|
||||
self.address,
|
||||
topology,
|
||||
));
|
||||
}
|
||||
SocketType::TCP => {
|
||||
rt.spawn(tcp::start_tcpsocket(
|
||||
self.socket_listening_address,
|
||||
self.input_tx,
|
||||
received_messages_buffer_output_tx,
|
||||
self.address,
|
||||
topology,
|
||||
));
|
||||
}
|
||||
SocketType::None => (),
|
||||
}
|
||||
|
||||
rt.block_on(async {
|
||||
let future_results = join!(
|
||||
received_messages_buffer_input_controller_future,
|
||||
received_messages_buffer_output_controller_future,
|
||||
mix_traffic_future,
|
||||
loop_cover_traffic_future,
|
||||
out_queue_control_future,
|
||||
provider_polling_future,
|
||||
);
|
||||
|
||||
assert!(
|
||||
future_results.0.is_ok()
|
||||
&& future_results.1.is_ok()
|
||||
&& future_results.2.is_ok()
|
||||
&& future_results.3.is_ok()
|
||||
&& future_results.4.is_ok()
|
||||
&& future_results.5.is_ok()
|
||||
);
|
||||
});
|
||||
|
||||
// this line in theory should never be reached as the runtime should be permanently blocked on traffic senders
|
||||
eprintln!("The client went kaput...");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
use futures::io::Error;
|
||||
use sfw_provider_requests::requests::{ProviderRequest, PullRequest, RegisterRequest};
|
||||
use sfw_provider_requests::responses::{
|
||||
ProviderResponse, ProviderResponseError, PullResponse, RegisterResponse,
|
||||
};
|
||||
use sfw_provider_requests::AuthToken;
|
||||
use sphinx::route::DestinationAddressBytes;
|
||||
use std::net::{Shutdown, SocketAddr};
|
||||
use std::time::Duration;
|
||||
use tokio::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProviderClientError {
|
||||
ClientAlreadyRegisteredError,
|
||||
EmptyAuthTokenError,
|
||||
NetworkError,
|
||||
|
||||
InvalidRequestError,
|
||||
InvalidResponseError,
|
||||
InvalidResponseLengthError,
|
||||
}
|
||||
|
||||
impl From<io::Error> for ProviderClientError {
|
||||
fn from(_: Error) -> Self {
|
||||
use ProviderClientError::*;
|
||||
|
||||
NetworkError
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProviderResponseError> for ProviderClientError {
|
||||
fn from(err: ProviderResponseError) -> Self {
|
||||
use ProviderClientError::*;
|
||||
match err {
|
||||
ProviderResponseError::MarshalError => InvalidRequestError,
|
||||
ProviderResponseError::UnmarshalError => InvalidResponseError,
|
||||
ProviderResponseError::UnmarshalErrorInvalidLength => InvalidResponseLengthError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProviderClient {
|
||||
provider_network_address: SocketAddr,
|
||||
our_address: DestinationAddressBytes,
|
||||
auth_token: Option<AuthToken>,
|
||||
}
|
||||
|
||||
impl ProviderClient {
|
||||
pub fn new(
|
||||
provider_network_address: SocketAddr,
|
||||
our_address: DestinationAddressBytes,
|
||||
auth_token: Option<AuthToken>,
|
||||
) -> Self {
|
||||
// DH temporary: the provider's client port is not in the topology, but we can't change that
|
||||
// right now without messing up the existing Go mixnet. So I'm going to hardcode this
|
||||
// for the moment until the Go mixnet goes away.
|
||||
let provider_socket = SocketAddr::new(provider_network_address.ip(), 9000);
|
||||
|
||||
ProviderClient {
|
||||
provider_network_address: provider_socket,
|
||||
our_address,
|
||||
auth_token,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_token(&mut self, auth_token: AuthToken) {
|
||||
self.auth_token = Some(auth_token)
|
||||
}
|
||||
|
||||
pub async fn send_request(&self, bytes: Vec<u8>) -> Result<Vec<u8>, ProviderClientError> {
|
||||
let mut socket = tokio::net::TcpStream::connect(self.provider_network_address).await?;
|
||||
println!("keep alive: {:?}", socket.keepalive());
|
||||
socket.set_keepalive(Some(Duration::from_secs(2))).unwrap();
|
||||
socket.write_all(&bytes[..]).await?;
|
||||
if let Err(_e) = socket.shutdown(Shutdown::Write) {
|
||||
// TODO: make it a silent log once we have a proper logging library
|
||||
// eprintln!("failed to close write part of the socket; err = {:?}", e)
|
||||
}
|
||||
|
||||
let mut response = Vec::new();
|
||||
socket.read_to_end(&mut response).await?;
|
||||
if let Err(_e) = socket.shutdown(Shutdown::Read) {
|
||||
// TODO: make it a silent log once we have a proper logging library
|
||||
// eprintln!("failed to close read part of the socket; err = {:?}", e)
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn retrieve_messages(&self) -> Result<Vec<Vec<u8>>, ProviderClientError> {
|
||||
if self.auth_token.is_none() {
|
||||
return Err(ProviderClientError::EmptyAuthTokenError);
|
||||
}
|
||||
|
||||
let pull_request = PullRequest::new(self.our_address, self.auth_token.unwrap());
|
||||
let bytes = pull_request.to_bytes();
|
||||
|
||||
let response = self.send_request(bytes).await?;
|
||||
println!("Received the following response: {:?}", response);
|
||||
|
||||
let parsed_response = PullResponse::from_bytes(&response)?;
|
||||
Ok(parsed_response.messages)
|
||||
}
|
||||
|
||||
pub async fn register(&self) -> Result<AuthToken, ProviderClientError> {
|
||||
if self.auth_token.is_some() {
|
||||
return Err(ProviderClientError::ClientAlreadyRegisteredError);
|
||||
}
|
||||
|
||||
let register_request = RegisterRequest::new(self.our_address);
|
||||
let bytes = register_request.to_bytes();
|
||||
|
||||
let response = self.send_request(bytes).await?;
|
||||
let parsed_response = RegisterResponse::from_bytes(&response)?;
|
||||
|
||||
Ok(parsed_response.auth_token)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
use crate::banner;
|
||||
use crate::identity::mixnet;
|
||||
use crate::persistence::pathfinder::Pathfinder;
|
||||
use crate::persistence::pemstore::PemStore;
|
||||
use clap::ArgMatches;
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
println!("{}", banner());
|
||||
println!("Initialising client...");
|
||||
|
||||
let id = matches.value_of("id").unwrap().to_string(); // required for now
|
||||
let pathfinder = Pathfinder::new(id);
|
||||
|
||||
println!("Writing keypairs to {:?}...", pathfinder.config_dir);
|
||||
let mix_keys = mixnet::KeyPair::new();
|
||||
let pem_store = PemStore::new(pathfinder);
|
||||
pem_store.write(mix_keys);
|
||||
|
||||
println!("Client configuration completed.\n\n\n")
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
pub mod init;
|
||||
pub mod run;
|
||||
pub mod tcpsocket;
|
||||
pub mod websocket;
|
||||
@@ -1,17 +0,0 @@
|
||||
use crate::banner;
|
||||
//use crate::clients::NymClient;
|
||||
//use crate::persistence::pemstore;
|
||||
use clap::ArgMatches;
|
||||
|
||||
pub fn execute(_matches: &ArgMatches) {
|
||||
println!("{}", banner());
|
||||
panic!("For time being this command is deprecated! Please use 'websocket' instead");
|
||||
//
|
||||
// let is_local = matches.is_present("local");
|
||||
// let id = matches.value_of("id").unwrap().to_string();
|
||||
// println!("Starting client...");
|
||||
//
|
||||
// let keypair = pemstore::read_keypair_from_disk(id);
|
||||
// let client = NymClient::new(keypair.public_bytes(), is_local);
|
||||
// client.start("127.0.0.1:9000".parse().unwrap()).unwrap();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
use crate::banner;
|
||||
use crate::clients::{NymClient, SocketType};
|
||||
use crate::persistence::pemstore;
|
||||
use crate::sockets::tcp;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
println!("{}", banner());
|
||||
|
||||
let id = matches.value_of("id").unwrap().to_string();
|
||||
let port = match matches.value_of("port").unwrap_or("9001").parse::<u16>() {
|
||||
Ok(n) => n,
|
||||
Err(err) => panic!("Invalid port value provided - {:?}", err),
|
||||
};
|
||||
|
||||
let directory_server = matches
|
||||
.value_of("directory")
|
||||
.unwrap_or("https://directory.nymtech.net")
|
||||
.to_string();
|
||||
|
||||
println!("Starting TCP socket on port: {:?}", port);
|
||||
println!("Listening for messages...");
|
||||
|
||||
let socket_address = ("127.0.0.1", port)
|
||||
.to_socket_addrs()
|
||||
.expect("Failed to combine host and port")
|
||||
.next()
|
||||
.expect("Failed to extract the socket address from the iterator");
|
||||
|
||||
let keypair = pemstore::read_keypair_from_disk(id);
|
||||
let auth_token = None;
|
||||
|
||||
let client = NymClient::new(
|
||||
keypair.public_bytes(),
|
||||
socket_address.clone(),
|
||||
directory_server,
|
||||
auth_token,
|
||||
SocketType::TCP,
|
||||
);
|
||||
|
||||
client.start().unwrap();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
use crate::banner;
|
||||
use crate::clients::{NymClient, SocketType};
|
||||
use crate::persistence::pemstore;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
println!("{}", banner());
|
||||
|
||||
let id = matches.value_of("id").unwrap().to_string();
|
||||
let port = match matches.value_of("port").unwrap_or("9001").parse::<u16>() {
|
||||
Ok(n) => n,
|
||||
Err(err) => panic!("Invalid port value provided - {:?}", err),
|
||||
};
|
||||
|
||||
let directory_server = matches
|
||||
.value_of("directory")
|
||||
.unwrap_or("https://directory.nymtech.net")
|
||||
.to_string();
|
||||
|
||||
println!("Starting websocket on port: {:?}", port);
|
||||
println!("Listening for messages...");
|
||||
|
||||
let socket_address = ("127.0.0.1", port)
|
||||
.to_socket_addrs()
|
||||
.expect("Failed to combine host and port")
|
||||
.next()
|
||||
.expect("Failed to extract the socket address from the iterator");
|
||||
|
||||
let keypair = pemstore::read_keypair_from_disk(id);
|
||||
// TODO: reading auth_token from disk (if exists);
|
||||
let auth_token = None;
|
||||
let client = NymClient::new(
|
||||
keypair.public_bytes(),
|
||||
socket_address,
|
||||
directory_server,
|
||||
auth_token,
|
||||
SocketType::WebSocket,
|
||||
);
|
||||
|
||||
client.start().unwrap();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
|
||||
// This keypair serves as the user's identity within the Mixnet
|
||||
pub struct KeyPair {
|
||||
pub private: Scalar,
|
||||
pub public: MontgomeryPoint,
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
pub fn new() -> KeyPair {
|
||||
let (private, public) = sphinx::crypto::keygen();
|
||||
KeyPair { private, public }
|
||||
}
|
||||
|
||||
pub fn from_bytes(private_bytes: Vec<u8>, public_bytes: Vec<u8>) -> KeyPair {
|
||||
let mut bytes = [0; 32];
|
||||
bytes.copy_from_slice(&private_bytes[..]);
|
||||
let private = Scalar::from_canonical_bytes(bytes).unwrap();
|
||||
let mut bytes = [0; 32];
|
||||
bytes.copy_from_slice(&public_bytes[..]);
|
||||
let public = MontgomeryPoint(bytes);
|
||||
KeyPair { private, public }
|
||||
}
|
||||
|
||||
pub fn private_bytes(&self) -> [u8; 32] {
|
||||
self.private.to_bytes()
|
||||
}
|
||||
|
||||
pub fn public_bytes(&self) -> [u8; 32] {
|
||||
self.public.to_bytes()
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod mixnet;
|
||||
@@ -1 +0,0 @@
|
||||
// TODO types for Validator keys will go in here once we hook this up.
|
||||
@@ -1,5 +0,0 @@
|
||||
pub mod clients;
|
||||
pub mod identity;
|
||||
pub mod persistence;
|
||||
pub mod sockets;
|
||||
pub mod utils;
|
||||
+25
-88
@@ -1,95 +1,42 @@
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use std::process;
|
||||
|
||||
pub mod clients;
|
||||
mod commands;
|
||||
mod identity;
|
||||
mod persistence;
|
||||
mod sockets;
|
||||
mod utils;
|
||||
mod mix_peer;
|
||||
mod node;
|
||||
|
||||
fn main() {
|
||||
let arg_matches = App::new("Nym Client")
|
||||
let arg_matches = App::new("Nym Mixnode")
|
||||
.version("0.1.0")
|
||||
.author("Nymtech")
|
||||
.about("Implementation of the Nym Client")
|
||||
.subcommand(
|
||||
SubCommand::with_name("init")
|
||||
.about("Initialise a Nym client. Do this first!")
|
||||
.arg(Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-mixnet-client we want to create config for.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("provider")
|
||||
.long("provider")
|
||||
.help("Id of the provider we have preference to connect to. If left empty, a random provider will be chosen.")
|
||||
.takes_value(true)
|
||||
)
|
||||
)
|
||||
.about("Implementation of the Loopix-based Mixnode")
|
||||
.subcommand(
|
||||
SubCommand::with_name("run")
|
||||
.about("Run a persistent Nym client process")
|
||||
.arg(Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-mixnet-client we want to run.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.about("Starts the mixnode")
|
||||
.arg(
|
||||
Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
.help("The custom host on which the mixnode will be running")
|
||||
.takes_value(true),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("tcpsocket")
|
||||
.about("Run Nym client that listens for bytes on a TCP socket")
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.help("Port for TCP socket to listen on")
|
||||
.help("The port on which the mixnode will be listening")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("layer")
|
||||
.long("layer")
|
||||
.help("The mixnet layer of this particular node")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-mixnet-client we want to run.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("websocket")
|
||||
.about("Run Nym client that listens on a websocket")
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.help("Port for websocket to listen on")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-mixnet-client we want to run.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
Arg::with_name("local")
|
||||
.long("local")
|
||||
.help("Flag to indicate whether the client is expected to run on a local deployment.")
|
||||
.takes_value(false),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
@@ -99,17 +46,9 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod built_info {
|
||||
// The file has been placed there by the build script.
|
||||
include!(concat!(env!("OUT_DIR"), "/built.rs"));
|
||||
}
|
||||
|
||||
fn execute(matches: ArgMatches) -> Result<(), String> {
|
||||
match matches.subcommand() {
|
||||
("init", Some(m)) => Ok(commands::init::execute(m)),
|
||||
("run", Some(m)) => Ok(commands::run::execute(m)),
|
||||
("tcpsocket", Some(m)) => Ok(commands::tcpsocket::execute(m)),
|
||||
("websocket", Some(m)) => Ok(commands::websocket::execute(m)),
|
||||
("run", Some(m)) => Ok(node::runner::start(m)),
|
||||
_ => Err(usage()),
|
||||
}
|
||||
}
|
||||
@@ -119,8 +58,7 @@ fn usage() -> String {
|
||||
}
|
||||
|
||||
fn banner() -> String {
|
||||
format!(
|
||||
r#"
|
||||
return r#"
|
||||
|
||||
_ __ _ _ _ __ ___
|
||||
| '_ \| | | | '_ \ _ \
|
||||
@@ -128,9 +66,8 @@ fn banner() -> String {
|
||||
|_| |_|\__, |_| |_| |_|
|
||||
|___/
|
||||
|
||||
(client - version {:})
|
||||
(mixnode)
|
||||
|
||||
"#,
|
||||
built_info::PKG_VERSION
|
||||
)
|
||||
"#
|
||||
.to_string();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use std::error::Error;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use tokio::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MixPeer {
|
||||
connection: SocketAddrV4,
|
||||
}
|
||||
|
||||
impl MixPeer {
|
||||
// note that very soon `next_hop_address` will be changed to `next_hop_metadata`
|
||||
pub fn new(next_hop_address: [u8; 32]) -> MixPeer {
|
||||
let b = next_hop_address;
|
||||
let host = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
|
||||
let port: u16 = u16::from_be_bytes([b[4], b[5]]);
|
||||
let socket_address = SocketAddrV4::new(host, port);
|
||||
MixPeer {
|
||||
connection: socket_address,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send(&self, bytes: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
let next_hop_address = self.connection.clone();
|
||||
let mut stream = tokio::net::TcpStream::connect(next_hop_address).await?;
|
||||
stream.write_all(&bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
self.connection.to_string()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
use futures::channel::mpsc;
|
||||
use futures::lock::Mutex;
|
||||
use futures::StreamExt;
|
||||
use nym_client::clients::directory;
|
||||
use nym_client::clients::directory::metrics::MixMetric;
|
||||
use nym_client::clients::directory::requests::metrics_mixes_post::MetricsMixPoster;
|
||||
use nym_client::clients::directory::DirectoryClient;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
const METRICS_INTERVAL: u64 = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MetricsReporter {
|
||||
received: u64,
|
||||
sent: HashMap<String, u64>,
|
||||
}
|
||||
|
||||
impl MetricsReporter {
|
||||
pub(crate) fn new() -> Self {
|
||||
MetricsReporter {
|
||||
received: 0,
|
||||
sent: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_arc_mutex(self) -> Arc<Mutex<Self>> {
|
||||
Arc::new(Mutex::new(self))
|
||||
}
|
||||
|
||||
async fn increment_received_metrics(metrics: Arc<Mutex<MetricsReporter>>) {
|
||||
let mut unlocked = metrics.lock().await;
|
||||
unlocked.received += 1;
|
||||
}
|
||||
|
||||
pub(crate) async fn run_received_metrics_control(
|
||||
metrics: Arc<Mutex<MetricsReporter>>,
|
||||
mut rx: mpsc::Receiver<()>,
|
||||
) {
|
||||
while let Some(_) = rx.next().await {
|
||||
MetricsReporter::increment_received_metrics(metrics.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn increment_sent_metrics(metrics: Arc<Mutex<MetricsReporter>>, sent_to: String) {
|
||||
let mut unlocked = metrics.lock().await;
|
||||
let receiver_count = unlocked.sent.entry(sent_to).or_insert(0);
|
||||
*receiver_count += 1;
|
||||
}
|
||||
|
||||
pub(crate) async fn run_sent_metrics_control(
|
||||
metrics: Arc<Mutex<MetricsReporter>>,
|
||||
mut rx: mpsc::Receiver<String>,
|
||||
) {
|
||||
while let Some(sent_metric) = rx.next().await {
|
||||
MetricsReporter::increment_sent_metrics(metrics.clone(), sent_metric).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn acquire_and_reset_metrics(
|
||||
metrics: Arc<Mutex<MetricsReporter>>,
|
||||
) -> (u64, HashMap<String, u64>) {
|
||||
let mut unlocked = metrics.lock().await;
|
||||
let received = unlocked.received;
|
||||
|
||||
let sent = std::mem::replace(&mut unlocked.sent, HashMap::new());
|
||||
unlocked.received = 0;
|
||||
|
||||
(received, sent)
|
||||
}
|
||||
|
||||
pub(crate) async fn run_metrics_sender(
|
||||
metrics: Arc<Mutex<MetricsReporter>>,
|
||||
cfg: directory::Config,
|
||||
pub_key_str: String,
|
||||
) {
|
||||
let delay_duration = Duration::from_secs(METRICS_INTERVAL);
|
||||
let directory_client = directory::Client::new(cfg);
|
||||
loop {
|
||||
tokio::time::delay_for(delay_duration).await;
|
||||
let (received, sent) =
|
||||
MetricsReporter::acquire_and_reset_metrics(metrics.clone()).await;
|
||||
directory_client
|
||||
.metrics_post
|
||||
.post(&MixMetric {
|
||||
pub_key: pub_key_str.clone(),
|
||||
received,
|
||||
sent,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use futures::channel::mpsc;
|
||||
use futures::lock::Mutex;
|
||||
use sphinx::header::delays::Delay as SphinxDelay;
|
||||
use sphinx::{ProcessedPacket, SphinxPacket};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::prelude::*;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use crate::mix_peer::MixPeer;
|
||||
use crate::node::metrics::MetricsReporter;
|
||||
use futures::SinkExt;
|
||||
use nym_client::clients::directory;
|
||||
|
||||
mod metrics;
|
||||
mod presence;
|
||||
pub mod runner;
|
||||
|
||||
pub struct Config {
|
||||
directory_server: String,
|
||||
layer: usize,
|
||||
public_key: MontgomeryPoint,
|
||||
secret_key: Scalar,
|
||||
socket_address: SocketAddr,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn public_key_string(&self) -> String {
|
||||
let key_bytes = self.public_key.to_bytes().to_vec();
|
||||
base64::encode_config(&key_bytes, base64::URL_SAFE)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MixProcessingError {
|
||||
SphinxRecoveryError,
|
||||
ReceivedFinalHopError,
|
||||
}
|
||||
|
||||
impl From<sphinx::ProcessingError> for MixProcessingError {
|
||||
// for time being just have a single error instance for all possible results of sphinx::ProcessingError
|
||||
fn from(_: sphinx::ProcessingError) -> Self {
|
||||
use MixProcessingError::*;
|
||||
|
||||
SphinxRecoveryError
|
||||
}
|
||||
}
|
||||
|
||||
struct ForwardingData {
|
||||
packet: SphinxPacket,
|
||||
delay: SphinxDelay,
|
||||
recipient: MixPeer,
|
||||
sent_metrics_tx: mpsc::Sender<String>,
|
||||
}
|
||||
|
||||
// TODO: this will need to be changed if MixPeer will live longer than our Forwarding Data
|
||||
impl ForwardingData {
|
||||
fn new(
|
||||
packet: SphinxPacket,
|
||||
delay: SphinxDelay,
|
||||
recipient: MixPeer,
|
||||
sent_metrics_tx: mpsc::Sender<String>,
|
||||
) -> Self {
|
||||
ForwardingData {
|
||||
packet,
|
||||
delay,
|
||||
recipient,
|
||||
sent_metrics_tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessingData defines all data required to correctly unwrap sphinx packets
|
||||
struct ProcessingData {
|
||||
secret_key: Scalar,
|
||||
received_metrics_tx: mpsc::Sender<()>,
|
||||
sent_metrics_tx: mpsc::Sender<String>,
|
||||
}
|
||||
|
||||
impl ProcessingData {
|
||||
fn new(
|
||||
secret_key: Scalar,
|
||||
received_metrics_tx: mpsc::Sender<()>,
|
||||
sent_metrics_tx: mpsc::Sender<String>,
|
||||
) -> Self {
|
||||
ProcessingData {
|
||||
secret_key,
|
||||
received_metrics_tx,
|
||||
sent_metrics_tx,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_arc_mutex(self) -> Arc<Mutex<Self>> {
|
||||
Arc::new(Mutex::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
struct PacketProcessor {}
|
||||
|
||||
impl PacketProcessor {
|
||||
pub async fn process_sphinx_data_packet(
|
||||
packet_data: &[u8],
|
||||
processing_data: Arc<Mutex<ProcessingData>>,
|
||||
) -> Result<ForwardingData, MixProcessingError> {
|
||||
// we received something resembling a sphinx packet, report it!
|
||||
let processing_data = processing_data.lock().await;
|
||||
let mut received_sender = processing_data.received_metrics_tx.clone();
|
||||
|
||||
received_sender.send(()).await.unwrap();
|
||||
|
||||
let packet = SphinxPacket::from_bytes(packet_data.to_vec())?;
|
||||
let (next_packet, next_hop_address, delay) =
|
||||
match packet.process(processing_data.secret_key) {
|
||||
ProcessedPacket::ProcessedPacketForwardHop(packet, address, delay) => {
|
||||
(packet, address, delay)
|
||||
}
|
||||
_ => return Err(MixProcessingError::ReceivedFinalHopError),
|
||||
};
|
||||
|
||||
let next_mix = MixPeer::new(next_hop_address);
|
||||
|
||||
let fwd_data = ForwardingData::new(
|
||||
next_packet,
|
||||
delay,
|
||||
next_mix,
|
||||
processing_data.sent_metrics_tx.clone(),
|
||||
);
|
||||
Ok(fwd_data)
|
||||
}
|
||||
|
||||
async fn wait_and_forward(mut forwarding_data: ForwardingData) {
|
||||
let delay_duration = Duration::from_nanos(forwarding_data.delay.get_value());
|
||||
tokio::time::delay_for(delay_duration).await;
|
||||
forwarding_data
|
||||
.sent_metrics_tx
|
||||
.send(forwarding_data.recipient.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("RECIPIENT: {:?}", forwarding_data.recipient);
|
||||
match forwarding_data
|
||||
.recipient
|
||||
.send(forwarding_data.packet.to_bytes())
|
||||
.await
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
println!(
|
||||
"failed to write bytes to next mix peer. err = {:?}",
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the MixNode will live for whole duration of this program
|
||||
pub struct MixNode {
|
||||
directory_server: String,
|
||||
network_address: SocketAddr,
|
||||
public_key: MontgomeryPoint,
|
||||
secret_key: Scalar,
|
||||
// TODO: use it later to enforce forward travel
|
||||
// layer: usize,
|
||||
}
|
||||
|
||||
impl MixNode {
|
||||
pub fn new(config: &Config) -> Self {
|
||||
MixNode {
|
||||
directory_server: config.directory_server.clone(),
|
||||
network_address: config.socket_address,
|
||||
secret_key: config.secret_key,
|
||||
public_key: config.public_key,
|
||||
// layer: config.layer,
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_socket_connection(
|
||||
mut socket: tokio::net::TcpStream,
|
||||
processing_data: Arc<Mutex<ProcessingData>>,
|
||||
) {
|
||||
// NOTE: processing_data is copied here!!
|
||||
let mut buf = [0u8; sphinx::PACKET_SIZE];
|
||||
|
||||
// In a loop, read data from the socket and write the data back.
|
||||
loop {
|
||||
match socket.read(&mut buf).await {
|
||||
// socket closed
|
||||
Ok(n) if n == 0 => {
|
||||
println!("Remote connection closed.");
|
||||
return;
|
||||
}
|
||||
Ok(_) => {
|
||||
let fwd_data = PacketProcessor::process_sphinx_data_packet(
|
||||
buf.as_ref(),
|
||||
processing_data.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
PacketProcessor::wait_and_forward(fwd_data).await;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed to read from socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Write the some data back
|
||||
if let Err(e) = socket.write_all(b"foomp").await {
|
||||
println!("failed to write reply to socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Create the runtime, probably later move it to MixNode itself?
|
||||
let mut rt = Runtime::new()?;
|
||||
|
||||
let (received_tx, received_rx) = mpsc::channel(1024);
|
||||
let (sent_tx, sent_rx) = mpsc::channel(1024);
|
||||
|
||||
let directory_cfg = directory::Config {
|
||||
base_url: self.directory_server.clone(),
|
||||
};
|
||||
let pub_key_str =
|
||||
base64::encode_config(&self.public_key.to_bytes().to_vec(), base64::URL_SAFE);
|
||||
|
||||
let metrics = MetricsReporter::new().add_arc_mutex();
|
||||
rt.spawn(MetricsReporter::run_received_metrics_control(
|
||||
metrics.clone(),
|
||||
received_rx,
|
||||
));
|
||||
rt.spawn(MetricsReporter::run_sent_metrics_control(
|
||||
metrics.clone(),
|
||||
sent_rx,
|
||||
));
|
||||
rt.spawn(MetricsReporter::run_metrics_sender(
|
||||
metrics,
|
||||
directory_cfg,
|
||||
pub_key_str,
|
||||
));
|
||||
|
||||
// Spawn the root task
|
||||
rt.block_on(async {
|
||||
let mut listener = tokio::net::TcpListener::bind(self.network_address).await?;
|
||||
let processing_data =
|
||||
ProcessingData::new(self.secret_key, received_tx, sent_tx).add_arc_mutex();
|
||||
|
||||
loop {
|
||||
let (socket, _) = listener.accept().await?;
|
||||
|
||||
let thread_processing_data = processing_data.clone();
|
||||
tokio::spawn(async move {
|
||||
MixNode::process_socket_connection(socket, thread_processing_data).await;
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use crate::node;
|
||||
use nym_client::clients::directory;
|
||||
use nym_client::clients::directory::presence::MixNodePresence;
|
||||
use nym_client::clients::directory::requests::presence_mixnodes_post::PresenceMixNodesPoster;
|
||||
use nym_client::clients::directory::DirectoryClient;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct Notifier {
|
||||
pub net_client: directory::Client,
|
||||
presence: MixNodePresence,
|
||||
}
|
||||
|
||||
impl Notifier {
|
||||
pub fn new(node_config: &node::Config) -> Notifier {
|
||||
let config = directory::Config {
|
||||
base_url: node_config.directory_server.clone(),
|
||||
};
|
||||
let net_client = directory::Client::new(config);
|
||||
let presence = MixNodePresence {
|
||||
host: node_config.socket_address.to_string(), // note: the directory server determines the real incoming IP itself, but uses the socket. Host here is just a placeholder.
|
||||
pub_key: node_config.public_key_string(),
|
||||
layer: node_config.layer as u64,
|
||||
last_seen: 0,
|
||||
};
|
||||
Notifier {
|
||||
net_client,
|
||||
presence,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify(&self) {
|
||||
self.net_client
|
||||
.presence_mix_nodes_post
|
||||
.post(&self.presence)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn run(&self) {
|
||||
loop {
|
||||
self.notify();
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use crate::banner;
|
||||
use crate::node;
|
||||
use crate::node::presence;
|
||||
use crate::node::MixNode;
|
||||
use clap::ArgMatches;
|
||||
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::thread;
|
||||
|
||||
pub fn start(matches: &ArgMatches) {
|
||||
println!("{}", banner());
|
||||
println!("Starting mixnode...");
|
||||
|
||||
let config = new_config(matches);
|
||||
|
||||
// println!("Startup on: {}", config.socket_address);
|
||||
println!("Listening for incoming packets...");
|
||||
|
||||
let mix = MixNode::new(&config);
|
||||
thread::spawn(move || {
|
||||
let notifier = presence::Notifier::new(&config);
|
||||
notifier.run();
|
||||
});
|
||||
mix.start().unwrap();
|
||||
}
|
||||
|
||||
fn new_config(matches: &ArgMatches) -> node::Config {
|
||||
let host = matches.value_of("host").unwrap_or("0.0.0.0");
|
||||
|
||||
let port = match matches.value_of("port").unwrap_or("1789").parse::<u16>() {
|
||||
Ok(n) => n,
|
||||
Err(err) => panic!("Invalid port value provided - {:?}", err),
|
||||
};
|
||||
|
||||
let layer = match matches.value_of("layer").unwrap().parse::<usize>() {
|
||||
Ok(n) => n,
|
||||
Err(err) => panic!("Invalid layer value provided - {:?}", err),
|
||||
};
|
||||
|
||||
let is_local = matches.is_present("local");
|
||||
|
||||
let socket_address = (host, port)
|
||||
.to_socket_addrs()
|
||||
.expect("Failed to combine host and port")
|
||||
.next()
|
||||
.expect("Failed to extract the socket address from the iterator");
|
||||
|
||||
let (secret_key, public_key) = sphinx::crypto::keygen();
|
||||
|
||||
let directory_server = if is_local {
|
||||
"http://localhost:8080".to_string()
|
||||
} else {
|
||||
"https://directory.nymtech.net".to_string()
|
||||
};
|
||||
|
||||
node::Config {
|
||||
directory_server,
|
||||
layer,
|
||||
public_key,
|
||||
socket_address,
|
||||
secret_key,
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod pathfinder;
|
||||
pub mod pemstore;
|
||||
@@ -1,21 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Pathfinder {
|
||||
pub config_dir: PathBuf,
|
||||
pub private_mix_key: PathBuf,
|
||||
pub public_mix_key: PathBuf,
|
||||
}
|
||||
|
||||
impl Pathfinder {
|
||||
pub fn new(id: String) -> Pathfinder {
|
||||
let os_config_dir = dirs::config_dir().unwrap(); // grabs the OS default config dir
|
||||
let config_dir = os_config_dir.join("nym").join("clients").join(id);
|
||||
let private_mix_key = config_dir.join("private.pem");
|
||||
let public_mix_key = config_dir.join("public.pem");
|
||||
Pathfinder {
|
||||
config_dir,
|
||||
private_mix_key,
|
||||
public_mix_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
use crate::identity::mixnet::KeyPair;
|
||||
use crate::persistence::pathfinder::Pathfinder;
|
||||
use pem::{encode, parse, Pem};
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn read_keypair_from_disk(id: String) -> KeyPair {
|
||||
let pathfinder = Pathfinder::new(id);
|
||||
let pem_store = PemStore::new(pathfinder);
|
||||
let keypair = pem_store.read();
|
||||
keypair
|
||||
}
|
||||
|
||||
pub struct PemStore {
|
||||
config_dir: PathBuf,
|
||||
private_mix_key: PathBuf,
|
||||
public_mix_key: PathBuf,
|
||||
}
|
||||
|
||||
impl PemStore {
|
||||
pub fn new(pathfinder: Pathfinder) -> PemStore {
|
||||
PemStore {
|
||||
config_dir: pathfinder.config_dir,
|
||||
private_mix_key: pathfinder.private_mix_key,
|
||||
public_mix_key: pathfinder.public_mix_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self) -> KeyPair {
|
||||
let private = self.read_file(self.private_mix_key.clone());
|
||||
let public = self.read_file(self.public_mix_key.clone());
|
||||
|
||||
KeyPair::from_bytes(private, public)
|
||||
}
|
||||
|
||||
fn read_file(&self, filepath: PathBuf) -> Vec<u8> {
|
||||
let mut pem_bytes = File::open(filepath).unwrap();
|
||||
let mut buf = Vec::new();
|
||||
pem_bytes.read_to_end(&mut buf).unwrap();
|
||||
let pem = parse(&buf).unwrap();
|
||||
pem.contents
|
||||
}
|
||||
// This should be refactored and made more generic for when we have other kinds of
|
||||
// KeyPairs that we want to persist (e.g. validator keypairs, or keys for
|
||||
// signing vs encryption). However, for the moment, it does the job.
|
||||
pub fn write(&self, key_pair: KeyPair) {
|
||||
std::fs::create_dir_all(self.config_dir.clone()).unwrap();
|
||||
|
||||
self.write_pem_file(
|
||||
self.private_mix_key.clone(),
|
||||
key_pair.private_bytes(),
|
||||
String::from("SPHINX CURVE25519 PRIVATE KEY"),
|
||||
);
|
||||
self.write_pem_file(
|
||||
self.public_mix_key.clone(),
|
||||
key_pair.public_bytes(),
|
||||
String::from("SPHINX CURVE25519 PUBLIC KEY"),
|
||||
);
|
||||
}
|
||||
|
||||
fn write_pem_file(&self, filepath: PathBuf, data: [u8; 32], tag: String) {
|
||||
let pem = Pem {
|
||||
tag,
|
||||
contents: data.to_vec(),
|
||||
};
|
||||
let key = encode(&pem);
|
||||
|
||||
let mut file = File::create(filepath).unwrap();
|
||||
file.write_all(key.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
// TODO: we can put all the TOML config templating code in here once we get to that.
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod tcp;
|
||||
pub mod ws;
|
||||
@@ -1,305 +0,0 @@
|
||||
use crate::clients::directory::presence::Topology;
|
||||
use crate::clients::BufferResponse;
|
||||
use crate::clients::InputMessage;
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use futures::future::FutureExt;
|
||||
use futures::io::Error;
|
||||
use futures::SinkExt;
|
||||
use sphinx::route::{Destination, DestinationAddressBytes};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
const SEND_REQUEST_PREFIX: u8 = 1;
|
||||
const FETCH_REQUEST_PREFIX: u8 = 2;
|
||||
const GET_CLIENTS_REQUEST_PREFIX: u8 = 3;
|
||||
const OWN_DETAILS_REQUEST_PREFIX: u8 = 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TCPSocketError {
|
||||
FailedToStartSocketError,
|
||||
UnknownSocketError,
|
||||
IncompleteDataError,
|
||||
UnknownRequestError,
|
||||
}
|
||||
|
||||
impl From<io::Error> for TCPSocketError {
|
||||
fn from(err: Error) -> Self {
|
||||
use TCPSocketError::*;
|
||||
match err.kind() {
|
||||
io::ErrorKind::ConnectionRefused => FailedToStartSocketError,
|
||||
io::ErrorKind::ConnectionReset => FailedToStartSocketError,
|
||||
io::ErrorKind::ConnectionAborted => FailedToStartSocketError,
|
||||
io::ErrorKind::NotConnected => FailedToStartSocketError,
|
||||
|
||||
io::ErrorKind::AddrInUse => FailedToStartSocketError,
|
||||
io::ErrorKind::AddrNotAvailable => FailedToStartSocketError,
|
||||
_ => UnknownSocketError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum ClientRequest {
|
||||
Send {
|
||||
message: Vec<u8>,
|
||||
recipient_address: DestinationAddressBytes,
|
||||
},
|
||||
Fetch,
|
||||
GetClients,
|
||||
OwnDetails,
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for ClientRequest {
|
||||
type Error = TCPSocketError;
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
use TCPSocketError::*;
|
||||
if data.is_empty() {
|
||||
return Err(IncompleteDataError);
|
||||
}
|
||||
|
||||
match data[0] {
|
||||
SEND_REQUEST_PREFIX => parse_send_request(data),
|
||||
FETCH_REQUEST_PREFIX => Ok(ClientRequest::Fetch),
|
||||
GET_CLIENTS_REQUEST_PREFIX => Ok(ClientRequest::GetClients),
|
||||
OWN_DETAILS_REQUEST_PREFIX => Ok(ClientRequest::OwnDetails),
|
||||
_ => Err(UnknownRequestError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_send_request(data: &[u8]) -> Result<ClientRequest, TCPSocketError> {
|
||||
if data.len() < 1 + 32 + 1 {
|
||||
// make sure it has the prefix, destination and at least single byte of data
|
||||
return Err(TCPSocketError::IncompleteDataError);
|
||||
}
|
||||
|
||||
let mut recipient_address = [0u8; 32];
|
||||
recipient_address.copy_from_slice(&data[1..33]);
|
||||
|
||||
let message = data[33..].to_vec();
|
||||
|
||||
Ok(ClientRequest::Send {
|
||||
message,
|
||||
recipient_address,
|
||||
})
|
||||
}
|
||||
|
||||
impl ClientRequest {
|
||||
async fn handle_send(
|
||||
msg: Vec<u8>,
|
||||
recipient_address: DestinationAddressBytes,
|
||||
mut input_tx: mpsc::UnboundedSender<InputMessage>,
|
||||
) -> ServerResponse {
|
||||
println!("send handle. sending to: {:?}, msg: {:?}", recipient_address, msg);
|
||||
let dummy_surb = [0; 16];
|
||||
let input_msg = InputMessage(Destination::new(recipient_address, dummy_surb), msg);
|
||||
|
||||
println!("ALMOST ABOUT TO SOMEDAY SEND {:?}", input_msg);
|
||||
input_tx.send(input_msg).await.unwrap();
|
||||
|
||||
ServerResponse::Send
|
||||
}
|
||||
|
||||
async fn handle_fetch(mut msg_query: mpsc::UnboundedSender<BufferResponse>) -> ServerResponse {
|
||||
println!("fetch handle");
|
||||
let (res_tx, res_rx) = oneshot::channel();
|
||||
if msg_query.send(res_tx).await.is_err() {
|
||||
return ServerResponse::Error {
|
||||
message: "Server failed to receive messages".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let messages = res_rx.map(|msg| msg).await;
|
||||
|
||||
if messages.is_err() {
|
||||
return ServerResponse::Error {
|
||||
message: "Server failed to receive messages".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let messages = messages.unwrap();
|
||||
println!("fetched {} messages", messages.len());
|
||||
ServerResponse::Fetch {
|
||||
messages,
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_get_clients(topology: &Topology) -> ServerResponse {
|
||||
println!("get clients handle");
|
||||
let clients = topology
|
||||
.mix_provider_nodes
|
||||
.iter()
|
||||
.flat_map(|provider| provider.registered_clients.iter())
|
||||
.map(|client| base64::decode_config(&client.pub_key, base64::URL_SAFE).unwrap()) // TODO: this can potentially throw an error
|
||||
.collect();
|
||||
ServerResponse::GetClients { clients }
|
||||
}
|
||||
|
||||
async fn handle_own_details(self_address_bytes: DestinationAddressBytes) -> ServerResponse {
|
||||
println!("own details handle");
|
||||
ServerResponse::OwnDetails {
|
||||
address: self_address_bytes.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum ServerResponse {
|
||||
Send,
|
||||
Fetch { messages: Vec<Vec<u8>> },
|
||||
GetClients { clients: Vec<Vec<u8>> },
|
||||
OwnDetails { address: Vec<u8> },
|
||||
Error { message: String },
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for ServerResponse {
|
||||
fn into(self) -> Vec<u8> {
|
||||
match self {
|
||||
ServerResponse::Send => b"ok".to_vec(),
|
||||
ServerResponse::Fetch {messages} =>encode_fetched_messages(messages),
|
||||
ServerResponse::GetClients {clients} => encode_list_of_clients(clients),
|
||||
ServerResponse::OwnDetails {address} => address,
|
||||
ServerResponse::Error { message } => message.as_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// num_msgs || len1 || len2 || ... || msg1 || msg2 || ...
|
||||
fn encode_fetched_messages(messages: Vec<Vec<u8>>) -> Vec<u8> {
|
||||
// for reciprocal of this look into sfw-provider-requests::responses::PullResponse::from_bytes()
|
||||
|
||||
let num_msgs = messages.len() as u16;
|
||||
let msgs_lens: Vec<u16> = messages.iter().map(|msg| msg.len() as u16).collect();
|
||||
|
||||
num_msgs
|
||||
.to_be_bytes()
|
||||
.to_vec()
|
||||
.into_iter()
|
||||
.chain(
|
||||
msgs_lens
|
||||
.into_iter()
|
||||
.flat_map(|len| len.to_be_bytes().to_vec().into_iter()),
|
||||
)
|
||||
.chain(messages.iter().flat_map(|msg| msg.clone().into_iter()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn encode_list_of_clients(clients: Vec<Vec<u8>>) -> Vec<u8> {
|
||||
println!("clients: {:?}", clients);
|
||||
// we can just concat all clients since all of them got to be 32 bytes long
|
||||
// (if not, then we have bigger problem somewhere up the line)
|
||||
|
||||
// converts [[1,2,3],[4,5,6],...] into [1,2,3,4,5,6,...]
|
||||
clients.into_iter().flatten().collect()
|
||||
}
|
||||
|
||||
impl ServerResponse {
|
||||
fn new_error(message: String) -> ServerResponse {
|
||||
ServerResponse::Error { message }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn handle_connection(data: &[u8], request_handling_data: RequestHandlingData) -> Result<ServerResponse, TCPSocketError> {
|
||||
let request = ClientRequest::try_from(data)?;
|
||||
let response = match request {
|
||||
ClientRequest::Send {
|
||||
message,
|
||||
recipient_address
|
||||
} => ClientRequest::handle_send(message, recipient_address, request_handling_data.msg_input).await,
|
||||
ClientRequest::Fetch => ClientRequest::handle_fetch(request_handling_data.msg_query).await,
|
||||
ClientRequest::GetClients => ClientRequest::handle_get_clients(request_handling_data.topology.borrow()).await,
|
||||
ClientRequest::OwnDetails => ClientRequest::handle_own_details(request_handling_data.self_address).await,
|
||||
};
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
struct RequestHandlingData {
|
||||
msg_input: mpsc::UnboundedSender<InputMessage>,
|
||||
msg_query: mpsc::UnboundedSender<BufferResponse>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Arc<Topology>,
|
||||
}
|
||||
|
||||
async fn accept_connection(
|
||||
mut socket: tokio::net::TcpStream,
|
||||
msg_input: mpsc::UnboundedSender<InputMessage>,
|
||||
msg_query: mpsc::UnboundedSender<BufferResponse>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Topology,
|
||||
) {
|
||||
let address = socket
|
||||
.peer_addr()
|
||||
.expect("connected streams should have a peer address");
|
||||
println!("Peer address: {}", address);
|
||||
|
||||
let topology = Arc::new(topology);
|
||||
|
||||
let mut buf = [0u8; 2048];
|
||||
|
||||
// In a loop, read data from the socket and write the data back.
|
||||
loop {
|
||||
// TODO: shutdowns?
|
||||
|
||||
let response = match socket.read(&mut buf).await {
|
||||
// socket closed
|
||||
Ok(n) if n == 0 => {
|
||||
println!("Remote connection closed.");
|
||||
return;
|
||||
}
|
||||
Ok(n) => {
|
||||
let request_handling_data = RequestHandlingData {
|
||||
topology: topology.clone(),
|
||||
msg_input: msg_input.clone(),
|
||||
msg_query: msg_query.clone(),
|
||||
self_address: self_address.clone(),
|
||||
};
|
||||
match handle_connection(&buf[..n], request_handling_data).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => ServerResponse::new_error(format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("failed to read from socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let response_vec: Vec<u8> = response.into();
|
||||
if let Err(e) = socket.write_all(&response_vec).await {
|
||||
eprintln!("failed to write reply to socket; err = {:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_tcpsocket(
|
||||
address: SocketAddr,
|
||||
message_tx: mpsc::UnboundedSender<InputMessage>,
|
||||
received_messages_query_tx: mpsc::UnboundedSender<BufferResponse>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Topology,
|
||||
) -> Result<(), TCPSocketError> {
|
||||
let mut listener = tokio::net::TcpListener::bind(address).await?;
|
||||
|
||||
while let Ok((stream, _)) = listener.accept().await {
|
||||
// it's fine to be cloning the channel on all new connection, because in principle
|
||||
// this server should only EVER have a single client connected
|
||||
tokio::spawn(accept_connection(
|
||||
stream,
|
||||
message_tx.clone(),
|
||||
received_messages_query_tx.clone(),
|
||||
self_address,
|
||||
topology.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
eprintln!("The tcpsocket went kaput...");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
use crate::clients::directory::presence::Topology;
|
||||
use crate::clients::BufferResponse;
|
||||
use crate::clients::InputMessage;
|
||||
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use futures::future::FutureExt;
|
||||
use futures::io::Error;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sphinx::route::{Destination, DestinationAddressBytes};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use tungstenite::protocol::Message;
|
||||
|
||||
struct Connection {
|
||||
address: SocketAddr,
|
||||
msg_input: mpsc::UnboundedSender<InputMessage>,
|
||||
msg_query: mpsc::UnboundedSender<BufferResponse>,
|
||||
rx: UnboundedReceiver<Message>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Topology,
|
||||
tx: UnboundedSender<Message>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WebSocketError {
|
||||
FailedToStartSocketError,
|
||||
UnknownSocketError,
|
||||
}
|
||||
|
||||
impl From<io::Error> for WebSocketError {
|
||||
fn from(err: Error) -> Self {
|
||||
use WebSocketError::*;
|
||||
match err.kind() {
|
||||
io::ErrorKind::ConnectionRefused => FailedToStartSocketError,
|
||||
io::ErrorKind::ConnectionReset => FailedToStartSocketError,
|
||||
io::ErrorKind::ConnectionAborted => FailedToStartSocketError,
|
||||
io::ErrorKind::NotConnected => FailedToStartSocketError,
|
||||
|
||||
io::ErrorKind::AddrInUse => FailedToStartSocketError,
|
||||
io::ErrorKind::AddrNotAvailable => FailedToStartSocketError,
|
||||
_ => UnknownSocketError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
enum ClientRequest {
|
||||
Send {
|
||||
message: String,
|
||||
recipient_address: String,
|
||||
},
|
||||
Fetch,
|
||||
GetClients,
|
||||
OwnDetails,
|
||||
}
|
||||
|
||||
impl From<Message> for ClientRequest {
|
||||
fn from(msg: Message) -> Self {
|
||||
let text_msg = match msg {
|
||||
Message::Text(msg) => msg,
|
||||
Message::Binary(_) => panic!("binary messages are not supported!"),
|
||||
Message::Close(_) => panic!("todo: handle close!"),
|
||||
_ => panic!("Other types of messages are also unsupported!"),
|
||||
};
|
||||
serde_json::from_str(&text_msg).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientRequest {
|
||||
async fn handle_send(
|
||||
msg: String,
|
||||
recipient_address: String,
|
||||
mut input_tx: mpsc::UnboundedSender<InputMessage>,
|
||||
) -> ServerResponse {
|
||||
let address_vec = match base64::decode_config(&recipient_address, base64::URL_SAFE) {
|
||||
Err(e) => {
|
||||
return ServerResponse::Error {
|
||||
message: e.to_string(),
|
||||
}
|
||||
}
|
||||
Ok(hex) => hex,
|
||||
};
|
||||
|
||||
if address_vec.len() != 32 {
|
||||
return ServerResponse::Error {
|
||||
message: "InvalidDestinationLength".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut address = [0; 32];
|
||||
address.copy_from_slice(&address_vec);
|
||||
|
||||
let dummy_surb = [0; 16];
|
||||
|
||||
let input_msg = InputMessage(Destination::new(address, dummy_surb), msg.into_bytes());
|
||||
|
||||
println!("ALMOST ABOUT TO SOMEDAY SEND {:?}", input_msg);
|
||||
input_tx.send(input_msg).await.unwrap();
|
||||
|
||||
ServerResponse::Send
|
||||
}
|
||||
|
||||
async fn handle_fetch(mut msg_query: mpsc::UnboundedSender<BufferResponse>) -> ServerResponse {
|
||||
let (res_tx, res_rx) = oneshot::channel();
|
||||
if msg_query.send(res_tx).await.is_err() {
|
||||
return ServerResponse::Error {
|
||||
message: "Server failed to receive messages".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let messages = res_rx.map(|msg| msg).await;
|
||||
|
||||
if messages.is_err() {
|
||||
return ServerResponse::Error {
|
||||
message: "Server failed to receive messages".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let messages = messages.unwrap();
|
||||
let messages_as_b64 = messages
|
||||
.iter()
|
||||
.map(|message| base64::encode_config(message, base64::URL_SAFE))
|
||||
.collect();
|
||||
ServerResponse::Fetch {
|
||||
messages: messages_as_b64,
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_get_clients(topology: Topology) -> ServerResponse {
|
||||
let clients = topology
|
||||
.mix_provider_nodes
|
||||
.into_iter()
|
||||
.flat_map(|provider| provider.registered_clients.into_iter())
|
||||
.map(|client| client.pub_key)
|
||||
.collect();
|
||||
ServerResponse::GetClients { clients }
|
||||
}
|
||||
|
||||
async fn handle_own_details(self_address_bytes: DestinationAddressBytes) -> ServerResponse {
|
||||
let self_address = base64::encode_config(&self_address_bytes, base64::URL_SAFE);
|
||||
ServerResponse::OwnDetails {
|
||||
address: self_address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
enum ServerResponse {
|
||||
Send,
|
||||
Fetch { messages: Vec<String> },
|
||||
GetClients { clients: Vec<String> },
|
||||
OwnDetails { address: String },
|
||||
Error { message: String },
|
||||
}
|
||||
|
||||
impl Into<Message> for ServerResponse {
|
||||
fn into(self) -> Message {
|
||||
let str_res = serde_json::to_string(&self).unwrap();
|
||||
Message::Text(str_res)
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_connection(conn: Connection) {
|
||||
let mut conn = conn;
|
||||
while let Some(msg) = conn.rx.next().await {
|
||||
println!("Received a message from {}: {}", conn.address, msg);
|
||||
let request: ClientRequest = msg.into();
|
||||
|
||||
let response = match request {
|
||||
ClientRequest::Send {
|
||||
message,
|
||||
recipient_address,
|
||||
} => {
|
||||
ClientRequest::handle_send(message, recipient_address, conn.msg_input.clone()).await
|
||||
}
|
||||
ClientRequest::Fetch => ClientRequest::handle_fetch(conn.msg_query.clone()).await,
|
||||
ClientRequest::GetClients => {
|
||||
ClientRequest::handle_get_clients(conn.topology.clone()).await
|
||||
}
|
||||
ClientRequest::OwnDetails => ClientRequest::handle_own_details(conn.self_address).await,
|
||||
};
|
||||
|
||||
conn.tx
|
||||
.unbounded_send(response.into())
|
||||
.expect("Failed to forward message");
|
||||
}
|
||||
}
|
||||
|
||||
async fn accept_connection(
|
||||
stream: tokio::net::TcpStream,
|
||||
msg_input: mpsc::UnboundedSender<InputMessage>,
|
||||
msg_query: mpsc::UnboundedSender<BufferResponse>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Topology,
|
||||
) {
|
||||
let address = stream
|
||||
.peer_addr()
|
||||
.expect("connected streams should have a peer address");
|
||||
println!("Peer address: {}", address);
|
||||
|
||||
let mut ws_stream = tokio_tungstenite::accept_async(stream)
|
||||
.await
|
||||
.expect("Error during the websocket handshake occurred");
|
||||
|
||||
println!("New WebSocket connection: {}", address);
|
||||
|
||||
// Create a channel for our stream, which other sockets will use to
|
||||
// send us messages. Then register our address with the stream to send
|
||||
// data to us.
|
||||
let (msg_tx, msg_rx) = futures::channel::mpsc::unbounded();
|
||||
let (response_tx, mut response_rx) = futures::channel::mpsc::unbounded();
|
||||
let conn = Connection {
|
||||
address,
|
||||
rx: msg_rx,
|
||||
tx: response_tx,
|
||||
topology,
|
||||
msg_input,
|
||||
msg_query,
|
||||
self_address,
|
||||
};
|
||||
tokio::spawn(handle_connection(conn));
|
||||
|
||||
while let Some(message) = ws_stream.next().await {
|
||||
let message = message.expect("Failed to get request");
|
||||
msg_tx
|
||||
.unbounded_send(message)
|
||||
.expect("Failed to forward request");
|
||||
if let Some(resp) = response_rx.next().await {
|
||||
ws_stream.send(resp).await.expect("Failed to send response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_websocket(
|
||||
address: SocketAddr,
|
||||
message_tx: mpsc::UnboundedSender<InputMessage>,
|
||||
received_messages_query_tx: mpsc::UnboundedSender<BufferResponse>,
|
||||
self_address: DestinationAddressBytes,
|
||||
topology: Topology,
|
||||
) -> Result<(), WebSocketError> {
|
||||
let mut listener = tokio::net::TcpListener::bind(address).await?;
|
||||
|
||||
while let Ok((stream, _)) = listener.accept().await {
|
||||
// it's fine to be cloning the channel on all new connection, because in principle
|
||||
// this server should only EVER have a single client connected
|
||||
tokio::spawn(accept_connection(
|
||||
stream,
|
||||
message_tx.clone(),
|
||||
received_messages_query_tx.clone(),
|
||||
self_address,
|
||||
topology.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
eprintln!("The websocket went kaput...");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
pub enum AddressType {
|
||||
V4,
|
||||
V6,
|
||||
}
|
||||
|
||||
impl Into<u8> for AddressType {
|
||||
fn into(self) -> u8 {
|
||||
use AddressType::*;
|
||||
|
||||
match self {
|
||||
V4 => 4,
|
||||
V6 => 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AddressTypeError {
|
||||
InvalidPrefixError,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for AddressType {
|
||||
type Error = AddressTypeError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
use AddressType::*;
|
||||
use AddressTypeError::*;
|
||||
|
||||
match value {
|
||||
4 => Ok(V4),
|
||||
6 => Ok(V6),
|
||||
_ => Err(InvalidPrefixError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// FLAG || port || octets || zeropad
|
||||
pub fn encoded_bytes_from_socket_address(address: SocketAddr) -> [u8; 32] {
|
||||
let port_bytes = address.port().to_be_bytes();
|
||||
|
||||
let encoded_host: Vec<u8> = match address.ip() {
|
||||
IpAddr::V4(ip) => std::iter::once(AddressType::V4.into())
|
||||
.chain(port_bytes.iter().cloned())
|
||||
.chain(ip.octets().iter().cloned())
|
||||
.chain(std::iter::repeat(0))
|
||||
.take(32)
|
||||
.collect(),
|
||||
IpAddr::V6(ip) => std::iter::once(AddressType::V6.into())
|
||||
.chain(port_bytes.iter().cloned())
|
||||
.chain(ip.octets().iter().cloned())
|
||||
.chain(std::iter::repeat(0))
|
||||
.take(32)
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let mut address_bytes = [0u8; 32];
|
||||
address_bytes.copy_from_slice(&encoded_host[..32]);
|
||||
|
||||
address_bytes
|
||||
}
|
||||
|
||||
pub fn socket_address_from_encoded_bytes(b: [u8; 32]) -> SocketAddr {
|
||||
let address_type: AddressType = b[0].try_into().unwrap();
|
||||
|
||||
let port: u16 = u16::from_be_bytes([b[1], b[2]]);
|
||||
|
||||
let ip = match address_type {
|
||||
AddressType::V4 => IpAddr::V4(Ipv4Addr::new(b[3], b[4], b[5], b[6])),
|
||||
AddressType::V6 => {
|
||||
let mut address_octets = [0u8; 16];
|
||||
address_octets.copy_from_slice(&b[3..19]);
|
||||
IpAddr::V6(Ipv6Addr::from(address_octets))
|
||||
}
|
||||
};
|
||||
|
||||
SocketAddr::new(ip, port)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
pub fn zero_pad_to_32(mut bytes: Vec<u8>) -> [u8; 32] {
|
||||
assert!(bytes.len() <= 32);
|
||||
if bytes.len() != 32 {
|
||||
bytes.resize(32, 0);
|
||||
}
|
||||
let mut padded_bytes = [0; 32];
|
||||
padded_bytes.copy_from_slice(&bytes[..]);
|
||||
padded_bytes
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod zero_padding_to_32_bytes {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod with_empty_input {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_returns_32_zeros() {
|
||||
let input = vec![];
|
||||
let result = zero_pad_to_32(input);
|
||||
assert_eq!([0u8; 32], result);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod with_all_bytes_set_to_1 {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_32_ones() {
|
||||
let input = vec![1u8; 32];
|
||||
let result = zero_pad_to_32(input);
|
||||
assert_eq!([1u8; 32], result);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod with_3_bytes_set {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_returns_input_zero_padded_to_32_bytes() {
|
||||
let input = vec![1u8; 3];
|
||||
let result = zero_pad_to_32(input);
|
||||
let expected_content = vec![
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
];
|
||||
assert_eq!(expected_content, result.to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod with_oversized_input {
|
||||
use super::*;
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn it_panics() {
|
||||
let input = vec![1u8; 33];
|
||||
zero_pad_to_32(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pub mod addressing;
|
||||
pub mod bytes;
|
||||
pub mod poisson;
|
||||
pub mod sphinx;
|
||||
pub mod topology;
|
||||
@@ -1,6 +0,0 @@
|
||||
use rand_distr::{Distribution, Exp};
|
||||
|
||||
pub fn sample(average_delay: f64) -> f64 {
|
||||
let exp = Exp::new(1.0 / average_delay).unwrap();
|
||||
exp.sample(&mut rand::thread_rng())
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
use crate::clients::directory::presence::Topology;
|
||||
use crate::utils::{addressing, bytes, topology};
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use sphinx::route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier};
|
||||
use sphinx::SphinxPacket;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub const LOOP_COVER_MESSAGE_PAYLOAD: &[u8] = b"The cake is a lie!";
|
||||
|
||||
pub fn loop_cover_message(
|
||||
our_address: DestinationAddressBytes,
|
||||
surb_id: SURBIdentifier,
|
||||
topology: &Topology,
|
||||
) -> (SocketAddr, SphinxPacket) {
|
||||
let destination = Destination::new(our_address, surb_id);
|
||||
|
||||
encapsulate_message(destination, LOOP_COVER_MESSAGE_PAYLOAD.to_vec(), topology)
|
||||
}
|
||||
|
||||
pub fn encapsulate_message(
|
||||
recipient: Destination,
|
||||
message: Vec<u8>,
|
||||
topology: &Topology,
|
||||
) -> (SocketAddr, SphinxPacket) {
|
||||
let mixes_route = topology::route_from(&topology);
|
||||
let first_provider = topology.mix_provider_nodes.first().unwrap();
|
||||
let decoded_key_bytes =
|
||||
base64::decode_config(&first_provider.pub_key, base64::URL_SAFE).unwrap();
|
||||
let key_bytes = bytes::zero_pad_to_32(decoded_key_bytes);
|
||||
let key = MontgomeryPoint(key_bytes);
|
||||
|
||||
let provider = Node::new(
|
||||
addressing::encoded_bytes_from_socket_address(first_provider.host.clone().parse().unwrap()),
|
||||
key,
|
||||
);
|
||||
|
||||
let route = [mixes_route, vec![provider]].concat();
|
||||
|
||||
let delays = sphinx::header::delays::generate(route.len());
|
||||
|
||||
// build the packet
|
||||
let packet = sphinx::SphinxPacket::new(message, &route[..], &recipient, &delays).unwrap();
|
||||
|
||||
let first_node_address =
|
||||
addressing::socket_address_from_encoded_bytes(route.first().unwrap().address);
|
||||
|
||||
(first_node_address, packet)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
use crate::clients::directory;
|
||||
use crate::clients::directory::presence::MixNodePresence;
|
||||
use crate::clients::directory::presence::Topology;
|
||||
use crate::clients::directory::requests::presence_topology_get::PresenceTopologyGetRequester;
|
||||
use crate::clients::directory::DirectoryClient;
|
||||
use crate::utils::{addressing, bytes};
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use rand::seq::SliceRandom;
|
||||
use sphinx::route::Node as SphinxNode;
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub(crate) fn get_topology(directory_server: String) -> Topology {
|
||||
println!("Using directory server: {:?}", directory_server);
|
||||
let directory_config = directory::Config {
|
||||
base_url: directory_server,
|
||||
};
|
||||
let directory = directory::Client::new(directory_config);
|
||||
|
||||
let topology = directory
|
||||
.presence_topology
|
||||
.get()
|
||||
.expect("Failed to retrieve network topology.");
|
||||
topology
|
||||
}
|
||||
|
||||
pub(crate) fn route_from(topology: &Topology) -> Vec<SphinxNode> {
|
||||
let mut layered_topology: HashMap<u64, Vec<MixNodePresence>> = HashMap::new();
|
||||
let mixes = topology.mix_nodes.iter();
|
||||
for mix in mixes {
|
||||
let layer_nodes = layered_topology.entry(mix.layer).or_insert(Vec::new());
|
||||
layer_nodes.push(mix.clone());
|
||||
}
|
||||
|
||||
let num_layers = layered_topology.len() as u64;
|
||||
let mut route = vec![];
|
||||
|
||||
for x in 1..=num_layers {
|
||||
let nodes = &layered_topology[&x];
|
||||
let the_node = nodes.choose(&mut rand::thread_rng()).unwrap();
|
||||
route.push(the_node);
|
||||
}
|
||||
|
||||
route
|
||||
.iter()
|
||||
.map(|mix| {
|
||||
let address_bytes =
|
||||
addressing::encoded_bytes_from_socket_address(mix.host.clone().parse().unwrap());
|
||||
let decoded_key_bytes = base64::decode_config(&mix.pub_key, base64::URL_SAFE).unwrap();
|
||||
let key_bytes = bytes::zero_pad_to_32(decoded_key_bytes);
|
||||
let key = MontgomeryPoint(key_bytes);
|
||||
SphinxNode {
|
||||
address: address_bytes,
|
||||
pub_key: key,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Reference in New Issue
Block a user