diff --git a/.gitignore b/.gitignore index 53eaa21960..c384ecb2ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target **/*.rs.bk +/*/target +/test_inbox \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 58ab40b76e..a25f5f394f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,6 +514,7 @@ dependencies = [ "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)", "rand 0.7.2 (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)", ] @@ -653,6 +654,13 @@ name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sfw-provider-requests" +version = "0.1.0" +dependencies = [ + "sphinx 0.1.0", +] + [[package]] name = "sha2" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index b62645736e..d05c5ba220 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,5 +12,6 @@ curve25519-dalek = "1.2.3" hex = "0.4.0" futures = "0.3.1" rand = "0.7.2" +sfw-provider-requests = { path = "./sfw-provider-requests" } sphinx = { path = "../sphinx" } tokio = { version = "0.2.4", features = ["full"] } \ No newline at end of file diff --git a/sfw-provider-requests/Cargo.lock b/sfw-provider-requests/Cargo.lock new file mode 100644 index 0000000000..de92d696c4 --- /dev/null +++ b/sfw-provider-requests/Cargo.lock @@ -0,0 +1,463 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aes-ctr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aes-soft" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aesni" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "blake2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-cipher-trait" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +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)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ctr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "curve25519-dalek" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +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)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hkdf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "keystream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lioness" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +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)", + "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)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_distr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +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)", + "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)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sfw-provider-requests" +version = "0.1.0" +dependencies = [ + "sphinx 0.1.0", +] + +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sphinx" +version = "0.1.0" +dependencies = [ + "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hkdf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lioness 0.1.2 (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)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stream-cipher" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "subtle" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" +"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" +"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +"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 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 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 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 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 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 digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"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 hkdf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3" +"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +"checksum keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum lioness 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" +"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 typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/sfw-provider-requests/Cargo.toml b/sfw-provider-requests/Cargo.toml new file mode 100644 index 0000000000..0dd4cf228f --- /dev/null +++ b/sfw-provider-requests/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "sfw-provider-requests" +version = "0.1.0" +authors = ["Jedrzej Stuczynski "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sphinx = { path = "../../sphinx" } diff --git a/sfw-provider-requests/src/lib.rs b/sfw-provider-requests/src/lib.rs new file mode 100644 index 0000000000..efc7bf8ef9 --- /dev/null +++ b/sfw-provider-requests/src/lib.rs @@ -0,0 +1,5 @@ +pub mod requests; +pub mod responses; + +pub const DUMMY_MESSAGE_CONTENT: &[u8] = + b"[DUMMY MESSAGE] Wanting something does not give you the right to have it."; diff --git a/sfw-provider-requests/src/requests.rs b/sfw-provider-requests/src/requests.rs new file mode 100644 index 0000000000..cd185ec6a6 --- /dev/null +++ b/sfw-provider-requests/src/requests.rs @@ -0,0 +1,147 @@ +const PULL_REQUEST_MESSAGE_PREFIX: [u8; 2] = [1, 0]; +const REGISTER_MESSAGE_PREFIX: [u8; 2] = [0, 1]; + +// TODO: how to do it more nicely, considering all sfw-provider-requests implement same trait that is exercised here? +#[derive(Debug)] +pub enum ProviderRequests { + PullMessages(PullRequest), + Register(RegisterRequest), +} + +impl ProviderRequests { + pub fn to_bytes(&self) -> Vec { + use ProviderRequests::*; + match self { + PullMessages(pr) => pr.to_bytes(), + Register(pr) => pr.to_bytes(), + } + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + use ProviderRequests::*; + if bytes.len() < 2 { + return Err(ProviderRequestError::UnmarshalError); + } + let mut received_prefix = [0; 2]; + received_prefix.copy_from_slice(&bytes[..2]); + match received_prefix { + PULL_REQUEST_MESSAGE_PREFIX => Ok(PullMessages(PullRequest::from_bytes(bytes)?)), + REGISTER_MESSAGE_PREFIX => Ok(Register(RegisterRequest::from_bytes(bytes)?)), + _ => Err(ProviderRequestError::UnmarshalErrorIncorrectPrefix), + } + } +} + +#[derive(Debug)] +pub enum ProviderRequestError { + MarshalError, + UnmarshalError, + UnmarshalErrorIncorrectPrefix, +} + +pub trait ProviderRequest +where + Self: Sized, +{ + fn get_prefix() -> [u8; 2]; + fn to_bytes(&self) -> Vec; + fn from_bytes(bytes: &[u8]) -> Result; +} + +#[derive(Debug)] +pub struct PullRequest { + // TODO: public keys, signatures, tokens, etc. basically some kind of authentication bs + pub destination_address: sphinx::route::DestinationAddressBytes, +} + +impl PullRequest { + pub fn new(destination_address: sphinx::route::DestinationAddressBytes) -> Self { + PullRequest { + destination_address, + } + } +} + +impl ProviderRequest for PullRequest { + fn get_prefix() -> [u8; 2] { + PULL_REQUEST_MESSAGE_PREFIX + } + + fn to_bytes(&self) -> Vec { + Self::get_prefix() + .to_vec() + .into_iter() + .chain(self.destination_address.iter().cloned()) + .collect() + } + + fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 2 + 32 { + return Err(ProviderRequestError::UnmarshalError); + } + + let mut received_prefix = [0u8; 2]; + received_prefix.copy_from_slice(&bytes[..2]); + if received_prefix != Self::get_prefix() { + return Err(ProviderRequestError::UnmarshalErrorIncorrectPrefix); + } + + let mut destination_address = [0u8; 32]; + destination_address.copy_from_slice(&bytes[2..]); + + Ok(PullRequest { + destination_address, + }) + } +} + +#[derive(Debug)] +pub struct RegisterRequest {} + +impl ProviderRequest for RegisterRequest { + fn get_prefix() -> [u8; 2] { + unimplemented!() + } + + fn to_bytes(&self) -> Vec { + unimplemented!() + } + + fn from_bytes(bytes: &[u8]) -> Result { + unimplemented!() + } +} + +#[cfg(test)] +mod creating_pull_request { + use super::*; + + #[test] + fn it_is_possible_to_recover_it_from_bytes() { + let address = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, + ]; + let pull_request = PullRequest::new(address); + let bytes = pull_request.to_bytes(); + + let recovered = PullRequest::from_bytes(&bytes).unwrap(); + assert_eq!(address, recovered.destination_address); + } + + #[test] + fn it_is_possible_to_recover_it_from_bytes_with_enum_wrapper() { + let address = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, + ]; + let pull_request = PullRequest::new(address); + let bytes = pull_request.to_bytes(); + + let recovered = ProviderRequests::from_bytes(&bytes).unwrap(); + match recovered { + ProviderRequests::PullMessages(req) => assert_eq!(address, req.destination_address), + _ => panic!("expected to recover pull request!"), + } + } +} diff --git a/sfw-provider-requests/src/responses.rs b/sfw-provider-requests/src/responses.rs new file mode 100644 index 0000000000..86b622fa5e --- /dev/null +++ b/sfw-provider-requests/src/responses.rs @@ -0,0 +1,122 @@ +use std::convert::TryInto; + +#[derive(Debug)] +pub enum ProviderResponseError { + MarshalError, + UnmarshalError, + UnmarshalErrorInvalidLength, +} + +pub trait ProviderResponse +where + Self: Sized, +{ + fn to_bytes(&self) -> Vec; + fn from_bytes(bytes: &[u8]) -> Result; +} + +#[derive(Debug)] +pub struct PullResponse { + pub messages: Vec>, +} + +impl PullResponse { + pub fn new(messages: Vec>) -> Self { + PullResponse { messages } + } +} + +// TODO: This should go into some kind of utils module/crate +fn read_be_u16(input: &mut &[u8]) -> u16 { + let (int_bytes, rest) = input.split_at(std::mem::size_of::()); + *input = rest; + u16::from_be_bytes(int_bytes.try_into().unwrap()) +} + +// TODO: currently this allows for maximum 64kB payload - if we go over that in sphinx, +// we need to update this code. +impl ProviderResponse for PullResponse { + // num_msgs || len1 || len2 || ... || msg1 || msg2 || ... + fn to_bytes(&self) -> Vec { + let num_msgs = self.messages.len() as u16; + let msgs_lens: Vec = self.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(self.messages.iter().flat_map(|msg| msg.clone().into_iter())) + .collect() + } + + fn from_bytes(bytes: &[u8]) -> Result { + // can we read number of messages? + if bytes.len() < 2 { + return Err(ProviderResponseError::UnmarshalErrorInvalidLength); + } + + let mut bytes_copy = bytes.clone(); + let num_msgs = read_be_u16(&mut bytes_copy); + + // can we read all lengths of messages? + if bytes_copy.len() < (num_msgs * 2) as usize { + return Err(ProviderResponseError::UnmarshalErrorInvalidLength); + } + + let msgs_lens: Vec<_> = (0..num_msgs) + .map(|_| read_be_u16(&mut bytes_copy)) + .collect(); + + let required_remaining_len = msgs_lens + .iter() + .fold(0usize, |acc, &len| acc + (len as usize)); + + // can we read messages themselves? + if bytes_copy.len() != required_remaining_len { + return Err(ProviderResponseError::UnmarshalErrorInvalidLength); + } + + let msgs = msgs_lens + .iter() + .scan(0usize, |i, &len| { + let j = *i + (len as usize); + let msg = bytes_copy[*i..j].to_vec(); + *i = j; + Some(msg) + }) + .collect(); + + Ok(PullResponse { messages: msgs }) + } +} + +#[cfg(test)] +mod creating_pull_response { + use super::*; + + #[test] + fn it_is_possible_to_recover_it_from_bytes() { + let msg1 = vec![1, 2, 3, 4, 5]; + let msg2 = vec![]; + let msg3 = vec![ + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, + 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, + 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, + 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, + 2, 3, 4, 5, 1, 2, 3, 4, 5, + ]; + let msg4 = vec![1, 2, 3, 4, 5, 6, 7]; + + let msgs = vec![msg1, msg2, msg3, msg4]; + let pull_response = PullResponse::new(msgs.clone()); + let bytes = pull_response.to_bytes(); + + let recovered = PullResponse::from_bytes(&bytes).unwrap(); + assert_eq!(msgs, recovered.messages); + } +} diff --git a/src/main.rs b/src/main.rs index e89641e0b2..c811ca9764 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,9 +17,14 @@ fn execute(matches: ArgMatches) -> Result<(), String> { fn run(matches: &ArgMatches) { println!("Running the service provider!"); - let host = matches.value_of("host").unwrap_or("0.0.0.0"); + let mix_host = matches.value_of("mixHost").unwrap_or("0.0.0.0"); + let mix_port = match matches.value_of("mixPort").unwrap().parse::() { + Ok(n) => n, + Err(err) => panic!("Invalid port value provided - {:?}", err), + }; - let port = match matches.value_of("port").unwrap().parse::() { + let client_host = matches.value_of("clientHost").unwrap_or("0.0.0.0"); + let client_port = match matches.value_of("clientPort").unwrap().parse::() { Ok(n) => n, Err(err) => panic!("Invalid port value provided - {:?}", err), }; @@ -37,23 +42,43 @@ fn run(matches: &ArgMatches) { let store_dir = PathBuf::from(matches.value_of("storeDir").unwrap()); - println!("The value of host is: {:?}", host); - println!("The value of port is: {:?}", port); + println!("The value of mix_host is: {:?}", mix_host); + println!("The value of mix_port is: {:?}", mix_port); + println!("The value of client_host is: {:?}", client_host); + println!("The value of client_port is: {:?}", client_port); println!("The value of key is: {:?}", secret_key); - println!("The value of storeDir is: {:?}", store_dir); + println!("The value of store_dir is: {:?}", store_dir); - let socket_address = (host, port) + let mix_socket_address = (mix_host, mix_port) .to_socket_addrs() .expect("Failed to combine host and port") .next() .expect("Failed to extract the socket address from the iterator"); - println!("The full combined socket address is {}", socket_address); + let client_socket_address = (client_host, client_port) + .to_socket_addrs() + .expect("Failed to combine host and port") + .next() + .expect("Failed to extract the socket address from the iterator"); + + println!( + "The full combined mix socket address is {}", + mix_socket_address + ); + println!( + "The full combined client socket address is {}", + client_socket_address + ); // make sure our socket_address is equal to our predefined-hardcoded value - assert_eq!("127.0.0.1:8081", socket_address.to_string()); + assert_eq!("127.0.0.1:8081", mix_socket_address.to_string()); - let provider = ServiceProvider::new(socket_address, secret_key, store_dir); + let provider = ServiceProvider::new( + mix_socket_address, + client_socket_address, + secret_key, + store_dir, + ); provider.start_listening().unwrap() } @@ -66,17 +91,28 @@ fn main() { SubCommand::with_name("run") .about("Starts the service provider") .arg( - Arg::with_name("host") - .short("h") - .long("host") - .help("The custom host on which the service provider will be running") + Arg::with_name("mixHost") + .long("mixHost") + .help("The custom host on which the service provider will be running for receiving sphinx packets") .takes_value(true), ) .arg( - Arg::with_name("port") - .short("p") - .long("port") - .help("The port on which the service provider will be listening") + Arg::with_name("mixPort") + .long("mixPort") + .help("The port on which the service provider will be listening for sphinx packets") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("clientHost") + .long("clientHost") + .help("The custom host on which the service provider will be running for receiving client sfw-provider-requests") + .takes_value(true), + ) + .arg( + Arg::with_name("clientPort") + .long("clientPort") + .help("The port on which the service provider will be listening for client sfw-provider-requests") .takes_value(true) .required(true), ) @@ -89,7 +125,7 @@ fn main() { ) .arg( Arg::with_name("storeDir") - .short("sdir") + .short("s") .long("storeDir") .help("Directory storing all packets for the clients") .takes_value(true) diff --git a/src/provider/client_handling/mod.rs b/src/provider/client_handling/mod.rs new file mode 100644 index 0000000000..7618c7f1dc --- /dev/null +++ b/src/provider/client_handling/mod.rs @@ -0,0 +1,76 @@ +use crate::provider::storage::{ClientStorage, StoreError}; +use sfw_provider_requests::requests::{ProviderRequestError, ProviderRequests, PullRequest}; +use sfw_provider_requests::responses::{ProviderResponse, PullResponse}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; + +#[derive(Debug)] +pub enum ClientProcessingError { + ClientDoesntExistError, + StoreError, + InvalidRequest, +} + +impl From for ClientProcessingError { + fn from(_: ProviderRequestError) -> Self { + use ClientProcessingError::*; + + InvalidRequest + } +} + +impl From for ClientProcessingError { + fn from(e: StoreError) -> Self { + match e { + StoreError::ClientDoesntExistError => ClientProcessingError::ClientDoesntExistError, + _ => ClientProcessingError::StoreError, + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct ClientProcessingData { + store_dir: PathBuf, +} + +impl ClientProcessingData { + pub(crate) fn new(store_dir: PathBuf) -> Self { + ClientProcessingData { store_dir } + } + + pub(crate) fn add_arc_rwlock(self) -> Arc> { + Arc::new(RwLock::new(self)) + } +} + +pub(crate) struct ClientRequestProcessor(()); + +impl ClientRequestProcessor { + pub(crate) fn process_client_request( + data: &[u8], + processing_data: &RwLock, + ) -> Result, ClientProcessingError> { + let client_request = ProviderRequests::from_bytes(&data)?; + println!("received the following request: {:?}", client_request); + match client_request { + ProviderRequests::Register(req) => unimplemented!(), + ProviderRequests::PullMessages(req) => { + Ok(ClientRequestProcessor::process_pull_messages_request( + req, + processing_data.read().unwrap().store_dir.as_path(), + )? + .to_bytes()) + } + } + } + + fn process_pull_messages_request( + req: PullRequest, + store_dir: &Path, + ) -> Result { + println!("processing pull!"); + let retrieved_messages = + ClientStorage::retrieve_client_files(req.destination_address, store_dir)?; + Ok(PullResponse::new(retrieved_messages)) + } +} diff --git a/src/provider/mix_handling/mod.rs b/src/provider/mix_handling/mod.rs new file mode 100644 index 0000000000..23d46c2d86 --- /dev/null +++ b/src/provider/mix_handling/mod.rs @@ -0,0 +1,83 @@ +use crate::provider::storage::StoreData; +use curve25519_dalek::scalar::Scalar; +use sphinx::{ProcessedPacket, SphinxPacket}; +use std::path::PathBuf; +use std::sync::{Arc, RwLock}; + +// TODO: this will probably need to be moved elsewhere I imagine +// DUPLICATE WITH MIXNODE CODE!!! +#[derive(Debug)] +pub enum MixProcessingError { + SphinxRecoveryError, + ReceivedForwardHopError, + InvalidPayload, + NonMatchingRecipient, + FileIOFailure, +} + +impl From 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 + } +} + +impl From for MixProcessingError { + fn from(_: std::io::Error) -> Self { + use MixProcessingError::*; + + FileIOFailure + } +} + +// ProcessingData defines all data required to correctly unwrap sphinx packets +#[derive(Debug, Clone)] +pub(crate) struct MixProcessingData { + secret_key: Scalar, + pub(crate) store_dir: PathBuf, +} + +impl MixProcessingData { + pub(crate) fn new(secret_key: Scalar, store_dir: PathBuf) -> Self { + MixProcessingData { + secret_key, + store_dir, + } + } + + pub(crate) fn add_arc_rwlock(self) -> Arc> { + Arc::new(RwLock::new(self)) + } +} + +pub(crate) struct MixPacketProcessor(()); + +impl MixPacketProcessor { + pub fn process_sphinx_data_packet( + packet_data: &[u8], + processing_data: &RwLock, + ) -> Result { + let packet = SphinxPacket::from_bytes(packet_data.to_vec())?; + let read_processing_data = processing_data.read().unwrap(); + let (client_address, client_surb_id, payload) = + match packet.process(read_processing_data.secret_key) { + ProcessedPacket::ProcessedPacketFinalHop(client_address, surb_id, payload) => { + (client_address, surb_id, payload) + } + _ => return Err(MixProcessingError::ReceivedForwardHopError), + }; + + // TODO: should provider try to be recovering plaintext? this would potentially make client retrieve messages of non-constant length, + // perhaps provider should be re-padding them on retrieval or storing full data? + let (payload_destination, message) = payload + .try_recover_destination_and_plaintext() + .ok_or_else(|| MixProcessingError::InvalidPayload)?; + if client_address != payload_destination { + return Err(MixProcessingError::NonMatchingRecipient); + } + + Ok(StoreData::new(client_address, client_surb_id, message)) + } +} diff --git a/src/provider/mod.rs b/src/provider/mod.rs index fcc5ba3c69..1b65a42a4c 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -1,146 +1,45 @@ -use std::fs::File; -use std::io::Write; -use std::net::SocketAddr; -use std::path::{Path, PathBuf}; +use std::net::{Shutdown, SocketAddr}; +use std::path::PathBuf; use std::sync::Arc; use std::sync::RwLock; use curve25519_dalek::scalar::Scalar; -use rand::Rng; -use sphinx::{ProcessedPacket, SphinxPacket}; -use sphinx::route::{DestinationAddressBytes, SURBIdentifier}; use tokio::prelude::*; use tokio::runtime::Runtime; +use crate::provider::client_handling::{ClientProcessingData, ClientRequestProcessor}; +use crate::provider::mix_handling::{MixPacketProcessor, MixProcessingData}; +use crate::provider::storage::ClientStorage; + +mod client_handling; +mod mix_handling; +mod storage; + + // TODO: if we ever create config file, this should go there const STORED_MESSAGE_FILENAME_LENGTH: usize = 16; - - -// TODO: this will probably need to be moved elsewhere I imagine -// DUPLICATE WITH MIXNODE CODE!!! -#[derive(Debug)] -pub enum MixProcessingError { - SphinxRecoveryError, - ReceivedForwardHopError, - InvalidPayload, - NonMatchingRecipient, - FileIOFailure, -} - -impl From 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 - } -} - -impl From for MixProcessingError { - fn from(_: std::io::Error) -> Self { - use MixProcessingError::*; - - FileIOFailure - } -} - - -// ProcessingData defines all data required to correctly unwrap sphinx packets -// Do note that we're copying this struct around and hence the secret_key. -// It might, or might not be, what we want -#[derive(Debug, Clone)] -struct ProcessingData { - secret_key: Scalar, - store_dir: PathBuf, -} - -impl ProcessingData { - fn new(secret_key: Scalar, store_dir: PathBuf) -> Self { - ProcessingData { - secret_key, - store_dir, - } - } - - fn add_arc_rwlock(self) -> Arc> { - Arc::new(RwLock::new(self)) - } -} - -struct StoreData { - client_address: DestinationAddressBytes, - client_surb_id: SURBIdentifier, - message: Vec, -} - - -struct PacketProcessor(()); - -impl PacketProcessor { - fn process_sphinx_data_packet(packet_data: &[u8], processing_data: &RwLock) -> Result { - let packet = SphinxPacket::from_bytes(packet_data.to_vec())?; - let read_processing_data = processing_data.read().unwrap(); - let (client_address, client_surb_id, payload) = match packet.process(read_processing_data.secret_key) { - ProcessedPacket::ProcessedPacketFinalHop(client_address, surb_id, payload) => (client_address, surb_id, payload), - _ => return Err(MixProcessingError::ReceivedForwardHopError), - }; - - let (payload_destination, message) = payload.try_recover_destination_and_plaintext().ok_or_else(|| MixProcessingError::InvalidPayload)?; - if client_address != payload_destination { - return Err(MixProcessingError::NonMatchingRecipient); - } - - Ok(StoreData { - client_address, - client_surb_id, - message, - }) - } - - fn generate_random_file_name() -> String { - rand::thread_rng().sample_iter(&rand::distributions::Alphanumeric).take(STORED_MESSAGE_FILENAME_LENGTH).collect::() - } - - fn store_processed_data(store_data: StoreData, store_dir: &Path) -> Result<(), MixProcessingError> { - let client_dir_name = hex::encode(store_data.client_address); - let full_store_dir = store_dir.join(client_dir_name); - let full_store_path = full_store_dir.join(PacketProcessor::generate_random_file_name()); - println!("going to store: {:?} in file: {:?}", store_data.message, full_store_path); - - // TODO: what to do with surbIDs?? - - // we can use normal io here, no need for tokio as it's all happening in one thread per connection - std::fs::create_dir_all(full_store_dir)?; - let mut file = File::create(full_store_path)?; - file.write_all(store_data.message.as_ref())?; - - - Ok(()) - } -} +const MESSAGE_RETRIEVAL_LIMIT: usize = 2; pub struct ServiceProvider { - network_address: SocketAddr, + mix_network_address: SocketAddr, + client_network_address: SocketAddr, secret_key: Scalar, store_dir: PathBuf, } impl ServiceProvider { - pub fn new(network_address: SocketAddr, secret_key: Scalar, store_dir: PathBuf) -> Self { + pub fn new(mix_network_address: SocketAddr, client_network_address: SocketAddr, secret_key: Scalar, store_dir: PathBuf) -> Self { ServiceProvider { - network_address, + mix_network_address, + client_network_address, secret_key, store_dir, } } - async fn process_socket_connection(mut socket: tokio::net::TcpStream, processing_data: Arc>) { - // TODO: we will actually need to distinguish multiple types of requests here; - // either from mixnodes to store final hop information - // or from clients to pull messages - + async fn process_mixnet_socket_connection(mut socket: tokio::net::TcpStream, processing_data: Arc>) { let mut buf = [0u8; sphinx::PACKET_SIZE]; // In a loop, read data from the socket and write the data back. @@ -152,15 +51,16 @@ impl ServiceProvider { return; } Ok(_) => { - let store_data = match PacketProcessor::process_sphinx_data_packet(buf.as_ref(), processing_data.as_ref()) { + let store_data = match MixPacketProcessor::process_sphinx_data_packet(buf.as_ref(), processing_data.as_ref()) { Ok(sd) => sd, Err(e) => { eprintln!("failed to process sphinx packet; err = {:?}", e); return; } }; - PacketProcessor::store_processed_data(store_data, processing_data.read().unwrap().store_dir.as_path()).unwrap_or_else(|e| { - eprintln!("failed to store processed sphinx message; err = {:?}", e) + ClientStorage::store_processed_data(store_data, processing_data.read().unwrap().store_dir.as_path()).unwrap_or_else(|e| { + eprintln!("failed to store processed sphinx message; err = {:?}", e); + return; }); } Err(e) => { @@ -177,6 +77,91 @@ impl ServiceProvider { } } + async fn send_response(mut socket: tokio::net::TcpStream, data: &[u8]) { + if let Err(e) = socket.write_all(data).await { + eprintln!("failed to write reply to socket; err = {:?}", e) + } + if let Err(e) = socket.shutdown(Shutdown::Write) { + eprintln!("failed to close write part of the socket; err = {:?}", e) + } + } + + // TODO: FIGURE OUT HOW TO SET READ_DEADLINES IN TOKIO + async fn process_client_socket_connection(mut socket: tokio::net::TcpStream, processing_data: Arc>) { + let mut buf = [0; 1024]; + + // TODO: restore the for loop once we go back to persistent tcp socket connection + let response = match socket.read(&mut buf).await { + // socket closed + Ok(n) if n == 0 => { + println!("Remote connection closed."); + Err(()) + } + Ok(n) => { + match ClientRequestProcessor::process_client_request(buf[..n].as_ref(), processing_data.as_ref()) { + Err(e) => { + eprintln!("failed to process client request; err = {:?}", e); + Err(()) + } + Ok(res) => Ok(res), + } + } + Err(e) => { + eprintln!("failed to read from socket; err = {:?}", e); + Err(()) + } + }; + + if let Err(e) = socket.shutdown(Shutdown::Read) { + eprintln!("failed to close read part of the socket; err = {:?}", e) + } + + match response { + Ok(res) => { + println!("should send this response! {:?}", res); + ServiceProvider::send_response(socket, &res).await; + } + _ => { + println!("we failed..."); + ServiceProvider::send_response(socket, b"bad foomp").await; + } + } + } + + async fn start_mixnet_listening(&self) -> Result<(), Box> { + let mut listener = tokio::net::TcpListener::bind(self.mix_network_address).await?; + let processing_data = MixProcessingData::new(self.secret_key, self.store_dir.clone()).add_arc_rwlock(); + + loop { + let (socket, _) = listener.accept().await?; + // do note that the underlying data is NOT copied here; arc is incremented and lock is shared + // (if I understand it all correctly) + let thread_processing_data = processing_data.clone(); + tokio::spawn(async move { + ServiceProvider::process_mixnet_socket_connection(socket, thread_processing_data).await + }); + } + } + + async fn start_client_listening(&self) -> Result<(), Box> { + let mut listener = tokio::net::TcpListener::bind(self.client_network_address).await?; + let processing_data = ClientProcessingData::new(self.store_dir.clone()).add_arc_rwlock(); + + loop { + let (socket, _) = listener.accept().await?; + // do note that the underlying data is NOT copied here; arc is incremented and lock is shared + // (if I understand it all correctly) + let thread_processing_data = processing_data.clone(); + tokio::spawn(async move { + ServiceProvider::process_client_socket_connection(socket, thread_processing_data).await + }); + } + } + + async fn start_listeners(&self) -> (Result<(), Box>, Result<(), Box>) { + futures::future::join(self.start_mixnet_listening(), self.start_client_listening()).await + } + pub fn start_listening(&self) -> Result<(), Box> { // Create the runtime, probably later move it to Provider struct itself? @@ -186,17 +171,13 @@ impl ServiceProvider { // 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, self.store_dir.clone()).add_arc_rwlock(); + let future_results = self.start_listeners().await; + assert!(future_results.0.is_ok() && future_results.1.is_ok()) + }); - loop { - let (socket, _) = listener.accept().await?; - let thread_processing_data = processing_data.clone(); - tokio::spawn(async move { - ServiceProvider::process_socket_connection(socket, thread_processing_data).await - }); - } - }) + // this line in theory should never be reached as the runtime should be permanently blocked on listeners + eprintln!("The server went kaput..."); + Ok(()) } } diff --git a/src/provider/storage/mod.rs b/src/provider/storage/mod.rs new file mode 100644 index 0000000000..cead9e2db0 --- /dev/null +++ b/src/provider/storage/mod.rs @@ -0,0 +1,126 @@ +use crate::provider::{MESSAGE_RETRIEVAL_LIMIT, STORED_MESSAGE_FILENAME_LENGTH}; +use rand::Rng; +use sfw_provider_requests::DUMMY_MESSAGE_CONTENT; +use sphinx::route::{DestinationAddressBytes, SURBIdentifier}; +use std::fs::File; +use std::io; +use std::io::Write; +use std::path::{Path, PathBuf}; + +pub enum StoreError { + ClientDoesntExistError, + FileIOFailure, +} + +impl From for StoreError { + fn from(_: std::io::Error) -> Self { + use StoreError::*; + + FileIOFailure + } +} + +pub struct StoreData { + client_address: DestinationAddressBytes, + client_surb_id: SURBIdentifier, + message: Vec, +} + +impl StoreData { + pub(crate) fn new( + client_address: DestinationAddressBytes, + client_surb_id: SURBIdentifier, + message: Vec, + ) -> Self { + StoreData { + client_address, + client_surb_id, + message, + } + } +} + +// TODO: replace with database +pub struct ClientStorage(()); + +// TODO: change it to some generic implementation to inject fs +impl ClientStorage { + fn generate_random_file_name() -> String { + rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(STORED_MESSAGE_FILENAME_LENGTH) + .collect::() + } + + fn dummy_message() -> Vec { + // TODO: should it be padded to constant length? + DUMMY_MESSAGE_CONTENT.to_vec() + } + + pub fn store_processed_data(store_data: StoreData, store_dir: &Path) -> io::Result<()> { + let client_dir_name = hex::encode(store_data.client_address); + let full_store_dir = store_dir.join(client_dir_name); + let full_store_path = full_store_dir.join(ClientStorage::generate_random_file_name()); + println!( + "going to store: {:?} in file: {:?}", + store_data.message, full_store_path + ); + + // TODO: what to do with surbIDs?? + + // TODO: this should be called when client sends 'register' request! + std::fs::create_dir_all(full_store_dir)?; + + // we can use normal io here, no need for tokio as it's all happening in one thread per connection + let mut file = File::create(full_store_path)?; + file.write_all(store_data.message.as_ref())?; + + Ok(()) + } + + pub fn retrieve_client_files( + client_address: DestinationAddressBytes, + store_dir: &Path, + ) -> Result>, StoreError> { + let client_dir_name = hex::encode(client_address); + let full_store_dir = store_dir.join(client_dir_name); + + println!("going to lookup: {:?}!", full_store_dir); + if !full_store_dir.exists() { + return Err(StoreError::ClientDoesntExistError); + } + + let msgs: Vec<_> = std::fs::read_dir(full_store_dir)? + .map(|entry| entry.unwrap()) + .filter(|entry| { + let is_file = entry.metadata().unwrap().is_file(); + if !is_file { + eprintln!( + "potentially corrupted client inbox! - found a non-file - {:?}", + entry.path() + ); + } + is_file + }) + .map(|entry| { + let content = std::fs::read(entry.path()).unwrap(); + ClientStorage::delete_file(entry.path()); + content + }) // TODO: THIS MAP IS UNSAFE (BOTH READING AND DELETING)!! + .chain(std::iter::repeat(ClientStorage::dummy_message())) + .take(MESSAGE_RETRIEVAL_LIMIT) + .collect(); + + println!("retrieved the following data: {:?}", msgs); + + Ok(msgs) + } + + // TODO: THIS NEEDS A LOCKING MECHANISM!!! (or a db layer on top - basically 'ClientStorage' on steroids) + // TODO 2: This should only be called AFTER we sent the reply. Because if client's connection failed after sending request + // the messages would be deleted but he wouldn't have received them + fn delete_file(path: PathBuf) { + println!("Here {:?} will be deleted!", path); + std::fs::remove_file(path); // another argument for db layer -> remove_file is NOT guaranteed to immediately get rid of the file + } +}