diff --git a/.travis.yml b/.travis.yml index bf149680d5..5425860532 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,5 +11,5 @@ before_script: - rustup component add rustfmt script: - cargo build - - cargo test -- --test-threads=1 + - cargo test --all - cargo fmt -- --check \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ae1522fe8c..888bfdfa31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,9 +9,9 @@ dependencies = [ "byteorder", "bytes 0.4.12", "env_logger 0.7.1", - "futures 0.3.4", + "futures 0.3.5", "integer-encoding", - "log 0.4.8", + "log 0.4.11", "protobuf", "protobuf-codegen-pure", "tokio 0.1.22", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" dependencies = [ "memchr", ] @@ -115,14 +115,14 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "arc-swap" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663a8e9a99154b5fb793032533f6328da35e23aac63d5c152279aa8ba356825" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" [[package]] name = "array-init" @@ -144,9 +144,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "assert-json-diff" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c356497fd3417158bcb318266ac83c391219ca3a5fa659049f42e0041ab57d6" +checksum = "4259cbe96513d2f1073027a259fc2ca917feb3026a5a8d984e3628e490255cc0" dependencies = [ "extend", "serde", @@ -161,7 +161,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -172,9 +172,9 @@ checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" @@ -243,9 +243,9 @@ dependencies = [ [[package]] name = "blake3" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f88a20f7dc23e3896bcbd85add056543c87215de721468b90e0c85d5a9f365" +checksum = "ce4f9586c9a3151c4b49b19e82ba163dd073614dd057e53c969e1a4db5b52720" dependencies = [ "arrayref", "arrayvec", @@ -274,7 +274,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.1", + "generic-array 0.14.4", ] [[package]] @@ -283,7 +283,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa136449e765dc7faa244561ccae839c394048667929af599b5d931ebe7b7f10" dependencies = [ - "generic-array 0.14.1", + "generic-array 0.14.4", ] [[package]] @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "bs58" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" [[package]] name = "built" @@ -334,9 +334,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" [[package]] name = "byte-tools" @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "bytes" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "cargo-lock" @@ -380,9 +380,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" [[package]] name = "cfg-if" @@ -402,9 +402,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.11" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits", @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.0" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", @@ -426,15 +426,6 @@ dependencies = [ "vec_map", ] -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -dependencies = [ - "cc", -] - [[package]] name = "client-core" version = "0.8.0-dev" @@ -444,10 +435,10 @@ dependencies = [ "crypto", "directory-client", "dirs 2.0.2", - "futures 0.3.4", + "futures 0.3.5", "gateway-client", "gateway-requests", - "log 0.4.8", + "log 0.4.11", "nymsphinx", "pemstore", "rand 0.7.3", @@ -456,7 +447,6 @@ dependencies = [ "tempfile", "tokio 0.2.22", "topology", - "url 2.1.1", ] [[package]] @@ -485,7 +475,7 @@ checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ "atty", "lazy_static", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -561,7 +551,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cfg-if", "crossbeam-utils", "lazy_static", @@ -572,12 +562,13 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ "cfg-if", "crossbeam-utils", + "maybe-uninit", ] [[package]] @@ -586,7 +577,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cfg-if", "lazy_static", ] @@ -600,10 +591,10 @@ dependencies = [ "bs58", "digest 0.9.0", "ed25519-dalek", - "generic-array 0.14.1", + "generic-array 0.14.4", "hkdf 0.9.0", "hmac 0.8.1", - "log 0.4.8", + "log 0.4.11", "nymsphinx-types", "pemstore", "pretty_env_logger", @@ -628,8 +619,8 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.1", - "subtle 2.2.2", + "generic-array 0.14.4", + "subtle 2.2.3", ] [[package]] @@ -653,14 +644,27 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" +checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.2.2", + "subtle 2.2.3", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.2.3", "zeroize", ] @@ -685,7 +689,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.1", + "generic-array 0.14.4", ] [[package]] @@ -693,7 +697,7 @@ name = "directory-client" version = "0.1.0" dependencies = [ "directory-client-models", - "log 0.4.8", + "log 0.4.11", "mockito", "pretty_env_logger", "reqwest", @@ -737,7 +741,7 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", "redox_users", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -754,27 +758,38 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "dtoa" -version = "0.4.5" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" + +[[package]] +name = "ed25519" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" +checksum = "bf038a7b6fd7ef78ad3348b63f3a17550877b0e28f8d68bcc94894d1412158bc" +dependencies = [ + "signature", +] [[package]] name = "ed25519-dalek" -version = "1.0.0-pre.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" +checksum = "53d2e93f837d749c16d118e7ddf7a4dfd0ac8f452cf51e46e9348824e5ef6851" dependencies = [ - "clear_on_drop", - "curve25519-dalek", + "curve25519-dalek 3.0.0", + "ed25519", "rand 0.7.3", - "sha2", + "serde", + "sha2 0.9.1", + "zeroize", ] [[package]] name = "encoding_rs" -version = "0.8.22" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" +checksum = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" dependencies = [ "cfg-if", ] @@ -787,7 +802,7 @@ checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ "atty", "humantime", - "log 0.4.8", + "log 0.4.11", "regex", "termcolor", ] @@ -800,7 +815,7 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", "humantime", - "log 0.4.8", + "log 0.4.11", "regex", "termcolor", ] @@ -811,19 +826,19 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "version_check 0.9.1", + "version_check 0.9.2", ] [[package]] name = "extend" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9db393664b0e6c6230a14115e7e798f80b70f54038dc21165db24c6b7f28fc" +checksum = "f47da3a72ec598d9c8937a7ebca8962a5c7a1f28444e38c2b33c771ba3f55f05" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] @@ -834,9 +849,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fnv" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" @@ -860,7 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -893,9 +908,9 @@ checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" [[package]] name = "futures" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ "futures-channel", "futures-core", @@ -908,9 +923,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", "futures-sink", @@ -918,15 +933,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-executor" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ "futures-core", "futures-task", @@ -935,39 +950,42 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] name = "futures-sink" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] [[package]] name = "futures-util" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ "futures-channel", "futures-core", @@ -976,6 +994,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", + "pin-project", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -996,12 +1015,17 @@ name = "gateway-client" version = "0.1.0" dependencies = [ "crypto", - "futures 0.3.4", + "futures 0.3.5", "gateway-requests", - "log 0.4.8", + "log 0.4.11", "nymsphinx", "tokio 0.2.22", "tokio-tungstenite", + "tungstenite 0.11.1", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.17", + "wasm-timer", + "wasm-utils", ] [[package]] @@ -1010,14 +1034,14 @@ version = "0.1.0" dependencies = [ "bs58", "crypto", - "futures 0.3.4", - "log 0.4.8", + "futures 0.3.5", + "log 0.4.11", "nymsphinx", "pemstore", "rand 0.7.3", "serde", "serde_json", - "tokio-tungstenite", + "tungstenite 0.11.1", ] [[package]] @@ -1031,11 +1055,12 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.1" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2664c2cf08049036f31015b04c6ac3671379a1d86f52ed2416893f16022deb" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", + "version_check 0.9.2", ] [[package]] @@ -1046,7 +1071,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -1058,42 +1083,48 @@ checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" [[package]] name = "h2" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff" +checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "fnv", "futures-core", "futures-sink", "futures-util", "http", "indexmap", - "log 0.4.8", "slab", "tokio 0.2.22", "tokio-util", + "tracing", ] [[package]] name = "handlebars" -version = "3.0.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba758d094d31274eb49d15da6f326b96bf3185239a6359bf684f3d5321148900" +checksum = "5deefd4816fb852b1ff3cb48f6c41da67be2d0e1d20b26a7a3b076da11f064b1" dependencies = [ - "log 0.4.8", + "log 0.4.11", "pest", "pest_derive", - "quick-error", + "quick-error 2.0.0", "serde", "serde_json", ] +[[package]] +name = "hashbrown" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" + [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -1144,7 +1175,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "fnv", "itoa", ] @@ -1155,7 +1186,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "http", ] @@ -1171,7 +1202,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error", + "quick-error 1.2.3", ] [[package]] @@ -1195,11 +1226,11 @@ dependencies = [ [[package]] name = "hyper" -version = "0.13.5" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96816e1d921eca64d208a85aab4f7798455a8e34229ee5a88c935bdee1b78b14" +checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "futures-channel", "futures-core", "futures-util", @@ -1208,23 +1239,23 @@ dependencies = [ "http-body", "httparse", "itoa", - "log 0.4.8", - "net2", "pin-project", + "socket2", "time", "tokio 0.2.22", "tower-service", + "tracing", "want", ] [[package]] name = "hyper-tls" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3adcd308402b9553630734e9c36b77a7e48b3821251ca2493e8cd596763aafaa" +checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" dependencies = [ - "bytes 0.5.4", - "hyper 0.13.5", + "bytes 0.5.6", + "hyper 0.13.7", "native-tls", "tokio 0.2.22", "tokio-tls", @@ -1254,11 +1285,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.3.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", + "hashbrown", ] [[package]] @@ -1267,7 +1299,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", ] [[package]] @@ -1291,6 +1323,12 @@ dependencies = [ "libc", ] +[[package]] +name = "ipnet" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" + [[package]] name = "iron" version = "0.6.1" @@ -1309,9 +1347,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "js-sys" @@ -1352,9 +1390,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.72" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" [[package]] name = "lioness" @@ -1392,14 +1430,14 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.8", + "log 0.4.11", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -1430,11 +1468,11 @@ checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "memoffset" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", ] [[package]] @@ -1491,9 +1529,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ "cfg-if", "fuchsia-zircon", @@ -1501,7 +1539,7 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log 0.4.8", + "log 0.4.11", "miow 0.2.1", "net2", "slab", @@ -1510,21 +1548,21 @@ dependencies = [ [[package]] name = "mio-named-pipes" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" +checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ - "log 0.4.8", + "log 0.4.11", "mio", - "miow 0.3.3", - "winapi 0.3.8", + "miow 0.3.5", + "winapi 0.3.9", ] [[package]] name = "mio-uds" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", @@ -1545,20 +1583,20 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" dependencies = [ "socket2", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "mixnet-client" version = "0.1.0" dependencies = [ - "futures 0.3.4", - "log 0.4.8", + "futures 0.3.5", + "log 0.4.11", "nymsphinx", "tokio 0.2.22", "tokio-util", @@ -1575,7 +1613,7 @@ dependencies = [ "difference", "httparse", "lazy_static", - "log 0.4.8", + "log 0.4.11", "percent-encoding 2.1.0", "rand 0.7.3", "regex", @@ -1596,7 +1634,7 @@ checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" dependencies = [ "lazy_static", "libc", - "log 0.4.8", + "log 0.4.11", "openssl", "openssl-probe", "openssl-sys", @@ -1608,39 +1646,39 @@ dependencies = [ [[package]] name = "net2" -version = "0.2.33" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" dependencies = [ "cfg-if", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", ] [[package]] name = "num_cpus" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", "libc", @@ -1658,10 +1696,10 @@ dependencies = [ "directory-client", "dirs 3.0.1", "dotenv", - "futures 0.3.4", + "futures 0.3.5", "gateway-client", "gateway-requests", - "log 0.4.8", + "log 0.4.11", "nymsphinx", "pemstore", "pretty_env_logger", @@ -1679,19 +1717,23 @@ dependencies = [ [[package]] name = "nym-client-wasm" -version = "0.7.5" +version = "0.8.0" dependencies = [ + "built", "console_error_panic_hook", "crypto", - "directory-client-models", - "log 0.4.8", + "directory-client", + "futures 0.3.5", + "gateway-client", + "js-sys", "nymsphinx", "rand 0.7.3", "serde", - "serde_json", "topology", "wasm-bindgen", + "wasm-bindgen-futures 0.4.17", "wasm-bindgen-test", + "wasm-utils", "wee_alloc", ] @@ -1706,9 +1748,9 @@ dependencies = [ "directory-client", "dirs 2.0.2", "dotenv", - "futures 0.3.4", + "futures 0.3.5", "gateway-requests", - "log 0.4.8", + "log 0.4.11", "mixnet-client", "nymsphinx", "pemstore", @@ -1732,12 +1774,12 @@ dependencies = [ "clap", "config", "crypto", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "directory-client", "dirs 2.0.2", "dotenv", - "futures 0.3.4", - "log 0.4.8", + "futures 0.3.5", + "log 0.4.11", "mixnet-client", "nymsphinx", "pemstore", @@ -1761,10 +1803,10 @@ dependencies = [ "directory-client", "dirs 3.0.1", "dotenv", - "futures 0.3.4", + "futures 0.3.5", "gateway-client", "gateway-requests", - "log 0.4.8", + "log 0.4.11", "nymsphinx", "ordered-buffer", "pin-project", @@ -1777,7 +1819,6 @@ dependencies = [ "tempfile", "tokio 0.2.22", "topology", - "url 2.1.1", ] [[package]] @@ -1792,9 +1833,9 @@ dependencies = [ "config", "dirs 2.0.2", "dotenv", - "futures 0.3.4", + "futures 0.3.5", "iron", - "log 0.4.8", + "log 0.4.11", "pretty_env_logger", "router", "serde", @@ -1861,7 +1902,7 @@ dependencies = [ name = "nymsphinx-chunking" version = "0.1.0" dependencies = [ - "log 0.4.8", + "log 0.4.11", "nymsphinx-addressing", "nymsphinx-params", "nymsphinx-types", @@ -1886,7 +1927,7 @@ dependencies = [ name = "nymsphinx-framing" version = "0.1.0" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "nymsphinx-params", "nymsphinx-types", "tokio-util", @@ -1913,6 +1954,12 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +[[package]] +name = "once_cell" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -1927,9 +1974,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.29" +version = "0.10.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd" +checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" dependencies = [ "bitflags", "cfg-if", @@ -1947,11 +1994,11 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.55" +version = "0.9.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8" +checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cc", "libc", "pkg-config", @@ -1962,7 +2009,7 @@ dependencies = [ name = "ordered-buffer" version = "0.1.0" dependencies = [ - "log 0.4.8", + "log 0.4.11", ] [[package]] @@ -1983,7 +2030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" dependencies = [ "lock_api 0.3.4", - "parking_lot_core 0.7.1", + "parking_lot_core 0.7.2", ] [[package]] @@ -2009,21 +2056,21 @@ dependencies = [ "redox_syscall", "rustc_version", "smallvec 0.6.13", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e136c1904604defe99ce5fd71a28d473fa60a12255d511aa78a9ddf11237aeb" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ "cfg-if", "cloudabi 0.0.3", "libc", "redox_syscall", - "smallvec 1.4.1", - "winapi 0.3.8", + "smallvec 1.4.2", + "winapi 0.3.9", ] [[package]] @@ -2037,8 +2084,8 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec 1.4.1", - "winapi 0.3.8", + "smallvec 1.4.2", + "winapi 0.3.9", ] [[package]] @@ -2108,9 +2155,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] @@ -2178,28 +2225,28 @@ version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] name = "pin-project-lite" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" +checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" [[package]] name = "pin-utils" -version = "0.1.0-alpha.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "plugin" @@ -2212,9 +2259,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "pretty_env_logger" @@ -2224,46 +2271,44 @@ checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" dependencies = [ "chrono", "env_logger 0.6.2", - "log 0.4.8", + "log 0.4.11", ] [[package]] name = "proc-macro-error" -version = "0.4.12" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", - "version_check 0.9.1", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", + "version_check 0.9.2", ] [[package]] name = "proc-macro-error-attr" -version = "0.4.12" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", - "syn-mid", - "version_check 0.9.1", + "proc-macro2 1.0.20", + "quote 1.0.7", + "version_check 0.9.2", ] [[package]] name = "proc-macro-hack" -version = "0.5.15" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" [[package]] name = "proc-macro-nested" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" @@ -2276,11 +2321,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" dependencies = [ - "unicode-xid 0.2.0", + "unicode-xid 0.2.1", ] [[package]] @@ -2312,9 +2357,9 @@ dependencies = [ name = "proxy-helpers" version = "0.1.0" dependencies = [ - "bytes 0.5.4", - "futures 0.3.4", - "log 0.4.8", + "bytes 0.5.6", + "futures 0.3.5", + "log 0.4.11", "ordered-buffer", "socks5-requests", "tokio 0.2.22", @@ -2341,6 +2386,12 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-error" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" + [[package]] name = "quote" version = "0.6.13" @@ -2352,11 +2403,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.19", + "proc-macro2 1.0.20", ] [[package]] @@ -2375,7 +2426,7 @@ dependencies = [ "rand_os", "rand_pcg", "rand_xorshift", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -2479,7 +2530,7 @@ checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ "libc", "rand_core 0.4.2", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -2493,7 +2544,7 @@ dependencies = [ "libc", "rand_core 0.4.2", "rdrand", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -2526,15 +2577,15 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", @@ -2543,9 +2594,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.6" +version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ "aho-corasick", "memchr", @@ -2555,37 +2606,38 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "reqwest" -version = "0.10.4" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b81e49ddec5109a9dcfc5f2a317ff53377c915e9ae9d4f2fb50914b85614e2" +checksum = "e9eaa17ac5d7b838b7503d118fa16ad88f440498bf9ffe5424e621f93190d61e" dependencies = [ - "base64 0.11.0", - "bytes 0.5.4", + "base64 0.12.3", + "bytes 0.5.6", "encoding_rs", "futures-core", "futures-util", "http", "http-body", - "hyper 0.13.5", + "hyper 0.13.7", "hyper-tls", + "ipnet", "js-sys", "lazy_static", - "log 0.4.8", + "log 0.4.11", "mime 0.3.16", "mime_guess 2.0.3", "native-tls", @@ -2594,12 +2646,11 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "time", "tokio 0.2.22", "tokio-tls", "url 2.1.1", "wasm-bindgen", - "wasm-bindgen-futures 0.4.10", + "wasm-bindgen-futures 0.4.17", "web-sys", "winreg", ] @@ -2623,11 +2674,11 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ - "base64 0.11.0", + "base64 0.12.3", "blake2b_simd", "constant_time_eq", "crossbeam-utils", @@ -2650,9 +2701,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "safemem" @@ -2662,12 +2713,12 @@ checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "schannel" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -2684,9 +2735,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a" +checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" dependencies = [ "bitflags", "core-foundation", @@ -2697,9 +2748,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f" +checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" dependencies = [ "core-foundation-sys", "libc", @@ -2723,29 +2774,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.106" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.106" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] name = "serde_json" -version = "1.0.51" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", @@ -2791,9 +2842,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ "block-buffer 0.7.3", "digest 0.8.1", @@ -2801,16 +2852,35 @@ dependencies = [ "opaque-debug 0.2.3", ] +[[package]] +name = "sha2" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "signal-hook-registry" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" dependencies = [ "arc-swap", "libc", ] +[[package]] +name = "signature" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" + [[package]] name = "siphasher" version = "0.2.3" @@ -2835,7 +2905,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.10.2", ] @@ -2852,7 +2922,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.11.0", ] @@ -2867,9 +2937,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "snafu" @@ -2902,7 +2972,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -2924,14 +2994,14 @@ dependencies = [ "bs58", "byteorder", "chacha", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "hkdf 0.8.0", "hmac 0.7.1", "lioness", - "log 0.4.8", + "log 0.4.11", "rand 0.7.3", "rand_distr", - "sha2", + "sha2 0.8.2", ] [[package]] @@ -2940,8 +3010,8 @@ version = "0.8.0" dependencies = [ "clap", "dirs 2.0.2", - "futures 0.3.4", - "log 0.4.8", + "futures 0.3.5", + "log 0.4.11", "nymsphinx", "ordered-buffer", "pretty_env_logger", @@ -2970,7 +3040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" dependencies = [ "block-cipher", - "generic-array 0.14.1", + "generic-array 0.14.4", ] [[package]] @@ -2987,9 +3057,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" +checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" [[package]] name = "syn" @@ -3004,36 +3074,25 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" -dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "unicode-xid 0.2.0", -] - -[[package]] -name = "syn-mid" -version = "0.5.0" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "unicode-xid 0.2.1", ] [[package]] name = "synstructure" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", - "unicode-xid 0.2.0", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", + "unicode-xid 0.2.1", ] [[package]] @@ -3047,7 +3106,7 @@ dependencies = [ "rand 0.7.3", "redox_syscall", "remove_dir_all", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -3079,15 +3138,21 @@ dependencies = [ [[package]] name = "time" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "redox_syscall", - "winapi 0.3.8", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", ] +[[package]] +name = "tinyvec" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" + [[package]] name = "tokio" version = "0.1.22" @@ -3114,7 +3179,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "fnv", "futures-core", "iovec", @@ -3129,7 +3194,7 @@ dependencies = [ "signal-hook-registry", "slab", "tokio-macros", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -3171,7 +3236,7 @@ checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", "futures 0.1.29", - "log 0.4.8", + "log 0.4.11", ] [[package]] @@ -3180,9 +3245,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", ] [[package]] @@ -3194,7 +3259,7 @@ dependencies = [ "crossbeam-utils", "futures 0.1.29", "lazy_static", - "log 0.4.8", + "log 0.4.11", "mio", "num_cpus", "parking_lot 0.9.0", @@ -3234,7 +3299,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0049c119b6d505c4447f5c64873636c7af6c75ab0d45fd9f618d82acb8016d" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "futures-core", "tokio 0.2.22", ] @@ -3250,7 +3315,7 @@ dependencies = [ "crossbeam-utils", "futures 0.1.29", "lazy_static", - "log 0.4.8", + "log 0.4.11", "num_cpus", "slab", "tokio-executor", @@ -3285,7 +3350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c" dependencies = [ "futures-util", - "log 0.4.8", + "log 0.4.11", "pin-project", "tokio 0.2.22", "tungstenite 0.11.1", @@ -3297,10 +3362,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes 0.5.4", + "bytes 0.5.6", "futures-core", "futures-sink", - "log 0.4.8", + "log 0.4.11", "pin-project-lite", "tokio 0.2.22", ] @@ -3320,7 +3385,7 @@ version = "0.1.0" dependencies = [ "bs58", "crypto", - "log 0.4.8", + "log 0.4.11", "nymsphinx-addressing", "nymsphinx-types", "pretty_env_logger", @@ -3334,6 +3399,26 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +[[package]] +name = "tracing" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" +dependencies = [ + "cfg-if", + "log 0.4.11", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" +dependencies = [ + "lazy_static", +] + [[package]] name = "traitobject" version = "0.1.0" @@ -3342,9 +3427,9 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "try-lock" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tungstenite" @@ -3354,11 +3439,11 @@ checksum = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" dependencies = [ "base64 0.11.0", "byteorder", - "bytes 0.5.4", + "bytes 0.5.6", "http", "httparse", "input_buffer", - "log 0.4.8", + "log 0.4.11", "rand 0.7.3", "sha-1 0.8.2", "url 2.1.1", @@ -3373,11 +3458,11 @@ checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" dependencies = [ "base64 0.12.3", "byteorder", - "bytes 0.5.4", + "bytes 0.5.6", "http", "httparse", "input_buffer", - "log 0.4.8", + "log 0.4.11", "rand 0.7.3", "sha-1 0.9.1", "url 2.1.1", @@ -3401,9 +3486,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.11.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" [[package]] name = "ucd-trie" @@ -3426,7 +3511,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.1", + "version_check 0.9.2", ] [[package]] @@ -3440,18 +3525,18 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" dependencies = [ - "smallvec 1.4.1", + "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" @@ -3461,9 +3546,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "unsafe-any" @@ -3506,21 +3591,21 @@ checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" name = "validator-client" version = "0.1.0" dependencies = [ - "log 0.4.8", + "log 0.4.11", "pretty_env_logger", ] [[package]] name = "vcpkg" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" [[package]] name = "vec_map" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-checker" @@ -3537,9 +3622,9 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "version_check" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "want" @@ -3547,7 +3632,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log 0.4.8", + "log 0.4.11", "try-lock", ] @@ -3557,6 +3642,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasm-bindgen" version = "0.2.67" @@ -3577,10 +3668,10 @@ checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.8", - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "log 0.4.11", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", "wasm-bindgen-shared", ] @@ -3599,9 +3690,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.10" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" +checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" dependencies = [ "cfg-if", "js-sys", @@ -3615,7 +3706,7 @@ version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" dependencies = [ - "quote 1.0.3", + "quote 1.0.7", "wasm-bindgen-macro-support", ] @@ -3625,9 +3716,9 @@ version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3663,6 +3754,33 @@ dependencies = [ "quote 0.6.13", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures 0.3.5", + "js-sys", + "parking_lot 0.11.0", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.17", + "web-sys", +] + +[[package]] +name = "wasm-utils" +version = "0.1.0" +dependencies = [ + "futures 0.3.5", + "js-sys", + "tungstenite 0.11.1", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.17", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.44" @@ -3691,7 +3809,7 @@ dependencies = [ "cfg-if", "libc", "memory_units", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -3702,9 +3820,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -3724,11 +3842,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -3739,11 +3857,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -3762,7 +3880,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 2.1.0", "rand_core 0.5.1", "zeroize", ] @@ -3782,8 +3900,8 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.3", - "syn 1.0.38", + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 7402f97d30..ffa921ff23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,9 +33,19 @@ members = [ "common/socks5/requests", "common/socks5/proxy-helpers", "common/topology", + "common/wasm-utils", "gateway", "gateway/gateway-requests", "service-providers/sphinx-socks", "mixnode", "validator", ] + +default-members = [ + "clients/native", + "clients/socks5", +# "clients/webassembly", + "gateway", + "mixnode", + "validator", +] diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index 00e983236c..9860343c9c 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -15,7 +15,6 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] } serde = { version = "1.0.104", features = ["derive"] } sled = "0.33" tokio = { version = "0.2", features = ["full"] } -url = "2.1" # internal config = { path = "../../common/config" } diff --git a/clients/client-core/src/client/mix_traffic.rs b/clients/client-core/src/client/mix_traffic.rs index 22dc96c787..1817d0dba1 100644 --- a/clients/client-core/src/client/mix_traffic.rs +++ b/clients/client-core/src/client/mix_traffic.rs @@ -32,10 +32,10 @@ impl MixMessage { const MAX_FAILURE_COUNT: usize = 100; -pub struct MixTrafficController<'a> { +pub struct MixTrafficController { // TODO: most likely to be replaced by some higher level construct as // later on gateway_client will need to be accessible by other entities - gateway_client: GatewayClient<'a, url::Url>, + gateway_client: GatewayClient, mix_rx: MixMessageReceiver, // TODO: this is temporary work-around. @@ -43,11 +43,8 @@ pub struct MixTrafficController<'a> { consecutive_gateway_failure_count: usize, } -impl<'a> MixTrafficController<'static> { - pub fn new( - mix_rx: MixMessageReceiver, - gateway_client: GatewayClient<'a, url::Url>, - ) -> MixTrafficController<'a> { +impl MixTrafficController { + pub fn new(mix_rx: MixMessageReceiver, gateway_client: GatewayClient) -> MixTrafficController { MixTrafficController { gateway_client, mix_rx, diff --git a/clients/native/src/client/mod.rs b/clients/native/src/client/mod.rs index 4c0bf9533a..9931f36829 100644 --- a/clients/native/src/client/mod.rs +++ b/clients/native/src/client/mod.rs @@ -179,24 +179,19 @@ impl NymClient { &mut self, mixnet_message_sender: MixnetMessageSender, ack_sender: AcknowledgementSender, - ) -> GatewayClient<'static, url::Url> { + ) -> GatewayClient { let gateway_id = self.config.get_base().get_gateway_id(); if gateway_id.is_empty() { panic!("The identity of the gateway is unknown - did you run `nym-client` init?") } - let gateway_address_str = self.config.get_base().get_gateway_listener(); - if gateway_address_str.is_empty() { + let gateway_address = self.config.get_base().get_gateway_listener(); + if gateway_address.is_empty() { panic!("The address of the gateway is unknown - did you run `nym-client` init?") } let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) .expect("provided gateway id is invalid!"); - // TODO: since we presumably now get something valid-ish from the `init`, can we just - // ditch url::Url and operate on `String`? - let gateway_address = - url::Url::parse(&gateway_address_str).expect("provided gateway address is invalid!"); - let mut gateway_client = GatewayClient::new( gateway_address, self.key_manager.identity_keypair(), @@ -256,7 +251,7 @@ impl NymClient { fn start_mix_traffic_controller( &mut self, mix_rx: MixMessageReceiver, - gateway_client: GatewayClient<'static, url::Url>, + gateway_client: GatewayClient, ) { info!("Starting mix traffic controller..."); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle()); diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index a8b6f45822..48baef67a1 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -72,7 +72,7 @@ async fn register_with_gateway( ) -> SharedKeys { let timeout = Duration::from_millis(1500); let mut gateway_client = GatewayClient::new_init( - url::Url::parse(&gateway.client_listener).unwrap(), + gateway.client_listener.clone(), gateway.identity_key, our_identity.clone(), timeout, diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 562a9635d6..adbfdf014f 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -21,7 +21,6 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] } serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization snafu = "0.4.1" tokio = { version = "0.2", features = ["rt-threaded"] } -url = "2.1" # internal client-core = { path = "../client-core" } diff --git a/clients/socks5/src/client/mod.rs b/clients/socks5/src/client/mod.rs index 4c04791352..727752a160 100644 --- a/clients/socks5/src/client/mod.rs +++ b/clients/socks5/src/client/mod.rs @@ -167,24 +167,19 @@ impl NymClient { &mut self, mixnet_message_sender: MixnetMessageSender, ack_sender: AcknowledgementSender, - ) -> GatewayClient<'static, url::Url> { + ) -> GatewayClient { let gateway_id = self.config.get_base().get_gateway_id(); if gateway_id.is_empty() { panic!("The identity of the gateway is unknown - did you run `nym-client` init?") } - let gateway_address_str = self.config.get_base().get_gateway_listener(); - if gateway_address_str.is_empty() { + let gateway_address = self.config.get_base().get_gateway_listener(); + if gateway_address.is_empty() { panic!("The address of the gateway is unknown - did you run `nym-client` init?") } let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) .expect("provided gateway id is invalid!"); - // TODO: since we presumably now get something valid-ish from the `init`, can we just - // ditch url::Url and operate on `String`? - let gateway_address = - url::Url::parse(&gateway_address_str).expect("provided gateway address is invalid!"); - let mut gateway_client = GatewayClient::new( gateway_address, self.key_manager.identity_keypair(), @@ -244,7 +239,7 @@ impl NymClient { fn start_mix_traffic_controller( &mut self, mix_rx: MixMessageReceiver, - gateway_client: GatewayClient<'static, url::Url>, + gateway_client: GatewayClient, ) { info!("Starting mix traffic controller..."); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle()); diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index c239c1b0f7..2a8fa07b2e 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -74,7 +74,7 @@ async fn register_with_gateway( ) -> SharedKeys { let timeout = Duration::from_millis(1500); let mut gateway_client = GatewayClient::new_init( - url::Url::parse(&gateway.client_listener).unwrap(), + gateway.client_listener.clone(), gateway.identity_key, our_identity.clone(), timeout, diff --git a/clients/socks5/src/socks/client.rs b/clients/socks5/src/socks/client.rs index d1c50c1b22..9e782d30ac 100644 --- a/clients/socks5/src/socks/client.rs +++ b/clients/socks5/src/socks/client.rs @@ -7,7 +7,6 @@ use super::{RESERVED, SOCKS_VERSION}; use client_core::client::inbound_messages::InputMessage; use client_core::client::inbound_messages::InputMessageSender; use futures::channel::mpsc; -use futures::core_reexport::pin::Pin; use futures::task::{Context, Poll}; use log::*; use nymsphinx::addressing::clients::Recipient; @@ -21,6 +20,7 @@ use proxy_helpers::proxy_runner::ProxyRunner; use rand::RngCore; use socks5_requests::{ConnectionId, Request}; use std::net::{Shutdown, SocketAddr}; +use std::pin::Pin; use tokio::prelude::*; use tokio::{self, net::TcpStream}; diff --git a/clients/webassembly/Cargo.toml b/clients/webassembly/Cargo.toml index 814481bc70..0cc25ece72 100644 --- a/clients/webassembly/Cargo.toml +++ b/clients/webassembly/Cargo.toml @@ -1,7 +1,8 @@ [package] +build = "build.rs" name = "nym-client-wasm" authors = ["Dave Hrycyszyn ", "Jedrzej Stuczynski "] -version = "0.7.5" +version = "0.8.0" edition = "2018" keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"] license = "Apache-2.0" @@ -16,30 +17,42 @@ default = ["console_error_panic_hook"] offline-test = [] [dependencies] -log = "0.4" +futures = "0.3" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -wasm-bindgen = "0.2" +wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } +wasm-bindgen-futures = "0.4" +js-sys = "0.3" rand = { version = "0.7.3", features = ["wasm-bindgen"] } # internal crypto = { path = "../../common/crypto" } nymsphinx = { path = "../../common/nymsphinx" } topology = { path = "../../common/topology" } -directory-client-models = { path = "../../common/client-libs/directory-client/models" } +directory-client = { path = "../../common/client-libs/directory-client" } +gateway-client = { path = "../../common/client-libs/gateway-client" } +wasm-utils = { path = "../../common/wasm-utils" } # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for # code size when deploying. -console_error_panic_hook = { version = "0.1.1", optional = true } +console_error_panic_hook = { version = "0.1", optional = true } # `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size # compared to the default allocator's ~10K. It is slower than the default # allocator, however. # # Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. -wee_alloc = { version = "0.4.2", optional = true } +wee_alloc = { version = "0.4", optional = true } + +[build-dependencies] +built = "0.4.3" [dev-dependencies] wasm-bindgen-test = "0.2" + +[package.metadata.wasm-pack.profile.release] +# this needs to be disabled until https://github.com/rustwasm/wasm-pack/issues/886 is resolved +wasm-opt = ["-Oz", "--enable-mutable-globals"] + + diff --git a/clients/webassembly/README.md b/clients/webassembly/README.md index 856bc21e4b..7fcf221035 100644 --- a/clients/webassembly/README.md +++ b/clients/webassembly/README.md @@ -10,7 +10,8 @@ This client is part of the [Nym](https://nymtech.net/docs) project. It's written ## Security Status -From a security point of view, this module is not yet complete. A key missing feature, cover traffic, will be implemented soon. You can build your applications, but don't rely on it for strong anonymity yet if your application needs cover traffic. +From a security point of view, this module is not yet complete. A key missing features include, but are not limited to: cover traffic, sending packets with delay according to Poisson distribution. +They should be implemented soon. You can build your applications, but don't rely on it for strong anonymity yet if your application needs cover traffic. ## Using it @@ -24,11 +25,11 @@ There's a demo web application in the `js-example` folder. To run it, first make This is a Rust crate which is set up to automatically cross-compile the contents of `src` to WebAssembly (aka wasm). It's published from the main [Nym platform monorepo](https://github.com/nymtech/nym) in the `clients/webassembly` directory. -First, make sure you've got all the [Rust wasm toolchain](https://rustwasm.github.io/book/game-of-life/setup.html) installed. Cross-compilation sounds scary but the Rust crew have enabled a remarkably simple setup. +First, make sure you've got all the [Rust wasm toolchain](https://rustwasm.github.io/docs/book/) installed. Cross-compilation sounds scary, but the Rust crew have enabled a remarkably simple setup. -Whenever you change any Rust in the `src` directory, run `wasm-pack build --scope nymproject` to update the built wasm artefact in the `pkg` directory. +Furthermore, [wasm-bindgen documentation](https://rustwasm.github.io/docs/wasm-bindgen/) provides excellent tips to solving common problems. -For now, when you compile `nym-client-wasm` using `wasm-pack build --scope nymproject` you will need to manually copy the file `client.js` into the `pkg` and `package.json` with entries from `package.json` on the main path. Once [these](https://github.com/rustwasm/wasm-pack/issues/840) [issues](https://github.com/rustwasm/rfcs/pull/8#issuecomment-564725214) get closed, this annoying extra step will go away. +Whenever you change any Rust in the `src` directory, run `wasm-pack build --scope nymproject` to update the built wasm artefact in the `pkg` directory. To be clear, this is not something that most JS developers need to worry about, this is only for Nym devs. The packages on NPM have all files in place. Just install and enjoy! diff --git a/clients/webassembly/src/models/mod.rs b/clients/webassembly/build.rs similarity index 84% rename from clients/webassembly/src/models/mod.rs rename to clients/webassembly/build.rs index b156775803..56d753472c 100644 --- a/clients/webassembly/src/models/mod.rs +++ b/clients/webassembly/build.rs @@ -12,5 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod keys; -pub mod topology; +use built; + +fn main() { + built::write_built_file().expect("Failed to acquire build-time information"); +} diff --git a/clients/webassembly/client.js b/clients/webassembly/client.js deleted file mode 100644 index c5381dc937..0000000000 --- a/clients/webassembly/client.js +++ /dev/null @@ -1,330 +0,0 @@ -import * as wasm from "."; -import { version } from './package.json'; -import { major, minor, parse } from "semver"; -/** - * A Nym identity, consisting of a public/private keypair and a Nym - * gateway address. - */ -export class Identity { - // in the future this should allow for loading from local storage - constructor() { - const raw_identity = JSON.parse(wasm.keygen()); - this.address = raw_identity.address; - this.privateKey = raw_identity.private_key; - this.publicKey = raw_identity.public_key; - } -} - -/** - * A Client which connects to a Nym gateway via websocket. All communication - * with the Nym network happens through this connection. - */ -export class Client { - constructor(directoryUrl, identity, authToken) { - this.authToken = authToken - this.gateway = null; // {socketAddress, mixAddress, conn} - this.identity = identity; - this.topology = null; - this.topologyEndpoint = directoryUrl + "/api/presence/topology"; - } - - /** - * @return {string} a user-pubkey@nym-gateway recipient address - */ - formatAsRecipient() { - return `${this.identity.address}@${this.gateway.mixAddress}` - } - - /** - * Get the current network topology, then connect to this client's Nym gateway - * via websocket. - */ - async start() { - await this.updateTopology(); - this._getInitialGateway(); - await this.connect(); - // TODO: a way to somehow await for our authenticate response to be processed - } - - _isRegistered() { - return this.authToken !== null - } - - /** - * Checks if given node is compatible with this client - */ - isNodeVersionCompatible(node) { - const clientVersion = parse(version); - const mixVersion = parse(node.version); - return major(clientVersion) === major(mixVersion) && minor(clientVersion) === minor(mixVersion) - } - - /** - * Update the Nym network topology. - * - * @returns an object containing the current Nym network topology - */ - async updateTopology() { - let response = await http('get', this.topologyEndpoint); - let topology = JSON.parse(response); // make sure it's a valid json - topology.mixNodes = topology.mixNodes.filter(this.isNodeVersionCompatible) - topology.gatewayNodes = topology.gatewayNodes.filter(this.isNodeVersionCompatible) - this.topology = topology; - this.onUpdatedTopology(); - return topology; - } - - /** - * Gets the address of a Nym gateway to send the Sphinx packet to. - * At present we choose the first gateway as the network should only be - * running one. Later, we will implement multiple gateways. - */ - _getInitialGateway() { - if (this.gateway !== null) { - console.error("tried to re-initialise gateway data"); - return; - } - if (this.topology === null || this.topology.gatewayNodes.length === 0) { - console.error("No gateways available on the network") - } - this.gateway = { - socketAddress: this.topology.gatewayNodes[0].clientListener, - mixAddress: this.topology.gatewayNodes[0].pubKey, - conn: null, - } - } - - /** - * Connect to the client's defined Nym gateway via websocket. - */ - connect() { - return new Promise((resolve, reject) => { - const conn = new WebSocket(this.gateway.socketAddress); - conn.onclose = this.onConnectionClose; - conn.onerror = (event) => { - this.onConnectionError(event); - reject(event); - }; - conn.onmessage = (event) => this.onMessage(event); - conn.onopen = (event) => { - this.onConnect(event); - if (this._isRegistered()) { - this.sendAuthenticateRequest(); - resolve(); // TODO: we should wait for authenticateResponse... - } else { - this.sendRegisterRequest(); - resolve(); // TODO: we should wait for registerResponse... - } - } - - this.gateway.conn = conn; - }) - } - - /** - * Sends a registration request to a Nym gateway node. Use it only if you - * haven't registered this client before. - */ - sendRegisterRequest() { - const registerReq = buildRegisterRequest(this.identity.address); - this.gateway.conn.send(registerReq); - this.onRegisterRequestSend(); - } - - /** - * Authenticates with a Nym gateway for this client. - * - * @param {string} token - */ - sendAuthenticateRequest(token) { - const authenticateReq = buildAuthenticateRequest(this.identity.address, token); - this.conn.send(authenticateReq); - this.onAuthenticateRequestSend(); - } - - /** - * Sends a message up the websocket to this client's Nym gateway. - * - * NOTE: this currently does not implement chunking and messages over ~1KB - * will cause a panic. This will be fixed in a future version. - * - * `message` must be a {string} at the moment. Binary `Blob` and `ArrayBuffer` - * will be supported soon. - * - * @param {*} message - * @param {string} recipient - */ - sendMessage(message, recipient) { - if (this.gateway === null || this.gateway.conn === null) { - console.error("Client was not initialised"); - return - } - if (message instanceof Blob || message instanceof ArrayBuffer) { - // but it wouldn't be difficult to implement it. - console.error("Binary messages are not yet supported"); - return - } - const sphinxPacket = wasm.create_sphinx_packet(JSON.stringify(this.topology), message, recipient); - this.gateway.conn.send(sphinxPacket); - this.onMessageSend(); - } - - /** - * A callback triggered when a message is received from this client's Nym - * gateway. - * - * The `event` may be a binary blob which was the payload of a Sphinx packet, - * or it may be a JSON control message (for example, the result of an - * authenticate request). - * @param {*} event - */ - onMessage(event) { - if (event.data instanceof Blob) { - this.onBlobResponse(event); - } else { - const receivedData = JSON.parse(event.data); - switch (receivedData.type) { - case "send": return this.onSendConfirmation(event); - case "authenticate": return this.onAuthenticateResponse(event); - case "error": return this.onErrorResponse(event); - case "register": return this.onRegisterResponse(event); - default: return this.onUnknownResponse(event); - } - } - } - - // all the callbacks that can be overwritten - - /** - * A callback that fires when network topology is updated. - */ - onUpdatedTopology() { - console.log("Default: Updated topology") - } - - /** - * - * @param {*} event - */ - onConnect(event) { - console.log("Default: Established gateway connection", event); - } - - onConnectionClose(event) { - console.log("Default: The the connection to gateway was closed", event); - } - - onConnectionError(event) { - console.error("Default: Gateway connection error: ", event); - } - - onAuthenticateRequestSend() { - console.log("Default: sent authentication request"); - } - - onRegisterRequestSend() { - console.log("Default: sent register request"); - } - - onMessageSend() { - console.log("Default: sent message through gateway to the mixnet"); - } - - onAuthenticated() { - console.log("Default: we are authenticated"); - } - - onSendConfirmation(event) { - console.log("Default: received send confirmation", event.data); - } - - onRegisterResponse(event) { - console.log("Default: received register response", event.data); - } - - onAuthenticateResponse(event) { - console.log("Default: received authentication response", event.data); - } - - onErrorResponse(event) { - console.error("Received error response", event.data); - } - - onUnknownResponse(event) { - console.error("Received unknown response", event); - } - - // Gateway returns any received data from the mix network as a Blob, - // So most likely this is your best bet to override - onBlobResponse(event) { - // note that the actual handling depends on the expected content, however, - // in this example we're just sending a text messages to ourselves and hence - // we can safely read it as text - let reader = new FileReader(); - - reader.onload = () => { - this.onText(reader.result) - }; - - reader.readAsText(event.data); - } - - /** - * @callback that makes a best-effort attempt to return decrypted Sphinx bytes as text. - * - * Note that no checks are performed to determine whether something is - * really text. If the received data is in fact binary, you'll get - * binary-as-text from this callback. - */ - onText(data) { - console.log("Default: parsed the following data", data); - } -} - -/** - * Build a JSON registration request. - * - * @param {string} address - */ -function buildRegisterRequest(address) { - return JSON.stringify({ "type": "register", "address": address }); -} - -/** - * Build a JSON authentication request. - * - * @param {string} address - * @param {string} token - */ -function buildAuthenticateRequest(address, token) { - return JSON.stringify({ "type": "authenticate", "address": address, "token": token }); -} - -/** - * Make an HTTP request. - * @param {string} method - * @param {string} url - */ -function http(method, url) { - return new Promise(function (resolve, reject) { - let xhr = new XMLHttpRequest(); - xhr.open(method, url); - xhr.onload = function () { - if (this.status >= 200 && this.status < 300) { - resolve(xhr.response); - } else { - reject({ - status: this.status, - statusText: xhr.statusText - }); - } - }; - xhr.onerror = function () { - reject({ - status: this.status, - statusText: xhr.statusText - }); - }; - xhr.send(); - }); -} diff --git a/clients/webassembly/js-example/index.html b/clients/webassembly/js-example/index.html index a023657b2d..fe167a99e5 100644 --- a/clients/webassembly/js-example/index.html +++ b/clients/webassembly/js-example/index.html @@ -8,8 +8,7 @@ -

