Compare commits

..

205 Commits

Author SHA1 Message Date
Dave Hrycyszyn 7c49155ffa Merge branch 'release/0.2.0' 2020-01-06 17:51:44 +00:00
Dave Hrycyszyn 32487b48e8 Added the glorious and talented J□drzej Stuczy□ski as author. 2020-01-06 17:51:25 +00:00
Dave Hrycyszyn f1500fd82c version bump 2020-01-06 17:50:24 +00:00
Dave Hrycyszyn 9176524e92 changelog for 0.2.0 2020-01-06 17:50:10 +00:00
Jedrzej Stuczynski b146dd4c22 Changelog file 2020-01-06 15:26:38 +00:00
Dave Hrycyszyn 4825bfe48a Merge pull request #44 from nymtech/feature/explicit_directory
Removed local flag and replaced it with explicit directory server
2020-01-06 14:58:18 +00:00
Jedrzej Stuczynski 50a68e44e5 Removed local flag and replaced it with explicit directory server 2020-01-06 14:52:57 +00:00
Dave Hrycyszyn f002b80de2 Merge pull request #43 from nymtech/feature/generic_ip_addressing
Feature/generic ip addressing
2020-01-06 14:43:52 +00:00
Jedrzej Stuczynski 85de3d1a32 IpV6 compatible nym-client 2020-01-06 14:42:17 +00:00
Jedrzej Stuczynski d1eedec210 conversion from address bytes to socket address and vice versa 2020-01-06 14:31:35 +00:00
Dave Hrycyszyn f9e2af3155 Merge pull request #40 from nymtech/feature/version_printing
using built to print version on startup
2020-01-06 12:28:29 +00:00
Jedrzej Stuczynski ea779ea1e8 using built to print version on startup 2020-01-06 12:27:57 +00:00
Dave Hrycyszyn 88d627e9dd Merge pull request #38 from nymtech/feature/tcp-socket-attempt
TCP socket for nym client
2019-12-20 16:39:14 +00:00
Jedrzej Stuczynski 386a877f13 TCP socket for nym client 2019-12-20 16:34:58 +00:00
Jędrzej Stuczyński fc07f78bcb Merge pull request #37 from nymtech/feature/electron-integration
Feature/websocket integration
2019-12-19 16:35:31 +00:00
Dave Hrycyszyn 019c9d6f96 websocket: filtering so that dummy/loop messages aren't pumped up to the websocket 2019-12-19 16:34:19 +00:00
Dave Hrycyszyn 49ae6d9c56 speeding up message rates 2019-12-19 16:33:45 +00:00
Dave Hrycyszyn 2e7c4214e1 main: removing required on websocket port (default is 9001) 2019-12-19 15:48:58 +00:00
Dave Hrycyszyn c001fe5908 websockets: starting to implement own_details and get_clients messages 2019-12-19 15:48:38 +00:00
Dave Hrycyszyn 3a8ce3d3d9 capitalization 2019-12-19 15:47:44 +00:00
Dave Hrycyszyn d5646515e1 cargo fmt run 2019-12-19 11:50:17 +00:00
Dave Hrycyszyn 5f3bbe626f Merge pull request #35 from nymtech/feature/websocket_message_retrieval
Feature/websocket message retrieval
2019-12-19 11:12:15 +00:00
Jedrzej Stuczynski 39a2b919ae Fixed compiler warnings 2019-12-18 17:15:55 +00:00
Jedrzej Stuczynski eba2b1f4ea Removed dummy response 2019-12-18 17:15:13 +00:00
Jedrzej Stuczynski b706d36e65 Ability for the websocket to retrieve stored messages 2019-12-18 17:10:35 +00:00
Jedrzej Stuczynski 04b065508e Working (kinda) received messages buffer 2019-12-18 16:25:22 +00:00
Jedrzej Stuczynski a9222eff5b Tasks for message buffer 2019-12-18 16:10:22 +00:00
Jedrzej Stuczynski 5d5d43eab2 Basic operations for the received messages buffer 2019-12-18 16:04:10 +00:00
Dave Hrycyszyn 1f0779857f Merge pull request #34 from nymtech/feature/client_registration
Feature/client registration
2019-12-18 15:44:44 +00:00
Jedrzej Stuczynski a958445309 Got rid of compiler warnings 2019-12-18 14:44:07 +00:00
Jedrzej Stuczynski 441a6c3e1b Client sending registration request on startup 2019-12-18 14:25:29 +00:00
Jedrzej Stuczynski 0fe7276d44 Method to update auth token of provider client + removed mut from register 2019-12-18 11:22:46 +00:00
Jedrzej Stuczynski 2b89be3031 Basic structure for client registration message send 2019-12-18 11:20:52 +00:00
Jedrzej Stuczynski bc143c16c0 Moved sending bytes to provider to separate method 2019-12-18 11:11:07 +00:00
Jedrzej Stuczynski d08e51461b Overwriting provider address at 'new' 2019-12-18 11:04:13 +00:00
Jedrzej Stuczynski ef0e1d081d Included address and auth token to provider client 2019-12-18 10:58:47 +00:00
Jedrzej Stuczynski 7a57078c65 Moved socket address from start method to new 2019-12-18 10:30:27 +00:00
Jedrzej Stuczynski 6726329e2c Optional auth token for client constructor 2019-12-18 10:26:53 +00:00
Jedrzej Stuczynski 812a0fe144 Deprecated run command 2019-12-18 10:25:32 +00:00
Jedrzej Stuczynski 5915e45961 Made code compile + moved address to provider client constructor 2019-12-18 10:22:24 +00:00
Dave Hrycyszyn c81f2e860c commands: removing unused import 2019-12-17 17:26:42 +00:00
Dave Hrycyszyn 4c3a5ac9d3 client: generating a random route. 2019-12-17 17:26:24 +00:00
Dave Hrycyszyn d2550c6a31 Merge pull request #33 from nymtech/feature/new_websocket_implementation
Feature/new websocket implementation
2019-12-17 16:10:10 +00:00
Jedrzej Stuczynski 3fb8ebbfee Changed tokio tungstenite to use specific commit 2019-12-17 16:05:25 +00:00
Jedrzej Stuczynski 4918ed50f1 Most-merge conflicts 2019-12-17 16:00:15 +00:00
Jedrzej Stuczynski 2f871ea320 Merge branch 'develop' into feature/new_websocket_implementation 2019-12-17 15:57:59 +00:00
Jędrzej Stuczyński 5cde753e6c Merge pull request #32 from nymtech/feature/client-public-key-as-provider-identity
Feature/client public key as provider identity
2019-12-17 15:32:14 +00:00
Jedrzej Stuczynski c02a44fbce Ability to send mix messages from websocket 2019-12-17 15:21:48 +00:00
Dave Hrycyszyn e1822495a6 socket clients: setting up with id and local parameters 2019-12-17 15:04:25 +00:00
Dave Hrycyszyn ddaf4b6a86 commands: using Nym banner on client start 2019-12-17 14:50:36 +00:00
Dave Hrycyszyn 127f6b4047 run: reading the client's keypair from disk whenever it's run 2019-12-17 14:48:44 +00:00
Dave Hrycyszyn 74e0fb849b keys: relying on the type system to ensure keys are 32 byte arrays 2019-12-17 14:48:20 +00:00
Dave Hrycyszyn a42dd55320 main: adding "id" parameter back onto "run" command 2019-12-17 14:47:45 +00:00
Dave Hrycyszyn 7b545c78ee Merge pull request #31 from nymtech/feature/client-cleanup
Import cleanup
2019-12-17 14:10:33 +00:00
Dave Hrycyszyn 8bf9dabdf1 Import cleanup 2019-12-17 14:09:41 +00:00
Jędrzej Stuczyński ba28917ba5 Merge pull request #30 from nymtech/feature/provider-from-topology
Feature/provider from topology
2019-12-17 13:43:50 +00:00
Dave Hrycyszyn 253dbdafaf Merge branch 'develop' into feature/provider-from-topology 2019-12-17 13:38:02 +00:00
Dave Hrycyszyn c508d1518d provider: using provider from topology instead of hardcoded 2019-12-17 12:42:10 +00:00
Jedrzej Stuczynski ca3cf706e4 Added local flag to socket startups 2019-12-17 12:36:40 +00:00
Jedrzej Stuczynski 3ddde4c8ef New websocket handler with working async 2019-12-17 12:17:49 +00:00
Dave Hrycyszyn b741c23a7c presence: adding comparison and debug to presence models 2019-12-17 11:30:16 +00:00
Jedrzej Stuczynski 40bec84397 Removed unused join3 import 2019-12-17 11:07:06 +00:00
Jedrzej Stuczynski a3f0e74dc7 Allowing the client to run all its traffic stream in parallel rather than just concurrently 2019-12-17 11:06:35 +00:00
Jedrzej Stuczynski ef15eb06ce Outdated comment 2019-12-17 10:57:33 +00:00
Jedrzej Stuczynski d0a07ac006 stash pop 2019-12-17 10:53:06 +00:00
Jędrzej Stuczyński 273e7df39a Merge pull request #26 from nymtech/feature/integrated_websocket
Dave didn't want to take any part in merging of this abomination of a pull confusion.
2019-12-17 10:49:00 +00:00
Jedrzej Stuczynski 2e4571b791 Merge branch 'develop' into feature/integrated_websocket 2019-12-17 10:47:49 +00:00
Jedrzej Stuczynski a978e6db9b Uncommited work before switching websocket implementation 2019-12-17 10:46:34 +00:00
Dave Hrycyszyn 11c6c0f78a directory: metrics module needs to be public 2019-12-17 10:35:15 +00:00
Dave Hrycyszyn 808a79062f Adding last_seen back in as I don't feel like making a persisted version of the model just now 2019-12-17 10:30:48 +00:00
Dave Hrycyszyn 65ae5c4cec presence: fixing post request test 2019-12-17 10:19:09 +00:00
Dave Hrycyszyn 92eccb096a Removing unused imports, commenting weird SocketAddr code 2019-12-17 10:18:00 +00:00
Dave Hrycyszyn 7fea03b57d Removing unused import 2019-12-17 10:17:16 +00:00
Dave Hrycyszyn 2cb4c89c8f presence: removing last_seen, it's set by server 2019-12-17 10:17:00 +00:00
Jedrzej Stuczynski 29106cef6f This should have been 10 separate commits 2019-12-16 17:47:11 +00:00
Jedrzej Stuczynski 3343eb60e2 Merge branch 'develop' into feature/integrated_websocket 2019-12-16 16:59:45 +00:00
Dave Hrycyszyn 82cf0502b8 rustfmt 2019-12-16 16:20:50 +00:00
Dave Hrycyszyn b1f4b22e9f run: socket address imports 2019-12-16 16:20:41 +00:00
Dave Hrycyszyn 4fbe240419 rustfmt 2019-12-16 16:20:25 +00:00
Dave Hrycyszyn 4a4976d56f run: serializing host address to bytes in constant-size format 2019-12-16 16:20:16 +00:00
Dave Hrycyszyn a25af016a6 rustfmt 2019-12-16 16:19:44 +00:00
Dave Hrycyszyn 02986bb2a0 rustfmt 2019-12-16 16:19:36 +00:00
Dave Hrycyszyn ad0f61ec3b rustfmt 2019-12-16 16:19:26 +00:00
Dave Hrycyszyn 9fe1d23694 provider client: fixing warning on unused keepalive check 2019-12-16 16:16:02 +00:00
Dave Hrycyszyn 8ac6a84a55 mixclient: using constant sized bytes for addressing 2019-12-16 16:15:28 +00:00
Dave Hrycyszyn d61f88635a Merge branch 'develop' of github.com:nymtech/nym-client into develop 2019-12-16 14:52:51 +00:00
Dave Hrycyszyn 5dacb4d92d lib: re-exporting identity and persistence. 2019-12-16 14:50:25 +00:00
Jedrzej Stuczynski beeb0a3560 Merge branch 'develop' into feature/poisson_loop_cover_traffic 2019-12-16 11:46:48 +00:00
Jędrzej Stuczyński 53d2d3a0e2 Merge pull request #25 from nymtech/feature/directory-server-option
Feature/directory server option
2019-12-16 11:44:08 +00:00
Jedrzej Stuczynski f5f2ecb65e Some cleanup + sample message sending 2019-12-16 11:43:15 +00:00
Dave Hrycyszyn d9a603aa1f run command: added the ability to start with a local directory server 2019-12-16 11:41:18 +00:00
Dave Hrycyszyn b32e1575a3 main: removed unused customcfg option 2019-12-16 11:41:00 +00:00
Jędrzej Stuczyński 63d1716b6a Merge pull request #24 from nymtech/feature/ws
Feature/ws
2019-12-16 11:35:07 +00:00
Jedrzej Stuczynski a472c23b48 Managed to combine cover traffic stream with out queue 2019-12-16 10:59:11 +00:00
Dave Hrycyszyn c3eedb709a Fixing URL for provdiders client 2019-12-16 10:55:57 +00:00
Dave Hrycyszyn 631827f5eb websocket: demonstrating send message in Rust code. 2019-12-14 17:09:00 +00:00
Dave Hrycyszyn 13d14cff95 presence provider: fixing tests 2019-12-14 16:58:31 +00:00
Dave Hrycyszyn 00e0a61237 mix client: commenting unused code 2019-12-14 16:57:59 +00:00
Dave Hrycyszyn 3d812a36d6 main: changing structure of socket args, removing unused args 2019-12-14 16:57:32 +00:00
Dave Hrycyszyn 066e0fa67b sockets: setting up websockets feature. 2019-12-14 16:57:11 +00:00
Dave Hrycyszyn 522c3d869c cargo: adding ws crate to enable websockets 2019-12-14 16:16:56 +00:00
Dave Hrycyszyn 60964436e2 Merge pull request #22 from nymtech/feature/libify
Corrects client URL for mix providers on directory
2019-12-14 16:14:34 +00:00
Dave Hrycyszyn fdd8cc85c7 presence: added registered_clients to the provider model 2019-12-14 15:37:40 +00:00
Dave Hrycyszyn 2a7fdeeccb presence: fixed incorrect URL for provider presence 2019-12-14 15:37:07 +00:00
Jedrzej Stuczynski dfece9bda5 Working loop cover traffic 2019-12-13 16:03:19 +00:00
Jedrzej Stuczynski 7dcc81eab4 Creating dummy sphinx loop message 2019-12-13 13:12:03 +00:00
Jędrzej Stuczyński 0a80bc6554 Merge pull request #21 from nymtech/feature/libify
Feature/libify
2019-12-13 12:50:15 +00:00
Dave Hrycyszyn f8c6f4633c Passing models by reference to keep borrow checker happy 2019-12-13 12:47:19 +00:00
Dave Hrycyszyn b0d31a88d5 cargo: set up as a lib 2019-12-13 12:44:46 +00:00
Jedrzej Stuczynski 27bf01eb28 Input channel created on new 2019-12-13 12:42:18 +00:00
Jedrzej Stuczynski 19819729a1 Sending messages via channel to mix traffic controller 2019-12-13 12:23:53 +00:00
Jedrzej Stuczynski 59b931b919 Basic delay loop for cover traffic stream 2019-12-13 11:36:02 +00:00
Jedrzej Stuczynski eee87a4d45 Sampling poisson distribution 2019-12-13 11:23:25 +00:00
Jedrzej Stuczynski 9114a10880 Initial structure for starting all traffic streams 2019-12-12 17:23:03 +00:00
Dave Hrycyszyn 951824f17a Merge branch 'develop' of github.com:nymtech/nym-client into develop 2019-12-12 16:45:50 +00:00
Dave Hrycyszyn 1468deb2c0 main: banner formatting 2019-12-12 16:45:39 +00:00
Jędrzej Stuczyński 1c3cf9c67b Merge pull request #19 from nymtech/feature/load-keys
Feature/load keys
2019-12-12 16:16:06 +00:00
Dave Hrycyszyn 722f2daaef pemstore: read_file can be private 2019-12-12 15:40:24 +00:00
Dave Hrycyszyn fd75fc1436 Merge pull request #18 from nymtech/feature/provider_polling
Feature/provider polling
2019-12-12 15:37:55 +00:00
Dave Hrycyszyn 71f06b1efc persistence: pem storage now working 2019-12-12 15:36:18 +00:00
Dave Hrycyszyn 14f0c1afbf Refactored so that we have sane persistence functions 2019-12-12 14:22:22 +00:00
Jedrzej Stuczynski ccca67acd5 Zeroed public keys to match local deployment + provider 'polling' 2019-12-12 14:15:08 +00:00
Jedrzej Stuczynski f28eac7f94 changed default destination address to be non-zero 2019-12-12 14:01:02 +00:00
Jedrzej Stuczynski 26bd084862 Merge branch 'develop' into feature/provider_polling 2019-12-12 13:58:16 +00:00
Jedrzej Stuczynski 536d86d6e3 Retrieving stored messages 2019-12-12 13:56:31 +00:00
Jędrzej Stuczyński ae6f118c88 Merge pull request #17 from nymtech/feature/persistent-keys
Feature/persistent keys
2019-12-12 13:03:59 +00:00
Jędrzej Stuczyński b0041eab17 Merge pull request #15 from nymtech/feature/extract-padding
Feature/extract padding
2019-12-12 12:52:18 +00:00
Dave Hrycyszyn fe45a5382e utils: removing useless assert 2019-12-12 12:50:46 +00:00
Dave Hrycyszyn 9819479096 init: using proper directory commands and displaying banner during init 2019-12-12 12:40:47 +00:00
Dave Hrycyszyn 53408ef393 main: splitting banner and usage into separate functions 2019-12-12 12:40:21 +00:00
Dave Hrycyszyn 4ed7f6a31f Changing to lower-level "dirs" crate for base directory config 2019-12-12 12:30:35 +00:00
Dave Hrycyszyn 67b21b1cd1 cargo: adding directories dependency 2019-12-12 11:35:11 +00:00
Dave Hrycyszyn 9ecff9b5bf init: writing pem files 2019-12-12 11:34:50 +00:00
Dave Hrycyszyn 45176a7ce0 main: messing with args and adding banner 2019-12-12 11:34:40 +00:00
Dave Hrycyszyn ecef8379b0 Cargo: adding pem dependencies. 2019-12-12 11:34:16 +00:00
Jędrzej Stuczyński 5cef7745bf Merge pull request #16 from nymtech/feature/wire-up-requests
directory: wire up all requests so that they're available for use
2019-12-12 11:07:02 +00:00
Dave Hrycyszyn 64b43875a8 directory: wire up all requests so that they're available for use 2019-12-11 17:17:29 +00:00
Dave Hrycyszyn eccf5abb7a Extracting bytes function into its own utility 2019-12-11 16:58:58 +00:00
Jedrzej Stuczynski 39bbecb55d Closing socket to server on being done 2019-12-11 16:42:25 +00:00
Dave Hrycyszyn 71527eebf7 run: looking a little cleaner 2019-12-11 16:35:39 +00:00
Dave Hrycyszyn f435eae5aa run: starting to name some functions 2019-12-11 16:18:53 +00:00
Dave Hrycyszyn 46b3f7d860 Exposing presence module 2019-12-11 16:00:36 +00:00
Jedrzej Stuczynski 639187776e Moved provider requests to subcrate in sfw provider 2019-12-11 15:50:29 +00:00
Jędrzej Stuczyński 41830250ab Merge pull request #14 from nymtech/feature/directory-integration
Feature/directory integration
2019-12-11 15:38:35 +00:00
Dave Hrycyszyn 84ce1611a1 client: packets are sending! 2019-12-11 15:33:27 +00:00
Jedrzej Stuczynski 456494f05f Requests for messages 2019-12-11 15:17:47 +00:00
Dave Hrycyszyn 5c59cb5c3d directory: presence for providers now working 2019-12-11 14:15:52 +00:00
Dave Hrycyszyn decebcf93f directory: presence mixnode post now working 2019-12-11 14:10:41 +00:00
Dave Hrycyszyn 1901727787 directory: coconodes presence now working 2019-12-11 14:07:38 +00:00
Dave Hrycyszyn 3a57939d55 directory: metrics_mixes_post complete 2019-12-11 11:53:28 +00:00
Dave Hrycyszyn d879192d83 directory: using new PersistedMixMetric model 2019-12-11 11:15:06 +00:00
Dave Hrycyszyn 8df4f91c22 directory: adding a PersistedMixMetric model (has a timestamp) 2019-12-11 11:14:46 +00:00
Dave Hrycyszyn 288c414075 directory: removing unused imports 2019-12-11 11:01:16 +00:00
Dave Hrycyszyn 5e734d1dce directory: retrieving mixmetrics complete 2019-12-11 11:00:16 +00:00
Dave Hrycyszyn ffa2967a00 directory: calling assert on topology mocks 2019-12-11 10:37:59 +00:00
Dave Hrycyszyn 16d5ca40e2 Fixing up client mod 2019-12-11 10:36:43 +00:00
Dave Hrycyszyn df1ec3f76b directory: calling assert on mocks 2019-12-11 10:36:35 +00:00
Dave Hrycyszyn c4fc537930 Adding a file for the Provider client to eventually live in 2019-12-11 10:36:23 +00:00
Dave Hrycyszyn d55e7482ed Fixing warning 2019-12-11 01:06:17 +00:00
Dave Hrycyszyn c5c4cec741 commands: removing redundant directory server check 2019-12-11 00:58:37 +00:00
Dave Hrycyszyn 372d21f44e commands: grouping into a subdirectory and cleaning up execution 2019-12-11 00:57:01 +00:00
Dave Hrycyszyn 1b70bd4d5a main: extracting init and socket commands. 2019-12-11 00:51:14 +00:00
Dave Hrycyszyn 5948725502 main: extracting the run command into its own module 2019-12-11 00:46:09 +00:00
Dave Hrycyszyn 2e55719a8a DirectoryClient cleanup 2019-12-11 00:34:54 +00:00
Dave Hrycyszyn e1f5de6cb7 Tightening up path usage in requests 2019-12-11 00:34:34 +00:00
Dave Hrycyszyn 48501b9305 Cleaning up junk methods in directory mod 2019-12-11 00:34:03 +00:00
Dave Hrycyszyn 44089ed558 Re-enabling directory requests in run 2019-12-11 00:33:27 +00:00
Dave Hrycyszyn 04612ca98b Ensuring that we can use the full glory of the topology fixture 2019-12-10 19:31:03 +00:00
Dave Hrycyszyn 61c8ed9c2e directory: checking that topology is returned with data 2019-12-10 19:28:15 +00:00
Dave Hrycyszyn 8f2d5f970a directory: adding path to request fields 2019-12-10 19:27:56 +00:00
Dave Hrycyszyn d814a3c41a directory: further tests on topology get request 2019-12-10 19:16:48 +00:00
Dave Hrycyszyn 492da93727 Adding serde_json, mostly for testing purposes 2019-12-10 19:06:38 +00:00
Dave Hrycyszyn c8c178c7e7 Fixing compiler warning 2019-12-10 18:34:08 +00:00
Dave Hrycyszyn fc4e4168db WIP 2019-12-10 18:24:51 +00:00
Dave Hrycyszyn ce5af2bc04 directory: moving presence models 2019-12-10 18:02:07 +00:00
Dave Hrycyszyn 8056dd0fc0 directory: setting up all requests 2019-12-10 17:42:13 +00:00
Dave Hrycyszyn e8c96da9da Moving requests into their own directory 2019-12-10 17:39:05 +00:00
Dave Hrycyszyn 78d3cbbe2c directory: shortening healthcheck request names 2019-12-10 17:31:23 +00:00
Dave Hrycyszyn 3e7476092a directory: removing proxy method 2019-12-10 17:29:15 +00:00
Dave Hrycyszyn ed81b16010 directory: using stored requester instead of proxy method 2019-12-10 17:27:46 +00:00
Dave Hrycyszyn cd700a8760 Having the full reqwest response returned 2019-12-10 16:59:55 +00:00
Dave Hrycyszyn e3c94b6592 whitespace 2019-12-10 16:59:23 +00:00
Dave Hrycyszyn 63fa94394a Doing a healthcheck on the directory server before using it. 2019-12-10 16:54:37 +00:00
Dave Hrycyszyn e47914a392 directory: healthcheck requester now returns a Response<> 2019-12-10 16:54:00 +00:00
Dave Hrycyszyn af28289904 directory: starting to work out how to store request types 2019-12-10 16:12:11 +00:00
Dave Hrycyszyn a2a87d72be Feeding a config object to the directory client 2019-12-10 15:49:13 +00:00
Dave Hrycyszyn e06a6f66ed Tests running again 2019-12-10 15:43:47 +00:00
Dave Hrycyszyn 3fe8ef72a5 WIP: the healthcheck requests work, main construction doesn't yet 2019-12-10 15:30:40 +00:00
Dave Hrycyszyn 85d1759d92 Merge branch 'develop' into feature/directory-integration 2019-12-10 13:22:13 +00:00
Dave Hrycyszyn b1d650c76d WIP 2019-12-09 17:59:54 +00:00
Dave Hrycyszyn 245c0baf4c Merge pull request #10 from nymtech/feature/command_line_arguments
Argument parsing
2019-12-09 12:35:11 +00:00
Jedrzej Stuczynski f92e211960 Argument parsing 2019-12-09 12:33:06 +00:00
Jedrzej Stuczynski 94231356d1 slightly increased default interval 2019-12-09 10:47:04 +00:00
Dave Hrycyszyn 5baa822eeb Removing dead comment 2019-12-02 21:23:19 +00:00
Dave Hrycyszyn bea04cf738 Sending continuous stream of packets in a loop. 2019-12-02 13:50:57 +00:00
Dave Hrycyszyn 92eb260313 Updating to work with constant sized packets 2019-11-29 15:55:06 +00:00
Dave Hrycyszyn 8ee4bd0fb9 Banging things around to get a duct-taped version working end-to-end 2019-11-29 12:30:03 +00:00
Dave Hrycyszyn 98ab153978 Sending packet :) 2019-11-28 19:32:32 +00:00
Dave Hrycyszyn fb7db57c5e Added tokio 2019-11-28 19:32:18 +00:00
Dave Hrycyszyn 9d85699ed7 Moved subclients into their own directory 2019-11-28 19:32:09 +00:00
Dave Hrycyszyn 4a95eb6b4b Started to sketch out the main client types. 2019-11-25 17:44:18 +00:00
Dave Hrycyszyn 29caeb04bb Started a readme 2019-11-25 17:44:02 +00:00
Dave Hrycyszyn 579a7df605 Goofing around with main() 2019-11-25 17:43:53 +00:00
Dave Hrycyszyn f4cba052b5 Adding local Sphinx as a dependency 2019-11-25 17:43:32 +00:00
Dave Hrycyszyn 3c64a2facd Initial commit 2019-11-25 15:42:31 +00:00
49 changed files with 3032 additions and 606 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
.idea
/target
**/*.rs.bk
/.idea/
+12
View File
@@ -0,0 +1,12 @@
# nym-client Changelog
* removed the `--local` flag
* introduced `--directory` argument to support arbitrary directory servers. Leaving it out will point the node at the "https://directory.nymtech.net" alpha testnet server
* IPv6 support
* client version number is now shown at node start
* directory server location is now shown at node start
* decrease default delays
## 0.1.0 - Initial Release
* The bare minimum set of features required by a Nym Client
Generated
+201 -64
View File
@@ -67,12 +67,21 @@ name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "assert-json-diff"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -88,7 +97,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -97,8 +106,8 @@ name = "backtrace-sys"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -167,6 +176,17 @@ dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "built"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
@@ -202,8 +222,12 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.47"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
@@ -219,6 +243,16 @@ dependencies = [
"keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.33.0"
@@ -238,7 +272,7 @@ name = "clear_on_drop"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -249,6 +283,16 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "colored"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.4"
@@ -286,7 +330,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -381,6 +425,11 @@ dependencies = [
"subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "digest"
version = "0.8.1"
@@ -404,7 +453,7 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -451,7 +500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -467,7 +516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -573,7 +622,7 @@ dependencies = [
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -618,10 +667,22 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "git2"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "h2"
version = "0.1.26"
@@ -644,7 +705,7 @@ name = "hermit-abi"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -778,7 +839,7 @@ name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -786,6 +847,16 @@ name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jobserver"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@@ -807,9 +878,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.65"
version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libgit2-sys"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libz-sys"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lioness"
version = "0.1.2"
@@ -892,7 +985,7 @@ dependencies = [
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -917,7 +1010,7 @@ version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -941,13 +1034,30 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mockito"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"assert-json-diff 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "native-tls"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -964,55 +1074,61 @@ version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nym-client"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"built 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mockito 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pem 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"sfw-provider-requests 0.1.0",
"sphinx 0.1.0",
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tungstenite 0.10.0 (git+https://github.com/dbcfd/tokio-tungstenite?rev=6dc2018cbfe8fe7ddd75ff977343086503135b38)",
"tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nym-mixnode"
version = "0.1.0"
dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nym-client 0.1.0",
"sphinx 0.1.0",
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
@@ -1027,7 +1143,7 @@ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1042,8 +1158,8 @@ version = "0.9.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1065,7 +1181,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1107,7 +1223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1137,7 +1253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1179,7 +1295,7 @@ version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1197,7 +1313,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1279,7 +1395,7 @@ name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1291,7 +1407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1364,7 +1480,7 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.9.24"
version = "0.9.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1444,7 +1560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1484,7 +1600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1543,7 +1659,7 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1570,7 +1686,7 @@ version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1627,7 +1743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "1.0.8"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1642,7 +1758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1652,7 +1768,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1680,7 +1796,7 @@ name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1705,14 +1821,14 @@ dependencies = [
[[package]]
name = "tokio"
version = "0.2.1"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1769,7 +1885,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1847,10 +1963,18 @@ dependencies = [
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "try-lock"
version = "0.2.2"
@@ -2046,6 +2170,7 @@ dependencies = [
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
"checksum assert-json-diff 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9881d306dee755eccf052d652b774a6b2861e86b4772f555262130e58e4f81d2"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
@@ -2058,17 +2183,20 @@ dependencies = [
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
"checksum built 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2315cfb416f86e05360edc950b1d7d25ecfb00f7f8eba60dbd7882a0f2e944"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum bytes 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c85319f157e4e26c703678e68e26ab71a46c0199286fa670b21cc9fec13d895"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8"
"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862"
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5"
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
@@ -2083,6 +2211,7 @@ dependencies = [
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736"
"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
@@ -2113,6 +2242,7 @@ dependencies = [
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c1af51ea8a906616af45a4ce78eacf25860f7a13ae7bf8a814693f0f4037a26"
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
@@ -2129,10 +2259,13 @@ dependencies = [
"checksum input_buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e1b822cc844905551931d6f81608ed5f50a79c1078a4e2b4d42dbc7c1eedfbf"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum keystream 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum libgit2-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4870c781f6063efb83150cd22c1ddf6ecf58531419e7570cdcced46970f64a16"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum lioness 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9"
"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
@@ -2148,8 +2281,11 @@ dependencies = [
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
"checksum mockito 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e524e85ea7c80559354217a6470c14abc2411802a9996aed1821559b9e28e3c"
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585"
@@ -2192,7 +2328,7 @@ dependencies = [
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab"
"checksum reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
@@ -2219,14 +2355,14 @@ dependencies = [
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941"
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
"checksum tokio 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "beeef686ef92a222de07e089f455d9f8478bbba9651718f9e4b276babe829082"
"checksum tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bcced6bb623d4bff3739c176c415f13c418f426395c169c9c3cd9a492c715b16"
"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
"checksum tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ca6df436c42b0c3330a82d855d2ef017cd793090ad550a6bc2184f4b933532ab"
@@ -2238,6 +2374,7 @@ dependencies = [
"checksum tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c32ffea4827978e9aa392d2f743d973c1dfa3730a2ed3f22ce1e6984da848c"
"checksum tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1739638e364e558128461fc1ad84d997702c8e31c2e6b18fb99842268199e827"
"checksum tokio-tungstenite 0.10.0 (git+https://github.com/dbcfd/tokio-tungstenite?rev=6dc2018cbfe8fe7ddd75ff977343086503135b38)" = "<none>"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
"checksum tungstenite 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0c2bd5aeb7dcd2bb32e472c8872759308495e5eccc942e929a513cd8d36110"
+27 -4
View File
@@ -1,16 +1,39 @@
[package]
name = "nym-mixnode"
version = "0.1.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
build = "build.rs"
name = "nym-client"
version = "0.2.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2018"
[lib]
name = "nym_client"
path = "src/lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base64 = "0.11.0"
clap = "2.33.0"
curve25519-dalek = "1.2.3"
dirs = "2.0.2"
futures = "0.3.1"
nym-client = { path = "../nym-client" }
hex = "0.4.0"
pem = "0.7.0"
rand = "0.7.2"
rand_distr = "0.2.2"
reqwest = "0.9.22"
serde = { version = "1.0.104", features = ["derive"] }
serde_json = "1.0.44"
sphinx = { path = "../sphinx" }
sfw-provider-requests = { path = "../nym-sfw-provider/sfw-provider-requests" }
tokio = { version = "0.2", features = ["full"] }
tungstenite = "0.9.2"
# putting this explicitly below everything and most likely, the next time we look into it, it will already have a proper release
tokio-tungstenite = { git = "https://github.com/dbcfd/tokio-tungstenite", rev="6dc2018cbfe8fe7ddd75ff977343086503135b38" }
[build-dependencies]
built = "0.3.2"
[dev-dependencies]
mockito = "0.22.0"
+6 -15
View File
@@ -1,19 +1,10 @@
# Nym Mixnode
# Nym Client
A Rust mixnode implementation.
The Nym Client communicates with the remote, decentralised nodes which make up the Nym system as a whole.
## Building
It needs to handle communication with 3 types of remote nodes. Here's the development status of each:
* check out the code
* [install rust](https://www.rust-lang.org/tools/install) (stable)
* `cargo build --release` (for a production build)
- [ ] Directory nodes
- [ ] Mix nodes
- [ ] Validator nodes
The built binary can be found at `target/release/nym-mixnode`
## Usage
* `nym-mixnode` prints a help message showing usage options
* `nym-mixnode run --help` prints a help message showing usage options for the run command
* `nym-mixnode run --layer 1` will start the mixnode in layer 1 (coordinate with other people to find out which layer you need to start yours in)
By default, the Nym Mixnode will start on port 1789. If desired, you can change the port using the `--port` option.
+5
View File
@@ -0,0 +1,5 @@
use built;
fn main() {
built::write_built_file().expect("Failed to acquire build-time information");
}
+19
View File
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersistedMixMetric {
pub pub_key: String,
pub received: u64,
pub sent: HashMap<String, u64>,
pub timestamp: u64,
}
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MixMetric {
pub pub_key: String,
pub received: u64,
pub sent: HashMap<String, u64>,
}
+68
View File
@@ -0,0 +1,68 @@
use crate::clients::directory::requests::health_check_get::{
HealthCheckRequester, Request as HealthCheckRequest,
};
use crate::clients::directory::requests::metrics_mixes_get::{
MetricsMixRequester, Request as MetricsMixRequest,
};
use crate::clients::directory::requests::metrics_mixes_post::{
MetricsMixPoster, Request as MetricsMixPost,
};
use crate::clients::directory::requests::presence_coconodes_post::{
PresenceCocoNodesPoster, Request as PresenceCocoNodesPost,
};
use crate::clients::directory::requests::presence_mixnodes_post::{
PresenceMixNodesPoster, Request as PresenceMixNodesPost,
};
use crate::clients::directory::requests::presence_providers_post::{
PresenceMixProviderPoster, Request as PresenceProvidersPost,
};
use crate::clients::directory::requests::presence_topology_get::{
PresenceTopologyGetRequester, Request as PresenceTopologyRequest,
};
pub mod metrics;
pub mod presence;
pub mod requests;
pub struct Config {
pub base_url: String,
}
pub trait DirectoryClient {
fn new(config: Config) -> Self;
}
pub struct Client {
pub health_check: HealthCheckRequest,
pub metrics_mixes: MetricsMixRequest,
pub metrics_post: MetricsMixPost,
pub presence_coconodes_post: PresenceCocoNodesPost,
pub presence_mix_nodes_post: PresenceMixNodesPost,
pub presence_providers_post: PresenceProvidersPost,
pub presence_topology: PresenceTopologyRequest,
}
impl DirectoryClient for Client {
fn new(config: Config) -> Client {
let health_check: HealthCheckRequest = HealthCheckRequest::new(config.base_url.clone());
let metrics_mixes: MetricsMixRequest = MetricsMixRequest::new(config.base_url.clone());
let metrics_post: MetricsMixPost = MetricsMixPost::new(config.base_url.clone());
let presence_topology: PresenceTopologyRequest =
PresenceTopologyRequest::new(config.base_url.clone());
let presence_coconodes_post: PresenceCocoNodesPost =
PresenceCocoNodesPost::new(config.base_url.clone());
let presence_mix_nodes_post: PresenceMixNodesPost =
PresenceMixNodesPost::new(config.base_url.clone());
let presence_providers_post: PresenceProvidersPost =
PresenceProvidersPost::new(config.base_url.clone());
Client {
health_check,
metrics_mixes,
metrics_post,
presence_coconodes_post,
presence_mix_nodes_post,
presence_providers_post,
presence_topology,
}
}
}
+41
View File
@@ -0,0 +1,41 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CocoPresence {
pub host: String,
pub pub_key: String,
pub last_seen: i64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MixNodePresence {
pub host: String,
pub pub_key: String,
pub layer: u64,
pub last_seen: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MixProviderPresence {
pub host: String,
pub pub_key: String,
pub registered_clients: Vec<MixProviderClient>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MixProviderClient {
pub pub_key: String,
}
// Topology shows us the current state of the overall Nym network
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Topology {
pub coco_nodes: Vec<CocoPresence>,
pub mix_nodes: Vec<MixNodePresence>,
pub mix_provider_nodes: Vec<MixProviderPresence>,
}
@@ -0,0 +1,60 @@
use reqwest::Response;
pub struct Request {
base_url: String,
path: String,
}
pub trait HealthCheckRequester {
fn new(base_url: String) -> Self;
fn get(&self) -> Result<Response, reqwest::Error>;
}
impl HealthCheckRequester for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/healthcheck".to_string(),
}
}
fn get(&self) -> Result<Response, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
reqwest::get(&url)
}
}
#[cfg(test)]
mod healthcheck_requests {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
#[should_panic]
fn it_returns_an_error() {
let _m = mock("GET", "/api/healthcheck").with_status(400).create();
let req = Request::new(mockito::server_url());
assert!(req.get().is_err());
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_200_status() {
let _m = mock("GET", "/api/healthcheck").with_status(200).create();
let req = Request::new(mockito::server_url());
assert!(req.get().is_ok());
_m.assert();
}
}
}
@@ -0,0 +1,239 @@
use crate::clients::directory::metrics::PersistedMixMetric;
pub struct Request {
base_url: String,
path: String,
}
pub trait MetricsMixRequester {
fn new(base_url: String) -> Self;
fn get(&self) -> Result<Vec<PersistedMixMetric>, reqwest::Error>;
}
impl MetricsMixRequester for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/metrics/mixes".to_string(),
}
}
fn get(&self) -> Result<Vec<PersistedMixMetric>, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let mix_metric_vec = reqwest::get(&url)?.json()?;
Ok(mix_metric_vec)
}
}
#[cfg(test)]
mod metrics_get_request {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
#[should_panic]
fn it_returns_an_error() {
let _m = mock("GET", "/api/metrics/mixes").with_status(400).create();
let req = Request::new(mockito::server_url());
req.get().unwrap();
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_200_status_and_a_correct_topology() {
let json = fixtures::mix_metrics_response_json();
let _m = mock("GET", "/api/metrics/mixes")
.with_status(200)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let result = req.get();
assert_eq!(true, result.is_ok());
assert_eq!(
1576061080635800000,
result.unwrap().first().unwrap().timestamp
);
_m.assert();
}
}
#[cfg(test)]
mod fixtures {
#[cfg(test)]
pub fn mix_metrics_response_json() -> String {
r#"[
{
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
"sent": {
"35.178.213.77:1789": 1,
"52.56.99.196:1789": 2
},
"received": 10,
"timestamp": 1576061080635800000
},
{
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
"sent": {
"3.8.176.11:1789": 2,
"35.178.212.193:1789": 2
},
"received": 4,
"timestamp": 1576061080806225700
},
{
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
"sent": {
"3.9.12.238:1789": 3
},
"received": 3,
"timestamp": 1576061080894667300
},
{
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
"sent": {
"3.9.12.238:1789": 5,
"35.176.155.107:1789": 3
},
"received": 8,
"timestamp": 1576061081254846500
},
{
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
"sent": {
"35.178.213.77:1789": 4,
"52.56.99.196:1789": 6
},
"received": 19,
"timestamp": 1576061081371549000
},
{
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
"sent": {
"3.8.176.11:1789": 4,
"35.178.212.193:1789": 2
},
"received": 6,
"timestamp": 1576061081498404900
},
{
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
"sent": {
"35.178.213.77:1789": 2,
"52.56.99.196:1789": 3
},
"received": 6,
"timestamp": 1576061081637625000
},
{
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
"sent": {
"3.8.176.11:1789": 5,
"35.178.212.193:1789": 4
},
"received": 9,
"timestamp": 1576061081805484800
},
{
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
"sent": {
"3.9.12.238:1789": 4,
"35.176.155.107:1789": 4
},
"received": 8,
"timestamp": 1576061081896562400
},
{
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
"sent": {
"3.9.12.238:1789": 2,
"35.176.155.107:1789": 4
},
"received": 6,
"timestamp": 1576061079255938600
},
{
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
"sent": {
"35.178.213.77:1789": 6
},
"received": 10,
"timestamp": 1576061079370829300
},
{
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
"sent": {
"3.8.176.11:1789": 2,
"35.178.212.193:1789": 5
},
"received": 7,
"timestamp": 1576061079497993200
},
{
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
"sent": {
"35.178.213.77:1789": 5,
"52.56.99.196:1789": 2
},
"received": 13,
"timestamp": 1576061079637208600
},
{
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
"sent": {
"3.8.176.11:1789": 5,
"35.178.212.193:1789": 4
},
"received": 9,
"timestamp": 1576061079806557200
},
{
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
"sent": {
"3.9.12.238:1789": 2,
"35.176.155.107:1789": 7
},
"received": 9,
"timestamp": 1576061079895988000
},
{
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
"sent": {
"3.9.12.238:1789": 3,
"35.176.155.107:1789": 2
},
"received": 5,
"timestamp": 1576061080255701500
},
{
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
"sent": {
"35.178.213.77:1789": 3,
"52.56.99.196:1789": 3
},
"received": 7,
"timestamp": 1576061080370956300
},
{
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
"sent": {
"3.8.176.11:1789": 5,
"35.178.212.193:1789": 1
},
"received": 6,
"timestamp": 1576061080501732900
}
]"#
.to_string()
}
}
}
@@ -0,0 +1,98 @@
use crate::clients::directory::metrics::MixMetric;
use reqwest::Response;
pub struct Request {
base_url: String,
path: String,
}
pub trait MetricsMixPoster {
fn new(base_url: String) -> Self;
fn post(&self, metric: &MixMetric) -> Result<Response, reqwest::Error>;
}
impl MetricsMixPoster for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/metrics/mixes".to_string(),
}
}
fn post(&self, metric: &MixMetric) -> Result<Response, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let client = reqwest::Client::new();
let mix_metric_vec = client.post(&url).json(&metric).send()?;
Ok(mix_metric_vec)
}
}
#[cfg(test)]
mod metrics_get_request {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
fn it_returns_an_error() {
let _m = mock("POST", "/api/metrics/mixes").with_status(400).create();
let req = Request::new(mockito::server_url());
let metric = fixtures::new_metric();
let result = req.post(&metric);
assert_eq!(400, result.unwrap().status());
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_200() {
let json = fixtures::mix_metrics_response_json();
let _m = mock("POST", "/api/metrics/mixes")
.with_status(201)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let metric = fixtures::new_metric();
let result = req.post(&metric);
assert_eq!(true, result.is_ok());
_m.assert();
}
}
#[cfg(test)]
mod fixtures {
use crate::clients::directory::metrics::MixMetric;
pub fn new_metric() -> MixMetric {
MixMetric {
pub_key: "abc".to_string(),
received: 666,
sent: Default::default(),
}
}
#[cfg(test)]
pub fn mix_metrics_response_json() -> String {
r#"
{
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
"sent": {
"35.178.213.77:1789": 1,
"52.56.99.196:1789": 2
},
"received": 10,
"timestamp": 1576061080635800000
}
"#
.to_string()
}
}
}
+7
View File
@@ -0,0 +1,7 @@
pub mod health_check_get;
pub mod metrics_mixes_get;
pub mod metrics_mixes_post;
pub mod presence_coconodes_post;
pub mod presence_mixnodes_post;
pub mod presence_providers_post;
pub mod presence_topology_get;
@@ -0,0 +1,86 @@
use crate::clients::directory::presence::CocoPresence;
use reqwest::Response;
pub struct Request {
base_url: String,
path: String,
}
pub trait PresenceCocoNodesPoster {
fn new(base_url: String) -> Self;
fn post(&self, presence: &CocoPresence) -> Result<Response, reqwest::Error>;
}
impl PresenceCocoNodesPoster for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/presence/coconodes".to_string(),
}
}
fn post(&self, presence: &CocoPresence) -> Result<Response, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let client = reqwest::Client::new();
let p = client.post(&url).json(&presence).send()?;
Ok(p)
}
}
#[cfg(test)]
mod metrics_get_request {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
fn it_returns_an_error() {
let _m = mock("POST", "/api/presence/coconodes")
.with_status(400)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(400, result.unwrap().status());
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_201() {
let json = r#"{
"ok": true
}"#;
let _m = mock("POST", "/api/presence/coconodes")
.with_status(201)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(true, result.is_ok());
_m.assert();
}
}
#[cfg(test)]
mod fixtures {
use crate::clients::directory::presence::CocoPresence;
pub fn new_presence() -> CocoPresence {
CocoPresence {
host: "foo.com".to_string(),
pub_key: "abc".to_string(),
last_seen: 666,
}
}
}
}
@@ -0,0 +1,87 @@
use crate::clients::directory::presence::MixNodePresence;
use reqwest::Response;
pub struct Request {
base_url: String,
path: String,
}
pub trait PresenceMixNodesPoster {
fn new(base_url: String) -> Self;
fn post(&self, presence: &MixNodePresence) -> Result<Response, reqwest::Error>;
}
impl PresenceMixNodesPoster for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/presence/mixnodes".to_string(),
}
}
fn post(&self, presence: &MixNodePresence) -> Result<Response, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let client = reqwest::Client::new();
let p = client.post(&url).json(&presence).send()?;
Ok(p)
}
}
#[cfg(test)]
mod metrics_get_request {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
fn it_returns_an_error() {
let _m = mock("POST", "/api/presence/mixnodes")
.with_status(400)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(400, result.unwrap().status());
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_201() {
let json = r#"{
"ok": true
}"#;
let _m = mock("POST", "/api/presence/mixnodes")
.with_status(201)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(true, result.is_ok());
_m.assert();
}
}
#[cfg(test)]
mod fixtures {
use crate::clients::directory::presence::MixNodePresence;
pub fn new_presence() -> MixNodePresence {
MixNodePresence {
host: "foo.com".to_string(),
pub_key: "abc".to_string(),
layer: 1,
last_seen: 0,
}
}
}
}
@@ -0,0 +1,85 @@
use crate::clients::directory::presence::MixProviderPresence;
use reqwest::Response;
pub struct Request {
base_url: String,
path: String,
}
pub trait PresenceMixProviderPoster {
fn new(base_url: String) -> Self;
fn post(&self, presence: &MixProviderPresence) -> Result<Response, reqwest::Error>;
}
impl PresenceMixProviderPoster for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/presence/mixproviders".to_string(),
}
}
fn post(&self, presence: &MixProviderPresence) -> Result<Response, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let client = reqwest::Client::new();
let p = client.post(&url).json(&presence).send()?;
Ok(p)
}
}
#[cfg(test)]
mod metrics_get_request {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
fn it_returns_an_error() {
let _m = mock("POST", "/api/presence/mixproviders")
.with_status(400)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(400, result.unwrap().status());
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_201() {
let json = r#"{
"ok": true
}"#;
let _m = mock("POST", "/api/presence/mixproviders")
.with_status(201)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let presence = fixtures::new_presence();
let result = req.post(&presence);
assert_eq!(true, result.is_ok());
_m.assert();
}
}
#[cfg(test)]
mod fixtures {
use crate::clients::directory::presence::MixProviderPresence;
pub fn new_presence() -> MixProviderPresence {
MixProviderPresence {
host: "foo.com".to_string(),
pub_key: "abc".to_string(),
registered_clients: vec![],
}
}
}
}
@@ -0,0 +1,306 @@
use crate::clients::directory::presence::Topology;
pub struct Request {
base_url: String,
path: String,
}
pub trait PresenceTopologyGetRequester {
fn new(base_url: String) -> Self;
fn get(&self) -> Result<Topology, reqwest::Error>;
}
impl PresenceTopologyGetRequester for Request {
fn new(base_url: String) -> Self {
Request {
base_url,
path: "/api/presence/topology".to_string(),
}
}
fn get(&self) -> Result<Topology, reqwest::Error> {
let url = format!("{}{}", self.base_url, self.path);
let topology: Topology = reqwest::get(&url)?.json()?;
Ok(topology)
}
}
#[cfg(test)]
mod topology_requests {
use super::*;
#[cfg(test)]
use mockito::mock;
#[cfg(test)]
mod on_a_400_status {
use super::*;
#[test]
#[should_panic]
fn it_panics() {
let _m = mock("GET", "/api/presence/topology")
.with_status(400)
.with_body("bad body")
.create();
let req = Request::new(mockito::server_url());
req.get().unwrap();
_m.assert();
}
}
#[cfg(test)]
mod on_a_200 {
use super::*;
#[test]
fn it_returns_a_response_with_200_status_and_a_correct_topology() {
let json = fixtures::topology_response_json();
let _m = mock("GET", "/api/presence/topology")
.with_status(200)
.with_body(json)
.create();
let req = Request::new(mockito::server_url());
let result = req.get();
assert_eq!(true, result.is_ok());
assert_eq!(
1575915097085539300,
result.unwrap().coco_nodes.first().unwrap().last_seen
);
_m.assert();
}
}
#[cfg(test)]
pub mod fixtures {
#[cfg(test)]
pub fn topology_response_json() -> String {
r#"{
"cocoNodes": [
{
"host": "3.8.244.109:4000",
"pubKey": "AAAAAAAAAAEKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEFuhRpy4HfcuxwcRI9sIWMo_LVmbk19g1gfMRlBrmZqoEQL6rDApVLZ9eMp-5IQK8WLlZpWf4Zjy7kZolARAyp_rHUQkH4PrDjgoPrKbm6qK_iejYpL7qx28Q3VeInMpwMIMaSbbW9y36sEVtGc2I0Iu5vS0sp8ESiVlQ5NaBz72deZ8oKJJ4IEPPHP99-b0UQX80fVIrNM88mMzKy0bHri9NFlmIG-e0G1cqmw_ry3XWGQkcr1M5RuNa6oX50w5QawAEVxd5FP5bE8bS4x54Csof11sQWUTwMp6Q7_3H7ZCTSlKSqujlOhmfqSHfGPO2sDIYPHDhDzjakZpKAZWWhn_hiR6DfPpomQ01ZYUhVKKSMxz7_VPjsQplP0bZXA2gfnkADUN8UQ0N9g_usIw73r4aZsOviMsRM8oByvsjVfUWc4_HTLSdnQyImFkHz9CiCmrIYL2dYQRePRatWggvBAyeRzntxI4jDqLKiBdi54ZlAKgV6MCRaJ7Bu7BtmLXrtK4sawAED3QYxuvOSZrbZdUr4yG-U9yVvJ9Klkf-5Mo4EYp3qTL2KBB6_LrZepjAQqp486YkZ03mTIezcsZ48EboXVTWKBZ3QnTI5tX-j4gGxQb7klOJc97qJkDxsvpz4F0ChgCUIZhpIItWHia7_R3Gi-b5siLIdQdUho9isn3kiDGm6t0NED2Bgy3ZxxQwzqsBZm4kPr2_fPX4YyvIoP9895YcGjZyE5iiRC_TE41RJmB1GZYdxegTMq3lNDllKgiqaiPgawAEJASDkmZHTwlg9YOev5OWpQD-FnhPkqVNo_QcDyRu9eoGcWSGFp2sYqjG2SpmiXq0VNnAO7AcKxRzDFu7TjfhlU3Kt0uTKIcrWVU1zFNbJNMjYEq90pp50nowwx8INz20IXET2ZNX6kIXYFCsEvPLZFlG2OoL6xg3uQS1qMl3lIS_VxdO_JfVe0rT65WsJ_P4Nkc1jYiuNPHY6d_iFO0BVYqX0sOCX73GC_TT13BR0jnPwDAVw0rGtYHsXBb8TKOsawAEZIClauuT1V3qOZnb7uRZhFXO-PKTxgc1LCzJt2ChOrMZaBpjlkf3IPpJ2UF4JH4kGaDeBf2k_S-FLAs3drK21efbi5P6_a4QTxAiiRimXGoQIyvOg462s6kP_ZRFufo8YYQHS4olaOeqU4564dNskg_uBPsFMz_2GNOhmn_15cJqP1jfkyD49Z16GTS5YLHgVl9bJKqyvLuypsToLbt1BJzipEP0L2OohuRm-_MvqvwwWKyjNQsubgee1K728d9AawAEBkGggcNVCtXyhoSqi3_w0tVxtkAYeud8sBeAtZHGs06me_QL8co0MFLlO-zdkUb4ZBq08rFEbgLOma8_3whleM8NIPaHNISp1q3IsIhB5zdXcZoGsqLixODBFHtID3YEHAlr4f9T_yh11yJ95xGCl_6Y37hpwLQVGyrfSfccM24mVFqnV3TT5Wdq3ile-jesUx1Q2G1yK_xVqc6itmk-kDuBjyZgzYi1-jsIXAjnhM9G7t8J_Bv5yGGZhLK2dCzM=",
"type": "validator",
"lastSeen": 1575915097085539300
},
{
"host": "3.9.129.61:4000",
"pubKey": "AAAAAAAAAAMKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEEv6RMevAQmLGkeK0uJKnMPPAtm8GgXjWSQijYdnxlPh5SJSNeJUbPZKWFFWdk8yIFXKa8jnzETtdGFKgUUt5AVUDpTBmEdwaHCzlFhXrttshy0V5OhPUlV8cGABmxbagMYm0bFPg0r-snSkrB9YG6wqJYQVeIMOCGYCPbHmDA8R_0-h8VkRKWs1d9KvQOK4kShqgZtYN71KJW8uDE4q2jsGDVvxFt1AgmU9b93xsXF17KrpZy5WxlLZ73HtnTD_oawAED4vd_rK-Kx_n8x_OdDiiEOPUlYDlDCQUqenU9XHKH3B6ijfkJ368wd3LDDVStjDwNORrAyUSw_VlSNUpd1XLC8d17gTaIq5ZI2fWuwwZaoN1JCsYU8fQ6USgtIehQX7IPP8EkFuNmuCBCmpr4schtYniGe9J8Q4dsV-TYPr2uLJkdx1r7luzF--I22k7NfQQM14QDci_0kgrgmZ54CJGkjXyOhCppBXg3fqLC6aFvT3ZocfiiXBJt0huGgPMDtYsawAECLh8KUdNsDolERwJ8v04bS5jI_KKf7uUnCHWuCELwbJSUI3OK1ufS1qSpauvSzVQSbrhEzrEfwQn4VtxQxJlX4UdDU-R-hafiZvVC6DLLAbuORBAC3FScn9W58CnezH4DvCp_w7nftDfdxeuungbZT9XaxS3iNC6PnFsWF6WM3DxMwrzOrFe6wEEoTSPe1mcUDrtwM5UksIvJr6MBRAXrdl0IdBTQr7cLwKe_KYi4siwdjfJEJtOh7oxQBxBg2UkawAEJAPZK2Gg2MQwpxdDT24lNQHF7FVfkO_LuhJwn0RbwNDSVeA4P6-tWL5TkCpqr8xYHfwQ6Z3ILfpGCZr8PspwIoRzqZHQ16f8Pq9xnr0hLEI9BOQU0FS2EtuyPgju5iwsAJAfehUzu6kNLphuLGsXoIZdXDG5mbylwh9JzAVXTwgaR0hNqyXVJxgbt7jcYaSEBFcMGV-hjXyVVNzBleE-G9o_noI_KWU4Ce7K-qOMcewMKfy_VEw-gVaD6dHz6AMoawAEE9XuOLwRttvKybAssZ9gsK-_YRUwuFOeRDIr3NX___9bx6pCc18adCIlH_8EJWFwXZ05ZpNNE88mYx7ZQ3aqaArZJRoWeZeKhqH_s05V10xbzkYX71G5cqz--8vr9ZlQRb2BeETF_Tdq_PLk7qbT8WTGIoq7ZwyDRQTgzvkCgyzj_hBLh2o7sSVNgUo38SFUTMn7YtvVFYlSrTDE3WKE-T-nh5SWdDBxgDTc3Bw8JpzNH-WkoJ4Lim7sB4Op1gEUawAEW4-kenlffwsNr_3b3aV0YuusLpxB03sxPzQ5B0CWNiVtbja1Z4tWhKGUUrdq_eUgMV0y5Of-BqNi5FspAQnhJBFSSxtOzRGV1h3qyUTksfZyed9z8zPI-ZPP9XXm7hYgJgDz_kxte-NfS9UG9q5AZetHUN4kGxXutjjzfUQZ9yTvhBKgKgTI2Dp_R_jZrWQ8F1BoWzIJzjddT1K2MvCQEkARYw08isbOeFmCwgVUcjxYZO45WyOmLQA7QJRL9WvA=",
"type": "validator",
"lastSeen": 1575915097388409000
},
{
"host": "3.9.222.1:4000",
"pubKey": "AAAAAAAAAAQKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAECh9xcxpjOp1r7kiNIgrI9GgAlvXwgHkTchOxUiyOzTq6FDWdGN64KiC3NDeyGTg8FmzvGzS3jREeJqOdr4G9ZGtWkauAITgLFiH62t-YntRslhr8_1shxlmzKiNKJN_QFflEq79pZIlWtp3N8LIHMvXRtl-zt2DMze4s02XDmEkviyVE4CkQUDtCc-2MfPT4JcmEFqtFIxjrXn18SbYg3c6XUQHsGIkuDrKuCTRlpC8kvmM0uVoIeWdmwDlZk4jUawAEJhRwK5ozjqIWRP1bFzBPS9VhaJnfKU9PeFYtN5beiAHrYr2ylIB3yDfmAQUdKDowDUm5nfJATejEjEnrTGxh70QtfoNV391rSns3F71tBwY62KLaNr8qnVfeSFHV3FcQTMHHF_8mDb5_11Rj6aiMvW0y6eetHo7CDPMdEyDPmok_U2ZM5BzOUnwjT21HtnvcKxKKwHJ_QGfnAHPyDIhNOMgxJCrVazOidLCHeYGpyCLw1ipeTyKOQX0_ByB8dH6AawAEGV1GuF5SSlT67B1ityPJK2ZwXjeeKB4gGdCG3qRtWxLTZfGhVm7YAYm2f5tw_wrsJAZ9FubVhateGg0ZN67NxZtsvOOejXz6743f7ijnQopPgd_8pH-iVf6BEcSO8ZdcHxNRUTayzjVLs99bwMo2zaPevW4X4G_bN4mh---aPkdGYHwaiklzUhqJ-eqycrYAFyjyEXaPBXLQm1rpczqluNvnKbd8Q9LZWukgm7_uWv_HxufIvdWgoq8bAt78UU3oawAEP9VDehhqrQG5-WHMB66XVxo1TgMM8aVV0SwAq3lCRkpiFBz_9kw8T1F9Hx2AiNrEGT1QLbdMkpms1cG_5gBBahQofdt_NmUs1jfTFXY9iyMy1Q7A6ZYaLP8Z6q-orc1cKqySY-BJZQ_CpGFfXS0OVniFDQ6v78ytPK7K-yRgT1PxFgm3rZqrG0Tjbrpsg2PUL5S5fuXfMhUosP0uoLj0D1guWAR9Y7kfFBIXaTSFMoa8fghVBUTRNhK9f72a8SxQawAEOiv71taLjKqaaWQ_QjcDhWbvjG1EnsCyI0toNjGkcF19x4Vk-5NC96_4ioUGz404IC0XN03roRnibRT_78D9vZFVCWCqve9EjdF5TcApx03zIP4JT2g2q0MKIGgGrwt4Pz6LO6yOfMm7B8Yraps8IV-nP1w7K1m9XKP_FvH8egl5GHJe-_omlC2YyL_b28jMLENbxDFD-3KPjZFBhSLrRukX2PlayYTwEiTtokA2R9_11vQvJgP8KFEjGHg6zsAMawAEBn2H_hz2knb8ltnpEA5YSKVcV3nUtojkCNi_WUz7xUKd7efw1oI_lbnKrS7HkyC0JkQUZ1pCWUlSXNmgjMEhsn823a1LFzpV7rOv4vayYvvFX61hB9R78VjpyxJiYpDwRZLiUY3AK4WY8NqFDbjXR7rT4CkFHEf-VhSQQ8ZNvlpod1nmeVQVizHH9e7Tq7wsWz-LWEk3Hx6LmcrgDsL79LZYG9JXU5IdvG8RvLNx9cSwEI8yxcchpISAaot7UoYQ=",
"type": "validator",
"lastSeen": 1575915094734973000
},
{
"host": "3.9.102.214:4000",
"pubKey": "AAAAAAAAAAIKwAECSqKy8I8KkSYIBSctxRBRxuR61PpAOwK0UQtkeuPRdwusAyaoBbvv1IBWyMEhvbgT4CtgUnGfYH2s06CIJ09lWWvQ0Jkgthq12mG73H9QSTNM8RITlF1X5ax9BV0EK34M5dUncn1uEYzJzcbaLjUarf2bqoy906dtQpppUWDRLJI6ycw7rKKJ4ZNUhgi4KAEGBsSgLqc0zDKs0rArwouZyz4ofoWnY68mdJKrVy6Zqz83DSdc7B2hqqkHX_Bfeb4SwAEOVCUN3EwiVroS5-TOq2o7hYSxphK9X0G23N-IBZ0Tr1Rl8XEiJ-OEy0rqnAKwmhAZJWnx3u8oXqbZtOWIZmzQSpcoxhgwfhdmTZJCqT2RVzZyeFItX4sVeilEP3z2xdsJs8-a1kg6UZnx1s1BNLBo7eZrreZygWojPCIDBn03fSAflXoVc5PpY2CGy5MA_IgWgSYBHDdoZEtigp_amjqK7Us44Db20XpLxMXfbahiqa7WKNnMgi6Ca2H67VtaaD8awAEF3zbE1nZRAa7a8vbU25c80YBYJBaW8P6FwXQI-K0Xk5MakwYeMMnIrm6w6IS_0XAO5YlD453GLqnxY8H1BEnRpfOnT7PE4el9mJ8MuYQMo6R2up0lGCmYM0YA9FORjroM3ng69SEPfJPCReG7LfJkERl_m2U403ertDRBYrlqCDagDfyI500srBcMrjSvV3oNouyyx3yZUrjLQfbHhDteQFsYdmakJs8Y-Q9-5MXCcrz6Qa4xwv522Euv0CCxkHcawAEYjfsU_zDhUZA1ey1aquWXlFOnx-iEALqxW1slDYHwQ1M2SILc-v_E6i1doa5e_bAZHVezBHFAlaNAVedNyHFFJxYAqAK3hbzbvl2glw3Q6h_rTXElymloqtaqVFIJ-oUWWOHsZBmu8EDA-HzvGCiBa_GbRaVfh2lE4ObeMXoJrEm_5dbxxeEic2l3IYeIz40N9ooQQOkQcOZdY4AXWYCavIAwWEJBjLtptJgCLu9a_zM1S5GsiyJHpdDs46WbP0EawAEWZ-95Sf0YAHujxRNLdXgpqe0ZF8loVwzZfvyMvqaxF1Ug274BqHuY_c5NdPAzuqoTwjfEn8NKEoaNqlumM75FUYbaTd7mXvk4WVYWjVnkO40dfQjRB7DYhvj0LBlbndAJ4wJIA2ilPYgjZsXVbNNh3e2j3u9eABd0VaFMbSb8Sz5_31r8HzoWmPJs3HiyuyANGFUA6CvAnMN6K3b-D8BhFZU_nPUTgu80o8_n6LQt-XWbaC_mTHzsnOjzBiPJxlYawAEW3bmOEtStH2T8q7vMkhchImp2-hg9MFYGBmEe9sSByTn3NUf8eksqXOC1dUjHkXoZm298FgUYLkNdnlxWpf993j5mEDoFxjcTB7scBD7k6nu6Nrs_wK0-seS8gsHrx9UK7GwAsi10q82Cm4PFyAtrWjmy_d9WLHuZt6VIOKunTs8cf0FwNUiMcvZsruqIFJcP7iWxdiFdUkh65P_iCz1ZEjJcj2GEZoq4v3a3by1aizGPaaiKc1jd_T-XJg_YpncawAEWnstu5b9WiZv0x8xfsiMk6YRlU0Cnj5svxLLXz_8drvwAa--GBY5yH0ke2EM6udMEi2EPeFcGTe6Sjs0YEhSbY7Uad_8suD2J4tIWJSWBbiyvh7rSqzv57m7BlsVcHfQJn_wNH-UlC9xkx8vg-LwfN8_FlxvHNPTc7XZG3lKYbwpUWlZxAziOYT1VQ-2K2bQQBBMdix-ht_SjccL1Dc2dP5kDazQ8yZV_8xnyeheazEedWe63uutfkHlZRg9YwP8=",
"type": "validator",
"lastSeen": 1575915094967382800
}
],
"mixNodes": [
{
"host": "35.176.155.107:1789",
"pubKey": "zSob16499jT7C3S3ky4GihNOjlU6aLfSRkf1xAxOwV0=",
"layer": 3,
"lastSeen": 1575915096805374500
},
{
"host": "18.130.86.190:1789",
"pubKey": "vCdpFc0NvW0NSqsuTxtjFtiSY35aXesgT3JNA8sSIXk=",
"layer": 1,
"lastSeen": 1575915097370376000
},
{
"host": "3.10.22.152:1789",
"pubKey": "OwOqwWjh_IlnaWS2PxO6odnhNahOYpRCkju50beQCTA=",
"layer": 1,
"lastSeen": 1575915097639423500
},
{
"host": "35.178.213.77:1789",
"pubKey": "nkkrUjgL8UJk05QydvWvFSvtRB6nmeV8RMvH5540J3s=",
"layer": 2,
"lastSeen": 1575915097895166500
},
{
"host": "52.56.99.196:1789",
"pubKey": "whHuBuEc6zyOZOquKbuATaH4Crml61V_3Y-MztpWhF4=",
"layer": 2,
"lastSeen": 1575915096255174700
},
{
"host": "3.9.12.238:1789",
"pubKey": "vk5Sr-Xyi0cTbugACv8U42ZJ6hs6cGDox0rpmXY94Fc=",
"layer": 3,
"lastSeen": 1575915096497827600
}
],
"mixProviderNodes": [
{
"host": "3.8.176.11:1789",
"pubKey": "54U6krAr-j9nQXFlsHk3io04_p0tctuqH71t7w_usgI=",
"registeredClients": [
{
"pubKey": "zOqdJFH49HcgGSCRnmbXGzovnwRLEPN0YGN1SCafTyo="
},
{
"pubKey": "fy9xo69hZ2UJ9uxhIS1YzKHZsH8saV-02AiyCNXPNUc="
},
{
"pubKey": "6hFCz42d5AODAoMXqcBWtoOoZh-7hPMDXbLKKhS7x3I="
},
{
"pubKey": "pPZMDzw0FyZ-LBAhwCvjlPGj1p2bO_vaWbRBc7Ojq3Q="
},
{
"pubKey": "kjl5poXt2GdIrHLuMBjmTBSChV-zMqsXFBhKZoIREVI="
},
{
"pubKey": "T1jMGuk7-rcIUWnVopAsdGzhAJ7ZVymwON2LzjuOfnY="
},
{
"pubKey": "3X0eKPkflx5Vzok0Gk0jm5-YEfvPAuWP55ovyBUOtXA="
},
{
"pubKey": "5wC3i8rCZolLKbWJ9U6eLieXNGLKM21dtL6lR30u_hE="
},
{
"pubKey": "1P6p7fgjwjlEepD9JgbN1V-rk9n36-hCmPN5P6y62n4="
},
{
"pubKey": "aBjlLQKKFroqhX_kvYLnMm1uq3FJdQWqVy9Q35zzERA="
},
{
"pubKey": "I0gVOPj6lv9ha60xPYKeAgbeUU8pdyMD-Y7Nb1nS9EQ="
},
{
"pubKey": "WgdvQ74QH1uFDWDL2YeApvv7oniNGh9BQJ_HZam20QA="
},
{
"pubKey": "Mlw23KaSL2hyrIjEZM76bZStt2iMzxVAqXwO5clJfxg="
},
{
"pubKey": "F9xzbjnMQVN4ZidcqN2ip9kVnI9wbS39aVayZGiMihY="
},
{
"pubKey": "s6pfVkZrUG--RNjfzS55N2oPvFkMdvgb1LUut6gqRy4="
},
{
"pubKey": "bSi-9k0jJNKc8PGx8M3SWFaNpORFjYw-NkWXRZVRWGU="
},
{
"pubKey": "pz6ahQcGOQcZBFx1tGmzRngqk6BecXB_wFd4WVdOQDU="
},
{
"pubKey": "5sfwIMcG2zRCxhDh4D9Evw1WPI5bfKZAShM_6o9Pu1I="
},
{
"pubKey": "9fZnxXy9onGPpZ3Ygckqw0okqCw3di02sLr-NTBr4SE="
},
{
"pubKey": "Q0TbbggOwzZjalUdi5eEHVFi9VMv-rMm5mJPUZZs12A="
},
{
"pubKey": "aPNyox_qAIGFB2-wZ0lc9iAWDN6jzLojApSiWVFjCks="
},
{
"pubKey": "DUKLEsIGMw-ucs3DjS7Ag9qCb5-C_A84DuIsZuLkdwI="
},
{
"pubKey": "YV84vPoSrLf1p9Sw6FnnrcCpS3kvpJUfKyKpnwk8z0Q="
},
{
"pubKey": "_IYEzZQoBAYeTxqzpEe_ez1-7pn7aId8AKliazy0qlE="
},
{
"pubKey": "srkOAoVU-a02lnEsoH_wOLLw7HFx_xHIZUSbnhjFwDw="
},
{
"pubKey": "LxSCBn_OEQq-hI2xDi6bfGoioRO_lSTIq6AQ9l1k5jg="
},
{
"pubKey": "OC0OOqtGfAytgZjthpjoKeYNa0VrtzfgZ0iO5Fag5y8="
},
{
"pubKey": "ImVEch2focRhm1ial1gA6YJPr6WDyW3oh-OgYcO5Ll4="
},
{
"pubKey": "yTDnzLvEaSq0mC9xNrtyjpAKtsIU6yRuBepCuWQMBm4="
},
{
"pubKey": "-LCUUc46HuL7iUEOMkrlVAkvvulRiQ7dR1QYh7bkKxw="
},
{
"pubKey": "Bx1MGpISig25rqe7mhoX68EROUPPzmF7yGLYah9DPgM="
},
{
"pubKey": "Z4Nu6iwLmgJ93yoIFTbTEBeDAHRwS-vo1T_K2Kv1FQo="
},
{
"pubKey": "cKFAGxllwAmEXCtDxG_T1iEm3-lKWUVQxxpDBje6mQU="
},
{
"pubKey": "pQV40whlQWUSXtrNTTePzO6sdq3zr1JUIWZWvD443nY="
},
{
"pubKey": "6Bb5HwnVqJPy5wcNsaHY-0y__coZCE7XC80kUkesnRU="
},
{
"pubKey": "COGdpfhmzNGR6YX820GqJIkjOihL8mr6-h-d3JlTDFA="
}
],
"lastSeen": 1575915097358694100
},
{
"host": "35.178.212.193:1789",
"pubKey": "sA-sxi038pEbGy4lgZWG-RdHHDkA6kZzu44G0LUxFSc=",
"registeredClients": [
{
"pubKey": "UE-7r6-bpw0b4T3GxOBVxlg02psx23DF2p5Tuf-OBSE="
},
{
"pubKey": "UnZuLpzq64_EPtIcr1Fd-5AESBCBLFnDMDsjUaOqrUA="
},
{
"pubKey": "4ExXPrW5w0nZIQ5ravBRT6H9r0RH0MXuOcGIF8HzUhg="
},
{
"pubKey": "wPsRpJPi1e2sjItyRKDkFACbxwu3Cw5GlYVPmdYxk2U="
},
{
"pubKey": "UfK5UvT3HUkT1SGbv1QGafy3in3uQ9a6NSy5EOT6k0k="
},
{
"pubKey": "5Giu-tJpGXU0S9Av75iAv5qDO0k6l8v_k9-UCcRUCl4="
},
{
"pubKey": "MnQxlmmKDybku4CfxsQQxfftilsaphF9Gq1w3MB1ZCE="
},
{
"pubKey": "GdP1fHVs2R65EkuWVWKZSz6WPDh0MgThyuBOv6_xsmQ="
},
{
"pubKey": "4JEtSrKsonmBuDvxJ9nITSu7iC4f8reutXRAVugPgS4="
},
{
"pubKey": "q4XyuUJbSGJaoRb3SmWzeX88V2dKB7sPTf72BAtQp3k="
},
{
"pubKey": "gTzKd1Ph5bpUw-JxTZiCe8RBfO-FsZiVYDYioQ-6dVg="
},
{
"pubKey": "NX4oaDLYEOmMUP_9pcEaZv5MJHJ4ZYAoxPQDxov7tRs="
},
{
"pubKey": "7fbk4oGQNlTW-tnWjVz8rWtKrtAicTsiNWgO98sqMyk="
},
{
"pubKey": "w1bfLpnd3rWu5JczB0nQfnE2S6nUCbx2AA7HDE48DQo="
}
],
"lastSeen": 1575915097869025000
}
]
}"#.to_string()
}
}
}
+52
View File
@@ -0,0 +1,52 @@
use sphinx::route::NodeAddressBytes;
use sphinx::SphinxPacket;
use std::net::SocketAddr;
use tokio::prelude::*;
pub struct MixClient {}
impl MixClient {
pub fn new() -> MixClient {
MixClient {}
}
// Sends a Sphinx packet to a mixnode.
pub async fn send(
&self,
packet: SphinxPacket,
mix_addr: SocketAddr,
) -> Result<(), Box<dyn std::error::Error>> {
let bytes = packet.to_bytes();
println!("socket addr: {:?}", mix_addr);
let mut stream = tokio::net::TcpStream::connect(mix_addr).await?;
stream.write_all(&bytes[..]).await?;
Ok(())
}
}
#[cfg(test)]
mod sending_a_sphinx_packet {
// use super::*;
// use sphinx::SphinxPacket;
#[test]
fn works() {
// arrange
// let directory = Client::new();
// let message = "Hello, Sphinx!".as_bytes().to_vec();
// let mixes = directory.get_mixes();
// let destination = directory.get_destination();
// let delays = sphinx::header::delays::generate(2);
// let packet = SphinxPacket::new(message, &mixes, &destination, &delays).unwrap();
// let mix_client = MixClient::new();
// let first_hop = mixes.first().unwrap();
//
// // act
// mix_client.send(packet, first_hop);
// assert
// wtf are we supposed to assert here?
}
}
+334
View File
@@ -0,0 +1,334 @@
use crate::clients::directory::presence::Topology;
use crate::clients::mix::MixClient;
use crate::clients::provider::ProviderClient;
use crate::sockets::tcp;
use crate::sockets::ws;
use crate::utils;
use crate::utils::topology::get_topology;
use futures::channel::{mpsc, oneshot};
use futures::join;
use futures::lock::Mutex as FMutex;
use futures::select;
use futures::{SinkExt, StreamExt};
use sfw_provider_requests::AuthToken;
use sphinx::route::{Destination, DestinationAddressBytes};
use sphinx::SphinxPacket;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::runtime::Runtime;
pub mod directory;
pub mod mix;
pub mod provider;
pub mod validator;
const LOOP_COVER_AVERAGE_DELAY: f64 = 0.5;
// seconds
const MESSAGE_SENDING_AVERAGE_DELAY: f64 = 0.5;
// seconds;
const FETCH_MESSAGES_DELAY: f64 = 1.0; // seconds;
// provider-poller sends polls service provider; receives messages
// provider-poller sends (TX) to ReceivedBufferController (RX)
// ReceivedBufferController sends (TX) to ... ??Client??
// outQueueController sends (TX) to TrafficStreamController (RX)
// TrafficStreamController sends messages to mixnet
// ... ??Client?? sends (TX) to outQueueController (RX)
// Loop cover traffic stream just sends messages to mixnet without any channel communication
struct MixMessage(SocketAddr, SphinxPacket);
struct MixTrafficController;
impl MixTrafficController {
// this was way more difficult to implement than what this code may suggest...
async fn run(mut rx: mpsc::UnboundedReceiver<MixMessage>) {
let mix_client = MixClient::new();
while let Some(mix_message) = rx.next().await {
println!(
"[MIX TRAFFIC CONTROL] - got a mix_message for {:?}",
mix_message.0
);
let send_res = mix_client.send(mix_message.1, mix_message.0).await;
match send_res {
Ok(_) => println!("We successfully sent the message!"),
Err(e) => eprintln!("We failed to send the message :( - {:?}", e),
};
}
}
}
pub type BufferResponse = oneshot::Sender<Vec<Vec<u8>>>;
struct ReceivedMessagesBuffer {
messages: Vec<Vec<u8>>,
}
impl ReceivedMessagesBuffer {
fn add_arc_futures_mutex(self) -> Arc<FMutex<Self>> {
Arc::new(FMutex::new(self))
}
fn new() -> Self {
ReceivedMessagesBuffer {
messages: Vec::new(),
}
}
async fn add_new_messages(buf: Arc<FMutex<Self>>, msgs: Vec<Vec<u8>>) {
println!("Adding new messages to the buffer! {:?}", msgs);
let mut unlocked = buf.lock().await;
unlocked.messages.extend(msgs);
}
async fn run_poller_input_controller(
buf: Arc<FMutex<Self>>,
mut poller_rx: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
) {
while let Some(new_messages) = poller_rx.next().await {
ReceivedMessagesBuffer::add_new_messages(buf.clone(), new_messages).await;
}
}
async fn acquire_and_empty(buf: Arc<FMutex<Self>>) -> Vec<Vec<u8>> {
let mut unlocked = buf.lock().await;
std::mem::replace(&mut unlocked.messages, Vec::new())
}
async fn run_query_output_controller(
buf: Arc<FMutex<Self>>,
mut query_receiver: mpsc::UnboundedReceiver<BufferResponse>,
) {
while let Some(request) = query_receiver.next().await {
let messages = ReceivedMessagesBuffer::acquire_and_empty(buf.clone()).await;
// if this fails, the whole application needs to blow
// because currently only this thread would fail
request.send(messages).unwrap();
}
}
}
pub enum SocketType {
TCP,
WebSocket,
None,
}
pub struct NymClient {
// to be replaced by something else I guess
address: DestinationAddressBytes,
pub input_tx: mpsc::UnboundedSender<InputMessage>,
// to be used by "send" function or socket, etc
input_rx: mpsc::UnboundedReceiver<InputMessage>,
socket_listening_address: SocketAddr,
directory: String,
auth_token: Option<AuthToken>,
socket_type: SocketType,
}
#[derive(Debug)]
pub struct InputMessage(pub Destination, pub Vec<u8>);
impl NymClient {
pub fn new(
address: DestinationAddressBytes,
socket_listening_address: SocketAddr,
directory: String,
auth_token: Option<AuthToken>,
socket_type: SocketType,
) -> Self {
let (input_tx, input_rx) = mpsc::unbounded::<InputMessage>();
NymClient {
address,
input_tx,
input_rx,
socket_listening_address,
directory,
auth_token,
socket_type,
}
}
async fn start_loop_cover_traffic_stream(
mut tx: mpsc::UnboundedSender<MixMessage>,
our_info: Destination,
topology: Topology,
) {
loop {
println!("[LOOP COVER TRAFFIC STREAM] - next cover message!");
let delay = utils::poisson::sample(LOOP_COVER_AVERAGE_DELAY);
let delay_duration = Duration::from_secs_f64(delay);
tokio::time::delay_for(delay_duration).await;
let cover_message =
utils::sphinx::loop_cover_message(our_info.address, our_info.identifier, &topology);
tx.send(MixMessage(cover_message.0, cover_message.1))
.await
.unwrap();
}
}
async fn control_out_queue(
mut mix_tx: mpsc::UnboundedSender<MixMessage>,
mut input_rx: mpsc::UnboundedReceiver<InputMessage>,
our_info: Destination,
topology: Topology,
) {
loop {
println!("[OUT QUEUE] here I will be sending real traffic (or loop cover if nothing is available)");
select! {
real_message = input_rx.next() => {
println!("[OUT QUEUE] - we got a real message!");
let real_message = real_message.expect("The channel must have closed! - if the client hasn't crashed, it should have!");
println!("real: {:?}", real_message);
let encapsulated_message = utils::sphinx::encapsulate_message(real_message.0, real_message.1, &topology);
mix_tx.send(MixMessage(encapsulated_message.0, encapsulated_message.1)).await.unwrap();
},
default => {
println!("[OUT QUEUE] - no real message - going to send extra loop cover");
let cover_message = utils::sphinx::loop_cover_message(our_info.address, our_info.identifier, &topology);
mix_tx.send(MixMessage(cover_message.0, cover_message.1)).await.unwrap();
}
};
let delay_duration = Duration::from_secs_f64(MESSAGE_SENDING_AVERAGE_DELAY);
tokio::time::delay_for(delay_duration).await;
}
}
async fn start_provider_polling(
provider_client: ProviderClient,
mut poller_tx: mpsc::UnboundedSender<Vec<Vec<u8>>>,
) {
let loop_message = &utils::sphinx::LOOP_COVER_MESSAGE_PAYLOAD.to_vec();
let dummy_message = &sfw_provider_requests::DUMMY_MESSAGE_CONTENT.to_vec();
loop {
let delay_duration = Duration::from_secs_f64(FETCH_MESSAGES_DELAY);
tokio::time::delay_for(delay_duration).await;
println!("[FETCH MSG] - Polling provider...");
let messages = provider_client.retrieve_messages().await.unwrap();
let good_messages = messages
.into_iter()
.filter(|message| message != loop_message && message != dummy_message)
.collect();
// if any of those fails, whole application should blow...
poller_tx.send(good_messages).await.unwrap();
}
}
pub fn start(self) -> Result<(), Box<dyn std::error::Error>> {
println!("Starting nym client");
let mut rt = Runtime::new()?;
let topology = get_topology(self.directory.clone());
// this is temporary and assumes there exists only a single provider.
let provider_address: SocketAddr = topology
.mix_provider_nodes
.first()
.unwrap()
.host
.parse()
.unwrap();
let mut provider_client =
ProviderClient::new(provider_address, self.address, self.auth_token);
// registration
rt.block_on(async {
match self.auth_token {
None => {
let auth_token = provider_client.register().await.unwrap();
provider_client.update_token(auth_token);
println!("Obtained new token! - {:?}", auth_token);
}
Some(token) => println!("Already got the token! - {:?}", token),
}
});
// channels for intercomponent communication
let (mix_tx, mix_rx) = mpsc::unbounded();
let (poller_input_tx, poller_input_rx) = mpsc::unbounded();
let (received_messages_buffer_output_tx, received_messages_buffer_output_rx) =
mpsc::unbounded();
let received_messages_buffer = ReceivedMessagesBuffer::new().add_arc_futures_mutex();
let received_messages_buffer_input_controller_future =
rt.spawn(ReceivedMessagesBuffer::run_poller_input_controller(
received_messages_buffer.clone(),
poller_input_rx,
));
let received_messages_buffer_output_controller_future =
rt.spawn(ReceivedMessagesBuffer::run_query_output_controller(
received_messages_buffer,
received_messages_buffer_output_rx,
));
let mix_traffic_future = rt.spawn(MixTrafficController::run(mix_rx));
let loop_cover_traffic_future = rt.spawn(NymClient::start_loop_cover_traffic_stream(
mix_tx.clone(),
Destination::new(self.address, Default::default()),
topology.clone(),
));
let out_queue_control_future = rt.spawn(NymClient::control_out_queue(
mix_tx,
self.input_rx,
Destination::new(self.address, Default::default()),
topology.clone(),
));
let provider_polling_future = rt.spawn(NymClient::start_provider_polling(
provider_client,
poller_input_tx,
));
match self.socket_type {
SocketType::WebSocket => {
rt.spawn(ws::start_websocket(
self.socket_listening_address,
self.input_tx,
received_messages_buffer_output_tx,
self.address,
topology,
));
}
SocketType::TCP => {
rt.spawn(tcp::start_tcpsocket(
self.socket_listening_address,
self.input_tx,
received_messages_buffer_output_tx,
self.address,
topology,
));
}
SocketType::None => (),
}
rt.block_on(async {
let future_results = join!(
received_messages_buffer_input_controller_future,
received_messages_buffer_output_controller_future,
mix_traffic_future,
loop_cover_traffic_future,
out_queue_control_future,
provider_polling_future,
);
assert!(
future_results.0.is_ok()
&& future_results.1.is_ok()
&& future_results.2.is_ok()
&& future_results.3.is_ok()
&& future_results.4.is_ok()
&& future_results.5.is_ok()
);
});
// this line in theory should never be reached as the runtime should be permanently blocked on traffic senders
eprintln!("The client went kaput...");
Ok(())
}
}
+118
View File
@@ -0,0 +1,118 @@
use futures::io::Error;
use sfw_provider_requests::requests::{ProviderRequest, PullRequest, RegisterRequest};
use sfw_provider_requests::responses::{
ProviderResponse, ProviderResponseError, PullResponse, RegisterResponse,
};
use sfw_provider_requests::AuthToken;
use sphinx::route::DestinationAddressBytes;
use std::net::{Shutdown, SocketAddr};
use std::time::Duration;
use tokio::prelude::*;
#[derive(Debug)]
pub enum ProviderClientError {
ClientAlreadyRegisteredError,
EmptyAuthTokenError,
NetworkError,
InvalidRequestError,
InvalidResponseError,
InvalidResponseLengthError,
}
impl From<io::Error> for ProviderClientError {
fn from(_: Error) -> Self {
use ProviderClientError::*;
NetworkError
}
}
impl From<ProviderResponseError> for ProviderClientError {
fn from(err: ProviderResponseError) -> Self {
use ProviderClientError::*;
match err {
ProviderResponseError::MarshalError => InvalidRequestError,
ProviderResponseError::UnmarshalError => InvalidResponseError,
ProviderResponseError::UnmarshalErrorInvalidLength => InvalidResponseLengthError,
}
}
}
pub struct ProviderClient {
provider_network_address: SocketAddr,
our_address: DestinationAddressBytes,
auth_token: Option<AuthToken>,
}
impl ProviderClient {
pub fn new(
provider_network_address: SocketAddr,
our_address: DestinationAddressBytes,
auth_token: Option<AuthToken>,
) -> Self {
// DH temporary: the provider's client port is not in the topology, but we can't change that
// right now without messing up the existing Go mixnet. So I'm going to hardcode this
// for the moment until the Go mixnet goes away.
let provider_socket = SocketAddr::new(provider_network_address.ip(), 9000);
ProviderClient {
provider_network_address: provider_socket,
our_address,
auth_token,
}
}
pub fn update_token(&mut self, auth_token: AuthToken) {
self.auth_token = Some(auth_token)
}
pub async fn send_request(&self, bytes: Vec<u8>) -> Result<Vec<u8>, ProviderClientError> {
let mut socket = tokio::net::TcpStream::connect(self.provider_network_address).await?;
println!("keep alive: {:?}", socket.keepalive());
socket.set_keepalive(Some(Duration::from_secs(2))).unwrap();
socket.write_all(&bytes[..]).await?;
if let Err(_e) = socket.shutdown(Shutdown::Write) {
// TODO: make it a silent log once we have a proper logging library
// eprintln!("failed to close write part of the socket; err = {:?}", e)
}
let mut response = Vec::new();
socket.read_to_end(&mut response).await?;
if let Err(_e) = socket.shutdown(Shutdown::Read) {
// TODO: make it a silent log once we have a proper logging library
// eprintln!("failed to close read part of the socket; err = {:?}", e)
}
Ok(response)
}
pub async fn retrieve_messages(&self) -> Result<Vec<Vec<u8>>, ProviderClientError> {
if self.auth_token.is_none() {
return Err(ProviderClientError::EmptyAuthTokenError);
}
let pull_request = PullRequest::new(self.our_address, self.auth_token.unwrap());
let bytes = pull_request.to_bytes();
let response = self.send_request(bytes).await?;
println!("Received the following response: {:?}", response);
let parsed_response = PullResponse::from_bytes(&response)?;
Ok(parsed_response.messages)
}
pub async fn register(&self) -> Result<AuthToken, ProviderClientError> {
if self.auth_token.is_some() {
return Err(ProviderClientError::ClientAlreadyRegisteredError);
}
let register_request = RegisterRequest::new(self.our_address);
let bytes = register_request.to_bytes();
let response = self.send_request(bytes).await?;
let parsed_response = RegisterResponse::from_bytes(&response)?;
Ok(parsed_response.auth_token)
}
}
+1
View File
@@ -0,0 +1 @@
+20
View File
@@ -0,0 +1,20 @@
use crate::banner;
use crate::identity::mixnet;
use crate::persistence::pathfinder::Pathfinder;
use crate::persistence::pemstore::PemStore;
use clap::ArgMatches;
pub fn execute(matches: &ArgMatches) {
println!("{}", banner());
println!("Initialising client...");
let id = matches.value_of("id").unwrap().to_string(); // required for now
let pathfinder = Pathfinder::new(id);
println!("Writing keypairs to {:?}...", pathfinder.config_dir);
let mix_keys = mixnet::KeyPair::new();
let pem_store = PemStore::new(pathfinder);
pem_store.write(mix_keys);
println!("Client configuration completed.\n\n\n")
}
+4
View File
@@ -0,0 +1,4 @@
pub mod init;
pub mod run;
pub mod tcpsocket;
pub mod websocket;
+17
View File
@@ -0,0 +1,17 @@
use crate::banner;
//use crate::clients::NymClient;
//use crate::persistence::pemstore;
use clap::ArgMatches;
pub fn execute(_matches: &ArgMatches) {
println!("{}", banner());
panic!("For time being this command is deprecated! Please use 'websocket' instead");
//
// let is_local = matches.is_present("local");
// let id = matches.value_of("id").unwrap().to_string();
// println!("Starting client...");
//
// let keypair = pemstore::read_keypair_from_disk(id);
// let client = NymClient::new(keypair.public_bytes(), is_local);
// client.start("127.0.0.1:9000".parse().unwrap()).unwrap();
}
+44
View File
@@ -0,0 +1,44 @@
use crate::banner;
use crate::clients::{NymClient, SocketType};
use crate::persistence::pemstore;
use crate::sockets::tcp;
use clap::ArgMatches;
use std::net::ToSocketAddrs;
pub fn execute(matches: &ArgMatches) {
println!("{}", banner());
let id = matches.value_of("id").unwrap().to_string();
let port = match matches.value_of("port").unwrap_or("9001").parse::<u16>() {
Ok(n) => n,
Err(err) => panic!("Invalid port value provided - {:?}", err),
};
let directory_server = matches
.value_of("directory")
.unwrap_or("https://directory.nymtech.net")
.to_string();
println!("Starting TCP socket on port: {:?}", port);
println!("Listening for messages...");
let socket_address = ("127.0.0.1", port)
.to_socket_addrs()
.expect("Failed to combine host and port")
.next()
.expect("Failed to extract the socket address from the iterator");
let keypair = pemstore::read_keypair_from_disk(id);
let auth_token = None;
let client = NymClient::new(
keypair.public_bytes(),
socket_address.clone(),
directory_server,
auth_token,
SocketType::TCP,
);
client.start().unwrap();
}
+43
View File
@@ -0,0 +1,43 @@
use crate::banner;
use crate::clients::{NymClient, SocketType};
use crate::persistence::pemstore;
use clap::ArgMatches;
use std::net::ToSocketAddrs;
pub fn execute(matches: &ArgMatches) {
println!("{}", banner());
let id = matches.value_of("id").unwrap().to_string();
let port = match matches.value_of("port").unwrap_or("9001").parse::<u16>() {
Ok(n) => n,
Err(err) => panic!("Invalid port value provided - {:?}", err),
};
let directory_server = matches
.value_of("directory")
.unwrap_or("https://directory.nymtech.net")
.to_string();
println!("Starting websocket on port: {:?}", port);
println!("Listening for messages...");
let socket_address = ("127.0.0.1", port)
.to_socket_addrs()
.expect("Failed to combine host and port")
.next()
.expect("Failed to extract the socket address from the iterator");
let keypair = pemstore::read_keypair_from_disk(id);
// TODO: reading auth_token from disk (if exists);
let auth_token = None;
let client = NymClient::new(
keypair.public_bytes(),
socket_address,
directory_server,
auth_token,
SocketType::WebSocket,
);
client.start().unwrap();
}
+33
View File
@@ -0,0 +1,33 @@
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
// This keypair serves as the user's identity within the Mixnet
pub struct KeyPair {
pub private: Scalar,
pub public: MontgomeryPoint,
}
impl KeyPair {
pub fn new() -> KeyPair {
let (private, public) = sphinx::crypto::keygen();
KeyPair { private, public }
}
pub fn from_bytes(private_bytes: Vec<u8>, public_bytes: Vec<u8>) -> KeyPair {
let mut bytes = [0; 32];
bytes.copy_from_slice(&private_bytes[..]);
let private = Scalar::from_canonical_bytes(bytes).unwrap();
let mut bytes = [0; 32];
bytes.copy_from_slice(&public_bytes[..]);
let public = MontgomeryPoint(bytes);
KeyPair { private, public }
}
pub fn private_bytes(&self) -> [u8; 32] {
self.private.to_bytes()
}
pub fn public_bytes(&self) -> [u8; 32] {
self.public.to_bytes()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod mixnet;
+1
View File
@@ -0,0 +1 @@
// TODO types for Validator keys will go in here once we hook this up.
+5
View File
@@ -0,0 +1,5 @@
pub mod clients;
pub mod identity;
pub mod persistence;
pub mod sockets;
pub mod utils;
+88 -25
View File
@@ -1,42 +1,95 @@
use clap::{App, Arg, ArgMatches, SubCommand};
use std::process;
mod mix_peer;
mod node;
pub mod clients;
mod commands;
mod identity;
mod persistence;
mod sockets;
mod utils;
fn main() {
let arg_matches = App::new("Nym Mixnode")
let arg_matches = App::new("Nym Client")
.version("0.1.0")
.author("Nymtech")
.about("Implementation of the Loopix-based Mixnode")
.about("Implementation of the Nym Client")
.subcommand(
SubCommand::with_name("init")
.about("Initialise a Nym client. Do this first!")
.arg(Arg::with_name("id")
.long("id")
.help("Id of the nym-mixnet-client we want to create config for.")
.takes_value(true)
.required(true)
)
.arg(Arg::with_name("provider")
.long("provider")
.help("Id of the provider we have preference to connect to. If left empty, a random provider will be chosen.")
.takes_value(true)
)
)
.subcommand(
SubCommand::with_name("run")
.about("Starts the mixnode")
.about("Run a persistent Nym client process")
.arg(Arg::with_name("id")
.long("id")
.help("Id of the nym-mixnet-client we want to run.")
.takes_value(true)
.required(true)
)
.arg(
Arg::with_name("host")
.long("host")
.help("The custom host on which the mixnode will be running")
Arg::with_name("directory")
.long("directory")
.help("Address of the directory server the client is getting topology from")
.takes_value(true),
)
)
.subcommand(
SubCommand::with_name("tcpsocket")
.about("Run Nym client that listens for bytes on a TCP socket")
.arg(
Arg::with_name("port")
.short("p")
.long("port")
.help("The port on which the mixnode will be listening")
.takes_value(true)
)
.arg(
Arg::with_name("layer")
.long("layer")
.help("The mixnet layer of this particular node")
.help("Port for TCP socket to listen on")
.takes_value(true)
.required(true),
)
.arg(
Arg::with_name("local")
.long("local")
.help("Flag to indicate whether the client is expected to run on a local deployment.")
.takes_value(false),
),
Arg::with_name("directory")
.long("directory")
.help("Address of the directory server the client is getting topology from")
.takes_value(true),
)
.arg(Arg::with_name("id")
.long("id")
.help("Id of the nym-mixnet-client we want to run.")
.takes_value(true)
.required(true)
)
)
.subcommand(
SubCommand::with_name("websocket")
.about("Run Nym client that listens on a websocket")
.arg(
Arg::with_name("port")
.short("p")
.long("port")
.help("Port for websocket to listen on")
.takes_value(true)
)
.arg(
Arg::with_name("directory")
.long("directory")
.help("Address of the directory server the client is getting topology from")
.takes_value(true),
)
.arg(Arg::with_name("id")
.long("id")
.help("Id of the nym-mixnet-client we want to run.")
.takes_value(true)
.required(true)
)
)
.get_matches();
@@ -46,9 +99,17 @@ fn main() {
}
}
pub mod built_info {
// The file has been placed there by the build script.
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
fn execute(matches: ArgMatches) -> Result<(), String> {
match matches.subcommand() {
("run", Some(m)) => Ok(node::runner::start(m)),
("init", Some(m)) => Ok(commands::init::execute(m)),
("run", Some(m)) => Ok(commands::run::execute(m)),
("tcpsocket", Some(m)) => Ok(commands::tcpsocket::execute(m)),
("websocket", Some(m)) => Ok(commands::websocket::execute(m)),
_ => Err(usage()),
}
}
@@ -58,7 +119,8 @@ fn usage() -> String {
}
fn banner() -> String {
return r#"
format!(
r#"
_ __ _ _ _ __ ___
| '_ \| | | | '_ \ _ \
@@ -66,8 +128,9 @@ fn banner() -> String {
|_| |_|\__, |_| |_| |_|
|___/
(mixnode)
(client - version {:})
"#
.to_string();
"#,
built_info::PKG_VERSION
)
}
-32
View File
@@ -1,32 +0,0 @@
use std::error::Error;
use std::net::{Ipv4Addr, SocketAddrV4};
use tokio::prelude::*;
#[derive(Debug)]
pub struct MixPeer {
connection: SocketAddrV4,
}
impl MixPeer {
// note that very soon `next_hop_address` will be changed to `next_hop_metadata`
pub fn new(next_hop_address: [u8; 32]) -> MixPeer {
let b = next_hop_address;
let host = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
let port: u16 = u16::from_be_bytes([b[4], b[5]]);
let socket_address = SocketAddrV4::new(host, port);
MixPeer {
connection: socket_address,
}
}
pub async fn send(&self, bytes: Vec<u8>) -> Result<(), Box<dyn Error>> {
let next_hop_address = self.connection.clone();
let mut stream = tokio::net::TcpStream::connect(next_hop_address).await?;
stream.write_all(&bytes).await?;
Ok(())
}
pub fn to_string(&self) -> String {
self.connection.to_string()
}
}
-94
View File
@@ -1,94 +0,0 @@
use futures::channel::mpsc;
use futures::lock::Mutex;
use futures::StreamExt;
use nym_client::clients::directory;
use nym_client::clients::directory::metrics::MixMetric;
use nym_client::clients::directory::requests::metrics_mixes_post::MetricsMixPoster;
use nym_client::clients::directory::DirectoryClient;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
const METRICS_INTERVAL: u64 = 3;
#[derive(Debug)]
pub struct MetricsReporter {
received: u64,
sent: HashMap<String, u64>,
}
impl MetricsReporter {
pub(crate) fn new() -> Self {
MetricsReporter {
received: 0,
sent: HashMap::new(),
}
}
pub(crate) fn add_arc_mutex(self) -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(self))
}
async fn increment_received_metrics(metrics: Arc<Mutex<MetricsReporter>>) {
let mut unlocked = metrics.lock().await;
unlocked.received += 1;
}
pub(crate) async fn run_received_metrics_control(
metrics: Arc<Mutex<MetricsReporter>>,
mut rx: mpsc::Receiver<()>,
) {
while let Some(_) = rx.next().await {
MetricsReporter::increment_received_metrics(metrics.clone()).await;
}
}
async fn increment_sent_metrics(metrics: Arc<Mutex<MetricsReporter>>, sent_to: String) {
let mut unlocked = metrics.lock().await;
let receiver_count = unlocked.sent.entry(sent_to).or_insert(0);
*receiver_count += 1;
}
pub(crate) async fn run_sent_metrics_control(
metrics: Arc<Mutex<MetricsReporter>>,
mut rx: mpsc::Receiver<String>,
) {
while let Some(sent_metric) = rx.next().await {
MetricsReporter::increment_sent_metrics(metrics.clone(), sent_metric).await;
}
}
async fn acquire_and_reset_metrics(
metrics: Arc<Mutex<MetricsReporter>>,
) -> (u64, HashMap<String, u64>) {
let mut unlocked = metrics.lock().await;
let received = unlocked.received;
let sent = std::mem::replace(&mut unlocked.sent, HashMap::new());
unlocked.received = 0;
(received, sent)
}
pub(crate) async fn run_metrics_sender(
metrics: Arc<Mutex<MetricsReporter>>,
cfg: directory::Config,
pub_key_str: String,
) {
let delay_duration = Duration::from_secs(METRICS_INTERVAL);
let directory_client = directory::Client::new(cfg);
loop {
tokio::time::delay_for(delay_duration).await;
let (received, sent) =
MetricsReporter::acquire_and_reset_metrics(metrics.clone()).await;
directory_client
.metrics_post
.post(&MixMetric {
pub_key: pub_key_str.clone(),
received,
sent,
})
.unwrap();
}
}
}
-263
View File
@@ -1,263 +0,0 @@
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
use futures::channel::mpsc;
use futures::lock::Mutex;
use sphinx::header::delays::Delay as SphinxDelay;
use sphinx::{ProcessedPacket, SphinxPacket};
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::prelude::*;
use tokio::runtime::Runtime;
use crate::mix_peer::MixPeer;
use crate::node::metrics::MetricsReporter;
use futures::SinkExt;
use nym_client::clients::directory;
mod metrics;
mod presence;
pub mod runner;
pub struct Config {
directory_server: String,
layer: usize,
public_key: MontgomeryPoint,
secret_key: Scalar,
socket_address: SocketAddr,
}
impl Config {
pub fn public_key_string(&self) -> String {
let key_bytes = self.public_key.to_bytes().to_vec();
base64::encode_config(&key_bytes, base64::URL_SAFE)
}
}
#[derive(Debug)]
pub enum MixProcessingError {
SphinxRecoveryError,
ReceivedFinalHopError,
}
impl From<sphinx::ProcessingError> for MixProcessingError {
// for time being just have a single error instance for all possible results of sphinx::ProcessingError
fn from(_: sphinx::ProcessingError) -> Self {
use MixProcessingError::*;
SphinxRecoveryError
}
}
struct ForwardingData {
packet: SphinxPacket,
delay: SphinxDelay,
recipient: MixPeer,
sent_metrics_tx: mpsc::Sender<String>,
}
// TODO: this will need to be changed if MixPeer will live longer than our Forwarding Data
impl ForwardingData {
fn new(
packet: SphinxPacket,
delay: SphinxDelay,
recipient: MixPeer,
sent_metrics_tx: mpsc::Sender<String>,
) -> Self {
ForwardingData {
packet,
delay,
recipient,
sent_metrics_tx,
}
}
}
// ProcessingData defines all data required to correctly unwrap sphinx packets
struct ProcessingData {
secret_key: Scalar,
received_metrics_tx: mpsc::Sender<()>,
sent_metrics_tx: mpsc::Sender<String>,
}
impl ProcessingData {
fn new(
secret_key: Scalar,
received_metrics_tx: mpsc::Sender<()>,
sent_metrics_tx: mpsc::Sender<String>,
) -> Self {
ProcessingData {
secret_key,
received_metrics_tx,
sent_metrics_tx,
}
}
fn add_arc_mutex(self) -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(self))
}
}
struct PacketProcessor {}
impl PacketProcessor {
pub async fn process_sphinx_data_packet(
packet_data: &[u8],
processing_data: Arc<Mutex<ProcessingData>>,
) -> Result<ForwardingData, MixProcessingError> {
// we received something resembling a sphinx packet, report it!
let processing_data = processing_data.lock().await;
let mut received_sender = processing_data.received_metrics_tx.clone();
received_sender.send(()).await.unwrap();
let packet = SphinxPacket::from_bytes(packet_data.to_vec())?;
let (next_packet, next_hop_address, delay) =
match packet.process(processing_data.secret_key) {
ProcessedPacket::ProcessedPacketForwardHop(packet, address, delay) => {
(packet, address, delay)
}
_ => return Err(MixProcessingError::ReceivedFinalHopError),
};
let next_mix = MixPeer::new(next_hop_address);
let fwd_data = ForwardingData::new(
next_packet,
delay,
next_mix,
processing_data.sent_metrics_tx.clone(),
);
Ok(fwd_data)
}
async fn wait_and_forward(mut forwarding_data: ForwardingData) {
let delay_duration = Duration::from_nanos(forwarding_data.delay.get_value());
tokio::time::delay_for(delay_duration).await;
forwarding_data
.sent_metrics_tx
.send(forwarding_data.recipient.to_string())
.await
.unwrap();
println!("RECIPIENT: {:?}", forwarding_data.recipient);
match forwarding_data
.recipient
.send(forwarding_data.packet.to_bytes())
.await
{
Ok(()) => (),
Err(e) => {
println!(
"failed to write bytes to next mix peer. err = {:?}",
e.to_string()
);
}
}
}
}
// the MixNode will live for whole duration of this program
pub struct MixNode {
directory_server: String,
network_address: SocketAddr,
public_key: MontgomeryPoint,
secret_key: Scalar,
// TODO: use it later to enforce forward travel
// layer: usize,
}
impl MixNode {
pub fn new(config: &Config) -> Self {
MixNode {
directory_server: config.directory_server.clone(),
network_address: config.socket_address,
secret_key: config.secret_key,
public_key: config.public_key,
// layer: config.layer,
}
}
async fn process_socket_connection(
mut socket: tokio::net::TcpStream,
processing_data: Arc<Mutex<ProcessingData>>,
) {
// NOTE: processing_data is copied here!!
let mut buf = [0u8; sphinx::PACKET_SIZE];
// In a loop, read data from the socket and write the data back.
loop {
match socket.read(&mut buf).await {
// socket closed
Ok(n) if n == 0 => {
println!("Remote connection closed.");
return;
}
Ok(_) => {
let fwd_data = PacketProcessor::process_sphinx_data_packet(
buf.as_ref(),
processing_data.clone(),
)
.await
.unwrap();
PacketProcessor::wait_and_forward(fwd_data).await;
}
Err(e) => {
println!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the some data back
if let Err(e) = socket.write_all(b"foomp").await {
println!("failed to write reply to socket; err = {:?}", e);
return;
}
}
}
pub fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
// Create the runtime, probably later move it to MixNode itself?
let mut rt = Runtime::new()?;
let (received_tx, received_rx) = mpsc::channel(1024);
let (sent_tx, sent_rx) = mpsc::channel(1024);
let directory_cfg = directory::Config {
base_url: self.directory_server.clone(),
};
let pub_key_str =
base64::encode_config(&self.public_key.to_bytes().to_vec(), base64::URL_SAFE);
let metrics = MetricsReporter::new().add_arc_mutex();
rt.spawn(MetricsReporter::run_received_metrics_control(
metrics.clone(),
received_rx,
));
rt.spawn(MetricsReporter::run_sent_metrics_control(
metrics.clone(),
sent_rx,
));
rt.spawn(MetricsReporter::run_metrics_sender(
metrics,
directory_cfg,
pub_key_str,
));
// Spawn the root task
rt.block_on(async {
let mut listener = tokio::net::TcpListener::bind(self.network_address).await?;
let processing_data =
ProcessingData::new(self.secret_key, received_tx, sent_tx).add_arc_mutex();
loop {
let (socket, _) = listener.accept().await?;
let thread_processing_data = processing_data.clone();
tokio::spawn(async move {
MixNode::process_socket_connection(socket, thread_processing_data).await;
});
}
})
}
}
-45
View File
@@ -1,45 +0,0 @@
use crate::node;
use nym_client::clients::directory;
use nym_client::clients::directory::presence::MixNodePresence;
use nym_client::clients::directory::requests::presence_mixnodes_post::PresenceMixNodesPoster;
use nym_client::clients::directory::DirectoryClient;
use std::thread;
use std::time::Duration;
pub struct Notifier {
pub net_client: directory::Client,
presence: MixNodePresence,
}
impl Notifier {
pub fn new(node_config: &node::Config) -> Notifier {
let config = directory::Config {
base_url: node_config.directory_server.clone(),
};
let net_client = directory::Client::new(config);
let presence = MixNodePresence {
host: node_config.socket_address.to_string(), // note: the directory server determines the real incoming IP itself, but uses the socket. Host here is just a placeholder.
pub_key: node_config.public_key_string(),
layer: node_config.layer as u64,
last_seen: 0,
};
Notifier {
net_client,
presence,
}
}
pub fn notify(&self) {
self.net_client
.presence_mix_nodes_post
.post(&self.presence)
.unwrap();
}
pub fn run(&self) {
loop {
self.notify();
thread::sleep(Duration::from_secs(5));
}
}
}
-63
View File
@@ -1,63 +0,0 @@
use crate::banner;
use crate::node;
use crate::node::presence;
use crate::node::MixNode;
use clap::ArgMatches;
use std::net::ToSocketAddrs;
use std::thread;
pub fn start(matches: &ArgMatches) {
println!("{}", banner());
println!("Starting mixnode...");
let config = new_config(matches);
// println!("Startup on: {}", config.socket_address);
println!("Listening for incoming packets...");
let mix = MixNode::new(&config);
thread::spawn(move || {
let notifier = presence::Notifier::new(&config);
notifier.run();
});
mix.start().unwrap();
}
fn new_config(matches: &ArgMatches) -> node::Config {
let host = matches.value_of("host").unwrap_or("0.0.0.0");
let port = match matches.value_of("port").unwrap_or("1789").parse::<u16>() {
Ok(n) => n,
Err(err) => panic!("Invalid port value provided - {:?}", err),
};
let layer = match matches.value_of("layer").unwrap().parse::<usize>() {
Ok(n) => n,
Err(err) => panic!("Invalid layer value provided - {:?}", err),
};
let is_local = matches.is_present("local");
let socket_address = (host, port)
.to_socket_addrs()
.expect("Failed to combine host and port")
.next()
.expect("Failed to extract the socket address from the iterator");
let (secret_key, public_key) = sphinx::crypto::keygen();
let directory_server = if is_local {
"http://localhost:8080".to_string()
} else {
"https://directory.nymtech.net".to_string()
};
node::Config {
directory_server,
layer,
public_key,
socket_address,
secret_key,
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod pathfinder;
pub mod pemstore;
+21
View File
@@ -0,0 +1,21 @@
use std::path::PathBuf;
pub struct Pathfinder {
pub config_dir: PathBuf,
pub private_mix_key: PathBuf,
pub public_mix_key: PathBuf,
}
impl Pathfinder {
pub fn new(id: String) -> Pathfinder {
let os_config_dir = dirs::config_dir().unwrap(); // grabs the OS default config dir
let config_dir = os_config_dir.join("nym").join("clients").join(id);
let private_mix_key = config_dir.join("private.pem");
let public_mix_key = config_dir.join("public.pem");
Pathfinder {
config_dir,
private_mix_key,
public_mix_key,
}
}
}
+72
View File
@@ -0,0 +1,72 @@
use crate::identity::mixnet::KeyPair;
use crate::persistence::pathfinder::Pathfinder;
use pem::{encode, parse, Pem};
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
pub fn read_keypair_from_disk(id: String) -> KeyPair {
let pathfinder = Pathfinder::new(id);
let pem_store = PemStore::new(pathfinder);
let keypair = pem_store.read();
keypair
}
pub struct PemStore {
config_dir: PathBuf,
private_mix_key: PathBuf,
public_mix_key: PathBuf,
}
impl PemStore {
pub fn new(pathfinder: Pathfinder) -> PemStore {
PemStore {
config_dir: pathfinder.config_dir,
private_mix_key: pathfinder.private_mix_key,
public_mix_key: pathfinder.public_mix_key,
}
}
pub fn read(&self) -> KeyPair {
let private = self.read_file(self.private_mix_key.clone());
let public = self.read_file(self.public_mix_key.clone());
KeyPair::from_bytes(private, public)
}
fn read_file(&self, filepath: PathBuf) -> Vec<u8> {
let mut pem_bytes = File::open(filepath).unwrap();
let mut buf = Vec::new();
pem_bytes.read_to_end(&mut buf).unwrap();
let pem = parse(&buf).unwrap();
pem.contents
}
// This should be refactored and made more generic for when we have other kinds of
// KeyPairs that we want to persist (e.g. validator keypairs, or keys for
// signing vs encryption). However, for the moment, it does the job.
pub fn write(&self, key_pair: KeyPair) {
std::fs::create_dir_all(self.config_dir.clone()).unwrap();
self.write_pem_file(
self.private_mix_key.clone(),
key_pair.private_bytes(),
String::from("SPHINX CURVE25519 PRIVATE KEY"),
);
self.write_pem_file(
self.public_mix_key.clone(),
key_pair.public_bytes(),
String::from("SPHINX CURVE25519 PUBLIC KEY"),
);
}
fn write_pem_file(&self, filepath: PathBuf, data: [u8; 32], tag: String) {
let pem = Pem {
tag,
contents: data.to_vec(),
};
let key = encode(&pem);
let mut file = File::create(filepath).unwrap();
file.write_all(key.as_bytes()).unwrap();
}
}
+1
View File
@@ -0,0 +1 @@
// TODO: we can put all the TOML config templating code in here once we get to that.
+2
View File
@@ -0,0 +1,2 @@
pub mod tcp;
pub mod ws;
+305
View File
@@ -0,0 +1,305 @@
use crate::clients::directory::presence::Topology;
use crate::clients::BufferResponse;
use crate::clients::InputMessage;
use futures::channel::{mpsc, oneshot};
use futures::future::FutureExt;
use futures::io::Error;
use futures::SinkExt;
use sphinx::route::{Destination, DestinationAddressBytes};
use std::io;
use std::net::SocketAddr;
use tokio::prelude::*;
use std::convert::TryFrom;
use std::sync::Arc;
use std::borrow::Borrow;
const SEND_REQUEST_PREFIX: u8 = 1;
const FETCH_REQUEST_PREFIX: u8 = 2;
const GET_CLIENTS_REQUEST_PREFIX: u8 = 3;
const OWN_DETAILS_REQUEST_PREFIX: u8 = 4;
#[derive(Debug)]
pub enum TCPSocketError {
FailedToStartSocketError,
UnknownSocketError,
IncompleteDataError,
UnknownRequestError,
}
impl From<io::Error> for TCPSocketError {
fn from(err: Error) -> Self {
use TCPSocketError::*;
match err.kind() {
io::ErrorKind::ConnectionRefused => FailedToStartSocketError,
io::ErrorKind::ConnectionReset => FailedToStartSocketError,
io::ErrorKind::ConnectionAborted => FailedToStartSocketError,
io::ErrorKind::NotConnected => FailedToStartSocketError,
io::ErrorKind::AddrInUse => FailedToStartSocketError,
io::ErrorKind::AddrNotAvailable => FailedToStartSocketError,
_ => UnknownSocketError,
}
}
}
enum ClientRequest {
Send {
message: Vec<u8>,
recipient_address: DestinationAddressBytes,
},
Fetch,
GetClients,
OwnDetails,
}
impl TryFrom<&[u8]> for ClientRequest {
type Error = TCPSocketError;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
use TCPSocketError::*;
if data.is_empty() {
return Err(IncompleteDataError);
}
match data[0] {
SEND_REQUEST_PREFIX => parse_send_request(data),
FETCH_REQUEST_PREFIX => Ok(ClientRequest::Fetch),
GET_CLIENTS_REQUEST_PREFIX => Ok(ClientRequest::GetClients),
OWN_DETAILS_REQUEST_PREFIX => Ok(ClientRequest::OwnDetails),
_ => Err(UnknownRequestError)
}
}
}
fn parse_send_request(data: &[u8]) -> Result<ClientRequest, TCPSocketError> {
if data.len() < 1 + 32 + 1 {
// make sure it has the prefix, destination and at least single byte of data
return Err(TCPSocketError::IncompleteDataError);
}
let mut recipient_address = [0u8; 32];
recipient_address.copy_from_slice(&data[1..33]);
let message = data[33..].to_vec();
Ok(ClientRequest::Send {
message,
recipient_address,
})
}
impl ClientRequest {
async fn handle_send(
msg: Vec<u8>,
recipient_address: DestinationAddressBytes,
mut input_tx: mpsc::UnboundedSender<InputMessage>,
) -> ServerResponse {
println!("send handle. sending to: {:?}, msg: {:?}", recipient_address, msg);
let dummy_surb = [0; 16];
let input_msg = InputMessage(Destination::new(recipient_address, dummy_surb), msg);
println!("ALMOST ABOUT TO SOMEDAY SEND {:?}", input_msg);
input_tx.send(input_msg).await.unwrap();
ServerResponse::Send
}
async fn handle_fetch(mut msg_query: mpsc::UnboundedSender<BufferResponse>) -> ServerResponse {
println!("fetch handle");
let (res_tx, res_rx) = oneshot::channel();
if msg_query.send(res_tx).await.is_err() {
return ServerResponse::Error {
message: "Server failed to receive messages".to_string(),
};
}
let messages = res_rx.map(|msg| msg).await;
if messages.is_err() {
return ServerResponse::Error {
message: "Server failed to receive messages".to_string(),
};
}
let messages = messages.unwrap();
println!("fetched {} messages", messages.len());
ServerResponse::Fetch {
messages,
}
}
async fn handle_get_clients(topology: &Topology) -> ServerResponse {
println!("get clients handle");
let clients = topology
.mix_provider_nodes
.iter()
.flat_map(|provider| provider.registered_clients.iter())
.map(|client| base64::decode_config(&client.pub_key, base64::URL_SAFE).unwrap()) // TODO: this can potentially throw an error
.collect();
ServerResponse::GetClients { clients }
}
async fn handle_own_details(self_address_bytes: DestinationAddressBytes) -> ServerResponse {
println!("own details handle");
ServerResponse::OwnDetails {
address: self_address_bytes.to_vec(),
}
}
}
enum ServerResponse {
Send,
Fetch { messages: Vec<Vec<u8>> },
GetClients { clients: Vec<Vec<u8>> },
OwnDetails { address: Vec<u8> },
Error { message: String },
}
impl Into<Vec<u8>> for ServerResponse {
fn into(self) -> Vec<u8> {
match self {
ServerResponse::Send => b"ok".to_vec(),
ServerResponse::Fetch {messages} =>encode_fetched_messages(messages),
ServerResponse::GetClients {clients} => encode_list_of_clients(clients),
ServerResponse::OwnDetails {address} => address,
ServerResponse::Error { message } => message.as_bytes().to_vec()
}
}
}
// num_msgs || len1 || len2 || ... || msg1 || msg2 || ...
fn encode_fetched_messages(messages: Vec<Vec<u8>>) -> Vec<u8> {
// for reciprocal of this look into sfw-provider-requests::responses::PullResponse::from_bytes()
let num_msgs = messages.len() as u16;
let msgs_lens: Vec<u16> = messages.iter().map(|msg| msg.len() as u16).collect();
num_msgs
.to_be_bytes()
.to_vec()
.into_iter()
.chain(
msgs_lens
.into_iter()
.flat_map(|len| len.to_be_bytes().to_vec().into_iter()),
)
.chain(messages.iter().flat_map(|msg| msg.clone().into_iter()))
.collect()
}
fn encode_list_of_clients(clients: Vec<Vec<u8>>) -> Vec<u8> {
println!("clients: {:?}", clients);
// we can just concat all clients since all of them got to be 32 bytes long
// (if not, then we have bigger problem somewhere up the line)
// converts [[1,2,3],[4,5,6],...] into [1,2,3,4,5,6,...]
clients.into_iter().flatten().collect()
}
impl ServerResponse {
fn new_error(message: String) -> ServerResponse {
ServerResponse::Error { message }
}
}
async fn handle_connection(data: &[u8], request_handling_data: RequestHandlingData) -> Result<ServerResponse, TCPSocketError> {
let request = ClientRequest::try_from(data)?;
let response = match request {
ClientRequest::Send {
message,
recipient_address
} => ClientRequest::handle_send(message, recipient_address, request_handling_data.msg_input).await,
ClientRequest::Fetch => ClientRequest::handle_fetch(request_handling_data.msg_query).await,
ClientRequest::GetClients => ClientRequest::handle_get_clients(request_handling_data.topology.borrow()).await,
ClientRequest::OwnDetails => ClientRequest::handle_own_details(request_handling_data.self_address).await,
};
Ok(response)
}
struct RequestHandlingData {
msg_input: mpsc::UnboundedSender<InputMessage>,
msg_query: mpsc::UnboundedSender<BufferResponse>,
self_address: DestinationAddressBytes,
topology: Arc<Topology>,
}
async fn accept_connection(
mut socket: tokio::net::TcpStream,
msg_input: mpsc::UnboundedSender<InputMessage>,
msg_query: mpsc::UnboundedSender<BufferResponse>,
self_address: DestinationAddressBytes,
topology: Topology,
) {
let address = socket
.peer_addr()
.expect("connected streams should have a peer address");
println!("Peer address: {}", address);
let topology = Arc::new(topology);
let mut buf = [0u8; 2048];
// In a loop, read data from the socket and write the data back.
loop {
// TODO: shutdowns?
let response = match socket.read(&mut buf).await {
// socket closed
Ok(n) if n == 0 => {
println!("Remote connection closed.");
return;
}
Ok(n) => {
let request_handling_data = RequestHandlingData {
topology: topology.clone(),
msg_input: msg_input.clone(),
msg_query: msg_query.clone(),
self_address: self_address.clone(),
};
match handle_connection(&buf[..n], request_handling_data).await {
Ok(res) => res,
Err(e) => ServerResponse::new_error(format!("{:?}", e))
}
}
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return;
}
};
let response_vec: Vec<u8> = response.into();
if let Err(e) = socket.write_all(&response_vec).await {
eprintln!("failed to write reply to socket; err = {:?}", e);
return;
}
}
}
pub async fn start_tcpsocket(
address: SocketAddr,
message_tx: mpsc::UnboundedSender<InputMessage>,
received_messages_query_tx: mpsc::UnboundedSender<BufferResponse>,
self_address: DestinationAddressBytes,
topology: Topology,
) -> Result<(), TCPSocketError> {
let mut listener = tokio::net::TcpListener::bind(address).await?;
while let Ok((stream, _)) = listener.accept().await {
// it's fine to be cloning the channel on all new connection, because in principle
// this server should only EVER have a single client connected
tokio::spawn(accept_connection(
stream,
message_tx.clone(),
received_messages_query_tx.clone(),
self_address,
topology.clone(),
));
}
eprintln!("The tcpsocket went kaput...");
Ok(())
}
+260
View File
@@ -0,0 +1,260 @@
use crate::clients::directory::presence::Topology;
use crate::clients::BufferResponse;
use crate::clients::InputMessage;
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
use futures::channel::{mpsc, oneshot};
use futures::future::FutureExt;
use futures::io::Error;
use futures::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize};
use sphinx::route::{Destination, DestinationAddressBytes};
use std::io;
use std::net::SocketAddr;
use tungstenite::protocol::Message;
struct Connection {
address: SocketAddr,
msg_input: mpsc::UnboundedSender<InputMessage>,
msg_query: mpsc::UnboundedSender<BufferResponse>,
rx: UnboundedReceiver<Message>,
self_address: DestinationAddressBytes,
topology: Topology,
tx: UnboundedSender<Message>,
}
#[derive(Debug)]
pub enum WebSocketError {
FailedToStartSocketError,
UnknownSocketError,
}
impl From<io::Error> for WebSocketError {
fn from(err: Error) -> Self {
use WebSocketError::*;
match err.kind() {
io::ErrorKind::ConnectionRefused => FailedToStartSocketError,
io::ErrorKind::ConnectionReset => FailedToStartSocketError,
io::ErrorKind::ConnectionAborted => FailedToStartSocketError,
io::ErrorKind::NotConnected => FailedToStartSocketError,
io::ErrorKind::AddrInUse => FailedToStartSocketError,
io::ErrorKind::AddrNotAvailable => FailedToStartSocketError,
_ => UnknownSocketError,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", rename_all = "camelCase")]
enum ClientRequest {
Send {
message: String,
recipient_address: String,
},
Fetch,
GetClients,
OwnDetails,
}
impl From<Message> for ClientRequest {
fn from(msg: Message) -> Self {
let text_msg = match msg {
Message::Text(msg) => msg,
Message::Binary(_) => panic!("binary messages are not supported!"),
Message::Close(_) => panic!("todo: handle close!"),
_ => panic!("Other types of messages are also unsupported!"),
};
serde_json::from_str(&text_msg).unwrap()
}
}
impl ClientRequest {
async fn handle_send(
msg: String,
recipient_address: String,
mut input_tx: mpsc::UnboundedSender<InputMessage>,
) -> ServerResponse {
let address_vec = match base64::decode_config(&recipient_address, base64::URL_SAFE) {
Err(e) => {
return ServerResponse::Error {
message: e.to_string(),
}
}
Ok(hex) => hex,
};
if address_vec.len() != 32 {
return ServerResponse::Error {
message: "InvalidDestinationLength".to_string(),
};
}
let mut address = [0; 32];
address.copy_from_slice(&address_vec);
let dummy_surb = [0; 16];
let input_msg = InputMessage(Destination::new(address, dummy_surb), msg.into_bytes());
println!("ALMOST ABOUT TO SOMEDAY SEND {:?}", input_msg);
input_tx.send(input_msg).await.unwrap();
ServerResponse::Send
}
async fn handle_fetch(mut msg_query: mpsc::UnboundedSender<BufferResponse>) -> ServerResponse {
let (res_tx, res_rx) = oneshot::channel();
if msg_query.send(res_tx).await.is_err() {
return ServerResponse::Error {
message: "Server failed to receive messages".to_string(),
};
}
let messages = res_rx.map(|msg| msg).await;
if messages.is_err() {
return ServerResponse::Error {
message: "Server failed to receive messages".to_string(),
};
}
let messages = messages.unwrap();
let messages_as_b64 = messages
.iter()
.map(|message| base64::encode_config(message, base64::URL_SAFE))
.collect();
ServerResponse::Fetch {
messages: messages_as_b64,
}
}
async fn handle_get_clients(topology: Topology) -> ServerResponse {
let clients = topology
.mix_provider_nodes
.into_iter()
.flat_map(|provider| provider.registered_clients.into_iter())
.map(|client| client.pub_key)
.collect();
ServerResponse::GetClients { clients }
}
async fn handle_own_details(self_address_bytes: DestinationAddressBytes) -> ServerResponse {
let self_address = base64::encode_config(&self_address_bytes, base64::URL_SAFE);
ServerResponse::OwnDetails {
address: self_address,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", rename_all = "camelCase")]
enum ServerResponse {
Send,
Fetch { messages: Vec<String> },
GetClients { clients: Vec<String> },
OwnDetails { address: String },
Error { message: String },
}
impl Into<Message> for ServerResponse {
fn into(self) -> Message {
let str_res = serde_json::to_string(&self).unwrap();
Message::Text(str_res)
}
}
async fn handle_connection(conn: Connection) {
let mut conn = conn;
while let Some(msg) = conn.rx.next().await {
println!("Received a message from {}: {}", conn.address, msg);
let request: ClientRequest = msg.into();
let response = match request {
ClientRequest::Send {
message,
recipient_address,
} => {
ClientRequest::handle_send(message, recipient_address, conn.msg_input.clone()).await
}
ClientRequest::Fetch => ClientRequest::handle_fetch(conn.msg_query.clone()).await,
ClientRequest::GetClients => {
ClientRequest::handle_get_clients(conn.topology.clone()).await
}
ClientRequest::OwnDetails => ClientRequest::handle_own_details(conn.self_address).await,
};
conn.tx
.unbounded_send(response.into())
.expect("Failed to forward message");
}
}
async fn accept_connection(
stream: tokio::net::TcpStream,
msg_input: mpsc::UnboundedSender<InputMessage>,
msg_query: mpsc::UnboundedSender<BufferResponse>,
self_address: DestinationAddressBytes,
topology: Topology,
) {
let address = stream
.peer_addr()
.expect("connected streams should have a peer address");
println!("Peer address: {}", address);
let mut ws_stream = tokio_tungstenite::accept_async(stream)
.await
.expect("Error during the websocket handshake occurred");
println!("New WebSocket connection: {}", address);
// Create a channel for our stream, which other sockets will use to
// send us messages. Then register our address with the stream to send
// data to us.
let (msg_tx, msg_rx) = futures::channel::mpsc::unbounded();
let (response_tx, mut response_rx) = futures::channel::mpsc::unbounded();
let conn = Connection {
address,
rx: msg_rx,
tx: response_tx,
topology,
msg_input,
msg_query,
self_address,
};
tokio::spawn(handle_connection(conn));
while let Some(message) = ws_stream.next().await {
let message = message.expect("Failed to get request");
msg_tx
.unbounded_send(message)
.expect("Failed to forward request");
if let Some(resp) = response_rx.next().await {
ws_stream.send(resp).await.expect("Failed to send response");
}
}
}
pub async fn start_websocket(
address: SocketAddr,
message_tx: mpsc::UnboundedSender<InputMessage>,
received_messages_query_tx: mpsc::UnboundedSender<BufferResponse>,
self_address: DestinationAddressBytes,
topology: Topology,
) -> Result<(), WebSocketError> {
let mut listener = tokio::net::TcpListener::bind(address).await?;
while let Ok((stream, _)) = listener.accept().await {
// it's fine to be cloning the channel on all new connection, because in principle
// this server should only EVER have a single client connected
tokio::spawn(accept_connection(
stream,
message_tx.clone(),
received_messages_query_tx.clone(),
self_address,
topology.clone(),
));
}
eprintln!("The websocket went kaput...");
Ok(())
}
+80
View File
@@ -0,0 +1,80 @@
use std::convert::{TryFrom, TryInto};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
pub enum AddressType {
V4,
V6,
}
impl Into<u8> for AddressType {
fn into(self) -> u8 {
use AddressType::*;
match self {
V4 => 4,
V6 => 6,
}
}
}
#[derive(Debug)]
pub enum AddressTypeError {
InvalidPrefixError,
}
impl TryFrom<u8> for AddressType {
type Error = AddressTypeError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
use AddressType::*;
use AddressTypeError::*;
match value {
4 => Ok(V4),
6 => Ok(V6),
_ => Err(InvalidPrefixError),
}
}
}
/// FLAG || port || octets || zeropad
pub fn encoded_bytes_from_socket_address(address: SocketAddr) -> [u8; 32] {
let port_bytes = address.port().to_be_bytes();
let encoded_host: Vec<u8> = match address.ip() {
IpAddr::V4(ip) => std::iter::once(AddressType::V4.into())
.chain(port_bytes.iter().cloned())
.chain(ip.octets().iter().cloned())
.chain(std::iter::repeat(0))
.take(32)
.collect(),
IpAddr::V6(ip) => std::iter::once(AddressType::V6.into())
.chain(port_bytes.iter().cloned())
.chain(ip.octets().iter().cloned())
.chain(std::iter::repeat(0))
.take(32)
.collect(),
};
let mut address_bytes = [0u8; 32];
address_bytes.copy_from_slice(&encoded_host[..32]);
address_bytes
}
pub fn socket_address_from_encoded_bytes(b: [u8; 32]) -> SocketAddr {
let address_type: AddressType = b[0].try_into().unwrap();
let port: u16 = u16::from_be_bytes([b[1], b[2]]);
let ip = match address_type {
AddressType::V4 => IpAddr::V4(Ipv4Addr::new(b[3], b[4], b[5], b[6])),
AddressType::V6 => {
let mut address_octets = [0u8; 16];
address_octets.copy_from_slice(&b[3..19]);
IpAddr::V6(Ipv6Addr::from(address_octets))
}
};
SocketAddr::new(ip, port)
}
+63
View File
@@ -0,0 +1,63 @@
pub fn zero_pad_to_32(mut bytes: Vec<u8>) -> [u8; 32] {
assert!(bytes.len() <= 32);
if bytes.len() != 32 {
bytes.resize(32, 0);
}
let mut padded_bytes = [0; 32];
padded_bytes.copy_from_slice(&bytes[..]);
padded_bytes
}
#[cfg(test)]
mod zero_padding_to_32_bytes {
use super::*;
#[cfg(test)]
mod with_empty_input {
use super::*;
#[test]
fn it_returns_32_zeros() {
let input = vec![];
let result = zero_pad_to_32(input);
assert_eq!([0u8; 32], result);
}
}
#[cfg(test)]
mod with_all_bytes_set_to_1 {
use super::*;
#[test]
fn it_returns_32_ones() {
let input = vec![1u8; 32];
let result = zero_pad_to_32(input);
assert_eq!([1u8; 32], result);
}
}
#[cfg(test)]
mod with_3_bytes_set {
use super::*;
#[test]
fn it_returns_input_zero_padded_to_32_bytes() {
let input = vec![1u8; 3];
let result = zero_pad_to_32(input);
let expected_content = vec![
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
assert_eq!(expected_content, result.to_vec());
}
}
#[cfg(test)]
mod with_oversized_input {
use super::*;
#[test]
#[should_panic]
fn it_panics() {
let input = vec![1u8; 33];
zero_pad_to_32(input);
}
}
}
+5
View File
@@ -0,0 +1,5 @@
pub mod addressing;
pub mod bytes;
pub mod poisson;
pub mod sphinx;
pub mod topology;
+6
View File
@@ -0,0 +1,6 @@
use rand_distr::{Distribution, Exp};
pub fn sample(average_delay: f64) -> f64 {
let exp = Exp::new(1.0 / average_delay).unwrap();
exp.sample(&mut rand::thread_rng())
}
+48
View File
@@ -0,0 +1,48 @@
use crate::clients::directory::presence::Topology;
use crate::utils::{addressing, bytes, topology};
use curve25519_dalek::montgomery::MontgomeryPoint;
use sphinx::route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier};
use sphinx::SphinxPacket;
use std::net::SocketAddr;
pub const LOOP_COVER_MESSAGE_PAYLOAD: &[u8] = b"The cake is a lie!";
pub fn loop_cover_message(
our_address: DestinationAddressBytes,
surb_id: SURBIdentifier,
topology: &Topology,
) -> (SocketAddr, SphinxPacket) {
let destination = Destination::new(our_address, surb_id);
encapsulate_message(destination, LOOP_COVER_MESSAGE_PAYLOAD.to_vec(), topology)
}
pub fn encapsulate_message(
recipient: Destination,
message: Vec<u8>,
topology: &Topology,
) -> (SocketAddr, SphinxPacket) {
let mixes_route = topology::route_from(&topology);
let first_provider = topology.mix_provider_nodes.first().unwrap();
let decoded_key_bytes =
base64::decode_config(&first_provider.pub_key, base64::URL_SAFE).unwrap();
let key_bytes = bytes::zero_pad_to_32(decoded_key_bytes);
let key = MontgomeryPoint(key_bytes);
let provider = Node::new(
addressing::encoded_bytes_from_socket_address(first_provider.host.clone().parse().unwrap()),
key,
);
let route = [mixes_route, vec![provider]].concat();
let delays = sphinx::header::delays::generate(route.len());
// build the packet
let packet = sphinx::SphinxPacket::new(message, &route[..], &recipient, &delays).unwrap();
let first_node_address =
addressing::socket_address_from_encoded_bytes(route.first().unwrap().address);
(first_node_address, packet)
}
+58
View File
@@ -0,0 +1,58 @@
use crate::clients::directory;
use crate::clients::directory::presence::MixNodePresence;
use crate::clients::directory::presence::Topology;
use crate::clients::directory::requests::presence_topology_get::PresenceTopologyGetRequester;
use crate::clients::directory::DirectoryClient;
use crate::utils::{addressing, bytes};
use curve25519_dalek::montgomery::MontgomeryPoint;
use rand::seq::SliceRandom;
use sphinx::route::Node as SphinxNode;
use std::collections::HashMap;
use std::net::SocketAddr;
pub(crate) fn get_topology(directory_server: String) -> Topology {
println!("Using directory server: {:?}", directory_server);
let directory_config = directory::Config {
base_url: directory_server,
};
let directory = directory::Client::new(directory_config);
let topology = directory
.presence_topology
.get()
.expect("Failed to retrieve network topology.");
topology
}
pub(crate) fn route_from(topology: &Topology) -> Vec<SphinxNode> {
let mut layered_topology: HashMap<u64, Vec<MixNodePresence>> = HashMap::new();
let mixes = topology.mix_nodes.iter();
for mix in mixes {
let layer_nodes = layered_topology.entry(mix.layer).or_insert(Vec::new());
layer_nodes.push(mix.clone());
}
let num_layers = layered_topology.len() as u64;
let mut route = vec![];
for x in 1..=num_layers {
let nodes = &layered_topology[&x];
let the_node = nodes.choose(&mut rand::thread_rng()).unwrap();
route.push(the_node);
}
route
.iter()
.map(|mix| {
let address_bytes =
addressing::encoded_bytes_from_socket_address(mix.host.clone().parse().unwrap());
let decoded_key_bytes = base64::decode_config(&mix.pub_key, base64::URL_SAFE).unwrap();
let key_bytes = bytes::zero_pad_to_32(decoded_key_bytes);
let key = MontgomeryPoint(key_bytes);
SphinxNode {
address: address_bytes,
pub_key: key,
}
})
.collect()
}