The WASM code is currently under work. The example should be restored in 0.8.1!

- - + \ No newline at end of file diff --git a/clients/webassembly/js-example/index.js b/clients/webassembly/js-example/index.js index dd08634842..54a46254d1 100644 --- a/clients/webassembly/js-example/index.js +++ b/clients/webassembly/js-example/index.js @@ -13,27 +13,40 @@ // limitations under the License. import { - Client, - Identity -} from "@nymproject/nym-client-wasm/client" + NymClient, + set_panic_hook +} from "@nymproject/nym-client-wasm" + +// current limitation of rust-wasm for async stuff : ( +let client = null async function main() { - // Set up identity and client - // let directory = "https://directory.nymtech.net"; - // let identity = new Identity(); - // let nymClient = new Client(directory, identity, null); - - // // Wire up events callbacks - // nymClient.onConnect = (_) => displaySenderAddress(nymClient); - // nymClient.onText = displayReceived; - // nymClient.onErrorResponse = (event) => alert("Received invalid gateway response", event.data); - // const sendButton = document.querySelector('#send-button'); - // sendButton.onclick = function () { - // sendMessageTo(nymClient); - // } - - // // Start the Nym client. Connects to a Nym gateway via websocket. - // await nymClient.start(); + // sets up better stack traces in case of in-rust panics + set_panic_hook(); + + // directory server we will use to get topology from + const directory = "https://qa-directory.nymtech.net"; //"http://localhost:8080"; + + client = new NymClient(directory); + + const on_message = (msg) => displayReceived(msg); + const on_connect = () => console.log("Established (and authenticated) gateway connection!"); + + client.set_on_message(on_message); + client.set_on_gateway_connect(on_connect); + + // this is current limitation of wasm in rust - for async methods you can't take self my reference... + // I'm trying to figure out if I can somehow hack my way around it, but for time being you have to re-assign + // the object (it's the same one) + client = await client.initial_setup(); + + const self_address = client.self_address(); + displaySenderAddress(self_address); + + const sendButton = document.querySelector('#send-button'); + sendButton.onclick = function () { + sendMessageTo(); + } } /** @@ -43,12 +56,13 @@ async function main() { * * @param {Client} nymClient the nym client to use for message sending */ -function sendMessageTo(nymClient) { - var message = document.getElementById("message").value; - var recipient = document.getElementById("recipient").value; - nymClient.sendMessage(message, recipient); +async function sendMessageTo() { + const message = document.getElementById("message").value; + const recipient = document.getElementById("recipient").value; + client = await client.send_message(message, recipient); displaySend(message); } + /** * Display messages that have been sent up the websocket. Colours them blue. * @@ -56,8 +70,15 @@ function sendMessageTo(nymClient) { */ function displaySend(message) { let timestamp = new Date().toISOString().substr(11, 12); - let out = "

" + timestamp + " sent >>> " + message + "

"; - document.getElementById("output").innerHTML = out + document.getElementById("output").innerHTML; + + let sendDiv = document.createElement("div") + let paragraph = document.createElement("p") + paragraph.setAttribute('style', 'color: blue') + let paragraphContent = document.createTextNode(timestamp + " sent >>> " + message) + paragraph.appendChild(paragraphContent) + + sendDiv.appendChild(paragraph) + document.getElementById("output").appendChild(sendDiv) } /** @@ -66,9 +87,17 @@ function displaySend(message) { * @param {string} message */ function displayReceived(message) { + const content = message.message + const replySurb = message.replySurb + let timestamp = new Date().toISOString().substr(11, 12); - let out = "

" + timestamp + " received >>> " + message + "

"; - document.getElementById("output").innerHTML = out + document.getElementById("output").innerHTML; + let receivedDiv = document.createElement("div") + let paragraph = document.createElement("p") + paragraph.setAttribute('style', 'color: green') + let paragraphContent = document.createTextNode(timestamp + " received >>> " + content + ((replySurb != null) ? "Reply SURB was attached here (but we can't do anything with it yet" : " (NO REPLY-SURB AVAILABLE)")) + paragraph.appendChild(paragraphContent) + receivedDiv.appendChild(paragraph) + document.getElementById("output").appendChild(receivedDiv) } @@ -77,8 +106,8 @@ function displayReceived(message) { * * @param {Client} nymClient */ -function displaySenderAddress(nymClient) { - document.getElementById("sender").value = nymClient.formatAsRecipient(); +function displaySenderAddress(address) { + document.getElementById("sender").value = address; } // Let's get started! diff --git a/clients/webassembly/js-example/package-lock.json b/clients/webassembly/js-example/package-lock.json index 933baf13ce..61890a61d3 100644 --- a/clients/webassembly/js-example/package-lock.json +++ b/clients/webassembly/js-example/package-lock.json @@ -5,19 +5,7 @@ "requires": true, "dependencies": { "@nymproject/nym-client-wasm": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@nymproject/nym-client-wasm/-/nym-client-wasm-0.7.5.tgz", - "integrity": "sha512-r5RW4aSqyzWUvnO01EwqWdA0UGcULGrNSTe9eTDo+EoprCp1ab3vFpJs4pcg64DhxkbNbTgFVbi6TZVxObKhPQ==", - "requires": { - "semver": "^7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - } - } + "version": "file:../pkg" }, "@types/events": { "version": "3.0.0", @@ -31,9 +19,9 @@ "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", "dev": true, "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "@types/events": "3.0.0", + "@types/minimatch": "3.0.3", + "@types/node": "14.0.1" } }, "@types/minimatch": { @@ -125,7 +113,7 @@ "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "dev": true, "requires": { - "@xtuc/ieee754": "^1.2.0" + "@xtuc/ieee754": "1.2.0" } }, "@webassemblyjs/leb128": { @@ -241,7 +229,7 @@ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { - "mime-types": "~2.1.24", + "mime-types": "2.1.27", "negotiator": "0.6.2" } }, @@ -257,10 +245,10 @@ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.1", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "ajv-errors": { @@ -299,7 +287,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "anymatch": { @@ -309,8 +297,8 @@ "dev": true, "optional": true, "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "normalize-path": "3.0.0", + "picomatch": "2.2.2" } }, "aproba": { @@ -349,7 +337,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -370,10 +358,9 @@ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "bn.js": "4.11.8", + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1" }, "dependencies": { "bn.js": { @@ -390,7 +377,7 @@ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { - "object-assign": "^4.1.1", + "object-assign": "4.1.1", "util": "0.10.3" }, "dependencies": { @@ -423,7 +410,7 @@ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.17.14" + "lodash": "4.17.15" } }, "async-each": { @@ -456,13 +443,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.3.0", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.2", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -471,7 +458,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -480,7 +467,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -489,7 +476,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -498,9 +485,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -549,15 +536,15 @@ "dev": true, "requires": { "bytes": "3.1.0", - "content-type": "~1.0.4", + "content-type": "1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "1.1.2", "http-errors": "1.7.2", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", + "on-finished": "2.3.0", "qs": "6.7.0", "raw-body": "2.4.0", - "type-is": "~1.6.17" + "type-is": "1.6.18" }, "dependencies": { "bytes": { @@ -574,12 +561,12 @@ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "dev": true, "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "array-flatten": "2.1.2", + "deep-equal": "1.1.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.2.3", + "multicast-dns-service-types": "1.1.0" } }, "brace-expansion": { @@ -588,7 +575,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -598,16 +585,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -616,7 +603,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -633,12 +620,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.4", + "safe-buffer": "5.1.2" } }, "browserify-cipher": { @@ -647,9 +634,9 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "browserify-aes": "1.2.0", + "browserify-des": "1.0.2", + "evp_bytestokey": "1.0.3" } }, "browserify-des": { @@ -658,10 +645,10 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "cipher-base": "1.0.4", + "des.js": "1.0.1", + "inherits": "2.0.4", + "safe-buffer": "5.1.2" } }, "browserify-rsa": { @@ -670,8 +657,8 @@ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" + "bn.js": "4.11.8", + "randombytes": "2.1.0" }, "dependencies": { "bn.js": { @@ -688,15 +675,14 @@ "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "dev": true, "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "bn.js": "5.1.1", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "elliptic": "6.5.2", + "inherits": "2.0.4", + "parse-asn1": "5.1.5", + "readable-stream": "3.6.0" }, "dependencies": { "readable-stream": { @@ -705,9 +691,9 @@ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "inherits": "2.0.4", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -724,7 +710,7 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "pako": "~1.0.5" + "pako": "1.0.11" } }, "buffer": { @@ -733,9 +719,9 @@ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "1.3.1", + "ieee754": "1.1.13", + "isarray": "1.0.0" } }, "buffer-from": { @@ -774,21 +760,21 @@ "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "dev": true, "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "bluebird": "3.7.2", + "chownr": "1.1.4", + "figgy-pudding": "3.5.2", + "glob": "7.1.6", + "graceful-fs": "4.2.4", + "infer-owner": "1.0.4", + "lru-cache": "5.1.1", + "mississippi": "3.0.0", + "mkdirp": "0.5.5", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.7.1", + "ssri": "6.0.1", + "unique-filename": "1.1.1", + "y18n": "4.0.0" } }, "cache-base": { @@ -797,15 +783,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.3.0", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.1", + "to-object-path": "0.3.0", + "union-value": "1.0.1", + "unset-value": "1.0.0" } }, "camelcase": { @@ -820,9 +806,9 @@ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -831,7 +817,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -843,14 +829,14 @@ "dev": true, "optional": true, "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" + "anymatch": "3.1.1", + "braces": "3.0.2", + "fsevents": "2.1.3", + "glob-parent": "5.1.1", + "is-binary-path": "2.1.0", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "readdirp": "3.4.0" }, "dependencies": { "braces": { @@ -860,7 +846,7 @@ "dev": true, "optional": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "7.0.1" } }, "fill-range": { @@ -870,7 +856,7 @@ "dev": true, "optional": true, "requires": { - "to-regex-range": "^5.0.1" + "to-regex-range": "5.0.1" } }, "glob-parent": { @@ -880,7 +866,7 @@ "dev": true, "optional": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "4.0.1" } }, "is-number": { @@ -897,7 +883,7 @@ "dev": true, "optional": true, "requires": { - "is-number": "^7.0.0" + "is-number": "7.0.0" } } } @@ -914,7 +900,7 @@ "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", "dev": true, "requires": { - "tslib": "^1.9.0" + "tslib": "1.13.0" } }, "cipher-base": { @@ -923,8 +909,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.4", + "safe-buffer": "5.1.2" } }, "class-utils": { @@ -933,10 +919,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -945,7 +931,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -956,9 +942,9 @@ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "3.1.0", + "strip-ansi": "5.2.0", + "wrap-ansi": "5.1.0" } }, "collection-visit": { @@ -967,8 +953,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -1010,7 +996,7 @@ "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "requires": { - "mime-db": ">= 1.43.0 < 2" + "mime-db": "1.44.0" } }, "compression": { @@ -1019,13 +1005,13 @@ "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, "requires": { - "accepts": "~1.3.5", + "accepts": "1.3.7", "bytes": "3.0.0", - "compressible": "~2.0.16", + "compressible": "2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", + "on-headers": "1.0.2", "safe-buffer": "5.1.2", - "vary": "~1.1.2" + "vary": "1.1.2" } }, "concat-map": { @@ -1040,10 +1026,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "buffer-from": "1.1.1", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "typedarray": "0.0.6" } }, "connect-history-api-fallback": { @@ -1097,12 +1083,12 @@ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "dev": true, "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "aproba": "1.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.5", + "rimraf": "2.7.1", + "run-queue": "1.0.3" } }, "copy-descriptor": { @@ -1117,18 +1103,18 @@ "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", "dev": true, "requires": { - "cacache": "^12.0.3", - "find-cache-dir": "^2.1.0", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "is-glob": "^4.0.1", - "loader-utils": "^1.2.3", - "minimatch": "^3.0.4", - "normalize-path": "^3.0.0", - "p-limit": "^2.2.1", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "webpack-log": "^2.0.0" + "cacache": "12.0.4", + "find-cache-dir": "2.1.0", + "glob-parent": "3.1.0", + "globby": "7.1.1", + "is-glob": "4.0.1", + "loader-utils": "1.4.0", + "minimatch": "3.0.4", + "normalize-path": "3.0.0", + "p-limit": "2.3.0", + "schema-utils": "1.0.0", + "serialize-javascript": "2.1.2", + "webpack-log": "2.0.0" } }, "core-util-is": { @@ -1143,8 +1129,8 @@ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "bn.js": "4.11.8", + "elliptic": "6.5.2" }, "dependencies": { "bn.js": { @@ -1161,11 +1147,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "cipher-base": "1.0.4", + "inherits": "2.0.4", + "md5.js": "1.3.5", + "ripemd160": "2.0.2", + "sha.js": "2.4.11" } }, "create-hmac": { @@ -1174,12 +1160,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.4", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "cross-spawn": { @@ -1188,11 +1174,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.7.1", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, "crypto-browserify": { @@ -1201,17 +1187,17 @@ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "1.0.1", + "browserify-sign": "4.1.0", + "create-ecdh": "4.0.3", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "diffie-hellman": "5.0.3", + "inherits": "2.0.4", + "pbkdf2": "3.0.17", + "public-encrypt": "4.0.3", + "randombytes": "2.1.0", + "randomfill": "1.0.4" } }, "cyclist": { @@ -1247,12 +1233,12 @@ "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", "dev": true, "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "is-arguments": "1.0.4", + "is-date-object": "1.0.2", + "is-regex": "1.0.5", + "object-is": "1.1.2", + "object-keys": "1.1.1", + "regexp.prototype.flags": "1.3.0" } }, "default-gateway": { @@ -1261,8 +1247,8 @@ "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", "dev": true, "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" + "execa": "1.0.0", + "ip-regex": "2.1.0" } }, "define-properties": { @@ -1271,7 +1257,7 @@ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "object-keys": "1.1.1" } }, "define-property": { @@ -1280,8 +1266,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1290,7 +1276,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -1299,7 +1285,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -1308,9 +1294,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -1321,13 +1307,13 @@ "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", "dev": true, "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" + "@types/glob": "7.1.1", + "globby": "6.1.0", + "is-path-cwd": "2.2.0", + "is-path-in-cwd": "2.1.0", + "p-map": "2.1.0", + "pify": "4.0.1", + "rimraf": "2.7.1" }, "dependencies": { "globby": { @@ -1336,11 +1322,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "glob": "7.1.6", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "pify": { @@ -1365,8 +1351,8 @@ "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1" } }, "destroy": { @@ -1393,9 +1379,9 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.1.0" }, "dependencies": { "bn.js": { @@ -1412,7 +1398,7 @@ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "requires": { - "path-type": "^3.0.0" + "path-type": "3.0.0" } }, "dns-equal": { @@ -1427,8 +1413,8 @@ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", "dev": true, "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" + "ip": "1.1.5", + "safe-buffer": "5.1.2" } }, "dns-txt": { @@ -1437,7 +1423,7 @@ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "dev": true, "requires": { - "buffer-indexof": "^1.0.0" + "buffer-indexof": "1.1.1" } }, "domain-browser": { @@ -1452,10 +1438,10 @@ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.4", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "stream-shift": "1.0.1" } }, "ee-first": { @@ -1470,13 +1456,13 @@ "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.7", + "hmac-drbg": "1.0.1", + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" }, "dependencies": { "bn.js": { @@ -1511,7 +1497,7 @@ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "enhanced-resolve": { @@ -1520,9 +1506,9 @@ "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" + "graceful-fs": "4.2.4", + "memory-fs": "0.5.0", + "tapable": "1.1.3" }, "dependencies": { "memory-fs": { @@ -1531,8 +1517,8 @@ "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.7", + "readable-stream": "2.3.7" } } } @@ -1543,7 +1529,7 @@ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "prr": "~1.0.1" + "prr": "1.0.1" } }, "es-abstract": { @@ -1552,17 +1538,17 @@ "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" + "es-to-primitive": "1.2.1", + "function-bind": "1.1.1", + "has": "1.0.3", + "has-symbols": "1.0.1", + "is-callable": "1.1.5", + "is-regex": "1.0.5", + "object-inspect": "1.7.0", + "object-keys": "1.1.1", + "object.assign": "4.1.0", + "string.prototype.trimleft": "2.1.2", + "string.prototype.trimright": "2.1.2" } }, "es-to-primitive": { @@ -1571,9 +1557,9 @@ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "1.1.5", + "is-date-object": "1.0.2", + "is-symbol": "1.0.3" } }, "escape-html": { @@ -1594,8 +1580,8 @@ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.3.0" } }, "esrecurse": { @@ -1604,15 +1590,7 @@ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } + "estraverse": "4.3.0" } }, "estraverse": { @@ -1645,7 +1623,7 @@ "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", "dev": true, "requires": { - "original": "^1.0.0" + "original": "1.0.2" } }, "evp_bytestokey": { @@ -1654,8 +1632,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "md5.js": "1.3.5", + "safe-buffer": "5.1.2" } }, "execa": { @@ -1664,13 +1642,13 @@ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.3", + "strip-eof": "1.0.0" } }, "expand-brackets": { @@ -1679,13 +1657,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1694,7 +1672,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1703,7 +1681,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1714,7 +1692,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "^1.0.1" + "homedir-polyfill": "1.0.3" } }, "express": { @@ -1723,36 +1701,36 @@ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "dev": true, "requires": { - "accepts": "~1.3.7", + "accepts": "1.3.7", "array-flatten": "1.1.1", "body-parser": "1.19.0", "content-disposition": "0.5.3", - "content-type": "~1.0.4", + "content-type": "1.0.4", "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", + "proxy-addr": "2.0.6", "qs": "6.7.0", - "range-parser": "~1.2.1", + "range-parser": "1.2.1", "safe-buffer": "5.1.2", "send": "0.17.1", "serve-static": "1.14.1", "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", + "statuses": "1.5.0", + "type-is": "1.6.18", "utils-merge": "1.0.1", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "array-flatten": { @@ -1769,8 +1747,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -1779,7 +1757,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -1790,14 +1768,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1806,7 +1784,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -1815,7 +1793,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -1824,7 +1802,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -1833,7 +1811,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -1842,9 +1820,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -1867,7 +1845,7 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.6.5" } }, "figgy-pudding": { @@ -1882,10 +1860,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -1894,7 +1872,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1906,12 +1884,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.3", + "statuses": "1.5.0", + "unpipe": "1.0.0" } }, "find-cache-dir": { @@ -1920,9 +1898,9 @@ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "commondir": "1.0.1", + "make-dir": "2.1.0", + "pkg-dir": "3.0.0" } }, "find-up": { @@ -1931,7 +1909,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "findup-sync": { @@ -1940,10 +1918,10 @@ "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "detect-file": "1.0.0", + "is-glob": "4.0.1", + "micromatch": "3.1.10", + "resolve-dir": "1.0.1" } }, "flush-write-stream": { @@ -1952,8 +1930,8 @@ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "inherits": "2.0.4", + "readable-stream": "2.3.7" } }, "follow-redirects": { @@ -1962,7 +1940,7 @@ "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", "dev": true, "requires": { - "debug": "^3.0.0" + "debug": "3.2.6" }, "dependencies": { "debug": { @@ -1971,7 +1949,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -2000,7 +1978,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fresh": { @@ -2015,8 +1993,8 @@ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "inherits": "2.0.4", + "readable-stream": "2.3.7" } }, "fs-write-stream-atomic": { @@ -2025,10 +2003,10 @@ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "graceful-fs": "4.2.4", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.7" } }, "fs.realpath": { @@ -2062,7 +2040,7 @@ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { - "pump": "^3.0.0" + "pump": "3.0.0" } }, "get-value": { @@ -2077,12 +2055,12 @@ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.4", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-parent": { @@ -2091,8 +2069,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -2101,7 +2079,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -2112,7 +2090,7 @@ "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, "requires": { - "global-prefix": "^3.0.0" + "global-prefix": "3.0.0" }, "dependencies": { "global-prefix": { @@ -2121,9 +2099,9 @@ "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "dev": true, "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "ini": "1.3.5", + "kind-of": "6.0.3", + "which": "1.3.1" } } } @@ -2134,11 +2112,11 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.3", + "ini": "1.3.5", + "is-windows": "1.0.2", + "which": "1.3.1" } }, "globby": { @@ -2147,12 +2125,12 @@ "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", "dev": true, "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "array-union": "1.0.2", + "dir-glob": "2.2.2", + "glob": "7.1.6", + "ignore": "3.3.10", + "pify": "3.0.0", + "slash": "1.0.0" }, "dependencies": { "pify": { @@ -2181,7 +2159,7 @@ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "function-bind": "1.1.1" } }, "has-flag": { @@ -2202,9 +2180,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -2213,8 +2191,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -2223,7 +2201,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2234,9 +2212,9 @@ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dev": true, "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "inherits": "2.0.4", + "readable-stream": "3.6.0", + "safe-buffer": "5.2.1" }, "dependencies": { "readable-stream": { @@ -2245,9 +2223,9 @@ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "inherits": "2.0.4", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2264,8 +2242,8 @@ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1" } }, "hello-wasm-pack": { @@ -2280,9 +2258,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "hash.js": "1.1.7", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "homedir-polyfill": { @@ -2291,7 +2269,7 @@ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { - "parse-passwd": "^1.0.0" + "parse-passwd": "1.0.0" } }, "hpack.js": { @@ -2300,10 +2278,10 @@ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "dev": true, "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "inherits": "2.0.4", + "obuf": "1.1.2", + "readable-stream": "2.3.7", + "wbuf": "1.7.3" } }, "html-entities": { @@ -2324,10 +2302,10 @@ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "dev": true, "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", + "statuses": "1.5.0", "toidentifier": "1.0.0" }, "dependencies": { @@ -2345,9 +2323,9 @@ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "eventemitter3": "4.0.4", + "follow-redirects": "1.11.0", + "requires-port": "1.0.0" } }, "http-proxy-middleware": { @@ -2356,10 +2334,10 @@ "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", "dev": true, "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" + "http-proxy": "1.18.1", + "is-glob": "4.0.1", + "lodash": "4.17.15", + "micromatch": "3.1.10" } }, "https-browserify": { @@ -2374,7 +2352,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "ieee754": { @@ -2401,8 +2379,8 @@ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "dev": true, "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "3.0.0", + "resolve-cwd": "2.0.0" } }, "imurmurhash": { @@ -2423,8 +2401,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -2445,8 +2423,8 @@ "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", "dev": true, "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" + "default-gateway": "4.2.0", + "ipaddr.js": "1.9.1" } }, "interpret": { @@ -2485,7 +2463,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2494,7 +2472,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2512,7 +2490,7 @@ "dev": true, "optional": true, "requires": { - "binary-extensions": "^2.0.0" + "binary-extensions": "2.0.0" } }, "is-buffer": { @@ -2533,7 +2511,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2542,7 +2520,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2559,9 +2537,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -2596,7 +2574,7 @@ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -2605,7 +2583,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2614,7 +2592,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2631,7 +2609,7 @@ "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", "dev": true, "requires": { - "is-path-inside": "^2.1.0" + "is-path-inside": "2.1.0" } }, "is-path-inside": { @@ -2640,7 +2618,7 @@ "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", "dev": true, "requires": { - "path-is-inside": "^1.0.2" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -2649,7 +2627,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-regex": { @@ -2658,7 +2636,7 @@ "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dev": true, "requires": { - "has": "^1.0.3" + "has": "1.0.3" } }, "is-stream": { @@ -2673,7 +2651,7 @@ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "has-symbols": "1.0.1" } }, "is-windows": { @@ -2730,7 +2708,7 @@ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.5" } }, "killable": { @@ -2745,6 +2723,15 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "2.0.0" + } + }, "loader-runner": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", @@ -2757,9 +2744,9 @@ "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "dev": true, "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "big.js": "5.2.2", + "emojis-list": "3.0.0", + "json5": "1.0.1" } }, "locate-path": { @@ -2768,8 +2755,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -2790,7 +2777,7 @@ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "yallist": "^3.0.2" + "yallist": "3.1.1" } }, "make-dir": { @@ -2799,8 +2786,17 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "pify": "4.0.1", + "semver": "5.7.1" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "1.0.0" } }, "map-cache": { @@ -2815,7 +2811,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "md5.js": { @@ -2824,9 +2820,9 @@ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "hash-base": "3.1.0", + "inherits": "2.0.4", + "safe-buffer": "5.1.2" } }, "media-typer": { @@ -2835,14 +2831,25 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "0.1.3", + "mimic-fn": "2.1.0", + "p-is-promise": "2.1.0" + } + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.7", + "readable-stream": "2.3.7" } }, "merge-descriptors": { @@ -2863,19 +2870,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.3", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "miller-rabin": { @@ -2884,8 +2891,8 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + "bn.js": "4.11.8", + "brorand": "1.1.0" }, "dependencies": { "bn.js": { @@ -2935,7 +2942,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -2950,16 +2957,16 @@ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "dev": true, "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "concat-stream": "1.6.2", + "duplexify": "3.7.1", + "end-of-stream": "1.4.4", + "flush-write-stream": "1.1.1", + "from2": "2.3.0", + "parallel-transform": "1.2.0", + "pump": "3.0.0", + "pumpify": "1.5.1", + "stream-each": "1.2.3", + "through2": "2.0.5" } }, "mixin-deep": { @@ -2968,8 +2975,8 @@ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -2978,7 +2985,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -2989,7 +2996,7 @@ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "1.2.5" } }, "move-concurrently": { @@ -2998,12 +3005,12 @@ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "dev": true, "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "aproba": "1.2.0", + "copy-concurrently": "1.0.5", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.5", + "rimraf": "2.7.1", + "run-queue": "1.0.3" } }, "ms": { @@ -3018,8 +3025,8 @@ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "dev": true, "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" + "dns-packet": "1.3.1", + "thunky": "1.1.0" } }, "multicast-dns-service-types": { @@ -3034,17 +3041,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.3", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "negotiator": { @@ -3077,29 +3084,29 @@ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", + "assert": "1.5.0", + "browserify-zlib": "0.2.0", + "buffer": "4.9.2", + "console-browserify": "1.2.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "3.1.0", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.7", + "stream-browserify": "2.0.2", + "stream-http": "2.8.3", + "string_decoder": "1.1.1", + "timers-browserify": "2.0.11", "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" + "url": "0.11.0", + "util": "0.11.1", + "vm-browserify": "1.1.2" }, "dependencies": { "punycode": { @@ -3122,7 +3129,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "object-assign": { @@ -3137,9 +3144,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -3148,7 +3155,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -3157,7 +3164,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3174,8 +3181,8 @@ "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "define-properties": "1.1.3", + "es-abstract": "1.17.5" } }, "object-keys": { @@ -3190,7 +3197,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -3199,10 +3206,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.3", + "function-bind": "1.1.1", + "has-symbols": "1.0.1", + "object-keys": "1.1.1" } }, "object.pick": { @@ -3211,7 +3218,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "obuf": { @@ -3241,7 +3248,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "opn": { @@ -3250,7 +3257,7 @@ "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "dev": true, "requires": { - "is-wsl": "^1.1.0" + "is-wsl": "1.1.0" } }, "original": { @@ -3259,7 +3266,7 @@ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "dev": true, "requires": { - "url-parse": "^1.4.3" + "url-parse": "1.4.7" } }, "os-browserify": { @@ -3268,6 +3275,23 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "1.0.0", + "lcid": "2.0.0", + "mem": "4.3.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -3280,7 +3304,7 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "p-try": "^2.0.0" + "p-try": "2.2.0" } }, "p-locate": { @@ -3289,7 +3313,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.3.0" } }, "p-map": { @@ -3304,7 +3328,7 @@ "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", "dev": true, "requires": { - "retry": "^0.12.0" + "retry": "0.12.0" } }, "p-try": { @@ -3325,9 +3349,9 @@ "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "cyclist": "1.0.1", + "inherits": "2.0.4", + "readable-stream": "2.3.7" } }, "parse-asn1": { @@ -3336,11 +3360,12 @@ "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "dev": true, "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "asn1.js": "4.10.1", + "browserify-aes": "1.2.0", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.17", + "safe-buffer": "5.1.2" } }, "parse-passwd": { @@ -3409,7 +3434,7 @@ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" }, "dependencies": { "pify": { @@ -3426,19 +3451,18 @@ "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "dev": true, "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "optional": true + "dev": true }, "pify": { "version": "4.0.1", @@ -3458,7 +3482,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pkg-dir": { @@ -3467,7 +3491,7 @@ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "^3.0.0" + "find-up": "3.0.0" } }, "portfinder": { @@ -3476,9 +3500,9 @@ "integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==", "dev": true, "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.1" + "async": "2.6.3", + "debug": "3.2.6", + "mkdirp": "0.5.5" }, "dependencies": { "debug": { @@ -3487,7 +3511,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -3528,7 +3552,7 @@ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", "dev": true, "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.1.2", "ipaddr.js": "1.9.1" } }, @@ -3544,12 +3568,12 @@ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "parse-asn1": "5.1.5", + "randombytes": "2.1.0", + "safe-buffer": "5.1.2" }, "dependencies": { "bn.js": { @@ -3566,8 +3590,8 @@ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.4", + "once": "1.4.0" } }, "pumpify": { @@ -3576,9 +3600,9 @@ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.7.1", + "inherits": "2.0.4", + "pump": "2.0.1" }, "dependencies": { "pump": { @@ -3587,8 +3611,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.4", + "once": "1.4.0" } } } @@ -3629,7 +3653,7 @@ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { - "safe-buffer": "^5.1.0" + "safe-buffer": "5.1.2" } }, "randomfill": { @@ -3638,8 +3662,8 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "randombytes": "2.1.0", + "safe-buffer": "5.1.2" } }, "range-parser": { @@ -3674,13 +3698,13 @@ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "readdirp": { @@ -3690,7 +3714,7 @@ "dev": true, "optional": true, "requires": { - "picomatch": "^2.2.1" + "picomatch": "2.2.2" } }, "regex-not": { @@ -3699,8 +3723,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "regexp.prototype.flags": { @@ -3709,8 +3733,8 @@ "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "define-properties": "1.1.3", + "es-abstract": "1.17.5" } }, "remove-trailing-separator": { @@ -3755,7 +3779,7 @@ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "3.0.0" } }, "resolve-dir": { @@ -3764,8 +3788,8 @@ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" }, "dependencies": { "global-modules": { @@ -3774,9 +3798,9 @@ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" } } } @@ -3811,7 +3835,7 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "7.1.6" } }, "ripemd160": { @@ -3820,8 +3844,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.1.0", + "inherits": "2.0.4" } }, "run-queue": { @@ -3830,7 +3854,7 @@ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { - "aproba": "^1.1.1" + "aproba": "1.2.0" } }, "safe-buffer": { @@ -3845,7 +3869,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -3860,9 +3884,9 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.2", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.4.1" } }, "select-hose": { @@ -3893,18 +3917,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.7.2", "mime": "1.6.0", "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "on-finished": "2.3.0", + "range-parser": "1.2.1", + "statuses": "1.5.0" }, "dependencies": { "ms": { @@ -3930,13 +3954,13 @@ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { - "accepts": "~1.3.4", + "accepts": "1.3.7", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "escape-html": "1.0.3", + "http-errors": "1.6.3", + "mime-types": "2.1.27", + "parseurl": "1.3.3" }, "dependencies": { "http-errors": { @@ -3945,10 +3969,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "statuses": "1.5.0" } }, "inherits": { @@ -3971,9 +3995,9 @@ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "dev": true, "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.3", "send": "0.17.1" } }, @@ -3989,10 +4013,10 @@ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -4001,7 +4025,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -4024,8 +4048,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.4", + "safe-buffer": "5.1.2" } }, "shebang-command": { @@ -4034,7 +4058,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -4061,14 +4085,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.3", + "use": "3.1.1" }, "dependencies": { "define-property": { @@ -4077,7 +4101,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -4086,7 +4110,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -4097,9 +4121,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -4108,7 +4132,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -4117,7 +4141,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -4126,7 +4150,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -4135,9 +4159,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -4148,7 +4172,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4157,7 +4181,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4168,8 +4192,8 @@ "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", "dev": true, "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.4.0", + "faye-websocket": "0.10.0", + "uuid": "3.4.0", "websocket-driver": "0.6.5" } }, @@ -4179,12 +4203,12 @@ "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", "dev": true, "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" + "debug": "3.2.6", + "eventsource": "1.0.7", + "faye-websocket": "0.11.3", + "inherits": "2.0.4", + "json3": "3.3.3", + "url-parse": "1.4.7" }, "dependencies": { "debug": { @@ -4193,7 +4217,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "faye-websocket": { @@ -4202,7 +4226,7 @@ "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", "dev": true, "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.6.5" } }, "ms": { @@ -4231,11 +4255,11 @@ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "dev": true, "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-support": { @@ -4244,8 +4268,8 @@ "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.1", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -4268,11 +4292,11 @@ "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "debug": "4.1.1", + "handle-thing": "2.0.1", + "http-deceiver": "1.2.7", + "select-hose": "2.0.0", + "spdy-transport": "3.0.0" }, "dependencies": { "debug": { @@ -4281,7 +4305,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -4298,12 +4322,12 @@ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "debug": "4.1.1", + "detect-node": "2.0.4", + "hpack.js": "2.1.6", + "obuf": "1.1.2", + "readable-stream": "3.6.0", + "wbuf": "1.7.3" }, "dependencies": { "debug": { @@ -4312,7 +4336,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -4327,9 +4351,9 @@ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "inherits": "2.0.4", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } } } @@ -4340,7 +4364,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, "ssri": { @@ -4349,7 +4373,7 @@ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "dev": true, "requires": { - "figgy-pudding": "^3.5.1" + "figgy-pudding": "3.5.2" } }, "static-extend": { @@ -4358,8 +4382,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -4368,7 +4392,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -4385,8 +4409,8 @@ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "inherits": "2.0.4", + "readable-stream": "2.3.7" } }, "stream-each": { @@ -4395,8 +4419,8 @@ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.4", + "stream-shift": "1.0.1" } }, "stream-http": { @@ -4405,11 +4429,11 @@ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "builtin-status-codes": "3.0.0", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.2" } }, "stream-shift": { @@ -4424,9 +4448,9 @@ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" } }, "string.prototype.trimend": { @@ -4435,8 +4459,8 @@ "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "define-properties": "1.1.3", + "es-abstract": "1.17.5" } }, "string.prototype.trimleft": { @@ -4445,9 +4469,9 @@ "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" + "define-properties": "1.1.3", + "es-abstract": "1.17.5", + "string.prototype.trimstart": "1.0.1" } }, "string.prototype.trimright": { @@ -4456,9 +4480,9 @@ "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" + "define-properties": "1.1.3", + "es-abstract": "1.17.5", + "string.prototype.trimend": "1.0.1" } }, "string.prototype.trimstart": { @@ -4467,8 +4491,8 @@ "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "define-properties": "1.1.3", + "es-abstract": "1.17.5" } }, "string_decoder": { @@ -4477,7 +4501,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "strip-ansi": { @@ -4486,7 +4510,7 @@ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "4.1.0" } }, "strip-eof": { @@ -4501,7 +4525,7 @@ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "tapable": { @@ -4516,9 +4540,9 @@ "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", "dev": true, "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" + "commander": "2.20.3", + "source-map": "0.6.1", + "source-map-support": "0.5.19" }, "dependencies": { "source-map": { @@ -4535,15 +4559,15 @@ "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "dev": true, "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" + "cacache": "12.0.4", + "find-cache-dir": "2.1.0", + "is-wsl": "1.1.0", + "schema-utils": "1.0.0", + "serialize-javascript": "2.1.2", + "source-map": "0.6.1", + "terser": "4.6.13", + "webpack-sources": "1.4.3", + "worker-farm": "1.7.0" }, "dependencies": { "source-map": { @@ -4560,8 +4584,8 @@ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "2.3.7", + "xtend": "4.0.2" } }, "thunky": { @@ -4576,7 +4600,7 @@ "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "dev": true, "requires": { - "setimmediate": "^1.0.4" + "setimmediate": "1.0.5" } }, "to-arraybuffer": { @@ -4591,7 +4615,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4600,7 +4624,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4611,10 +4635,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -4623,8 +4647,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "toidentifier": { @@ -4652,7 +4676,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "mime-types": "2.1.27" } }, "typedarray": { @@ -4667,10 +4691,10 @@ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "2.0.1" } }, "unique-filename": { @@ -4679,7 +4703,7 @@ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "requires": { - "unique-slug": "^2.0.0" + "unique-slug": "2.0.2" } }, "unique-slug": { @@ -4688,7 +4712,7 @@ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "requires": { - "imurmurhash": "^0.1.4" + "imurmurhash": "0.1.4" } }, "unpipe": { @@ -4703,8 +4727,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -4713,9 +4737,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -4749,7 +4773,7 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" } }, "urix": { @@ -4782,8 +4806,8 @@ "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", "dev": true, "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "querystringify": "2.1.1", + "requires-port": "1.0.0" } }, "use": { @@ -4851,10 +4875,10 @@ "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", "dev": true, "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.0" + "chokidar": "3.4.0", + "graceful-fs": "4.2.4", + "neo-async": "2.6.1", + "watchpack-chokidar2": "2.0.0" } }, "watchpack-chokidar2": { @@ -4864,7 +4888,7 @@ "dev": true, "optional": true, "requires": { - "chokidar": "^2.1.8" + "chokidar": "2.1.8" }, "dependencies": { "anymatch": { @@ -4874,8 +4898,8 @@ "dev": true, "optional": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" }, "dependencies": { "normalize-path": { @@ -4885,7 +4909,7 @@ "dev": true, "optional": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } } } @@ -4904,18 +4928,18 @@ "dev": true, "optional": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "2.0.0", + "async-each": "1.0.3", + "braces": "2.3.2", + "fsevents": "1.2.13", + "glob-parent": "3.1.0", + "inherits": "2.0.4", + "is-binary-path": "1.0.1", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.2.0" } }, "fsevents": { @@ -4932,7 +4956,7 @@ "dev": true, "optional": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.13.1" } }, "readdirp": { @@ -4942,9 +4966,9 @@ "dev": true, "optional": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.2.4", + "micromatch": "3.1.10", + "readable-stream": "2.3.7" } } } @@ -4955,7 +4979,7 @@ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, "requires": { - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "1.0.1" } }, "webpack": { @@ -4968,44 +4992,74 @@ "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/wasm-edit": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.3.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" + "acorn": "6.4.1", + "ajv": "6.12.2", + "ajv-keywords": "3.4.1", + "chrome-trace-event": "1.0.2", + "enhanced-resolve": "4.1.1", + "eslint-scope": "4.0.3", + "json-parse-better-errors": "1.0.2", + "loader-runner": "2.4.0", + "loader-utils": "1.4.0", + "memory-fs": "0.4.1", + "micromatch": "3.1.10", + "mkdirp": "0.5.5", + "neo-async": "2.6.1", + "node-libs-browser": "2.2.1", + "schema-utils": "1.0.0", + "tapable": "1.1.3", + "terser-webpack-plugin": "1.4.3", + "watchpack": "1.7.2", + "webpack-sources": "1.4.3" } }, "webpack-cli": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", - "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.1", - "findup-sync": "^3.0.0", - "global-modules": "^2.0.0", - "import-local": "^2.0.0", - "interpret": "^1.4.0", - "loader-utils": "^1.4.0", - "supports-color": "^6.1.0", - "v8-compile-cache": "^2.1.1", - "yargs": "^13.3.2" + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", + "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "dependencies": { + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "4.2.4", + "memory-fs": "0.4.1", + "tapable": "1.1.3" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "5.2.2", + "emojis-list": "2.1.0", + "json5": "1.0.1" + } + } } }, "webpack-dev-middleware": { @@ -5014,11 +5068,11 @@ "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", "dev": true, "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" + "memory-fs": "0.4.1", + "mime": "2.4.5", + "mkdirp": "0.5.5", + "range-parser": "1.2.1", + "webpack-log": "2.0.0" }, "dependencies": { "mime": { @@ -5036,38 +5090,38 @@ "dev": true, "requires": { "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", + "bonjour": "3.5.0", + "chokidar": "2.1.8", + "compression": "1.7.4", + "connect-history-api-fallback": "1.6.0", + "debug": "4.1.1", + "del": "4.1.1", + "express": "4.17.1", + "html-entities": "1.3.1", "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", - "serve-index": "^1.9.1", + "import-local": "2.0.0", + "internal-ip": "4.3.0", + "ip": "1.1.5", + "is-absolute-url": "3.0.3", + "killable": "1.0.1", + "loglevel": "1.6.8", + "opn": "5.5.0", + "p-retry": "3.0.1", + "portfinder": "1.0.26", + "schema-utils": "1.0.0", + "selfsigned": "1.10.7", + "semver": "6.3.0", + "serve-index": "1.9.1", "sockjs": "0.3.20", "sockjs-client": "1.4.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" + "spdy": "4.0.2", + "strip-ansi": "3.0.1", + "supports-color": "6.1.0", + "url": "0.11.0", + "webpack-dev-middleware": "3.7.2", + "webpack-log": "2.0.0", + "ws": "6.2.1", + "yargs": "13.3.2" }, "dependencies": { "ansi-regex": { @@ -5082,8 +5136,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" }, "dependencies": { "normalize-path": { @@ -5092,7 +5146,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } } } @@ -5109,18 +5163,18 @@ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "2.0.0", + "async-each": "1.0.3", + "braces": "2.3.2", + "fsevents": "1.2.13", + "glob-parent": "3.1.0", + "inherits": "2.0.4", + "is-binary-path": "1.0.1", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.2.0" } }, "debug": { @@ -5129,7 +5183,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "fsevents": { @@ -5145,7 +5199,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.13.1" } }, "ms": { @@ -5160,9 +5214,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.2.4", + "micromatch": "3.1.10", + "readable-stream": "2.3.7" } }, "semver": { @@ -5177,7 +5231,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "yargs": { @@ -5186,16 +5240,16 @@ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "cliui": "5.0.0", + "find-up": "3.0.0", + "get-caller-file": "2.0.5", + "require-directory": "2.1.1", + "require-main-filename": "2.0.0", + "set-blocking": "2.0.0", + "string-width": "3.1.0", + "which-module": "2.0.0", + "y18n": "4.0.0", + "yargs-parser": "13.1.2" } } } @@ -5206,8 +5260,8 @@ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "dev": true, "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" + "ansi-colors": "3.2.4", + "uuid": "3.4.0" } }, "webpack-sources": { @@ -5216,8 +5270,8 @@ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "source-list-map": "2.0.1", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -5234,7 +5288,7 @@ "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", "dev": true, "requires": { - "websocket-extensions": ">=0.1.1" + "websocket-extensions": "0.1.4" } }, "websocket-extensions": { @@ -5249,7 +5303,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -5264,7 +5318,7 @@ "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "requires": { - "errno": "~0.1.7" + "errno": "0.1.7" } }, "wrap-ansi": { @@ -5273,9 +5327,9 @@ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "3.2.1", + "string-width": "3.1.0", + "strip-ansi": "5.2.0" } }, "wrappy": { @@ -5290,7 +5344,7 @@ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", "dev": true, "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.1" } }, "xtend": { @@ -5317,16 +5371,17 @@ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "cliui": "5.0.0", + "find-up": "3.0.0", + "get-caller-file": "2.0.5", + "os-locale": "3.1.0", + "require-directory": "2.1.1", + "require-main-filename": "2.0.0", + "set-blocking": "2.0.0", + "string-width": "3.1.0", + "which-module": "2.0.0", + "y18n": "4.0.0", + "yargs-parser": "13.1.2" } }, "yargs-parser": { @@ -5335,8 +5390,8 @@ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "5.3.1", + "decamelize": "1.2.0" } } } diff --git a/clients/webassembly/js-example/package.json b/clients/webassembly/js-example/package.json index 72452e4650..63b03cfbba 100644 --- a/clients/webassembly/js-example/package.json +++ b/clients/webassembly/js-example/package.json @@ -34,6 +34,6 @@ "webpack-dev-server": "^3.11.0" }, "dependencies": { - "@nymproject/nym-client-wasm": "^0.7.5" + "@nymproject/nym-client-wasm": "file:../pkg" } } diff --git a/clients/webassembly/package.json b/clients/webassembly/package.json deleted file mode 100644 index f2d07eb7f7..0000000000 --- a/clients/webassembly/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files": [ - "client.js" - ], - "dependencies": { - "semver": "^7.3.2" - } -} diff --git a/clients/webassembly/react-example/package-lock.json b/clients/webassembly/react-example/package-lock.json index 722dfd1b9d..1e64ce46c6 100644 --- a/clients/webassembly/react-example/package-lock.json +++ b/clients/webassembly/react-example/package-lock.json @@ -1402,12 +1402,7 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, "@nymproject/nym-client-wasm": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@nymproject/nym-client-wasm/-/nym-client-wasm-0.7.5.tgz", - "integrity": "sha512-r5RW4aSqyzWUvnO01EwqWdA0UGcULGrNSTe9eTDo+EoprCp1ab3vFpJs4pcg64DhxkbNbTgFVbi6TZVxObKhPQ==", - "requires": { - "semver": "7.3.2" - } + "version": "file:../pkg" }, "@sheerun/mutationobserver-shim": { "version": "0.3.3", diff --git a/clients/webassembly/react-example/package.json b/clients/webassembly/react-example/package.json index 2f77db0d4f..4d7adf7c59 100644 --- a/clients/webassembly/react-example/package.json +++ b/clients/webassembly/react-example/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { - "@nymproject/nym-client-wasm": "^0.7.5", + "@nymproject/nym-client-wasm": "^0.8.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", diff --git a/clients/webassembly/react-example/src/App.js b/clients/webassembly/react-example/src/App.js index 40a96890fb..dbe401acae 100644 --- a/clients/webassembly/react-example/src/App.js +++ b/clients/webassembly/react-example/src/App.js @@ -15,13 +15,13 @@ import { } from 'reactstrap'; class App extends React.Component { - constructor(props) { - super(props); + constructor() { + super(); this.handleChangeReceiver = this.handleChangeReceiver.bind(this); this.handleChangeMessage = this.handleChangeMessage.bind(this); this.receivedMessage = this.receivedMessage.bind(this); this.state = { - nymClient: "", + nymClient: null, sender: "", receiver: "", message: "Hello mixnet!", @@ -32,63 +32,65 @@ class App extends React.Component { this.loadWasm(); } handleChangeReceiver(e) { - this.setState({receiver: e.target.value}); + this.setState({ receiver: e.target.value }); } handleChangeMessage(e) { - this.setState({message: e.target.value}); + this.setState({ message: e.target.value }); } loadWasm = async () => { try { - const wasm = await import('@nymproject/nym-client-wasm/client'); - this.setState({wasm}); + const wasm = await import('@nymproject/nym-client-wasm'); + this.setState({ wasm }); // Set up identity and client - let directory = "https://directory.nymtech.net"; - let identity = new wasm.Identity(); - let _nymClient = new wasm.Client(directory, identity, null); - _nymClient.onText = this.receivedMessage; - this.setState({nymClient: _nymClient}); + let directory = "https://qa-directory.nymtech.net"; + let _nymClient = new wasm.NymClient(directory); + _nymClient.set_on_message(this.receivedMessage); // Start the Nym client. Connects to a Nym gateway via websocket. - await _nymClient.start(); - let _sender = _nymClient.formatAsRecipient(); - this.setState({sender: _sender}); - } catch(err) { + _nymClient = await _nymClient.initial_setup(); + + this.setState({ nymClient: _nymClient }); + let _sender = _nymClient.self_address(); + this.setState({ sender: _sender }); + } catch (err) { console.error(`Unexpected error in loadWasm. [Message: ${err.message}]`); } } - sendmessage(message, receiver) { - this.state.nymClient.sendMessage(message, receiver); + async sendmessage(message, receiver) { let timestamp = new Date().toISOString().substr(11, 12); this.setState({ - transfers: this.state.transfers.concat({time: timestamp, direction: "sent", message: message}) + nymClient: await this.state.nymClient.send_message(message, receiver), + transfers: this.state.transfers.concat({ time: timestamp, direction: "sent", message: message, replySURB: "N/A" }) }) } - receivedMessage (message) { + receivedMessage(message) { let timestamp = new Date().toISOString().substr(11, 12); this.setState({ - transfers: this.state.transfers.concat({time: timestamp, direction: "received", message: message}) + transfers: this.state.transfers.concat({ time: timestamp, direction: "received", message: message.message, replySURB: "" + (message.replySURB != null) }) }) } renderTableData() { return this.state.transfers.map((transfers, index) => { - const { time, direction, message } = transfers //destructuring - - return ( + const { time, direction, message, replySURB } = transfers //destructuring + + return ( {direction === "sent" ? <> - {time} - {direction} - {message} + {time} + {direction} + {message} + {replySURB} - : + : <> - {time} - {direction} - {message} + {time} + {direction} + {message} + {replySURB} } - ) + ) }) } render() { @@ -116,14 +118,14 @@ class App extends React.Component {
- Test NYM by sending a private message + Test NYM by sending a private message
- - @@ -141,17 +143,17 @@ class App extends React.Component { -
-
- + ); } } diff --git a/clients/webassembly/react-example/src/index.js b/clients/webassembly/react-example/src/index.js index 830cbef53a..bca5680c38 100644 --- a/clients/webassembly/react-example/src/index.js +++ b/clients/webassembly/react-example/src/index.js @@ -8,8 +8,7 @@ import * as serviceWorker from './serviceWorker'; ReactDOM.render( -

The WASM code is currently under work. The example should be restored in 0.8.1!

- {/* */} +
, document.getElementById('root') ); diff --git a/clients/webassembly/src/built_info.rs b/clients/webassembly/src/built_info.rs new file mode 100644 index 0000000000..6a73d39ca8 --- /dev/null +++ b/clients/webassembly/src/built_info.rs @@ -0,0 +1,18 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The file has been placed there by the build script. + +#![allow(dead_code)] +include!(concat!(env!("OUT_DIR"), "/built.rs")); diff --git a/clients/webassembly/src/client/mod.rs b/clients/webassembly/src/client/mod.rs new file mode 100644 index 0000000000..acaf085514 --- /dev/null +++ b/clients/webassembly/src/client/mod.rs @@ -0,0 +1,260 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::built_info; +use crypto::asymmetric::{encryption, identity}; +use directory_client::DirectoryClient; +use futures::channel::mpsc; +use gateway_client::GatewayClient; +use js_sys::Promise; +use nymsphinx::acknowledgements::AckKey; +use nymsphinx::addressing::clients::Recipient; +use nymsphinx::preparer::MessagePreparer; +use rand::rngs::OsRng; +use received_processor::ReceivedMessagesProcessor; +use std::convert::TryInto; +use std::sync::Arc; +use std::time::Duration; +use topology::{gateway, NymTopology}; +use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::{future_to_promise, spawn_local}; +use wasm_utils::{console_log, console_warn}; + +pub(crate) mod received_processor; + +const DEFAULT_RNG: OsRng = OsRng; + +const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(200); +const DEFAULT_AVERAGE_ACK_DELAY: Duration = Duration::from_millis(200); +const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500); + +#[wasm_bindgen] +pub struct NymClient { + directory_server: String, + + // TODO: technically this doesn't need to be an Arc since wasm is run on a single thread + // however, once we eventually combine this code with the native-client's, it will make things + // easier. + identity: Arc, + encryption_keys: Arc, + ack_key: Arc, + + message_preparer: Option>, + // message_receiver: MessageReceiver, + + // TODO: this should be stored somewhere persistently + // received_keys: HashSet, + topology: Option, + gateway_client: Option, + + // callbacks + on_message: Option, + on_gateway_connect: Option, +} + +#[wasm_bindgen] +impl NymClient { + #[wasm_bindgen(constructor)] + pub fn new(directory_server: String) -> Self { + // for time being generate new keys each time... + let identity = identity::KeyPair::new_with_rng(&mut DEFAULT_RNG); + let encryption_keys = encryption::KeyPair::new_with_rng(&mut DEFAULT_RNG); + let ack_key = AckKey::new(&mut DEFAULT_RNG); + + Self { + identity: Arc::new(identity), + encryption_keys: Arc::new(encryption_keys), + ack_key: Arc::new(ack_key), + directory_server, + message_preparer: None, + // received_keys: Default::default(), + topology: None, + gateway_client: None, + + on_message: None, + on_gateway_connect: None, + } + } + + pub fn set_on_message(&mut self, on_message: js_sys::Function) { + self.on_message = Some(on_message); + } + + pub fn set_on_gateway_connect(&mut self, on_connect: js_sys::Function) { + console_log!("setting on connect..."); + self.on_gateway_connect = Some(on_connect) + } + + fn self_recipient(&self) -> Recipient { + Recipient::new( + self.identity.public_key().clone(), + self.encryption_keys.public_key().clone(), + self.gateway_client + .as_ref() + .expect("gateway connection was not established!") + .identity(), + ) + } + + pub fn self_address(&self) -> String { + self.self_recipient().to_string() + } + + // Right now it's impossible to have async exported functions to take `&self` rather than self + pub async fn initial_setup(self) -> Self { + let mut client = self.get_and_update_topology().await; + let gateway = client.choose_gateway(); + + let (mixnet_messages_sender, mixnet_messages_receiver) = mpsc::unbounded(); + let (ack_sender, ack_receiver) = mpsc::unbounded(); + + let mut gateway_client = GatewayClient::new( + gateway.client_listener.clone(), + Arc::clone(&client.identity), + gateway.identity_key, + None, + mixnet_messages_sender, + ack_sender, + DEFAULT_GATEWAY_RESPONSE_TIMEOUT, + ); + + gateway_client + .authenticate_and_start() + .await + .expect("could not authenticate and start up the gateway connection"); + + client.gateway_client = Some(gateway_client); + match client.on_gateway_connect.as_ref() { + Some(callback) => { + callback + .call0(&JsValue::null()) + .expect("on connect callback failed!"); + } + None => console_log!("Gateway connection established - no callback specified"), + }; + + let message_preparer = MessagePreparer::new( + DEFAULT_RNG, + client.self_recipient(), + DEFAULT_AVERAGE_PACKET_DELAY, + DEFAULT_AVERAGE_ACK_DELAY, + ); + + let received_processor = ReceivedMessagesProcessor::new( + Arc::clone(&client.encryption_keys), + Arc::clone(&client.ack_key), + ); + + client.message_preparer = Some(message_preparer); + + spawn_local(received_processor.start_processing( + mixnet_messages_receiver, + ack_receiver, + client.on_message.take().expect("on_message was not set!"), + )); + + client + } + + // Right now it's impossible to have async exported functions to take `&mut self` rather than mut self + // TODO: try Rc> approach? + pub async fn send_message(mut self, message: String, recipient: String) -> Self { + console_log!("Sending {} to {}", message, recipient); + + let message_bytes = message.into_bytes(); + let recipient = Recipient::try_from_base58_string(recipient).unwrap(); + + let topology = self + .topology + .as_ref() + .expect("did not obtain topology before"); + + let message_preparer = self.message_preparer.as_mut().unwrap(); + + let (split_message, _reply_keys) = message_preparer + .prepare_and_split_message(message_bytes, false, topology) + .expect("failed to split the message"); + + let mut socket_messages = Vec::with_capacity(split_message.len()); + for message_chunk in split_message { + // don't bother with acks etc. for time being + let prepared_fragment = message_preparer + .prepare_chunk_for_sending(message_chunk, topology, &self.ack_key, &recipient) + .unwrap(); + + console_warn!("packet is going to have round trip time of {:?}, but we're not going to do anything for acks anyway ", prepared_fragment.total_delay); + socket_messages.push(( + prepared_fragment.first_hop_address, + prepared_fragment.sphinx_packet, + )); + } + self.gateway_client + .as_mut() + .unwrap() + .batch_send_sphinx_packets(socket_messages) + .await + .unwrap(); + self + } + + pub(crate) fn choose_gateway(&self) -> &gateway::Node { + let topology = self + .topology + .as_ref() + .expect("did not obtain topology before"); + + // choose the first one available + assert!(!topology.gateways().is_empty()); + topology.gateways().first().unwrap() + } + + // Right now it's impossible to have async exported functions to take `&mut self` rather than mut self + // self: Rc + // or this: Rc> + pub async fn get_and_update_topology(mut self) -> Self { + let new_topology = self.get_nym_topology().await; + self.update_topology(new_topology); + self + } + + pub(crate) fn update_topology(&mut self, topology: NymTopology) { + self.topology = Some(topology) + } + + pub fn get_full_topology_json(&self) -> Promise { + let directory_client_config = directory_client::Config::new(self.directory_server.clone()); + let directory_client = directory_client::Client::new(directory_client_config); + future_to_promise(async move { + let topology = &directory_client.get_topology().await.unwrap(); + Ok(JsValue::from_serde(&topology).unwrap()) + }) + } + + pub(crate) async fn get_nym_topology(&self) -> NymTopology { + let directory_client_config = directory_client::Config::new(self.directory_server.clone()); + let directory_client = directory_client::Client::new(directory_client_config); + + match directory_client.get_topology().await { + Err(err) => panic!(err), + Ok(topology) => { + let nym_topology: NymTopology = topology + .try_into() + .ok() + .expect("this is not a NYM topology!"); + let version = built_info::PKG_VERSION; + nym_topology.filter_system_version(&version) + } + } + } +} diff --git a/clients/webassembly/src/client/received_processor.rs b/clients/webassembly/src/client/received_processor.rs new file mode 100644 index 0000000000..01c9b377df --- /dev/null +++ b/clients/webassembly/src/client/received_processor.rs @@ -0,0 +1,194 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crypto::asymmetric::encryption; +use futures::StreamExt; +use gateway_client::{AcknowledgementReceiver, MixnetMessageReceiver}; +use nymsphinx::acknowledgements::identifier::recover_identifier; +use nymsphinx::acknowledgements::AckKey; +use nymsphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID}; +use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::sync::Arc; +use wasm_bindgen::JsValue; +use wasm_utils::{console_error, console_log, console_warn}; + +#[derive(Serialize, Deserialize)] +pub struct ProcessedMessage { + pub message: String, + pub reply_surb: Option, +} + +impl From for ProcessedMessage { + fn from(reconstructed: ReconstructedMessage) -> Self { + ProcessedMessage { + message: String::from_utf8_lossy(&reconstructed.message).into_owned(), + reply_surb: reconstructed + .reply_surb + .map(|reply_surb| reply_surb.to_base58_string()), + } + } +} + +pub(crate) struct ReceivedMessagesProcessor { + local_encryption_keypair: Arc, + ack_key: Arc, + message_receiver: MessageReceiver, + + recently_reconstructed: HashSet, +} + +impl ReceivedMessagesProcessor { + pub(crate) fn new( + local_encryption_keypair: Arc, + ack_key: Arc, + ) -> Self { + ReceivedMessagesProcessor { + local_encryption_keypair, + ack_key, + message_receiver: MessageReceiver::new(), + recently_reconstructed: HashSet::new(), + } + } + + // TODO: duplicate code from received_buffer.rs in client-core.... + fn process_received_fragment(&mut self, raw_fragment: Vec) -> Option { + let fragment_data = match self + .message_receiver + .recover_plaintext(self.local_encryption_keypair.private_key(), raw_fragment) + { + Err(e) => { + console_warn!("failed to recover fragment data: {:?}. The whole underlying message might be corrupted and unrecoverable!", e); + return None; + } + Ok(frag_data) => frag_data, + }; + + if nymsphinx::cover::is_cover(&fragment_data) { + // currently won't be the case for a loooong time + console_log!("The message was a loop cover message! Skipping it"); + return None; + } + + let fragment = match self.message_receiver.recover_fragment(&fragment_data) { + Err(e) => { + console_warn!("failed to recover fragment from raw data: {:?}. The whole underlying message might be corrupted and unrecoverable!", e); + return None; + } + Ok(frag) => frag, + }; + + if self.recently_reconstructed.contains(&fragment.id()) { + console_warn!("Received a chunk of already re-assembled message ({:?})! It probably got here because the ack got lost", fragment.id()); + return None; + } + + // if we returned an error the underlying message is malformed in some way + match self.message_receiver.insert_new_fragment(fragment) { + Err(err) => match err { + MessageRecoveryError::MalformedReconstructedMessage(message_sets) => { + // TODO: should we really insert reconstructed sets? could this be abused for some attack? + for set_id in message_sets { + if !self.recently_reconstructed.insert(set_id) { + // or perhaps we should even panic at this point? + console_error!( + "Reconstructed another message containing already used set id!" + ) + } + } + None + } + _ => unreachable!( + "no other error kind should have been returned here! If so, it's a bug!" + ), + }, + Ok(reconstruction_result) => match reconstruction_result { + Some((reconstructed_message, used_sets)) => { + for set_id in used_sets { + if !self.recently_reconstructed.insert(set_id) { + // or perhaps we should even panic at this point? + console_error!( + "Reconstructed another message containing already used set id!" + ) + } + } + Some(reconstructed_message.into()) + } + None => None, + }, + } + } + + // TODO: duplicate code from acknowledgement listener... + fn process_received_ack(&self, ack_content: Vec) { + let frag_id = match recover_identifier(&self.ack_key, &ack_content) + .map(FragmentIdentifier::try_from_bytes) + { + Some(Ok(frag_id)) => frag_id, + _ => { + console_warn!("Received invalid ACK!"); // should we do anything else about that? + return; + } + }; + + // if we received an ack for cover message or a reply there will be nothing to remove, + // because nothing was inserted in the first place + if frag_id == COVER_FRAG_ID { + return; + } else if frag_id.is_reply() { + console_warn!("Received an ack for a reply message - no need to do anything! (don't know what to do!)"); + // TODO: probably there will need to be some extra procedure here, something to notify + // user that his reply reached the recipient (since we got an ack) + return; + } + + console_log!( + "Received an ack for fragment {:?} but can't do anything more about it just yet...", + frag_id + ); + + // here be ack handling... + } + + // TODO: this needs to have a shutdown signal! + pub(crate) async fn start_processing( + mut self, + mixnet_messages_receiver: MixnetMessageReceiver, + ack_receiver: AcknowledgementReceiver, + on_message: js_sys::Function, + ) { + let mut fused_mixnet_messages_receiver = mixnet_messages_receiver.fuse(); + let mut fused_ack_receiver = ack_receiver.fuse(); + let this = JsValue::null(); + + loop { + futures::select! { + mix_msgs = fused_mixnet_messages_receiver.next() => { + for mix_msg in mix_msgs.unwrap() { + if let Some(processed) = self.process_received_fragment(mix_msg) { + let arg1 = JsValue::from_serde(&processed).unwrap(); + on_message.call1(&this, &arg1).expect("on message failed!"); + } + } + } + acks = fused_ack_receiver.next() => { + for ack in acks.unwrap() { + self.process_received_ack(ack); + } + } + } + } + } +} diff --git a/clients/webassembly/src/lib.rs b/clients/webassembly/src/lib.rs index a23791853b..da772b60c9 100644 --- a/clients/webassembly/src/lib.rs +++ b/clients/webassembly/src/lib.rs @@ -11,321 +11,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crypto::asymmetric::encryption; -pub use models::keys::keygen; -use models::topology::Topology; -use nymsphinx::addressing::clients::Recipient; -use nymsphinx::addressing::nodes::{NodeIdentity, NymNodeRoutingAddress}; -use nymsphinx::params::DEFAULT_NUM_MIX_HOPS; -use nymsphinx::Node as SphinxNode; -use nymsphinx::{delays, NodeAddressBytes, SphinxPacket}; -use rand::rngs::OsRng; -use serde::{Deserialize, Serialize}; -use std::convert::TryFrom; -use std::convert::TryInto; -use std::net::SocketAddr; -use std::time::Duration; -use topology::NymTopology; -use wasm_bindgen::prelude::*; - -mod models; -mod utils; - -const DEFAULT_RNG: OsRng = OsRng; -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global -// allocator. -#[cfg(feature = "wee_alloc")] -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -#[derive(Serialize, Deserialize)] -pub struct JsonRoute { - nodes: Vec, -} +use wasm_bindgen::prelude::*; -#[wasm_bindgen] -#[derive(Clone, Serialize, Deserialize)] -pub struct NodeData { - address: String, - public_key: String, -} +pub(crate) mod built_info; +#[cfg(target_arch = "wasm32")] +mod client; -/// Creates a Gateway payload for use in JavaScript applications, using wasm. -/// It contains encoded address of first hop as well as the actual Sphinx Packet with the data. -/// -/// The `wasm-pack build` command will cause this to output JS bindings and a -/// wasm executable in the `pkg/` directory. -/// -/// Message chunking is currently not implemented. If the message exceeds the -/// capacity of a single Sphinx packet, the extra information will be discarded. -/// #[wasm_bindgen] -pub fn create_sphinx_packet(topology_json: &str, msg: &str, recipient: &str) -> Vec { - utils::set_panic_hook(); // nicer js errors. - - let recipient = Recipient::try_from_base58_string(recipient).unwrap(); - - let route = - sphinx_route_to(topology_json, &recipient.gateway()).expect("todo: error handling..."); - let average_delay = Duration::from_secs_f64(0.1); - let delays = delays::generate_from_average_duration(route.len(), average_delay); - - // TODO: once we are able to reconstruct split messages use this instead - // let split_message = split_and_prepare_payloads(&msg.as_bytes()); - // assert_eq!(split_message.len(), 1); - // let message = split_message.first().unwrap().clone(); - - let message = msg.as_bytes().to_vec(); - - let destination = recipient.as_sphinx_destination(); - let sphinx_packet = SphinxPacket::new(message, &route, &destination, &delays).unwrap(); - payload(sphinx_packet, route) -} - -/// Concatenate the gateway address bytes with the Sphinx packet. -/// -/// The Nym gateway node has no idea what is inside the Sphinx packet, or where -/// it should send a packet it receives. So we prepend the packet with the -/// address bytes of the first mix inside the packet, so that the gateway can -/// forward the packet to it. -fn payload(sphinx_packet: SphinxPacket, route: Vec) -> Vec { - let packet = sphinx_packet.to_bytes(); - let first_node_address = - NymNodeRoutingAddress::try_from(route.first().unwrap().address.clone()).unwrap(); - - first_node_address - .as_bytes() - .into_iter() - .chain(packet.into_iter()) - .collect() -} - -/// Attempts to create a Sphinx route, which is a `Vec`, from a -/// JSON string. -/// -/// # Panics -/// -/// This function panics if the supplied `raw_route` json string can't be -/// extracted to a `JsonRoute`. -fn sphinx_route_to( - topology_json: &str, - gateway_identity: &NodeIdentity, -) -> Option> { - let topology = Topology::new(topology_json); - let nym_topology: NymTopology = topology.try_into().ok()?; - let route = nym_topology - .random_route_to_gateway(&mut DEFAULT_RNG, DEFAULT_NUM_MIX_HOPS, gateway_identity) - .expect("invalid route produced"); - assert_eq!(4, route.len()); - Some(route) -} - -impl TryFrom for SphinxNode { - // We really should start actually using errors rather than unwrapping on everything - type Error = (); - - fn try_from(node_data: NodeData) -> Result { - let addr: SocketAddr = node_data.address.parse().unwrap(); - let address: NodeAddressBytes = NymNodeRoutingAddress::from(addr).try_into().unwrap(); - let pub_key = encryption::PublicKey::from_base58_string(node_data.public_key) - .unwrap() - .into(); - - Ok(SphinxNode { address, pub_key }) - } -} - -#[cfg(test)] -mod test_constructing_a_sphinx_packet { - // the below test is no longer true, as the produced length is 1372 bytes + 7 (for IPV4) or + 19 (for IPV6) - // conceptually everything works as before, only the 0 padding was removed as it served no purpose here - - // #[test] - // fn produces_1404_bytes() { - // // 32 byte address + 1372 byte sphinx packet - // let packet = create_gateway_sphinx_packet( - // topology_fixture(), - // "foomp", - // "AetTDvynUNB2N35rvCVDxkPR593Cx4PCe4QQKrMgm5RR", - // ); - // assert_eq!(1404, packet.len()); - // } -} - -#[cfg(test)] -mod building_a_topology_from_json { - use super::*; - - #[test] - #[should_panic] - fn panics_on_empty_string() { - sphinx_route_to( - "", - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - } - - #[test] - #[should_panic] - fn panics_on_bad_json() { - sphinx_route_to( - "bad bad bad not json", - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - } - - #[test] - #[should_panic] - fn panics_when_there_are_no_mixnodes() { - let mut topology = Topology::new(topology_fixture()); - topology.set_mixnodes(vec![]); - let json = serde_json::to_string(&topology).unwrap(); - sphinx_route_to( - &json, - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - } - - #[test] - #[should_panic] - fn panics_when_there_are_not_enough_mixnodes() { - let mut topology = Topology::new(topology_fixture()); - let node = topology.get_current_raw_mixnodes().first().unwrap().clone(); - topology.set_mixnodes(vec![node]); // 1 mixnode isn't enough. Panic! - let json = serde_json::to_string(&topology).unwrap(); - sphinx_route_to( - &json, - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - } - - #[test] - #[cfg_attr(feature = "offline-test", ignore)] - fn test_works_on_happy_json() { - let route = sphinx_route_to( - topology_fixture(), - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - assert_eq!(4, route.len()); - } - - #[test] - fn test_works_on_happy_json_when_serialized() { - let topology = Topology::new(topology_fixture()); - let json = serde_json::to_string(&topology).unwrap(); - let route = sphinx_route_to( - &json, - &NodeIdentity::from_base58_string("FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3") - .unwrap(), - ) - .unwrap(); - assert_eq!(4, route.len()); - } -} - -#[cfg(test)] -mod topology_fixture { - use super::*; - - #[test] - fn is_valid() { - let _nym_topology: NymTopology = Topology::new(topology_fixture()).try_into().unwrap(); - } -} - -#[cfg(test)] -fn topology_fixture() -> &'static str { - r#" - { - "cocoNodes": [], - "mixNodes": [ - { - "host": "nym.300baud.de:1789", - "pubKey": "AetTDvynUNB2N35rvCVDxkPR593Cx4PCe4QQKrMgm5RR", - "version": "0.6.0", - "location": "Falkenstein, DE", - "layer": 3, - "lastSeen": 1587572945877713700 - }, - { - "host": "testnet_nymmixnode.roussel-zeter.eu:1789", - "pubKey": "9wJ3zLoyat41e4ZgT1AWeueExv5c6uwnjvkRepj8Ebis", - "version": "0.6.0", - "location": "Geneva, CH", - "layer": 3, - "lastSeen": 1587572945907250400 - }, - { - "host": "185.144.83.134:1789", - "pubKey": "59tCzpCYsiKXz89rtvNiEYwQDdkseSShPEkifQXhsCgA", - "version": "0.6.0", - "location": "Bucharest", - "layer": 1, - "lastSeen": 1587572946007431400 - }, - { - "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789", - "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG", - "version": "0.6.0", - "location": "Glarus", - "layer": 1, - "lastSeen": 1587572945920982000 - }, - { - "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789", - "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG", - "version": "0.6.0", - "location": "Glarus", - "layer": 2, - "lastSeen": 1587572945920982000 - }, - { - "host": "[2a0a:e5c0:2:2:0:c8ff:fe68:bf6b]:1789", - "pubKey": "J9f9uS1hN8iwcN2STqH55fPRYqt7McEPyhNzpTYsxNdG", - "version": "0.6.0", - "location": "Glarus", - "layer": 2, - "lastSeen": 1587572945920982000 - } - ], - "mixProviderNodes":[], - "gatewayNodes": [ - { - "clientListener": "139.162.246.48:9000", - "mixnetListener": "139.162.246.48:1789", - "identityKey": "FE7zC2sJZrhXgQWvzXXVH8GHi2xXRynX8UWK8rD8ikf3", - "sphinxKey": "BnLYqQjb8K6TmW5oFdNZrUTocGxa3rgzBvapQrf8XUbF", - "version": "0.6.0", - "location": "London, UK", - "registeredClients": [ - { - "pubKey": "5pgrc4gPHP2tBQgfezcdJ2ZAjipoAsy6evrqHdxBbVXq" - } - ], - "lastSeen": 1587572946261865200 - }, - { - "clientListener": "127.0.0.1:9000", - "mixnetListener": "127.0.0.1:1789", - "identityKey": "7hU4RNHtGC1FreLYLoBXXTH8AdaqU913NbqCv5Fu4z1r", - "sphinxKey": "3KCpz1HCD8DqnQjemT1uuBZipmHFXM4V5btxLXwvM1gG", - "version": "0.6.0", - "location": "unknown", - "registeredClients": [], - "lastSeen": 1587572946304564700 - } - ] - } - "# +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); } diff --git a/clients/webassembly/src/models/keys.rs b/clients/webassembly/src/models/keys.rs deleted file mode 100644 index 1f7713bac3..0000000000 --- a/clients/webassembly/src/models/keys.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crypto::asymmetric::identity; -use serde::{Deserialize, Serialize}; -use std::convert::{TryFrom, TryInto}; -use wasm_bindgen::prelude::*; - -#[derive(Serialize, Deserialize, Debug)] -pub struct GatewayIdentity { - private_key: String, - public_key: String, - address: String, -} - -impl TryFrom for GatewayIdentity { - type Error = serde_json::Error; - - fn try_from(msg: String) -> Result { - serde_json::from_str(&msg) - } -} - -impl TryInto for GatewayIdentity { - type Error = serde_json::Error; - - fn try_into(self) -> Result { - serde_json::to_string(&self) - } -} - -#[wasm_bindgen] -pub fn keygen() -> String { - let keypair = identity::KeyPair::new(); - let address = keypair.public_key().derive_destination_address(); - - GatewayIdentity { - private_key: keypair.private_key().to_base58_string(), - public_key: keypair.public_key().to_base58_string(), - address: address.to_base58_string(), - } - .try_into() - .unwrap() -} diff --git a/clients/webassembly/src/models/topology.rs b/clients/webassembly/src/models/topology.rs deleted file mode 100644 index 5c9c5cf9f7..0000000000 --- a/clients/webassembly/src/models/topology.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::Serializer; -use std::convert::TryInto; -use topology::NymTopology; - -#[derive(Clone, Debug)] -pub struct Topology { - inner: directory_client_models::presence::Topology, -} - -impl serde::Serialize for Topology { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer, - { - self.inner.serialize(serializer) - } -} - -impl Topology { - pub fn new(json: &str) -> Self { - if json.is_empty() { - panic!("empty json passed"); - } - - Topology { - inner: serde_json::from_str(json).unwrap(), - } - } - - #[cfg(test)] - pub(crate) fn set_mixnodes( - &mut self, - mix_nodes: Vec, - ) { - self.inner.mix_nodes = mix_nodes - } - - #[cfg(test)] - pub(crate) fn get_current_raw_mixnodes( - &self, - ) -> Vec { - self.inner.mix_nodes.clone() - } -} - -impl TryInto for Topology { - type Error = directory_client_models::presence::TopologyConversionError; - - fn try_into(self) -> Result { - self.inner.try_into() - } -} diff --git a/clients/webassembly/src/utils.rs b/clients/webassembly/src/utils.rs deleted file mode 100644 index b1d7929dc9..0000000000 --- a/clients/webassembly/src/utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn set_panic_hook() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); -} diff --git a/common/client-libs/directory-client/Cargo.toml b/common/client-libs/directory-client/Cargo.toml index 7740a9e8d1..090d8fd59b 100644 --- a/common/client-libs/directory-client/Cargo.toml +++ b/common/client-libs/directory-client/Cargo.toml @@ -12,7 +12,7 @@ offline-test = [] [dependencies] log = "0.4" pretty_env_logger = "0.3" -serde = { version = "1.0.104", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } reqwest = { version = "0.10", features = ["json"] } ## internal @@ -20,4 +20,4 @@ directory-client-models = { path = "models" } [dev-dependencies] mockito = "0.23.0" -tokio = { version = "0.2", features = ["macros"] } \ No newline at end of file +tokio = { version = "0.2", features = ["macros"] } \ No newline at end of file diff --git a/common/client-libs/directory-client/models/Cargo.toml b/common/client-libs/directory-client/models/Cargo.toml index 257fde64dc..3f2c9c352c 100644 --- a/common/client-libs/directory-client/models/Cargo.toml +++ b/common/client-libs/directory-client/models/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = { version = "1.0.104", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } crypto = { path = "../../../crypto" } topology = { path = "../../../topology" } diff --git a/common/client-libs/gateway-client/Cargo.toml b/common/client-libs/gateway-client/Cargo.toml index ab4372aa19..b9216371e0 100644 --- a/common/client-libs/gateway-client/Cargo.toml +++ b/common/client-libs/gateway-client/Cargo.toml @@ -11,14 +11,38 @@ edition = "2018" # the entire crate futures = "0.3" log = "0.4" -tokio = { version = "0.2", features = ["macros", "rt-core", "stream", "sync", "time"] } -tokio-tungstenite = "0.11" # internal crypto = { path = "../../crypto" } gateway-requests = { path = "../../../gateway/gateway-requests" } nymsphinx = { path = "../../nymsphinx" } +[dependencies.tungstenite] +version = "0.11" +default-features = false + +# non-wasm-only dependencies +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio] +version = "0.2" +features = ["macros", "rt-core", "stream", "sync", "time"] + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite] +version = "0.11" + +# wasm-only dependencies +[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen] +version = "0.2" + +[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen-futures] +version = "0.4" + +[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils] +path = "../../wasm-utils" + +# only import it in wasm. Prefer proper tokio timer in non-wasm +[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer] +version = "0.2" + [dev-dependencies] # for tests #url = "2.1" diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs new file mode 100644 index 0000000000..36e75d5dc9 --- /dev/null +++ b/common/client-libs/gateway-client/src/client.rs @@ -0,0 +1,431 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::cleanup_socket_message; +use crate::error::GatewayClientError; +use crate::packet_router::PacketRouter; +pub use crate::packet_router::{ + AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender, +}; +use crate::socket_state::{PartiallyDelegated, SocketState}; +use crypto::asymmetric::identity; +use futures::{FutureExt, SinkExt, StreamExt}; +use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes; +use gateway_requests::authentication::iv::AuthenticationIV; +use gateway_requests::registration::handshake::{client_handshake, SharedKeys, DEFAULT_RNG}; +use gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse}; +use nymsphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket}; +use std::convert::TryFrom; +use std::sync::Arc; +use std::time::Duration; +use tungstenite::protocol::Message; + +#[cfg(not(target_arch = "wasm32"))] +use tokio_tungstenite::connect_async; + +#[cfg(target_arch = "wasm32")] +use wasm_timer; +#[cfg(target_arch = "wasm32")] +use wasm_utils::websocket::JSWebsocket; + +pub struct GatewayClient { + authenticated: bool, + // can be String, string slices, `url::Url`, `http::Uri`, etc. + gateway_address: String, + gateway_identity: identity::PublicKey, + local_identity: Arc, + shared_key: Option>, + connection: SocketState, + packet_router: PacketRouter, + response_timeout_duration: Duration, +} + +impl GatewayClient { + // TODO: put it all in a Config struct + pub fn new( + gateway_address: String, + local_identity: Arc, + gateway_identity: identity::PublicKey, + shared_key: Option>, + mixnet_message_sender: MixnetMessageSender, + ack_sender: AcknowledgementSender, + response_timeout_duration: Duration, + ) -> Self { + GatewayClient { + authenticated: false, + gateway_address, + gateway_identity, + local_identity, + shared_key, + connection: SocketState::NotConnected, + packet_router: PacketRouter::new(ack_sender, mixnet_message_sender), + response_timeout_duration, + } + } + + pub fn new_init( + gateway_address: String, + gateway_identity: identity::PublicKey, + local_identity: Arc, + response_timeout_duration: Duration, + ) -> Self { + use futures::channel::mpsc; + + // note: this packet_router is completely invalid in normal circumstances, but "works" + // perfectly fine here, because it's not meant to be used + let (ack_tx, _) = mpsc::unbounded(); + let (mix_tx, _) = mpsc::unbounded(); + let packet_router = PacketRouter::new(ack_tx, mix_tx); + + GatewayClient { + authenticated: false, + gateway_address, + gateway_identity, + local_identity, + shared_key: None, + connection: SocketState::NotConnected, + packet_router, + response_timeout_duration, + } + } + + pub fn identity(&self) -> identity::PublicKey { + self.gateway_identity + } + + pub async fn close_connection(&mut self) -> Result<(), GatewayClientError> { + if self.connection.is_partially_delegated() { + self.recover_socket_connection().await?; + } + + match std::mem::replace(&mut self.connection, SocketState::NotConnected) { + #[cfg(not(target_arch = "wasm32"))] + SocketState::Available(mut socket) => Ok(socket.close(None).await?), + #[cfg(target_arch = "wasm32")] + SocketState::Available(mut socket) => Ok(socket.close(None).await), + SocketState::PartiallyDelegated(_) => { + unreachable!("this branch should have never been reached!") + } + _ => Ok(()), // no need to do anything in those cases + } + } + + pub async fn establish_connection(&mut self) -> Result<(), GatewayClientError> { + #[cfg(not(target_arch = "wasm32"))] + let ws_stream = match connect_async(&self.gateway_address).await { + Ok((ws_stream, _)) => ws_stream, + Err(e) => return Err(GatewayClientError::NetworkError(e)), + }; + + #[cfg(target_arch = "wasm32")] + let ws_stream = match JSWebsocket::new(&self.gateway_address) { + Ok(ws_stream) => ws_stream, + Err(e) => return Err(GatewayClientError::NetworkErrorWasm(e)), + }; + + self.connection = SocketState::Available(ws_stream); + Ok(()) + } + + async fn read_control_response(&mut self) -> Result { + // we use the fact that all request responses are Message::Text and only pushed + // sphinx packets are Message::Binary + + let conn = match self.connection { + SocketState::Available(ref mut conn) => conn, + _ => return Err(GatewayClientError::ConnectionInInvalidState), + }; + + #[cfg(not(target_arch = "wasm32"))] + let timeout = tokio::time::delay_for(self.response_timeout_duration); + + // technically the `wasm_timer` also works outside wasm, but unless required, + // I really prefer to just stick to tokio + #[cfg(target_arch = "wasm32")] + let timeout = wasm_timer::Delay::new(self.response_timeout_duration); + + let mut fused_timeout = timeout.fuse(); + let mut fused_stream = conn.fuse(); + + loop { + futures::select! { + _ = &mut fused_timeout => { + break Err(GatewayClientError::Timeout); + } + msg = fused_stream.next() => { + let ws_msg = match cleanup_socket_message(msg) { + Err(err) => break Err(err), + Ok(msg) => msg + }; + match ws_msg { + Message::Binary(bin_msg) => { + self.packet_router.route_received(vec![bin_msg]); + } + Message::Text(txt_msg) => { + break ServerResponse::try_from(txt_msg).map_err(|_| GatewayClientError::MalformedResponse); + } + _ => (), + } + } + } + } + } + + // If we want to send a message (with response), we need to have a full control over the socket, + // as we need to be able to write the request and read the subsequent response + async fn send_websocket_message( + &mut self, + msg: Message, + ) -> Result { + let should_restart_mixnet_listener = if self.connection.is_partially_delegated() { + self.recover_socket_connection().await?; + true + } else { + false + }; + + let conn = match self.connection { + SocketState::Available(ref mut conn) => conn, + SocketState::NotConnected => return Err(GatewayClientError::ConnectionNotEstablished), + _ => return Err(GatewayClientError::ConnectionInInvalidState), + }; + conn.send(msg).await?; + let response = self.read_control_response().await; + + if should_restart_mixnet_listener { + self.start_listening_for_mixnet_messages()?; + } + response + } + + async fn batch_send_websocket_messages_without_response( + &mut self, + messages: Vec, + ) -> Result<(), GatewayClientError> { + match self.connection { + SocketState::Available(ref mut conn) => { + let stream_messages: Vec<_> = messages.into_iter().map(Ok).collect(); + let mut send_stream = futures::stream::iter(stream_messages); + Ok(conn.send_all(&mut send_stream).await?) + } + SocketState::PartiallyDelegated(ref mut partially_delegated) => { + partially_delegated + .batch_send_without_response(messages) + .await + } + SocketState::NotConnected => Err(GatewayClientError::ConnectionNotEstablished), + _ => Err(GatewayClientError::ConnectionInInvalidState), + } + } + + async fn send_websocket_message_without_response( + &mut self, + msg: Message, + ) -> Result<(), GatewayClientError> { + match self.connection { + SocketState::Available(ref mut conn) => Ok(conn.send(msg).await?), + SocketState::PartiallyDelegated(ref mut partially_delegated) => { + partially_delegated.send_without_response(msg).await + } + SocketState::NotConnected => Err(GatewayClientError::ConnectionNotEstablished), + _ => Err(GatewayClientError::ConnectionInInvalidState), + } + } + + pub async fn register(&mut self) -> Result { + if !self.connection.is_established() { + return Err(GatewayClientError::ConnectionNotEstablished); + } + + debug_assert!(self.connection.is_available()); + + let shared_key = match &mut self.connection { + SocketState::Available(ws_stream) => client_handshake( + &mut DEFAULT_RNG, + ws_stream, + self.local_identity.as_ref(), + self.gateway_identity, + ) + .await + .map_err(GatewayClientError::RegistrationFailure), + _ => unreachable!(), + }?; + + self.authenticated = true; + Ok(shared_key) + } + + pub async fn authenticate( + &mut self, + shared_key: Option, + ) -> Result { + if shared_key.is_none() && self.shared_key.is_none() { + return Err(GatewayClientError::NoSharedKeyAvailable); + } + if !self.connection.is_established() { + return Err(GatewayClientError::ConnectionNotEstablished); + } + // because of the previous check one of the unwraps MUST succeed + let shared_key = shared_key + .as_ref() + .unwrap_or_else(|| self.shared_key.as_ref().unwrap()); + let iv = AuthenticationIV::new_random(&mut DEFAULT_RNG); + let self_address = self + .local_identity + .as_ref() + .public_key() + .derive_destination_address(); + let encrypted_address = EncryptedAddressBytes::new(&self_address, shared_key, &iv); + + let msg = + ClientControlRequest::new_authenticate(self_address, encrypted_address, iv).into(); + + let authenticated = match self.send_websocket_message(msg).await? { + ServerResponse::Authenticate { status } => { + self.authenticated = status; + Ok(status) + } + ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)), + _ => unreachable!(), + }?; + Ok(authenticated) + } + + /// Helper method to either call register or authenticate based on self.shared_key value + pub async fn perform_initial_authentication( + &mut self, + ) -> Result, GatewayClientError> { + if self.shared_key.is_some() { + self.authenticate(None).await?; + } else { + let shared_key = self.register().await?; + self.shared_key = Some(Arc::new(shared_key)); + } + if self.authenticated { + // if we are authenticated it means we MUST have an associated shared_key + Ok(Arc::clone(&self.shared_key.as_ref().unwrap())) + } else { + Err(GatewayClientError::AuthenticationFailure) + } + } + + pub async fn batch_send_sphinx_packets( + &mut self, + packets: Vec<(NymNodeRoutingAddress, SphinxPacket)>, + ) -> Result<(), GatewayClientError> { + if !self.authenticated { + return Err(GatewayClientError::NotAuthenticated); + } + if !self.connection.is_established() { + return Err(GatewayClientError::ConnectionNotEstablished); + } + + let messages: Vec<_> = packets + .into_iter() + .map(|(address, packet)| { + BinaryRequest::new_forward_request(address, packet).into_ws_message( + self.shared_key + .as_ref() + .expect("no shared key present even though we're authenticated!"), + ) + }) + .collect(); + + self.batch_send_websocket_messages_without_response(messages) + .await + } + + // TODO: possibly make responses optional + pub async fn send_sphinx_packet( + &mut self, + address: NymNodeRoutingAddress, + packet: SphinxPacket, + ) -> Result<(), GatewayClientError> { + if !self.authenticated { + return Err(GatewayClientError::NotAuthenticated); + } + if !self.connection.is_established() { + return Err(GatewayClientError::ConnectionNotEstablished); + } + // note: into_ws_message encrypts the requests and adds a MAC on it. Perhaps it should + // be more explicit in the naming? + let msg = BinaryRequest::new_forward_request(address, packet).into_ws_message( + self.shared_key + .as_ref() + .expect("no shared key present even though we're authenticated!"), + ); + self.send_websocket_message_without_response(msg).await + } + + async fn recover_socket_connection(&mut self) -> Result<(), GatewayClientError> { + if self.connection.is_available() { + return Ok(()); + } + if !self.connection.is_partially_delegated() { + return Err(GatewayClientError::ConnectionInInvalidState); + } + + let conn = match std::mem::replace(&mut self.connection, SocketState::Invalid) { + SocketState::PartiallyDelegated(delegated_conn) => delegated_conn.merge().await?, + _ => unreachable!(), + }; + + self.connection = SocketState::Available(conn); + Ok(()) + } + + // Note: this requires prior authentication + pub fn start_listening_for_mixnet_messages(&mut self) -> Result<(), GatewayClientError> { + if !self.authenticated { + return Err(GatewayClientError::NotAuthenticated); + } + if self.connection.is_partially_delegated() { + return Ok(()); + } + if !self.connection.is_available() { + return Err(GatewayClientError::ConnectionInInvalidState); + } + + let partially_delegated = + match std::mem::replace(&mut self.connection, SocketState::Invalid) { + SocketState::Available(conn) => { + PartiallyDelegated::split_and_listen_for_mixnet_messages( + conn, + self.packet_router.clone(), + Arc::clone( + self.shared_key + .as_ref() + .expect("no shared key present even though we're authenticated!"), + ), + )? + } + _ => unreachable!(), + }; + + self.connection = SocketState::PartiallyDelegated(partially_delegated); + Ok(()) + } + + pub async fn authenticate_and_start(&mut self) -> Result, GatewayClientError> { + if !self.connection.is_established() { + self.establish_connection().await?; + } + let shared_key = self.perform_initial_authentication().await?; + + // this call is NON-blocking + self.start_listening_for_mixnet_messages()?; + + Ok(shared_key) + } +} diff --git a/common/client-libs/gateway-client/src/error.rs b/common/client-libs/gateway-client/src/error.rs index 6112f1bfa3..20e1209e04 100644 --- a/common/client-libs/gateway-client/src/error.rs +++ b/common/client-libs/gateway-client/src/error.rs @@ -14,13 +14,20 @@ use gateway_requests::registration::handshake::error::HandshakeError; use std::fmt::{self, Error, Formatter}; -use tokio_tungstenite::tungstenite::Error as WsError; +use tungstenite::Error as WsError; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::JsValue; #[derive(Debug)] pub enum GatewayClientError { ConnectionNotEstablished, GatewayError(String), NetworkError(WsError), + + // TODO: see if `JsValue` is a reasonable type for this + #[cfg(target_arch = "wasm32")] + NetworkErrorWasm(JsValue), + NoSharedKeyAvailable, ConnectionAbruptlyClosed, MalformedResponse, @@ -37,6 +44,13 @@ impl From for GatewayClientError { } } +#[cfg(target_arch = "wasm32")] +impl From for GatewayClientError { + fn from(err: JsValue) -> Self { + GatewayClientError::NetworkErrorWasm(err) + } +} + // better human readable representation of the error, mostly so that GatewayClientError // would implement std::error::Error impl fmt::Display for GatewayClientError { @@ -49,9 +63,15 @@ impl fmt::Display for GatewayClientError { write!(f, "no shared key was provided or obtained") } GatewayClientError::NotAuthenticated => write!(f, "client is not authenticated"), + GatewayClientError::NetworkError(err) => { write!(f, "there was a network error - {}", err) } + #[cfg(target_arch = "wasm32")] + GatewayClientError::NetworkErrorWasm(err) => { + write!(f, "there was a network error - {:?}", err) + } + GatewayClientError::ConnectionAbruptlyClosed => { write!(f, "connection was abruptly closed") } diff --git a/common/client-libs/gateway-client/src/lib.rs b/common/client-libs/gateway-client/src/lib.rs index 73f2ce00c8..1c2c495388 100644 --- a/common/client-libs/gateway-client/src/lib.rs +++ b/common/client-libs/gateway-client/src/lib.rs @@ -13,39 +13,22 @@ // limitations under the License. use crate::error::GatewayClientError; -use crate::packet_router::PacketRouter; -pub use crate::packet_router::{ +pub use client::GatewayClient; +pub use packet_router::{ AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender, }; -use crypto::asymmetric::identity; -use futures::stream::{SplitSink, SplitStream}; -use futures::{future::BoxFuture, FutureExt, SinkExt, Stream, StreamExt}; -use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes; -use gateway_requests::authentication::iv::AuthenticationIV; -use gateway_requests::registration::handshake::{client_handshake, SharedKeys, DEFAULT_RNG}; -use gateway_requests::{BinaryRequest, BinaryResponse, ClientControlRequest, ServerResponse}; -use log::*; -use nymsphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket}; -use std::convert::TryFrom; -use std::sync::Arc; -use std::time::Duration; -use tokio::net::TcpStream; -use tokio::sync::Notify; -use tokio_tungstenite::{ - connect_async, - tungstenite::{client::IntoClientRequest, protocol::Message, Error as WsError}, - WebSocketStream, -}; +use tungstenite::{protocol::Message, Error as WsError}; +pub mod client; pub mod error; pub mod packet_router; +pub mod socket_state; -/// A helper method to read an underlying message from the stream or return an error. -async fn read_ws_stream_message(conn: &mut S) -> Result -where - S: Stream> + Unpin, -{ - match conn.next().await { +/// Helper method for reading from websocket stream. Helps to flatten the structure. +pub(crate) fn cleanup_socket_message( + msg: Option>, +) -> Result { + match msg { Some(msg) => match msg { Ok(msg) => Ok(msg), Err(err) => Err(GatewayClientError::NetworkError(err)), @@ -53,464 +36,3 @@ where None => Err(GatewayClientError::ConnectionAbruptlyClosed), } } - -// TODO: some batching mechanism to allow reading and sending more than a single packet through - -// type alias for not having to type the whole thing every single time -type WsConn = WebSocketStream; - -// We have ownership over sink half of the connection, but the stream is owned -// by some other task, however, we can notify it to get the stream back. -struct PartiallyDelegated<'a> { - sink_half: SplitSink, - delegated_stream: ( - BoxFuture<'a, Result, GatewayClientError>>, - Arc, - ), -} - -impl<'a> PartiallyDelegated<'a> { - // TODO: this can be potentially bad as we have no direct restrictions of ensuring it's called - // within tokio runtime. Perhaps we should use the "old" way of passing explicit - // runtime handle to the constructor and using that instead? - fn split_and_listen_for_mixnet_messages( - conn: WsConn, - packet_router: PacketRouter, - shared_key: Arc, - ) -> Result { - // when called for, it NEEDS TO yield back the stream so that we could merge it and - // read control request responses. - let notify = Arc::new(Notify::new()); - let notify_clone = Arc::clone(¬ify); - - let (sink, mut stream) = conn.split(); - - let mixnet_receiver_future = async move { - let mut should_return = false; - while !should_return { - tokio::select! { - _ = notify_clone.notified() => { - should_return = true; - } - msg = read_ws_stream_message(&mut stream) => { - match msg? { - Message::Binary(bin_msg) => { - // this function decrypts the request and checks the MAC - let plaintext = match BinaryResponse::try_from_encrypted_tagged_bytes(bin_msg, shared_key.as_ref()) { - Ok(bin_response) => match bin_response { - BinaryResponse::PushedMixMessage(plaintext) => plaintext, - }, - Err(err) => { - warn!("message received from the gateway was malformed! - {:?}", err); - continue - } - }; - - // TODO: some batching mechanism to allow reading and sending more than - // one packet at the time, because the receiver can easily handle it - packet_router.route_received(vec![plaintext]) - }, - // I think that in the future we should perhaps have some sequence number system, i.e. - // so each request/response pair can be easily identified, so that if messages are - // not ordered (for some peculiar reason) we wouldn't lose anything. - // This would also require NOT discarding any text responses here. - - // TODO: those can return the "send confirmations" - perhaps it should be somehow worked around? - Message::Text(text) => debug!("received a text message - probably a response to some previous query! - {}", text), - _ => (), - }; - } - }; - } - Ok(stream) - }; - - let spawned_boxed_task = tokio::spawn(mixnet_receiver_future) - .map(|join_handle| { - join_handle.expect("task must have not failed to finish its execution!") - }) - .boxed(); - - Ok(PartiallyDelegated { - sink_half: sink, - delegated_stream: (spawned_boxed_task, notify), - }) - } - - // if we want to send a message and don't care about response, we can don't need to reunite the split, - // the sink itself is enough - async fn send_without_response(&mut self, msg: Message) -> Result<(), GatewayClientError> { - Ok(self.sink_half.send(msg).await?) - } - - async fn merge(self) -> Result { - let (stream_fut, notify) = self.delegated_stream; - notify.notify(); - let stream = stream_fut.await?; - // the error is thrown when trying to reunite sink and stream that did not originate - // from the same split which is impossible to happen here - Ok(self.sink_half.reunite(stream).unwrap()) - } -} - -// we can either have the stream itself or an option to re-obtain it -// by notifying the future owning it to finish the execution and awaiting the result -// which should be almost immediate (or an invalid state which should never, ever happen) -enum SocketState<'a> { - Available(WsConn), - PartiallyDelegated(PartiallyDelegated<'a>), - NotConnected, - Invalid, -} - -impl<'a> SocketState<'a> { - fn is_available(&self) -> bool { - match self { - SocketState::Available(_) => true, - _ => false, - } - } - - fn is_partially_delegated(&self) -> bool { - match self { - SocketState::PartiallyDelegated(_) => true, - _ => false, - } - } - - fn is_established(&self) -> bool { - match self { - SocketState::Available(_) | SocketState::PartiallyDelegated(_) => true, - _ => false, - } - } -} - -pub struct GatewayClient<'a, R> { - authenticated: bool, - // can be String, string slices, `url::Url`, `http::Uri`, etc. - gateway_address: R, - gateway_identity: identity::PublicKey, - local_identity: Arc, - shared_key: Option>, - connection: SocketState<'a>, - packet_router: PacketRouter, - response_timeout_duration: Duration, -} - -impl<'a, R> GatewayClient<'static, R> { - // TODO: put it all in a Config struct - pub fn new( - gateway_address: R, - local_identity: Arc, - gateway_identity: identity::PublicKey, - shared_key: Option>, - mixnet_message_sender: MixnetMessageSender, - ack_sender: AcknowledgementSender, - response_timeout_duration: Duration, - ) -> Self { - GatewayClient { - authenticated: false, - gateway_address, - gateway_identity, - local_identity, - shared_key, - connection: SocketState::NotConnected, - packet_router: PacketRouter::new(ack_sender, mixnet_message_sender), - response_timeout_duration, - } - } - - pub fn new_init( - gateway_address: R, - gateway_identity: identity::PublicKey, - local_identity: Arc, - response_timeout_duration: Duration, - ) -> Self { - use futures::channel::mpsc; - - // note: this packet_router is completely invalid in normal circumstances, but "works" - // perfectly fine here, because it's not meant to be used - let (ack_tx, _) = mpsc::unbounded(); - let (mix_tx, _) = mpsc::unbounded(); - let packet_router = PacketRouter::new(ack_tx, mix_tx); - - GatewayClient { - authenticated: false, - gateway_address, - gateway_identity, - local_identity, - shared_key: None, - connection: SocketState::NotConnected, - packet_router, - response_timeout_duration, - } - } - - pub async fn close_connection(&mut self) -> Result<(), GatewayClientError> { - if self.connection.is_partially_delegated() { - self.recover_socket_connection().await?; - } - - match std::mem::replace(&mut self.connection, SocketState::NotConnected) { - SocketState::Available(mut socket) => Ok(socket.close(None).await?), - SocketState::PartiallyDelegated(_) => { - unreachable!("this branch should have never been reached!") - } - _ => Ok(()), // no need to do anything in those cases - } - } - - pub async fn establish_connection(&mut self) -> Result<(), GatewayClientError> - where - R: IntoClientRequest + Unpin + Clone, - { - let ws_stream = match connect_async(self.gateway_address.clone()).await { - Ok((ws_stream, _)) => ws_stream, - Err(e) => return Err(GatewayClientError::NetworkError(e)), - }; - - self.connection = SocketState::Available(ws_stream); - Ok(()) - } - - async fn read_control_response(&mut self) -> Result { - // we use the fact that all request responses are Message::Text and only pushed - // sphinx packets are Message::Binary - - let conn = match self.connection { - SocketState::Available(ref mut conn) => conn, - _ => return Err(GatewayClientError::ConnectionInInvalidState), - }; - - let mut timeout = tokio::time::delay_for(self.response_timeout_duration); - - let mut res = None; - while res.is_none() { - tokio::select! { - _ = &mut timeout => { - res = Some(Err(GatewayClientError::Timeout)) - } - // just keep getting through socket buffer until we get to what we want... - // (or we time out) - msg = read_ws_stream_message(conn) => { - if let Err(err) = msg { - res = Some(Err(err)); - break; - } - match msg.unwrap() { - Message::Binary(bin_msg) => { - self.packet_router.route_received(vec![bin_msg]); - } - Message::Text(txt_msg) => { - res = Some(ServerResponse::try_from(txt_msg).map_err(|_| GatewayClientError::MalformedResponse)); - } - _ => (), - } - } - } - } - - res.expect("response value should have been written in one of the branches!. If you see this error, please report a bug!") - } - - // If we want to send a message (with response), we need to have a full control over the socket, - // as we need to be able to write the request and read the subsequent response - async fn send_websocket_message( - &mut self, - msg: Message, - ) -> Result { - let should_restart_mixnet_listener = if self.connection.is_partially_delegated() { - self.recover_socket_connection().await?; - true - } else { - false - }; - - let conn = match self.connection { - SocketState::Available(ref mut conn) => conn, - SocketState::NotConnected => return Err(GatewayClientError::ConnectionNotEstablished), - _ => return Err(GatewayClientError::ConnectionInInvalidState), - }; - conn.send(msg).await?; - let response = self.read_control_response().await; - - if should_restart_mixnet_listener { - self.start_listening_for_mixnet_messages()?; - } - response - } - - async fn send_websocket_message_without_response( - &mut self, - msg: Message, - ) -> Result<(), GatewayClientError> { - match self.connection { - SocketState::Available(ref mut conn) => Ok(conn.send(msg).await?), - SocketState::PartiallyDelegated(ref mut partially_delegated) => { - partially_delegated.send_without_response(msg).await - } - SocketState::NotConnected => Err(GatewayClientError::ConnectionNotEstablished), - _ => Err(GatewayClientError::ConnectionInInvalidState), - } - } - - pub async fn register(&mut self) -> Result { - if !self.connection.is_established() { - return Err(GatewayClientError::ConnectionNotEstablished); - } - - debug_assert!(self.connection.is_available()); - - match &mut self.connection { - SocketState::Available(ws_stream) => client_handshake( - &mut DEFAULT_RNG, - ws_stream, - self.local_identity.as_ref(), - self.gateway_identity, - ) - .await - .map_err(GatewayClientError::RegistrationFailure), - _ => unreachable!(), - } - } - - pub async fn authenticate( - &mut self, - shared_key: Option, - ) -> Result { - if shared_key.is_none() && self.shared_key.is_none() { - return Err(GatewayClientError::NoSharedKeyAvailable); - } - if !self.connection.is_established() { - return Err(GatewayClientError::ConnectionNotEstablished); - } - // because of the previous check one of the unwraps MUST succeed - let shared_key = shared_key - .as_ref() - .unwrap_or_else(|| self.shared_key.as_ref().unwrap()); - let iv = AuthenticationIV::new_random(&mut DEFAULT_RNG); - let self_address = self - .local_identity - .as_ref() - .public_key() - .derive_destination_address(); - let encrypted_address = EncryptedAddressBytes::new(&self_address, shared_key, &iv); - - let msg = - ClientControlRequest::new_authenticate(self_address, encrypted_address, iv).into(); - - let authenticated = match self.send_websocket_message(msg).await? { - ServerResponse::Authenticate { status } => { - self.authenticated = status; - Ok(status) - } - ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)), - _ => unreachable!(), - }?; - Ok(authenticated) - } - - /// Helper method to either call register or authenticate based on self.shared_key value - pub async fn perform_initial_authentication( - &mut self, - ) -> Result, GatewayClientError> { - if self.shared_key.is_some() { - self.authenticate(None).await?; - } else { - self.register().await?; - } - if self.authenticated { - // if we are authenticated it means we MUST have an associated shared_key - Ok(Arc::clone(&self.shared_key.as_ref().unwrap())) - } else { - Err(GatewayClientError::AuthenticationFailure) - } - } - - // TODO: possibly make responses optional - pub async fn send_sphinx_packet( - &mut self, - address: NymNodeRoutingAddress, - packet: SphinxPacket, - ) -> Result<(), GatewayClientError> { - if !self.authenticated { - return Err(GatewayClientError::NotAuthenticated); - } - if !self.connection.is_established() { - return Err(GatewayClientError::ConnectionNotEstablished); - } - // note: into_ws_message encrypts the requests and adds a MAC on it. Perhaps it should - // be more explicit in the naming? - let msg = BinaryRequest::new_forward_request(address, packet).into_ws_message( - self.shared_key - .as_ref() - .expect("no shared key present even though we're authenticated!"), - ); - self.send_websocket_message_without_response(msg).await - } - - async fn recover_socket_connection(&mut self) -> Result<(), GatewayClientError> { - if self.connection.is_available() { - return Ok(()); - } - if !self.connection.is_partially_delegated() { - return Err(GatewayClientError::ConnectionInInvalidState); - } - - let conn = match std::mem::replace(&mut self.connection, SocketState::Invalid) { - SocketState::PartiallyDelegated(delegated_conn) => delegated_conn.merge().await?, - _ => unreachable!(), - }; - - self.connection = SocketState::Available(conn); - Ok(()) - } - - // Note: this requires prior authentication - pub fn start_listening_for_mixnet_messages(&mut self) -> Result<(), GatewayClientError> { - if !self.authenticated { - return Err(GatewayClientError::NotAuthenticated); - } - if self.connection.is_partially_delegated() { - return Ok(()); - } - if !self.connection.is_available() { - return Err(GatewayClientError::ConnectionInInvalidState); - } - - let partially_delegated = - match std::mem::replace(&mut self.connection, SocketState::Invalid) { - SocketState::Available(conn) => { - PartiallyDelegated::split_and_listen_for_mixnet_messages( - conn, - self.packet_router.clone(), - Arc::clone( - self.shared_key - .as_ref() - .expect("no shared key present even though we're authenticated!"), - ), - )? - } - _ => unreachable!(), - }; - - self.connection = SocketState::PartiallyDelegated(partially_delegated); - Ok(()) - } - - pub async fn authenticate_and_start(&mut self) -> Result, GatewayClientError> - where - R: IntoClientRequest + Unpin + Clone, - { - if !self.connection.is_established() { - self.establish_connection().await?; - } - let shared_key = self.perform_initial_authentication().await?; - - // this call is NON-blocking - self.start_listening_for_mixnet_messages()?; - - Ok(shared_key) - } -} diff --git a/common/client-libs/gateway-client/src/packet_router.rs b/common/client-libs/gateway-client/src/packet_router.rs index cce32ed51e..3e99cbd4b2 100644 --- a/common/client-libs/gateway-client/src/packet_router.rs +++ b/common/client-libs/gateway-client/src/packet_router.rs @@ -27,13 +27,13 @@ pub type AcknowledgementSender = mpsc::UnboundedSender>>; pub type AcknowledgementReceiver = mpsc::UnboundedReceiver>>; #[derive(Clone, Debug)] -pub(super) struct PacketRouter { +pub struct PacketRouter { ack_sender: AcknowledgementSender, mixnet_message_sender: MixnetMessageSender, } impl PacketRouter { - pub(super) fn new( + pub fn new( ack_sender: AcknowledgementSender, mixnet_message_sender: MixnetMessageSender, ) -> Self { @@ -43,7 +43,7 @@ impl PacketRouter { } } - pub(super) fn route_received(&self, unwrapped_packets: Vec>) { + pub fn route_received(&self, unwrapped_packets: Vec>) { let mut received_messages = Vec::new(); let mut received_acks = Vec::new(); diff --git a/common/client-libs/gateway-client/src/socket_state.rs b/common/client-libs/gateway-client/src/socket_state.rs new file mode 100644 index 0000000000..1d2dcf9ba6 --- /dev/null +++ b/common/client-libs/gateway-client/src/socket_state.rs @@ -0,0 +1,205 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::cleanup_socket_message; +use crate::error::GatewayClientError; +use crate::packet_router::PacketRouter; +use futures::channel::oneshot; +use futures::stream::{SplitSink, SplitStream}; +use futures::{FutureExt, SinkExt, StreamExt}; +use gateway_requests::registration::handshake::SharedKeys; +use gateway_requests::BinaryResponse; +use log::*; +use std::sync::Arc; +use tungstenite::Message; + +#[cfg(not(target_arch = "wasm32"))] +use tokio::net::TcpStream; +#[cfg(not(target_arch = "wasm32"))] +use tokio_tungstenite::WebSocketStream; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_futures; +#[cfg(target_arch = "wasm32")] +use wasm_utils::websocket::JSWebsocket; + +// type alias for not having to type the whole thing every single time (and now it makes it easier +// to use different types based on compilation target) +#[cfg(not(target_arch = "wasm32"))] +type WsConn = WebSocketStream; + +#[cfg(target_arch = "wasm32")] +type WsConn = JSWebsocket; + +// We have ownership over sink half of the connection, but the stream is owned +// by some other task, however, we can notify it to get the stream back. + +type SplitStreamReceiver = oneshot::Receiver, GatewayClientError>>; + +pub(crate) struct PartiallyDelegated { + sink_half: SplitSink, + delegated_stream: (SplitStreamReceiver, oneshot::Sender<()>), +} + +impl PartiallyDelegated { + fn route_socket_message( + ws_msg: Message, + packet_router: &PacketRouter, + shared_key: &SharedKeys, + ) { + match ws_msg { + Message::Binary(bin_msg) => { + // this function decrypts the request and checks the MAC + let plaintext = + match BinaryResponse::try_from_encrypted_tagged_bytes(bin_msg, shared_key) { + Ok(bin_response) => match bin_response { + BinaryResponse::PushedMixMessage(plaintext) => plaintext, + }, + Err(err) => { + warn!( + "message received from the gateway was malformed! - {:?}", + err + ); + return; + } + }; + + // TODO: some batching mechanism to allow reading and sending more than + // one packet at the time, because the receiver can easily handle it + packet_router.route_received(vec![plaintext]) + } + // I think that in the future we should perhaps have some sequence number system, i.e. + // so each request/response pair can be easily identified, so that if messages are + // not ordered (for some peculiar reason) we wouldn't lose anything. + // This would also require NOT discarding any text responses here. + + // TODO: those can return the "send confirmations" - perhaps it should be somehow worked around? + Message::Text(text) => debug!( + "received a text message - probably a response to some previous query! - {}", + text + ), + _ => (), + }; + } + + pub(crate) fn split_and_listen_for_mixnet_messages( + conn: WsConn, + packet_router: PacketRouter, + shared_key: Arc, + ) -> Result { + // when called for, it NEEDS TO yield back the stream so that we could merge it and + // read control request responses. + let (notify_sender, notify_receiver) = oneshot::channel(); + let (stream_sender, stream_receiver) = oneshot::channel(); + + let (sink, mut stream) = conn.split(); + + let mixnet_receiver_future = async move { + let mut fused_receiver = notify_receiver.fuse(); + let mut fused_stream = (&mut stream).fuse(); + + let ret_err = loop { + futures::select! { + _ = fused_receiver => { + break Ok(()); + } + msg = fused_stream.next() => { + let ws_msg = match cleanup_socket_message(msg) { + Err(err) => break Err(err), + Ok(msg) => msg + }; + Self::route_socket_message(ws_msg, &packet_router, shared_key.as_ref()); + } + }; + }; + + match ret_err { + Err(err) => stream_sender.send(Err(err)), + Ok(_) => stream_sender.send(Ok(stream)), + } + .unwrap(); + }; + + #[cfg(target_arch = "wasm32")] + wasm_bindgen_futures::spawn_local(mixnet_receiver_future); + + #[cfg(not(target_arch = "wasm32"))] + tokio::spawn(mixnet_receiver_future); + + Ok(PartiallyDelegated { + sink_half: sink, + delegated_stream: (stream_receiver, notify_sender), + }) + } + + // if we want to send a message and don't care about response, we can don't need to reunite the split, + // the sink itself is enough + pub(crate) async fn send_without_response( + &mut self, + msg: Message, + ) -> Result<(), GatewayClientError> { + Ok(self.sink_half.send(msg).await?) + } + + pub(crate) async fn batch_send_without_response( + &mut self, + messages: Vec, + ) -> Result<(), GatewayClientError> { + let stream_messages: Vec<_> = messages.into_iter().map(Ok).collect(); + let mut send_stream = futures::stream::iter(stream_messages); + Ok(self.sink_half.send_all(&mut send_stream).await?) + } + + pub(crate) async fn merge(self) -> Result { + let (stream_receiver, notify) = self.delegated_stream; + notify.send(()).unwrap(); + let stream = stream_receiver.await.unwrap()?; + // the error is thrown when trying to reunite sink and stream that did not originate + // from the same split which is impossible to happen here + Ok(self.sink_half.reunite(stream).unwrap()) + } +} + +// we can either have the stream itself or an option to re-obtain it +// by notifying the future owning it to finish the execution and awaiting the result +// which should be almost immediate (or an invalid state which should never, ever happen) +pub(crate) enum SocketState { + Available(WsConn), + PartiallyDelegated(PartiallyDelegated), + NotConnected, + Invalid, +} + +impl SocketState { + pub(crate) fn is_available(&self) -> bool { + match self { + SocketState::Available(_) => true, + _ => false, + } + } + + pub(crate) fn is_partially_delegated(&self) -> bool { + match self { + SocketState::PartiallyDelegated(_) => true, + _ => false, + } + } + + pub(crate) fn is_established(&self) -> bool { + match self { + SocketState::Available(_) | SocketState::PartiallyDelegated(_) => true, + _ => false, + } + } +} diff --git a/common/crypto/Cargo.toml b/common/crypto/Cargo.toml index 3996d7bde6..f190c743c7 100644 --- a/common/crypto/Cargo.toml +++ b/common/crypto/Cargo.toml @@ -16,7 +16,7 @@ hkdf = "0.9" hmac = "0.8" stream-cipher = "0.4" x25519-dalek = "0.6" -ed25519-dalek = "1.0.0-pre.3" +ed25519-dalek = "1.0.0-pre.4" log = "0.4" pretty_env_logger = "0.3" rand = {version = "0.7.3", features = ["wasm-bindgen"]} diff --git a/common/crypto/src/asymmetric/identity/mod.rs b/common/crypto/src/asymmetric/identity/mod.rs index 86664e8054..6e00d34ea3 100644 --- a/common/crypto/src/asymmetric/identity/mod.rs +++ b/common/crypto/src/asymmetric/identity/mod.rs @@ -13,8 +13,9 @@ // limitations under the License. use bs58; +use ed25519_dalek::ed25519::signature::Signature as SignatureTrait; pub use ed25519_dalek::SignatureError; -pub use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH}; +pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH}; use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH}; use pemstore::traits::{PemStorableKey, PemStorableKeyPair}; use rand::{rngs::OsRng, CryptoRng, RngCore}; diff --git a/common/nymsphinx/Cargo.toml b/common/nymsphinx/Cargo.toml index e6863daa49..be7b5b5831 100644 --- a/common/nymsphinx/Cargo.toml +++ b/common/nymsphinx/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = {version = "0.7.3", features = ["wasm-bindgen"]} +rand = { version = "0.7.3", features = ["wasm-bindgen"] } rand_distr = "0.2.2" nymsphinx-acknowledgements = { path = "acknowledgements" } @@ -15,11 +15,15 @@ nymsphinx-addressing = { path = "addressing" } nymsphinx-anonymous-replies = { path = "anonymous-replies" } nymsphinx-chunking = { path = "chunking" } nymsphinx-cover = { path = "cover" } -nymsphinx-framing = { path = "framing" } nymsphinx-params = { path = "params" } nymsphinx-types = { path = "types" } # those dependencies are due to intriducing preparer and receiver. Perpaphs that indicates they should be moved # to separate crate? crypto = { path = "../crypto" } -topology = { path = "../topology" } \ No newline at end of file +topology = { path = "../topology" } + +# do not include this when compiling into wasm as it somehow when combined together with reqwest, it will require +# net2 via tokio-util -> tokio -> mio -> net2 +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nymsphinx-framing] +path = "framing" \ No newline at end of file diff --git a/common/nymsphinx/addressing/src/clients.rs b/common/nymsphinx/addressing/src/clients.rs index 6fa6e21c6b..8295df64ef 100644 --- a/common/nymsphinx/addressing/src/clients.rs +++ b/common/nymsphinx/addressing/src/clients.rs @@ -19,7 +19,7 @@ const CLIENT_ENCRYPTION_KEY_SIZE: usize = encryption::PUBLIC_KEY_SIZE; pub type ClientIdentity = identity::PublicKey; const CLIENT_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH; -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +#[derive(Debug)] pub enum RecipientFormattingError { MalformedRecipientError, MalformedIdentityError(identity::SignatureError), diff --git a/common/nymsphinx/src/lib.rs b/common/nymsphinx/src/lib.rs index 4a6fe347c0..3d13558103 100644 --- a/common/nymsphinx/src/lib.rs +++ b/common/nymsphinx/src/lib.rs @@ -22,6 +22,7 @@ pub use nymsphinx_addressing as addressing; pub use nymsphinx_anonymous_replies as anonymous_replies; pub use nymsphinx_chunking as chunking; pub use nymsphinx_cover as cover; +#[cfg(not(target_arch = "wasm32"))] pub use nymsphinx_framing as framing; pub use nymsphinx_params as params; pub use nymsphinx_types::*; diff --git a/common/socks5/requests/src/request.rs b/common/socks5/requests/src/request.rs index c908525a63..c4fe1979cc 100644 --- a/common/socks5/requests/src/request.rs +++ b/common/socks5/requests/src/request.rs @@ -13,7 +13,7 @@ pub enum RequestFlag { Send = 1, } -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum RequestError { AddressLengthTooShort, AddressTooShort, @@ -224,19 +224,19 @@ mod request_deserialization_tests { #[test] fn returns_error_when_zero_bytes() { let request_bytes = Vec::new(); - assert_eq!( - RequestError::NoData, - Request::try_from_bytes(&request_bytes).unwrap_err() - ); + match Request::try_from_bytes(&request_bytes).unwrap_err() { + RequestError::NoData => {} + _ => unreachable!(), + } } #[test] fn returns_error_when_connection_id_too_short() { let request_bytes = [RequestFlag::Connect as u8, 1, 2, 3, 4, 5, 6, 7].to_vec(); // 7 bytes connection id - assert_eq!( - RequestError::ConnectionIdTooShort, - Request::try_from_bytes(&request_bytes).unwrap_err() - ); + match Request::try_from_bytes(&request_bytes).unwrap_err() { + RequestError::ConnectionIdTooShort => {} + _ => unreachable!(), + } } } @@ -249,24 +249,24 @@ mod request_deserialization_tests { let request_bytes1 = [RequestFlag::Connect as u8, 1, 2, 3, 4, 5, 6, 7, 8].to_vec(); // 8 bytes connection id, 0 bytes address length (2 were expected) let request_bytes2 = [RequestFlag::Connect as u8, 1, 2, 3, 4, 5, 6, 7, 8, 0].to_vec(); // 8 bytes connection id, 1 bytes address length (2 were expected) - assert_eq!( - RequestError::AddressLengthTooShort, - Request::try_from_bytes(&request_bytes1).unwrap_err() - ); + match Request::try_from_bytes(&request_bytes1).unwrap_err() { + RequestError::AddressLengthTooShort => {} + _ => unreachable!(), + } - assert_eq!( - RequestError::AddressLengthTooShort, - Request::try_from_bytes(&request_bytes2).unwrap_err() - ); + match Request::try_from_bytes(&request_bytes2).unwrap_err() { + RequestError::AddressLengthTooShort => {} + _ => unreachable!(), + } } #[test] fn returns_error_when_address_too_short_for_given_address_length() { let request_bytes = [RequestFlag::Connect as u8, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1].to_vec(); // 8 bytes connection id, 2 bytes address length, missing address - assert_eq!( - RequestError::AddressTooShort, - Request::try_from_bytes(&request_bytes).unwrap_err() - ); + match Request::try_from_bytes(&request_bytes).unwrap_err() { + RequestError::AddressTooShort => {} + _ => unreachable!(), + } } #[test] @@ -302,10 +302,11 @@ mod request_deserialization_tests { .cloned() .chain(recipient_bytes.iter().take(40).cloned()) .collect(); - assert_eq!( - RequestError::ReturnAddressTooShort, - Request::try_from_bytes(&request_bytes).unwrap_err() - ); + + match Request::try_from_bytes(&request_bytes).unwrap_err() { + RequestError::ReturnAddressTooShort => {} + _ => unreachable!(), + } } #[test] diff --git a/common/topology/Cargo.toml b/common/topology/Cargo.toml index de50a9d97e..b7027cd47b 100644 --- a/common/topology/Cargo.toml +++ b/common/topology/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" bs58 = "0.3.0" log = "0.4" pretty_env_logger = "0.3" -rand = "0.7.2" +rand = { version = "0.7.3", features = ["wasm-bindgen"] } ## internal crypto = { path = "../crypto" } diff --git a/common/wasm-utils/Cargo.toml b/common/wasm-utils/Cargo.toml new file mode 100644 index 0000000000..7dfefb7771 --- /dev/null +++ b/common/wasm-utils/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "wasm-utils" +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] +futures = "0.3" +js-sys = "0.3" +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" + +# we don't want entire tokio-tungstenite, tungstenite itself is just fine - we just want message and error enums +[dependencies.tungstenite] +version = "0.11" +default-features = false + +[dependencies.web-sys] +version = "0.3" +features = [ + "BinaryType", + "Blob", + "CloseEvent", + "ErrorEvent", + "FileReader", + "MessageEvent", + "ProgressEvent", + "WebSocket", + "Window", +] \ No newline at end of file diff --git a/common/wasm-utils/src/lib.rs b/common/wasm-utils/src/lib.rs new file mode 100644 index 0000000000..6ba4241b23 --- /dev/null +++ b/common/wasm-utils/src/lib.rs @@ -0,0 +1,62 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use js_sys::Promise; +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsValue; +use wasm_bindgen_futures::JsFuture; +use web_sys::window; + +pub mod websocket; + +// will cause messages to be written as if console.log("...") was called +#[macro_export] +macro_rules! console_log { + ($($t:tt)*) => ($crate::log(&format_args!($($t)*).to_string())) +} + +// will cause messages to be written as if console.warm("...") was called +#[macro_export] +macro_rules! console_warn { + ($($t:tt)*) => ($crate::warn(&format_args!($($t)*).to_string())) +} + +// will cause messages to be written as if console.error("...") was called +#[macro_export] +macro_rules! console_error { + ($($t:tt)*) => ($crate::error(&format_args!($($t)*).to_string())) +} + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + pub fn log(s: &str); + + #[wasm_bindgen(js_namespace = console)] + pub fn warn(s: &str); + + #[wasm_bindgen(js_namespace = console)] + pub fn error(s: &str); +} + +pub async fn sleep(ms: i32) -> Result<(), JsValue> { + let promise = Promise::new(&mut |yes, _| { + let win = window().expect("no window available!"); + win.set_timeout_with_callback_and_timeout_and_arguments_0(&yes, ms) + .unwrap(); + }); + let js_fut = JsFuture::from(promise); + js_fut.await?; + Ok(()) +} diff --git a/common/wasm-utils/src/websocket/mod.rs b/common/wasm-utils/src/websocket/mod.rs new file mode 100644 index 0000000000..7d11080903 --- /dev/null +++ b/common/wasm-utils/src/websocket/mod.rs @@ -0,0 +1,301 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::websocket::state::State; +use crate::{console_error, console_log}; +use futures::{Sink, Stream}; +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::VecDeque; +use std::io; +use std::pin::Pin; +use std::rc::Rc; +use std::task::{Context, Poll, Waker}; +use tungstenite::{Error as WsError, Message as WsMessage}; // use tungstenite Message and Error types for easier compatibility with `ClientHandshake` +use wasm_bindgen::closure::Closure; +use wasm_bindgen::JsCast; +use wasm_bindgen::JsValue; +use web_sys::{CloseEvent, ErrorEvent, MessageEvent, WebSocket}; + +mod state; + +// Unfortunately this can't be cleanly done with TryFrom/TryInto traits as both are foreign types +fn try_message_event_into_ws_message(msg_event: MessageEvent) -> Result { + match msg_event.data() { + buf if buf.is_instance_of::() => { + let array = js_sys::Uint8Array::new(&buf); + Ok(WsMessage::Binary(array.to_vec())) + } + blob if blob.is_instance_of::() => { + console_error!("received a blob on the websocket - ignoring it!"); + // we really don't want to bother dealing with Blobs, because it requires juggling filereaders, + // having event handlers to see when they're done, etc. + // + we shouldn't even get one [a blob] to begin with + // considering that our binary mode is (should be) set to array buffer. + Err(WsError::Io(io::Error::from(io::ErrorKind::InvalidInput))) + } + text if text.is_string() => match text.as_string() { + Some(text) => Ok(WsMessage::Text(text)), + None => Err(WsError::Utf8), + }, + _ => Err(WsError::Protocol(Cow::from( + "received a websocket message that is neither a String, ArrayBuffer or a Blob", + ))), + } +} + +// Safety: when compiled to wasm32 everything is going to be running on a single thread and so there +// is no shared memory right now. +// +// Eventually it should be made `Send` properly. Wakers should probably be replaced with AtomicWaker +// and the item queue put behind an Arc>. +// It might also be worth looking at what https://crates.io/crates/send_wrapper could provide. +// Because I'm not sure Mutex would solve the `Closure` issue. It's the problem for later. +// +// ************************************ +// SUPER IMPORTANT TODO: ONCE WASM IN RUST MATURES AND BECOMES MULTI-THREADED THIS MIGHT +// LEAD TO RUNTIME MEMORY CORRUPTION!! +// ************************************ +// +unsafe impl Send for JSWebsocket {} + +#[derive(Debug)] +pub struct JSWebsocket { + socket: web_sys::WebSocket, + + message_queue: Rc>>>, + + /// Waker of a task wanting to read incoming messages. + stream_waker: Rc>>, + + /// Waker of a task wanting to write to the sink. + sink_waker: Rc>>, + + /// Waker of a sink wanting to close the connection. + close_waker: Rc>>, + + // The callback closures. We need to store them as they will invalidate their + // corresponding JS callback whenever they are dropped, so if we were to + // normally return from `new` then our registered closures will + // raise an exception when invoked. + _on_open: Closure, + _on_error: Closure, + _on_close: Closure, + _on_message: Closure, +} + +impl JSWebsocket { + pub fn new(url: &str) -> Result { + let ws = WebSocket::new(url)?; + // we don't want to ever have to deal with blobs + ws.set_binary_type(web_sys::BinaryType::Arraybuffer); + + let message_queue = Rc::new(RefCell::new(VecDeque::new())); + let message_queue_clone = Rc::clone(&message_queue); + + let stream_waker: Rc>> = Rc::new(RefCell::new(None)); + let stream_waker_clone = Rc::clone(&stream_waker); + let stream_waker_clone2 = Rc::clone(&stream_waker); + + let sink_waker: Rc>> = Rc::new(RefCell::new(None)); + let sink_waker_clone = Rc::clone(&sink_waker); + let sink_waker_clone2 = Rc::clone(&sink_waker); + + let close_waker: Rc>> = Rc::new(RefCell::new(None)); + let close_waker_clone = Rc::clone(&close_waker); + + let on_message = Closure::wrap(Box::new(move |msg_event| { + let ws_message = try_message_event_into_ws_message(msg_event); + message_queue_clone.borrow_mut().push_back(ws_message); + + // if there is a task waiting for messages - wake the executor! + if let Some(waker) = stream_waker_clone.borrow_mut().take() { + waker.wake() + } + }) as Box); + + let url_clone = url.to_string(); + let on_open = Closure::wrap(Box::new(move |_| { + // in case there was a sink send request made before connection was fully established + console_log!("Websocket to {:?} is now open!", url_clone); + + // if there is a task waiting to write messages - wake the executor! + if let Some(waker) = sink_waker_clone.borrow_mut().take() { + waker.wake() + } + + // no need to wake the stream_waker because we won't have any message to send + // immediately anyway. It only makes sense to wake it during on_message (if any) + }) as Box); + + let on_error = Closure::wrap(Box::new(move |e: ErrorEvent| { + console_error!("Websocket error event: {:?}", e); + }) as Box); + + let on_close = Closure::wrap(Box::new(move |e: CloseEvent| { + console_log!("Websocket close event: {:?}", e); + // something was waiting for the close event! + if let Some(waker) = close_waker_clone.borrow_mut().take() { + waker.wake() + } + + // TODO: are waking those sufficient to prevent memory leaks? + if let Some(waker) = stream_waker_clone2.borrow_mut().take() { + waker.wake() + } + + if let Some(waker) = sink_waker_clone2.borrow_mut().take() { + waker.wake() + } + }) as Box); + + ws.set_onmessage(Some(on_message.as_ref().unchecked_ref())); + ws.set_onerror(Some(on_error.as_ref().unchecked_ref())); + ws.set_onopen(Some(on_open.as_ref().unchecked_ref())); + ws.set_onclose(Some(on_close.as_ref().unchecked_ref())); + + Ok(JSWebsocket { + socket: ws, + message_queue, + stream_waker, + sink_waker, + close_waker, + + _on_open: on_open, + _on_error: on_error, + _on_close: on_close, + _on_message: on_message, + }) + } + + pub async fn close(&mut self, code: Option) { + if let Some(code) = code { + self.socket + .close_with_code(code) + .expect("failed to close the socket!"); + } else { + self.socket.close().expect("failed to close the socket!"); + } + } + + fn state(&self) -> State { + self.socket.ready_state().into() + } +} + +impl Drop for JSWebsocket { + fn drop(&mut self) { + match self.state() { + State::Closed | State::Closing => {} // no need to do anything here + _ => self + .socket + .close() + .expect("failed to close WebSocket during drop!"), + } + + self.socket.set_onmessage(None); + self.socket.set_onerror(None); + self.socket.set_onopen(None); + self.socket.set_onclose(None); + } +} + +impl Stream for JSWebsocket { + type Item = Result; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // if there's anything in the internal queue, keep returning that + let ws_message = self.message_queue.borrow_mut().pop_front(); + match ws_message { + Some(message) => Poll::Ready(Some(message)), + None => { + // if connection is closed or closing it means no more useful messages will ever arrive + // and hence we should signal this. + match self.state() { + State::Closing | State::Closed => Poll::Ready(None), + State::Open | State::Connecting => { + // clone the waker to be able to notify the executor once we get a new message + *self.stream_waker.borrow_mut() = Some(cx.waker().clone()); + Poll::Pending + } + } + } + } + } +} + +impl Sink for JSWebsocket { + type Error = WsError; + + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.state() { + State::Connecting => { + // clone the waker to be able to notify the executor once we get connected + *self.sink_waker.borrow_mut() = Some(cx.waker().clone()); + Poll::Pending + } + + State::Open => Poll::Ready(Ok(())), + State::Closing | State::Closed => Poll::Ready(Err(WsError::AlreadyClosed)), + } + } + + fn start_send(self: Pin<&mut Self>, item: WsMessage) -> Result<(), Self::Error> { + // the only possible errors, per https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send + + // are `INVALID_STATE_ERR` which is when connection is not in open state + + // and `SYNTAX_ERR` which is when data is a string that has unpaired surrogates. This one + // is essentially impossible to happen in rust (assuming wasm_bindgen has done its jobs + // correctly, but even if not, there's nothing we can do ourselves. + + // hence we can map all errors to not open + + match self.state() { + State::Open => match item { + WsMessage::Binary(data) => self.socket.send_with_u8_array(&data), + WsMessage::Text(text) => self.socket.send_with_str(&text), + _ => unreachable!("those are not even exposed by the web_sys API"), + } + .map_err(|_| WsError::Io(io::Error::from(io::ErrorKind::NotConnected))), + + State::Closing | State::Closed => Err(WsError::AlreadyClosed), + State::Connecting => Err(WsError::Io(io::Error::from(io::ErrorKind::NotConnected))), + } + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + // TODO: can we/should we do anything more here? + Poll::Ready(Ok(())) + } + + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.state() { + State::Open | State::Connecting => { + // TODO: do we need to wait for closing event here? + *self.close_waker.borrow_mut() = Some(cx.waker().clone()); + + // close inner socket + Poll::Ready(self.socket.close().map_err(|_| todo!())) + } + // if we're already closed, nothing left to do! + State::Closed => Poll::Ready(Ok(())), + State::Closing => { + *self.close_waker.borrow_mut() = Some(cx.waker().clone()); + // wait for the close event... + Poll::Pending + } + } + } +} diff --git a/common/wasm-utils/src/websocket/state.rs b/common/wasm-utils/src/websocket/state.rs new file mode 100644 index 0000000000..60072040a4 --- /dev/null +++ b/common/wasm-utils/src/websocket/state.rs @@ -0,0 +1,38 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use web_sys::WebSocket; + +// convenience wrapper for state values provided by [`web_sys::WebSocket`] +/// The state values correspond to the `readyState` API of the `WebSocket`. +/// See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState) for more details. +#[repr(u16)] +pub(crate) enum State { + Connecting = 0, + Open = 1, + Closing = 2, + Closed = 3, +} + +impl From for State { + fn from(state: u16) -> Self { + match state { + WebSocket::CONNECTING => State::Connecting, + WebSocket::OPEN => State::Open, + WebSocket::CLOSING => State::Closing, + WebSocket::CLOSED => State::Closed, + n => panic!("{} is not a valid WebSocket state!", n), // should we panic here or change it into `TryFrom` instead? + } + } +} diff --git a/gateway/gateway-requests/Cargo.toml b/gateway/gateway-requests/Cargo.toml index d9c18b545e..52108be9b2 100644 --- a/gateway/gateway-requests/Cargo.toml +++ b/gateway/gateway-requests/Cargo.toml @@ -14,7 +14,12 @@ nymsphinx = { path = "../../common/nymsphinx" } rand = { version = "0.7.3", features = ["wasm-bindgen"] } serde = { version = "1.0.104", features = ["derive"] } serde_json = "1.0.44" -tokio-tungstenite = "0.11.0" crypto = { path = "../../common/crypto" } -pemstore = { path = "../../common/pemstore" } \ No newline at end of file +pemstore = { path = "../../common/pemstore" } + +[dependencies.tungstenite] +version = "0.11" +default-features = false + + diff --git a/gateway/gateway-requests/src/registration/handshake/client.rs b/gateway/gateway-requests/src/registration/handshake/client.rs index bbbf0c8c4c..9adf4ec92d 100644 --- a/gateway/gateway-requests/src/registration/handshake/client.rs +++ b/gateway/gateway-requests/src/registration/handshake/client.rs @@ -23,7 +23,7 @@ use futures::task::{Context, Poll}; use futures::{Future, Sink, Stream}; use rand::{CryptoRng, RngCore}; use std::pin::Pin; -use tokio_tungstenite::tungstenite::Message as WsMessage; +use tungstenite::Message as WsMessage; pub(crate) struct ClientHandshake<'a> { handshake_future: BoxFuture<'a, Result>, diff --git a/gateway/gateway-requests/src/registration/handshake/gateway.rs b/gateway/gateway-requests/src/registration/handshake/gateway.rs index 7aa64b109b..119401ced5 100644 --- a/gateway/gateway-requests/src/registration/handshake/gateway.rs +++ b/gateway/gateway-requests/src/registration/handshake/gateway.rs @@ -21,7 +21,7 @@ use futures::task::{Context, Poll}; use futures::{Future, Sink, Stream}; use rand::{CryptoRng, RngCore}; use std::pin::Pin; -use tokio_tungstenite::tungstenite::Message as WsMessage; +use tungstenite::Message as WsMessage; pub(crate) struct GatewayHandshake<'a> { handshake_future: BoxFuture<'a, Result>, diff --git a/gateway/gateway-requests/src/registration/handshake/mod.rs b/gateway/gateway-requests/src/registration/handshake/mod.rs index 2351b70f2d..f7e725c6c5 100644 --- a/gateway/gateway-requests/src/registration/handshake/mod.rs +++ b/gateway/gateway-requests/src/registration/handshake/mod.rs @@ -20,7 +20,7 @@ use crypto::asymmetric::identity; use futures::{Sink, Stream}; use rand::rngs::OsRng; use rand::{CryptoRng, RngCore}; -use tokio_tungstenite::tungstenite::{Error as WsError, Message as WsMessage}; +use tungstenite::{Error as WsError, Message as WsMessage}; // for ease of use pub const DEFAULT_RNG: OsRng = OsRng; diff --git a/gateway/gateway-requests/src/registration/handshake/state.rs b/gateway/gateway-requests/src/registration/handshake/state.rs index 2a7bb58bb8..ca89fb2ec1 100644 --- a/gateway/gateway-requests/src/registration/handshake/state.rs +++ b/gateway/gateway-requests/src/registration/handshake/state.rs @@ -27,7 +27,7 @@ use log::*; use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm}; use rand::{CryptoRng, RngCore}; use std::convert::{TryFrom, TryInto}; -use tokio_tungstenite::tungstenite::Message as WsMessage; +use tungstenite::Message as WsMessage; /// Handshake state. pub(crate) struct State<'a, S> { diff --git a/gateway/gateway-requests/src/types.rs b/gateway/gateway-requests/src/types.rs index 84ad90ccd5..31e78d4f2c 100644 --- a/gateway/gateway-requests/src/types.rs +++ b/gateway/gateway-requests/src/types.rs @@ -28,7 +28,7 @@ use std::{ convert::{TryFrom, TryInto}, fmt::{self, Error, Formatter}, }; -use tokio_tungstenite::tungstenite::protocol::Message; +use tungstenite::protocol::Message; #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type", rename_all = "camelCase")]