Compare commits
486 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4492b4b13 | |||
| 5585a83e3e | |||
| 308af24881 | |||
| 50d7fc73cb | |||
| 01043d7940 | |||
| 2d1961b8be | |||
| e891c68158 | |||
| b1fb032f43 | |||
| 23ea82952e | |||
| 9a65e44166 | |||
| 020cad897d | |||
| 5dfaff6296 | |||
| 5b03982043 | |||
| 8f6856d6fb | |||
| 976dd7aae2 | |||
| 0d21f4e937 | |||
| 1403449ad5 | |||
| e84af4f601 | |||
| 26b032c15c | |||
| cba3625394 | |||
| e1ddaff04d | |||
| 66ab5de442 | |||
| 0b9c03ca90 | |||
| c9dce0c1da | |||
| e00e77db15 | |||
| 1074449f91 | |||
| 08276e6e42 | |||
| 9a3d824a4a | |||
| 2789ee8f18 | |||
| a7ba643c35 | |||
| 28be53eefb | |||
| 219c45a352 | |||
| 1a3b83752e | |||
| c42f3c6844 | |||
| a5d3ba3900 | |||
| cdf0d44341 | |||
| 92f976a45d | |||
| 2bc858cde3 | |||
| 92e13a5d00 | |||
| 122f5d9f2e | |||
| 982ee0266c | |||
| 5f42a9bd05 | |||
| 1811df9ddb | |||
| 6bdfe7f895 | |||
| c6b286a1db | |||
| b3568a26f5 | |||
| 15ae0f521e | |||
| 2923d4b872 | |||
| d740e8b8a9 | |||
| a274edffba | |||
| eec211e038 | |||
| f5f888a0aa | |||
| 86ec1d6026 | |||
| bc3f5838f1 | |||
| 7e58b3273d | |||
| bed09bf8a4 | |||
| 28e55c6de6 | |||
| abb4537551 | |||
| b48f2f1660 | |||
| ccf8063a52 | |||
| 8694396942 | |||
| fb253e53a4 | |||
| fdd34863ba | |||
| 4ac95ad8cf | |||
| 132d550cb6 | |||
| efc5035144 | |||
| ebeac73f30 | |||
| 5303288b9c | |||
| bcac045c77 | |||
| d643df74b3 | |||
| 4c1c6d86c8 | |||
| 623448a220 | |||
| b403ce1e62 | |||
| 6faf8786ea | |||
| aaa4378b33 | |||
| 6512bfb4d9 | |||
| 1afabfd1b6 | |||
| f05e2880a9 | |||
| 81675008a6 | |||
| 8b4fc5719e | |||
| e4f7452241 | |||
| 9602379368 | |||
| 35ba39c196 | |||
| 6d09da40e0 | |||
| de44f21d64 | |||
| edc91e0e36 | |||
| 518cd21fd6 | |||
| b36ca2c4f1 | |||
| 2db79de722 | |||
| 3a9531b586 | |||
| f96d768341 | |||
| 26fb13fe2d | |||
| 67a9d80299 | |||
| 84249cab4b | |||
| f4305dfaa5 | |||
| 0c45c61c85 | |||
| 7d250b3384 | |||
| bb2029e21c | |||
| 0f0611f390 | |||
| 2904141c14 | |||
| c569a7a858 | |||
| 87db1fd8c1 | |||
| a1d2d09f28 | |||
| b949d7b221 | |||
| de468760d6 | |||
| 30a78df986 | |||
| e8622a190a | |||
| 75f098f002 | |||
| b034a07439 | |||
| 68956456dd | |||
| aa048cabe6 | |||
| 5dc67b995e | |||
| 721e4bda8b | |||
| 2673f83116 | |||
| bc68513a78 | |||
| 91250f199a | |||
| 3ec92a0784 | |||
| 70a9317ab3 | |||
| 71e36065e5 | |||
| 389d1ba3b9 | |||
| 18f5d4084d | |||
| 83744962f1 | |||
| df08a894cc | |||
| 2354828481 | |||
| 74693bda6f | |||
| 613ff5da71 | |||
| a11937699f | |||
| eb59ca77ef | |||
| 12d07fd870 | |||
| 1d18def642 | |||
| 70d4bce42f | |||
| c81454e00b | |||
| ac4ee2bcf2 | |||
| 9184c119d6 | |||
| 216b114346 | |||
| 793dbdef7e | |||
| 432e1e6065 | |||
| c8a02e1354 | |||
| 698345dbe9 | |||
| 5568073c17 | |||
| addb721d66 | |||
| 3bbf959086 | |||
| 0db4aa5f39 | |||
| f41ee7700d | |||
| 1c335d3172 | |||
| 191b3c09e2 | |||
| 725b4de74a | |||
| ce038bf56a | |||
| 8727038443 | |||
| afbed0e438 | |||
| b6a026da83 | |||
| fc74b723fa | |||
| b1fe1f6073 | |||
| 043ca9a63e | |||
| 46b49eea2f | |||
| 7430eb99cf | |||
| 111cccea97 | |||
| 5e9d87b1ad | |||
| c28b320b66 | |||
| a80a1bbe34 | |||
| c1808ae692 | |||
| d8277e851f | |||
| c795490164 | |||
| 3f2fa717c9 | |||
| c0be2330b0 | |||
| e86467d007 | |||
| e5afd54ce0 | |||
| 25d2af3b04 | |||
| 8e24583f2a | |||
| c09846bb36 | |||
| 86034bd955 | |||
| a9797879e8 | |||
| 407d2bba47 | |||
| 8f4b5ab4c7 | |||
| 0fd203371d | |||
| 68f2d8b925 | |||
| 973c30592f | |||
| 3886ec5291 | |||
| 929775c517 | |||
| 427893efef | |||
| cb33871934 | |||
| 4a86b24ff5 | |||
| 8f98de4abc | |||
| e6460208d3 | |||
| 3b7315d1e2 | |||
| 3aafe54887 | |||
| f08f19cd86 | |||
| 2e6a32b298 | |||
| 57df77a995 | |||
| 343c55f981 | |||
| 1660e0796d | |||
| b30f11ed7a | |||
| 2bdee705b7 | |||
| 31f567f1ef | |||
| 216573b65b | |||
| 4102690cf1 | |||
| a82ac9c50d | |||
| bb0257ccc6 | |||
| 142a70365f | |||
| 12ddf80fe9 | |||
| 34fcca052b | |||
| e06e7aa8f3 | |||
| 4d701be053 | |||
| 3bf02c558c | |||
| e7dcc8dc30 | |||
| b7f197d278 | |||
| 3412a0b7bd | |||
| 23951acdec | |||
| b56bb7f226 | |||
| f0fafe97fe | |||
| 9df360cf63 | |||
| 035ee3a402 | |||
| 035a2554ee | |||
| 4c8f8ff1b6 | |||
| 35cddab3bd | |||
| 0a5f6f2ca7 | |||
| 53253d443c | |||
| 07f2f9c39e | |||
| 1d4026ec71 | |||
| 6524fa3f9c | |||
| 6e24b2681b | |||
| 5ba20268dd | |||
| 4e03759c0f | |||
| a6be3e763f | |||
| 29ac119127 | |||
| 67ce93ffc8 | |||
| 08964f8775 | |||
| d8d2d84aa7 | |||
| 7d69fa3ed5 | |||
| dff7a8976a | |||
| 50fbe55be9 | |||
| 648543e536 | |||
| 3d2654923a | |||
| d03798629c | |||
| e470ac4b0f | |||
| 9324e3511f | |||
| 23d0607239 | |||
| ebba222a86 | |||
| fdbecb2a3f | |||
| 785513914c | |||
| c789853b32 | |||
| 97ec416b3e | |||
| 164c8ad05c | |||
| 7b02026476 | |||
| 1fb26b68c6 | |||
| 29fd8b8805 | |||
| 31b9048144 | |||
| 10c0e04926 | |||
| c0ad3ce1a6 | |||
| 82def1349f | |||
| 94a52aa2db | |||
| 50f65aa698 | |||
| e12314a6fa | |||
| 15e377e678 | |||
| 7b1dab8546 | |||
| 93e9dc5c1e | |||
| 0dcb046576 | |||
| 5288510979 | |||
| 81481832d8 | |||
| 27e704ab80 | |||
| da339a83cd | |||
| 99780d3eb0 | |||
| aee0ec7dec | |||
| b8e8beb62b | |||
| b4ef0ae4f3 | |||
| d9087bf2a9 | |||
| 2f29ee49db | |||
| abc5a58b19 | |||
| 01d7e3a5f2 | |||
| ea08fad2e0 | |||
| a47bbf1e67 | |||
| 1fe38b1b9c | |||
| ed489149dc | |||
| 190d3c4972 | |||
| ea62d01e65 | |||
| 97156c918b | |||
| d79013f1c1 | |||
| b69b221e62 | |||
| 266138dcf2 | |||
| a8299e867d | |||
| 7dc4d653c2 | |||
| 2f9e67e8b2 | |||
| 2c058bcbca | |||
| 528eba2faa | |||
| 7f7c37eeba | |||
| 18adb1f5bd | |||
| a521bc0f54 | |||
| 6f173ffebd | |||
| 7e31cbabe5 | |||
| e8e966b67a | |||
| 73af405400 | |||
| 037723eb90 | |||
| d432bebce8 | |||
| 0a3cffa1a1 | |||
| 796107c4c5 | |||
| fd0df9fe47 | |||
| 58a7f4ea5f | |||
| 725b8d6f8a | |||
| e5a1c1c97e | |||
| b894dbf243 | |||
| 92821c8d81 | |||
| af8360f363 | |||
| 8b12a31f73 | |||
| fd55eb678c | |||
| bb3ce645a4 | |||
| 4e339f1788 | |||
| dca9c7079c | |||
| 52a8909e77 | |||
| 9d2c445bb7 | |||
| 6a1c2fa5dd | |||
| 809c3f3607 | |||
| bebf0df2de | |||
| 5652eb7ee3 | |||
| b6ba8f8555 | |||
| 22bfd44065 | |||
| 3136346a01 | |||
| f536449f0c | |||
| 7659424f28 | |||
| eff40dd907 | |||
| 800af218a5 | |||
| f5c1b6dfdd | |||
| dfdfba5d2f | |||
| 047a483464 | |||
| 4a908e7e14 | |||
| bcf25135a1 | |||
| 087efbe553 | |||
| 2be0ab6474 | |||
| 9a1abfad9c | |||
| f7f119b100 | |||
| bd78f8833f | |||
| 4a081d6fa7 | |||
| 42268e044c | |||
| 48dda32c3e | |||
| a21ed92ac3 | |||
| ee71ae89f7 | |||
| a97377fdea | |||
| 1d4420820f | |||
| 596bc76cc6 | |||
| cc1b80229c | |||
| f07ac48a33 | |||
| 8abfc43fc8 | |||
| 7361d7a220 | |||
| 52d4ddb714 | |||
| ca60b8671c | |||
| 9e0bb80163 | |||
| ce7dcbc163 | |||
| cf93afb639 | |||
| 1119a9e55f | |||
| 51d2213819 | |||
| b567ee55f3 | |||
| 5ef77185a1 | |||
| 4ae8ae7231 | |||
| 2e7cd451ec | |||
| d301694404 | |||
| 752bce589b | |||
| 67c92b3e56 | |||
| d3570df968 | |||
| 261993ea90 | |||
| 0ae29eb5fa | |||
| 87408d4b7b | |||
| 503f723a64 | |||
| 9c72aac255 | |||
| 34a143696f | |||
| de22936ed1 | |||
| 9da9c95c80 | |||
| a7fe4697c5 | |||
| 1d9bced599 | |||
| a854118f19 | |||
| d496ee3031 | |||
| f29dd884f3 | |||
| e1181f756c | |||
| 4ca40fd3bc | |||
| 6483a62a7c | |||
| 83753af944 | |||
| 6f8ae53f0c | |||
| 2f867b75f2 | |||
| ea31e18d98 | |||
| d03af9de05 | |||
| 4013d0c939 | |||
| 3a261d22f5 | |||
| 2314baf0d3 | |||
| c882778583 | |||
| c67e0fee37 | |||
| 863aa4535a | |||
| 86c9ab2ef5 | |||
| 12faa23222 | |||
| 9cd463b22c | |||
| d7ec81ad0a | |||
| 2d3b4f4b91 | |||
| 131574cd3c | |||
| 8b29c612f8 | |||
| 9c67b73472 | |||
| 6b37a9b95c | |||
| 67ac1d9f4b | |||
| 28410eedad | |||
| 0fb182ccb9 | |||
| 7953e36e82 | |||
| 9cea2777d4 | |||
| 46d3591a4f | |||
| 5fc81db0d9 | |||
| fbdca2dcd5 | |||
| afb7825135 | |||
| c2a1ed855b | |||
| 210b5466bb | |||
| 33d5effbdc | |||
| fa5c512aa8 | |||
| c1b2a9aaa7 | |||
| cdef90c2a4 | |||
| 8e80651617 | |||
| 80775b7436 | |||
| 83dcd75cea | |||
| d52ea90cd2 | |||
| cb59153422 | |||
| 89f03e63c7 | |||
| 692f9cb198 | |||
| 455e735da4 | |||
| 4b34ed1f16 | |||
| 08cb39d0af | |||
| 1d851c390c | |||
| a69123ebc1 | |||
| e3e633fce4 | |||
| 09d053c557 | |||
| 2fa5c3c3b7 | |||
| 3f86919d44 | |||
| 4e7dbd93ed | |||
| 0944c127ac | |||
| 9cc28db732 | |||
| 21d27495f4 | |||
| 36ec2fef60 | |||
| 830a89cfd4 | |||
| c18766a617 | |||
| f1e61b16b1 | |||
| 3a5ed57eff | |||
| a0b1e00321 | |||
| 652f39d86d | |||
| 3372d38b2d | |||
| a3d9149d2a | |||
| 6a2412f5dd | |||
| 3ef40035ad | |||
| 4da04978be | |||
| 0649593116 | |||
| 818405982d | |||
| 7976776399 | |||
| 69eefaf91f | |||
| 7d694194ca | |||
| be49c3843a | |||
| bb04961b41 | |||
| a91b2dcafc | |||
| 7c04a10545 | |||
| 7eaef53c62 | |||
| d6a191a9b1 | |||
| 566eb87b83 | |||
| e4c8a6b72b | |||
| 9d9d530581 | |||
| 00b2ce18c8 | |||
| 72496ad2aa | |||
| d7985ef05d | |||
| 607297bf54 | |||
| 7c65101609 | |||
| 72e9fb1bc3 | |||
| 4099701852 | |||
| 0f0a428142 | |||
| 12584749c8 | |||
| e759db4ed4 | |||
| 7064e85e5a | |||
| 495ca35c1f | |||
| 3c07a690a2 | |||
| 7c808ae356 | |||
| e236b9f1af | |||
| 2585efc540 | |||
| d940bc8f31 | |||
| 2f7b3eec08 | |||
| c8bf454ccc | |||
| e7bd27a2d0 | |||
| 174206ca36 | |||
| 366335a015 | |||
| 9c5cd54264 | |||
| 1e35eeefaa | |||
| c3a812b3cb | |||
| 124712a954 | |||
| 4f6b2aea19 | |||
| ebea0166f1 | |||
| d05b313a99 | |||
| 689c4fc66c | |||
| c50e9a9ed7 | |||
| 23edeefcdc |
@@ -1,2 +1,5 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
RUST_LOG=info
|
||||
RUST_BACKTRACE=1
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Global owners. If you want to set more specific (per-directory, per-language) owners, see the write-up at
|
||||
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners
|
||||
* @durch @futurechimp @jstuczyn @neacsu
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Continuous integration
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' }}
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [stable, beta, nightly]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all
|
||||
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
@@ -0,0 +1,14 @@
|
||||
name: Clippy check
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
clippy_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- run: rustup component add clippy
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
@@ -0,0 +1,44 @@
|
||||
name: Mixnet Contract
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
mixnet-contract:
|
||||
# since it's going to be compiled into wasm, there's absolutely
|
||||
# no point in running CI on different OS-es
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [ stable, beta, nightly ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path contracts/mixnet/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path contracts/mixnet/Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path contracts/mixnet/Cargo.toml -- --check
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path contracts/mixnet/Cargo.toml -- -D warnings
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Generate TS types
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
tauri-wallet-types:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Generate TS
|
||||
run: cd tauri-wallet/src-tauri && cargo test
|
||||
- uses: EndBug/add-and-commit@v7.2.1 # https://github.com/marketplace/actions/add-commit
|
||||
with:
|
||||
add: '["tauri-wallet"]'
|
||||
message: '[ci skip] Generate TS types'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,39 @@
|
||||
name: Wasm Client
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
wasm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: test
|
||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path clients/webassembly/Cargo.toml -- --check
|
||||
|
||||
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: clippy
|
||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||
+15
@@ -1,3 +1,6 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/targetString
|
||||
**/*.rs.bk
|
||||
/*/target
|
||||
@@ -15,3 +18,15 @@ scripts/run_mix.sh
|
||||
scripts/start_local_tmux_network.sh
|
||||
/.floo
|
||||
/.flooignore
|
||||
qa-v4-topology.json
|
||||
qa-v6-topology.json
|
||||
v4-topology.json
|
||||
v6-topology.json
|
||||
/explorer/downloads/topology.json
|
||||
/explorer/public/downloads/mixmining.json
|
||||
/explorer/public/downloads/topology.json
|
||||
/clients/validator/examples/nym-driver-example/current-contract.txt
|
||||
validator-api/v4.json
|
||||
validator-api/v6.json
|
||||
**/node_modules
|
||||
validator-api/keypair
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: nym
|
||||
Upstream-Contact: Nym Technologies SA <contact@nymtech.net>
|
||||
Source: https://github.com/nymtech/nym
|
||||
|
||||
|
||||
Files: *clients/* *common/* *explorer/*
|
||||
Copyright: 2020, Nym Technologies SA <contact@nymtech.net>
|
||||
License: Apache-2.0
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
jobs:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
before_script:
|
||||
- rustup component add rustfmt
|
||||
script:
|
||||
- cargo build
|
||||
- cargo test -- --test-threads=1
|
||||
- cargo fmt -- --check
|
||||
+451
-15
@@ -1,6 +1,442 @@
|
||||
# Changelog
|
||||
|
||||
## [v0.8.0](https://github.com/nymtech/nym/tree/v0.8.0)
|
||||
## [v0.11.0](https://github.com/nymtech/nym/tree/v0.11.0) (2021-07-21)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.10.1...v0.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Investigate why --clients-host and --mix-host are distinct for gateways [\#435](https://github.com/nymtech/nym/issues/435)
|
||||
- Bugfix/verloc fixes and adjustments [\#618](https://github.com/nymtech/nym/pull/618) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Update the metrics endpoint [\#597](https://github.com/nymtech/nym/issues/597)
|
||||
- Intercontinental problems [\#143](https://github.com/nymtech/nym/issues/143)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Rename `PagedResponse` into `PagedMixnodeResponse` [\#657](https://github.com/nymtech/nym/issues/657)
|
||||
- Change `u64` layer type in contract code [\#648](https://github.com/nymtech/nym/issues/648)
|
||||
- Change `String` types of sphinx and identity keys in contract code [\#647](https://github.com/nymtech/nym/issues/647)
|
||||
- Remove the terrible `decimal_sub_one` once we update contract/validators [\#639](https://github.com/nymtech/nym/issues/639)
|
||||
- After update: failed to receive reply to our echo packet within 1.5s. Stopping the test [\#621](https://github.com/nymtech/nym/issues/621)
|
||||
- update to v0.10.1, it show ERROR message "failed to receive reply to our echo packet within 1.5s" [\#620](https://github.com/nymtech/nym/issues/620)
|
||||
- Make validator client send as much tokens for bonding as required [\#614](https://github.com/nymtech/nym/issues/614)
|
||||
- Update mixnode `init` to not query for entire topology [\#610](https://github.com/nymtech/nym/issues/610)
|
||||
- Potentially extend metrics with number of dropped packets [\#595](https://github.com/nymtech/nym/issues/595)
|
||||
- Delegated staking for gateways [\#579](https://github.com/nymtech/nym/issues/579)
|
||||
- Delegated staking for mixnodes [\#578](https://github.com/nymtech/nym/issues/578)
|
||||
- Improved mixnode and gateway info [\#577](https://github.com/nymtech/nym/issues/577)
|
||||
- Gateway bonding [\#576](https://github.com/nymtech/nym/issues/576)
|
||||
- No graceful degradation on low traffic [\#513](https://github.com/nymtech/nym/issues/513)
|
||||
- Network monitor should not update when 0 packets come back [\#456](https://github.com/nymtech/nym/issues/456)
|
||||
- Add mixnode statistics endpoint [\#406](https://github.com/nymtech/nym/issues/406)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Return the vec instead of the cache wrapper for topology [\#695](https://github.com/nymtech/nym/pull/695) ([neacsu](https://github.com/neacsu))
|
||||
- Updated sign command [\#694](https://github.com/nymtech/nym/pull/694) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- got rid of denomination error in webwallet bonding interface [\#691](https://github.com/nymtech/nym/pull/691) ([mfahampshire](https://github.com/mfahampshire))
|
||||
- Docker testing env [\#687](https://github.com/nymtech/nym/pull/687) ([neacsu](https://github.com/neacsu))
|
||||
- Changed Layer serde behaviour for easier usage [\#686](https://github.com/nymtech/nym/pull/686) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Merge the nym-wallet-web repo into a nym directory [\#684](https://github.com/nymtech/nym/pull/684) ([neacsu](https://github.com/neacsu))
|
||||
- Temporarily using non-cached gateways so we can get our next version … [\#683](https://github.com/nymtech/nym/pull/683) ([futurechimp](https://github.com/futurechimp))
|
||||
- Updating wallet URL in mixnode startup output [\#682](https://github.com/nymtech/nym/pull/682) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/node status api [\#680](https://github.com/nymtech/nym/pull/680) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Using specific commit of rocket cors [\#678](https://github.com/nymtech/nym/pull/678) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Disables nightly clippy CI [\#677](https://github.com/nymtech/nym/pull/677) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Minimize read/write cache contention [\#676](https://github.com/nymtech/nym/pull/676) ([durch](https://github.com/durch))
|
||||
- Feature/validator client upgrade [\#675](https://github.com/nymtech/nym/pull/675) ([futurechimp](https://github.com/futurechimp))
|
||||
- Use cached topology for clients [\#674](https://github.com/nymtech/nym/pull/674) ([neacsu](https://github.com/neacsu))
|
||||
- Use rocket 0.5-rc1, remove rocket-contrib [\#672](https://github.com/nymtech/nym/pull/672) ([durch](https://github.com/durch))
|
||||
- Feature/validator api config [\#671](https://github.com/nymtech/nym/pull/671) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fix a dependabot nag [\#670](https://github.com/nymtech/nym/pull/670) ([durch](https://github.com/durch))
|
||||
- Removed standalone network-monitor [\#669](https://github.com/nymtech/nym/pull/669) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Remove mut where possible, parallel cache requests [\#668](https://github.com/nymtech/nym/pull/668) ([durch](https://github.com/durch))
|
||||
- Rework validator client requests [\#667](https://github.com/nymtech/nym/pull/667) ([durch](https://github.com/durch))
|
||||
- Generalize cache, and cache gateways [\#666](https://github.com/nymtech/nym/pull/666) ([durch](https://github.com/durch))
|
||||
- Validator API server [\#665](https://github.com/nymtech/nym/pull/665) ([durch](https://github.com/durch))
|
||||
- Layer selection [\#664](https://github.com/nymtech/nym/pull/664) ([neacsu](https://github.com/neacsu))
|
||||
- Removing validator binaries, these should go into Github releases [\#663](https://github.com/nymtech/nym/pull/663) ([futurechimp](https://github.com/futurechimp))
|
||||
- Rename network-monitor [\#662](https://github.com/nymtech/nym/pull/662) ([durch](https://github.com/durch))
|
||||
- Adds @neacsu as code owner [\#661](https://github.com/nymtech/nym/pull/661) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/total delegation field [\#660](https://github.com/nymtech/nym/pull/660) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- contracts: Removed mixnode location from the bonding process [\#659](https://github.com/nymtech/nym/pull/659) ([neacsu](https://github.com/neacsu))
|
||||
- Use thiserror for validator-client [\#658](https://github.com/nymtech/nym/pull/658) ([durch](https://github.com/durch))
|
||||
- Feature/configurable verloc http ports [\#656](https://github.com/nymtech/nym/pull/656) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/describe location [\#655](https://github.com/nymtech/nym/pull/655) ([neacsu](https://github.com/neacsu))
|
||||
- Feature/host ip split [\#654](https://github.com/nymtech/nym/pull/654) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/cosmwasm 0.14.1 update [\#653](https://github.com/nymtech/nym/pull/653) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Allow passing optional explicit bond value [\#652](https://github.com/nymtech/nym/pull/652) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Introduced type aliases for mixnode and gateway keys [\#650](https://github.com/nymtech/nym/pull/650) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bugfix/delegation type fixes [\#649](https://github.com/nymtech/nym/pull/649) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removing the ancient explorer in preparation for a new dawn. [\#645](https://github.com/nymtech/nym/pull/645) ([futurechimp](https://github.com/futurechimp))
|
||||
- Testing code owners again [\#644](https://github.com/nymtech/nym/pull/644) ([futurechimp](https://github.com/futurechimp))
|
||||
- TypeScript client v0.12.0 [\#641](https://github.com/nymtech/nym/pull/641) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/reverse contract mapping [\#640](https://github.com/nymtech/nym/pull/640) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump websockets from 8.1 to 9.1 in /clients/native/examples/python-examples/websocket [\#638](https://github.com/nymtech/nym/pull/638) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Chore/clippy nightly fixes [\#636](https://github.com/nymtech/nym/pull/636) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/delegated staking [\#635](https://github.com/nymtech/nym/pull/635) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump ws from 6.2.1 to 6.2.2 in /clients/validator [\#634](https://github.com/nymtech/nym/pull/634) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump ws from 6.2.1 to 6.2.2 in /clients/native/examples/js-examples/websocket [\#633](https://github.com/nymtech/nym/pull/633) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump ws from 6.2.1 to 6.2.2 in /clients/webassembly/js-example [\#632](https://github.com/nymtech/nym/pull/632) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/stats endpoint [\#631](https://github.com/nymtech/nym/pull/631) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated all js related dependencies [\#629](https://github.com/nymtech/nym/pull/629) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/per layer count [\#628](https://github.com/nymtech/nym/pull/628) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Changed rewarding behaviour on not found bonds [\#627](https://github.com/nymtech/nym/pull/627) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump dns-packet from 1.3.1 to 1.3.4 in /clients/native/examples/js-examples/websocket [\#626](https://github.com/nymtech/nym/pull/626) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump dns-packet from 1.3.1 to 1.3.4 in /clients/webassembly/js-example [\#625](https://github.com/nymtech/nym/pull/625) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/update validator binaries [\#624](https://github.com/nymtech/nym/pull/624) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Checking for required bond rather than using hardcoded value [\#623](https://github.com/nymtech/nym/pull/623) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump browserslist from 4.14.1 to 4.16.6 in /clients/native/examples/js-examples/websocket [\#619](https://github.com/nymtech/nym/pull/619) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Changed omitted print to a debug call [\#617](https://github.com/nymtech/nym/pull/617) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.10.1](https://github.com/nymtech/nym/tree/v0.10.1) (2021-05-25)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.10.0...v0.10.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Prometheus metrics doesn't work [\#606](https://github.com/nymtech/nym/issues/606)
|
||||
- Bonding hostname vs. ip-address does not show up on NYM explorer [\#593](https://github.com/nymtech/nym/issues/593)
|
||||
- Cannot assign requested address [\#584](https://github.com/nymtech/nym/issues/584)
|
||||
- Native client upgrade command is broken [\#582](https://github.com/nymtech/nym/issues/582)
|
||||
- Spread directory requests across good validators [\#580](https://github.com/nymtech/nym/issues/580)
|
||||
- Change network monitor to use currency-based rewareds [\#540](https://github.com/nymtech/nym/issues/540)
|
||||
- Unregistration for protocol ipv6 does not work [\#511](https://github.com/nymtech/nym/issues/511)
|
||||
- Network monitor view on validators [\#373](https://github.com/nymtech/nym/issues/373)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Bugfix/unique node ownership [\#612](https://github.com/nymtech/nym/pull/612) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Decreased log severity for verloc-related functionalities [\#611](https://github.com/nymtech/nym/pull/611) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Disabled metrics reporting to the central server [\#609](https://github.com/nymtech/nym/pull/609) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/network monitor gateway pings [\#608](https://github.com/nymtech/nym/pull/608) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Implemented display traits for identity and encryption keys [\#607](https://github.com/nymtech/nym/pull/607) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/add node description api [\#605](https://github.com/nymtech/nym/pull/605) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/updated network monitor [\#604](https://github.com/nymtech/nym/pull/604) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/ping timings [\#603](https://github.com/nymtech/nym/pull/603) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump lodash from 4.17.20 to 4.17.21 in /clients/validator [\#602](https://github.com/nymtech/nym/pull/602) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump lodash from 4.17.20 to 4.17.21 in /clients/native/examples/js-examples/websocket [\#601](https://github.com/nymtech/nym/pull/601) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/add rocket [\#600](https://github.com/nymtech/nym/pull/600) ([futurechimp](https://github.com/futurechimp))
|
||||
- Bump url-parse from 1.4.7 to 1.5.1 in /clients/native/examples/js-examples/websocket [\#599](https://github.com/nymtech/nym/pull/599) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump url-parse from 1.4.7 to 1.5.1 in /clients/webassembly/js-example [\#598](https://github.com/nymtech/nym/pull/598) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Recalculating reward rates on appropriate value changes [\#594](https://github.com/nymtech/nym/pull/594) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Changed default mixnode query page limit [\#592](https://github.com/nymtech/nym/pull/592) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/more exposed client api [\#591](https://github.com/nymtech/nym/pull/591) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Contract adjustment to check for node ownership before allowing bonding [\#590](https://github.com/nymtech/nym/pull/590) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump ssri from 6.0.1 to 6.0.2 in /clients/webassembly/js-example [\#589](https://github.com/nymtech/nym/pull/589) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump ssri from 6.0.1 to 6.0.2 in /clients/native/examples/js-examples/websocket [\#588](https://github.com/nymtech/nym/pull/588) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Impl Error trait for ValidatorClientError [\#587](https://github.com/nymtech/nym/pull/587) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Checking for tx success when sending coins [\#586](https://github.com/nymtech/nym/pull/586) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Logging adjustment [\#585](https://github.com/nymtech/nym/pull/585) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/multiple validator endpoints [\#583](https://github.com/nymtech/nym/pull/583) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Refreshing nodes gets all available nodes from the contract [\#575](https://github.com/nymtech/nym/pull/575) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/simple payments [\#571](https://github.com/nymtech/nym/pull/571) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Minor cosmetic changes while reading around [\#568](https://github.com/nymtech/nym/pull/568) ([huitseeker](https://github.com/huitseeker))
|
||||
|
||||
## [v0.10.0](https://github.com/nymtech/nym/tree/v0.10.0) (2021-04-15)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/validator-client-0.10.0-rc1...v0.10.0)
|
||||
|
||||
This release brings a distributed directory authority powered by [Cosmos SDK](https://cosmos.network) and [CosmWasm](https://cosmwasm.com) smart contracts. It is designed to run [Testnet Finney](https://testnet-finney-explorer.nymtech.net), the new Nym testnet.
|
||||
|
||||
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- When I run this command :'./nym-mixnode run --id zzznym', an error occurs [\#548](https://github.com/nymtech/nym/issues/548)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Displaying address of the client on init [\#573](https://github.com/nymtech/nym/pull/573) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed nightly clippy warnings [\#572](https://github.com/nymtech/nym/pull/572) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Changed default client topology refresh rate from 30s to 5min [\#570](https://github.com/nymtech/nym/pull/570) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Adding the wallet url in startup instructions [\#569](https://github.com/nymtech/nym/pull/569) ([futurechimp](https://github.com/futurechimp))
|
||||
- Removed unused data from cargo.toml [\#567](https://github.com/nymtech/nym/pull/567) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/cli signing [\#566](https://github.com/nymtech/nym/pull/566) ([futurechimp](https://github.com/futurechimp))
|
||||
- Updated version number on the validator client [\#565](https://github.com/nymtech/nym/pull/565) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Renamed mixnode registration into bonding [\#564](https://github.com/nymtech/nym/pull/564) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- A pull request for discussion about contract state variables [\#563](https://github.com/nymtech/nym/pull/563) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/mixnet contract ci [\#562](https://github.com/nymtech/nym/pull/562) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/bonding adjustments [\#561](https://github.com/nymtech/nym/pull/561) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/migration additions [\#560](https://github.com/nymtech/nym/pull/560) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Changed default contract execution gas limit to 250\_000 \(from 9\_000\_000\_000\) [\#559](https://github.com/nymtech/nym/pull/559) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Missing quotes in mixnet\_contract\_address config field [\#558](https://github.com/nymtech/nym/pull/558) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated default validator url and contract address [\#557](https://github.com/nymtech/nym/pull/557) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump y18n from 4.0.0 to 4.0.1 in /clients/native/examples/js-examples/websocket [\#556](https://github.com/nymtech/nym/pull/556) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/bonding info on init [\#555](https://github.com/nymtech/nym/pull/555) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator client address getter [\#554](https://github.com/nymtech/nym/pull/554) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Added extra step for publishing validator client [\#553](https://github.com/nymtech/nym/pull/553) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator client rc3 [\#552](https://github.com/nymtech/nym/pull/552) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/upgrade update [\#551](https://github.com/nymtech/nym/pull/551) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/export coin helper [\#550](https://github.com/nymtech/nym/pull/550) ([futurechimp](https://github.com/futurechimp))
|
||||
- Chore/dependency updates [\#549](https://github.com/nymtech/nym/pull/549) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator query client [\#547](https://github.com/nymtech/nym/pull/547) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator client rc2 [\#546](https://github.com/nymtech/nym/pull/546) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/has node query validator client [\#545](https://github.com/nymtech/nym/pull/545) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Added contract query to check if given address owns a mixnode/gateway [\#544](https://github.com/nymtech/nym/pull/544) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [validator-client-0.10.0-rc1](https://github.com/nymtech/nym/tree/validator-client-0.10.0-rc1) (2021-03-24)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.2...validator-client-0.10.0-rc1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add option to whitelist IPv4 ranges to allowed.list in sphinx-socks [\#415](https://github.com/nymtech/nym/issues/415)
|
||||
- Mixmining monitoring for gateways [\#384](https://github.com/nymtech/nym/issues/384)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Network requester should periodically remove stale proxies [\#424](https://github.com/nymtech/nym/issues/424)
|
||||
- Network requester now prints correct version with --version [\#478](https://github.com/nymtech/nym/pull/478) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Change topology to work with validators. [\#538](https://github.com/nymtech/nym/issues/538)
|
||||
- Unable to rejoin the network after powerdown [\#514](https://github.com/nymtech/nym/issues/514)
|
||||
- nym-socks5-client 0.9.2 issue with outbound\_request\_filter.check [\#498](https://github.com/nymtech/nym/issues/498)
|
||||
- nym-socks5-client high CPU usage on idle [\#491](https://github.com/nymtech/nym/issues/491)
|
||||
- network requester too many Received a 'Send' before 'Connect' - going to buffer the data [\#483](https://github.com/nymtech/nym/issues/483)
|
||||
- Socks5 client loops on malformed - invalidaddress message [\#482](https://github.com/nymtech/nym/issues/482)
|
||||
- Socks5 client hangs [\#479](https://github.com/nymtech/nym/issues/479)
|
||||
- Network Requester -V flag does not print version [\#469](https://github.com/nymtech/nym/issues/469)
|
||||
- Gateway reconnection \(wasm\) [\#458](https://github.com/nymtech/nym/issues/458)
|
||||
- Client warning 'No valid topology' [\#343](https://github.com/nymtech/nym/issues/343)
|
||||
- private key file permission bits too open, readable for others [\#319](https://github.com/nymtech/nym/issues/319)
|
||||
- Fix dependabot security notice [\#267](https://github.com/nymtech/nym/issues/267)
|
||||
- Change how time intervals are serialized in configs [\#141](https://github.com/nymtech/nym/issues/141)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- RC1 published [\#543](https://github.com/nymtech/nym/pull/543) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/prep for publish [\#542](https://github.com/nymtech/nym/pull/542) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/bigger better stronger mnemonics [\#541](https://github.com/nymtech/nym/pull/541) ([futurechimp](https://github.com/futurechimp))
|
||||
- Removed a package-lock.json which seems to have been accidentally added [\#539](https://github.com/nymtech/nym/pull/539) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/convert to uhal [\#537](https://github.com/nymtech/nym/pull/537) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/topology conversion [\#536](https://github.com/nymtech/nym/pull/536) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/hook up url in validator client [\#535](https://github.com/nymtech/nym/pull/535) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/upgrade cosm client [\#534](https://github.com/nymtech/nym/pull/534) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/mix contract identity key [\#533](https://github.com/nymtech/nym/pull/533) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator client rust [\#532](https://github.com/nymtech/nym/pull/532) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/add currency helpers [\#531](https://github.com/nymtech/nym/pull/531) ([futurechimp](https://github.com/futurechimp))
|
||||
- Exporting Coin struct, needed for wallet [\#530](https://github.com/nymtech/nym/pull/530) ([futurechimp](https://github.com/futurechimp))
|
||||
- Getting correct user home dir in Python setup script [\#528](https://github.com/nymtech/nym/pull/528) ([futurechimp](https://github.com/futurechimp))
|
||||
- Temporarily disabling fs access [\#527](https://github.com/nymtech/nym/pull/527) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/validator client gateway bonding [\#526](https://github.com/nymtech/nym/pull/526) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed eslint errors in the validator client [\#525](https://github.com/nymtech/nym/pull/525) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/gateway bonding [\#524](https://github.com/nymtech/nym/pull/524) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fix the remove mixnode test [\#522](https://github.com/nymtech/nym/pull/522) ([futurechimp](https://github.com/futurechimp))
|
||||
- Bump elliptic from 6.5.3 to 6.5.4 in /clients/native/examples/js-examples/websocket [\#521](https://github.com/nymtech/nym/pull/521) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/fix go errors in examples [\#516](https://github.com/nymtech/nym/pull/516) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/initial mixnet contract [\#515](https://github.com/nymtech/nym/pull/515) ([futurechimp](https://github.com/futurechimp))
|
||||
- Running CI also on windows and macOS [\#512](https://github.com/nymtech/nym/pull/512) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/socks5 adjustments [\#510](https://github.com/nymtech/nym/pull/510) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed unused import in non-unix systems [\#509](https://github.com/nymtech/nym/pull/509) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Checking if the delay has already expired before attempting to put it… [\#508](https://github.com/nymtech/nym/pull/508) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Not including gateway non-delay when calculating total packet delay [\#507](https://github.com/nymtech/nym/pull/507) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Allowing for a single topology refresh failure [\#505](https://github.com/nymtech/nym/pull/505) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- More restrictive unix key files permissions [\#504](https://github.com/nymtech/nym/pull/504) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- More human-readable errors on mixnode/gateway startup [\#503](https://github.com/nymtech/nym/pull/503) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/ip filtering [\#502](https://github.com/nymtech/nym/pull/502) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/wasm client compilation fixes [\#501](https://github.com/nymtech/nym/pull/501) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed possible crash on invalid topology [\#500](https://github.com/nymtech/nym/pull/500) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/gateway monitoring [\#499](https://github.com/nymtech/nym/pull/499) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/GitHub actions and clippy cleanup [\#493](https://github.com/nymtech/nym/pull/493) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fix typos [\#492](https://github.com/nymtech/nym/pull/492) ([rex4539](https://github.com/rex4539))
|
||||
- Bump ini from 1.3.5 to 1.3.8 in /clients/native/examples/js-examples/websocket [\#490](https://github.com/nymtech/nym/pull/490) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump ini from 1.3.5 to 1.3.8 in /clients/webassembly/js-example [\#489](https://github.com/nymtech/nym/pull/489) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- display 0 on no validators rather than crash [\#488](https://github.com/nymtech/nym/pull/488) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- NGI0 - Updating licensing aspects according REUSE [\#487](https://github.com/nymtech/nym/pull/487) ([lnceballosz](https://github.com/lnceballosz))
|
||||
- Feature/removed topology [\#481](https://github.com/nymtech/nym/pull/481) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bugfix/explorer fixes [\#477](https://github.com/nymtech/nym/pull/477) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/0.9.2+only monitoring [\#475](https://github.com/nymtech/nym/pull/475) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.9.2](https://github.com/nymtech/nym/tree/v0.9.2) (2020-11-26)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.1...v0.9.2)
|
||||
|
||||
This release brings networking improvements, eliminating blocking calls and improving mixnode and gateway scalability.
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Putting initial packet onto the queue when establishing connection [\#471](https://github.com/nymtech/nym/pull/471) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Release/v0.9.2 [\#474](https://github.com/nymtech/nym/pull/474) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Minor mixnet client code simplification and optimization [\#472](https://github.com/nymtech/nym/pull/472) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.9.1](https://github.com/nymtech/nym/tree/v0.9.1) (2020-11-24)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.0...v0.9.1)
|
||||
|
||||
The main features of this release are:
|
||||
|
||||
- explicit `unregister` command for mixnodes
|
||||
- introduced gateway client reconnection in case of obvious network failures
|
||||
- changed network monitor to send at a constant, adjustable, rate
|
||||
- changed the way in which packets are delayed by mixnodes that should reduce number of tasks spawned
|
||||
- changed the way in which packets are forwarded to further mixes that should get rid of possible blocking
|
||||
|
||||
See the changelog for detailed release notes.
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Change how mix packets get delayed [\#361](https://github.com/nymtech/nym/issues/361)
|
||||
- Feature/socks improvements [\#423](https://github.com/nymtech/nym/pull/423) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/instant sending [\#359](https://github.com/nymtech/nym/pull/359) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Update main.js [\#441](https://github.com/nymtech/nym/pull/441) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bugfix/metrics fixes [\#434](https://github.com/nymtech/nym/pull/434) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bugfix/upgrade fix [\#421](https://github.com/nymtech/nym/pull/421) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Explicitly handling base58 key recovery errors [\#396](https://github.com/nymtech/nym/pull/396) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Corrected version on client-core [\#377](https://github.com/nymtech/nym/pull/377) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Gateway reconnections \(simple\) [\#457](https://github.com/nymtech/nym/issues/457)
|
||||
- Slow down network monitor sending rate [\#455](https://github.com/nymtech/nym/issues/455)
|
||||
- Deploy the new explorer on the same box as metrics. [\#433](https://github.com/nymtech/nym/issues/433)
|
||||
- Too many open files [\#366](https://github.com/nymtech/nym/issues/366)
|
||||
- nym-mixnode doesn't bind to any port \(Ubuntu 20.04\) [\#290](https://github.com/nymtech/nym/issues/290)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Updated message on shutdown [\#467](https://github.com/nymtech/nym/pull/467) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Additional feedback on unregistration on sigint [\#466](https://github.com/nymtech/nym/pull/466) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/upgrade additions [\#465](https://github.com/nymtech/nym/pull/465) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/nonblocking mix send [\#464](https://github.com/nymtech/nym/pull/464) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/delay queue mixnodes [\#462](https://github.com/nymtech/nym/pull/462) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/slowed down network monitor [\#461](https://github.com/nymtech/nym/pull/461) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/unregister command [\#460](https://github.com/nymtech/nym/pull/460) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Simple gateway client reconnection in obvious network failures [\#459](https://github.com/nymtech/nym/pull/459) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- temporarily disabled mixnode status dot [\#454](https://github.com/nymtech/nym/pull/454) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removed incentives form url [\#451](https://github.com/nymtech/nym/pull/451) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removed hardcoded 'good gateways' in favour of pseusorandom choice fr… [\#450](https://github.com/nymtech/nym/pull/450) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed the URL of the websocket [\#449](https://github.com/nymtech/nym/pull/449) ([futurechimp](https://github.com/futurechimp))
|
||||
- Extra argument to specify metrics websocket + long attribute [\#448](https://github.com/nymtech/nym/pull/448) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Explorer public folder being relative to the binary [\#447](https://github.com/nymtech/nym/pull/447) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Slightly friendlier upgrade argument description [\#446](https://github.com/nymtech/nym/pull/446) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated nym-run gateway id [\#445](https://github.com/nymtech/nym/pull/445) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Adjusted 'fastmode' settings [\#444](https://github.com/nymtech/nym/pull/444) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Added validators to dashboard + validator and block count [\#443](https://github.com/nymtech/nym/pull/443) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Adding keybase to allowed.list.sample [\#442](https://github.com/nymtech/nym/pull/442) ([futurechimp](https://github.com/futurechimp))
|
||||
- Spawning rocket as a blocking task [\#440](https://github.com/nymtech/nym/pull/440) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Passing validator base url as an argument [\#439](https://github.com/nymtech/nym/pull/439) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Changing default validator location to make it clear we're testnet [\#437](https://github.com/nymtech/nym/pull/437) ([futurechimp](https://github.com/futurechimp))
|
||||
- Added nym prefix to binary names [\#436](https://github.com/nymtech/nym/pull/436) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/explorer [\#431](https://github.com/nymtech/nym/pull/431) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated default sending rates [\#430](https://github.com/nymtech/nym/pull/430) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fixed bunch of clippy warnings [\#427](https://github.com/nymtech/nym/pull/427) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Starting cover traffic stream under correct condition [\#422](https://github.com/nymtech/nym/pull/422) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated validator topology [\#420](https://github.com/nymtech/nym/pull/420) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Added option to set incentives address during mix and gateway init [\#419](https://github.com/nymtech/nym/pull/419) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Flag to start network requester in open proxy mode [\#418](https://github.com/nymtech/nym/pull/418) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Renamed 'sphinx-socks' to 'network-requester' [\#417](https://github.com/nymtech/nym/pull/417) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated upgrade commands to set new default validator [\#413](https://github.com/nymtech/nym/pull/413) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/network monitor file topology [\#412](https://github.com/nymtech/nym/pull/412) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removed debug print statement [\#411](https://github.com/nymtech/nym/pull/411) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/controlled reinit [\#410](https://github.com/nymtech/nym/pull/410) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/max retry [\#409](https://github.com/nymtech/nym/pull/409) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Renamed directory arguments to validator [\#408](https://github.com/nymtech/nym/pull/408) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/no run config flag [\#405](https://github.com/nymtech/nym/pull/405) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/error on noninit [\#404](https://github.com/nymtech/nym/pull/404) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Using metrics interval received from server [\#403](https://github.com/nymtech/nym/pull/403) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator api update [\#402](https://github.com/nymtech/nym/pull/402) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/directory server transition [\#401](https://github.com/nymtech/nym/pull/401) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/wasm client fix [\#399](https://github.com/nymtech/nym/pull/399) ([futurechimp](https://github.com/futurechimp))
|
||||
- Fix compiler warnings for unneeded mut [\#398](https://github.com/nymtech/nym/pull/398) ([ethanfrey](https://github.com/ethanfrey))
|
||||
- Feature/fix dependabot alerts [\#393](https://github.com/nymtech/nym/pull/393) ([futurechimp](https://github.com/futurechimp))
|
||||
- moved new\_v4\_with\_node to test only section [\#392](https://github.com/nymtech/nym/pull/392) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/duration cleanup [\#391](https://github.com/nymtech/nym/pull/391) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/mix ed25519 identity [\#388](https://github.com/nymtech/nym/pull/388) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/double init prevention [\#386](https://github.com/nymtech/nym/pull/386) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/upgrade command [\#381](https://github.com/nymtech/nym/pull/381) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/remove validator [\#380](https://github.com/nymtech/nym/pull/380) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/version in config [\#376](https://github.com/nymtech/nym/pull/376) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/network monitor [\#369](https://github.com/nymtech/nym/pull/369) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Added sphinx socks to default workspace members [\#358](https://github.com/nymtech/nym/pull/358) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/wasm update [\#341](https://github.com/nymtech/nym/pull/341) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.9.0](https://github.com/nymtech/nym/tree/v0.9.0) (2020-11-13)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.8.1...v0.9.0)
|
||||
|
||||
The main features of this release are:
|
||||
|
||||
* a reputation tracking system which starts to link node reputation to quality of service
|
||||
* a new component, the `nym-network-monitor`, which tracks whether nodes are working properly and providing good service
|
||||
* automatic node registration and de-registration at node startup
|
||||
* working Cosmos validators with a `nym` token
|
||||
* starting to decentralize the old directory server into the validators
|
||||
* a new block explorer at https://testnet-explorer.nymtech.net which looks the same as the old dashboard but is the basis of something much more advanced. It can be run by anyone.
|
||||
* de-coupling metrics collection from directory services to make the system scale better overall
|
||||
* reliability and performance improvements for mixnode networking
|
||||
|
||||
See the changelog for detailed release notes.
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Nicer error if trying to run an uninitialised client/node [\#389](https://github.com/nymtech/nym/issues/389)
|
||||
- Gateway announcement [\#383](https://github.com/nymtech/nym/issues/383)
|
||||
- Add init flag for incentives address [\#382](https://github.com/nymtech/nym/issues/382)
|
||||
- Ed25519 Identity Keys for Mixnodes [\#379](https://github.com/nymtech/nym/issues/379)
|
||||
- Introduce version field to config files [\#375](https://github.com/nymtech/nym/issues/375)
|
||||
- Change `init` to not blow away existing keys \(if exist\) [\#368](https://github.com/nymtech/nym/issues/368)
|
||||
- Introduce an explicit `upgrade` command [\#367](https://github.com/nymtech/nym/issues/367)
|
||||
- Show remote hostname in socks5 connection messages [\#365](https://github.com/nymtech/nym/issues/365)
|
||||
- Make all `const` duration values more explicit. [\#333](https://github.com/nymtech/nym/issues/333)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- React wasm example not compiling [\#394](https://github.com/nymtech/nym/issues/394)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Make validator URL configurable [\#438](https://github.com/nymtech/nym/issues/438)
|
||||
- Change default directory location [\#432](https://github.com/nymtech/nym/issues/432)
|
||||
- Crank up the default bandwidth settings. [\#429](https://github.com/nymtech/nym/issues/429)
|
||||
- Change "sphinx-socks" to "nym-requester" [\#428](https://github.com/nymtech/nym/issues/428)
|
||||
- Clients should use only "active" nodes [\#390](https://github.com/nymtech/nym/issues/390)
|
||||
- Allow persistently changing config values from command line [\#387](https://github.com/nymtech/nym/issues/387)
|
||||
- Remove `--config` flag in `run` [\#385](https://github.com/nymtech/nym/issues/385)
|
||||
- Metrics server should return a metrics rate value [\#374](https://github.com/nymtech/nym/issues/374)
|
||||
- Integer staking [\#372](https://github.com/nymtech/nym/issues/372)
|
||||
- Mixnode and gateway blockchain registration [\#371](https://github.com/nymtech/nym/issues/371)
|
||||
- Remove presence notifications [\#370](https://github.com/nymtech/nym/issues/370)
|
||||
- Handle invalid base58 encoding for asymmetric key recovery \(encryption and identity\) [\#285](https://github.com/nymtech/nym/issues/285)
|
||||
- Socks5 nym client + bitcoin service provider [\#254](https://github.com/nymtech/nym/issues/254)
|
||||
- Message reception in webassembly client [\#204](https://github.com/nymtech/nym/issues/204)
|
||||
- Simplest possible staking system [\#157](https://github.com/nymtech/nym/issues/157)
|
||||
- Validator should hold topology [\#77](https://github.com/nymtech/nym/issues/77)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Release/v0.9.0 [\#453](https://github.com/nymtech/nym/pull/453) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.8.1](https://github.com/nymtech/nym/tree/v0.8.1) (2020-09-28)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.8.0...v0.8.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Hardcode two gateways for `client init` if none provided [\#352](https://github.com/nymtech/nym/issues/352)
|
||||
- Make mixnodes take layer with fewest nodes [\#351](https://github.com/nymtech/nym/issues/351)
|
||||
- Change default presence/metrics interval for mixnodes/gateways [\#349](https://github.com/nymtech/nym/issues/349)
|
||||
- Mixnodes should only be able to enter layers 1, 2, or 3 [\#348](https://github.com/nymtech/nym/issues/348)
|
||||
- Docs are inaccurate [\#337](https://github.com/nymtech/nym/issues/337)
|
||||
- Figure out the cause of high packet loss on testnet [\#159](https://github.com/nymtech/nym/issues/159)
|
||||
- Change Topology to GraphTopology [\#76](https://github.com/nymtech/nym/issues/76)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Hotfix/0.8.1 [\#357](https://github.com/nymtech/nym/pull/357) ([jstuczyn](https://github.com/jstuczyn))
|
||||
|
||||
## [v0.8.0](https://github.com/nymtech/nym/tree/v0.8.0) (2020-09-10)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.7.0...v0.8.0)
|
||||
|
||||
@@ -50,6 +486,7 @@ This release introduces, among other things, the following improvements:
|
||||
- Knocking down delay on message sending default [\#332](https://github.com/nymtech/nym/pull/332) ([futurechimp](https://github.com/futurechimp))
|
||||
- Made gateway mandatory during init [\#331](https://github.com/nymtech/nym/pull/331) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Renaming client binary [\#330](https://github.com/nymtech/nym/pull/330) ([futurechimp](https://github.com/futurechimp))
|
||||
- v0.8.0 Changelog update [\#328](https://github.com/nymtech/nym/pull/328) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/sphinx socks [\#326](https://github.com/nymtech/nym/pull/326) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/print client address on startup [\#325](https://github.com/nymtech/nym/pull/325) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/temp wasm example removal [\#324](https://github.com/nymtech/nym/pull/324) ([jstuczyn](https://github.com/jstuczyn))
|
||||
@@ -60,7 +497,6 @@ This release introduces, among other things, the following improvements:
|
||||
- Removed unused dependencies [\#315](https://github.com/nymtech/nym/pull/315) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/perf messing [\#311](https://github.com/nymtech/nym/pull/311) ([futurechimp](https://github.com/futurechimp))
|
||||
- Upgrades tungstenite libraries to new versions with 64MB message sizes. [\#310](https://github.com/nymtech/nym/pull/310) ([futurechimp](https://github.com/futurechimp))
|
||||
- Assigning connection shared key post registration [\#309](https://github.com/nymtech/nym/pull/309) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Assigning connection shared key post registration [\#308](https://github.com/nymtech/nym/pull/308) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/client binary api update [\#306](https://github.com/nymtech/nym/pull/306) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removes unused Cargo dependencies so we stay slim and trim. [\#305](https://github.com/nymtech/nym/pull/305) ([futurechimp](https://github.com/futurechimp))
|
||||
@@ -111,7 +547,7 @@ See the [changelog](https://github.com/nymtech/nym/blob/develop/CHANGELOG.md) fo
|
||||
**Closed issues:**
|
||||
|
||||
- Move to userpubkey@gatewaypubkey addresses. [\#235](https://github.com/nymtech/nym/issues/235)
|
||||
- Get `start\_local\_network.sh` working with the js example [\#227](https://github.com/nymtech/nym/issues/227)
|
||||
- Get `start_local_network.sh` working with the js example [\#227](https://github.com/nymtech/nym/issues/227)
|
||||
- Fix indeterminate test failure [\#218](https://github.com/nymtech/nym/issues/218)
|
||||
- Remove 'fetch' mechanism from desktop client's client in favour of push [\#211](https://github.com/nymtech/nym/issues/211)
|
||||
- Mixnode - load Sphinx keys like Gateway [\#209](https://github.com/nymtech/nym/issues/209)
|
||||
@@ -136,12 +572,12 @@ See the [changelog](https://github.com/nymtech/nym/blob/develop/CHANGELOG.md) fo
|
||||
- Bring health-checker into validator mix-mining [\#78](https://github.com/nymtech/nym/issues/78)
|
||||
- Solidify TCPSocket on client [\#72](https://github.com/nymtech/nym/issues/72)
|
||||
- scripts: run\_local\_network.sh doesn't die nicely [\#45](https://github.com/nymtech/nym/issues/45)
|
||||
- WASM version of the Sphinx packet [\#19](https://github.com/nymtech/nym/issues/19)
|
||||
- Persistent socket connection \(TCP Socket with provider\) [\#18](https://github.com/nymtech/nym/issues/18)
|
||||
- Persistent socket connection \(Websocket with client\) [\#17](https://github.com/nymtech/nym/issues/17)
|
||||
- Persistent socket connection \(TCP Socket with client\) [\#13](https://github.com/nymtech/nym/issues/13)
|
||||
- Persistent socket connection \(Websocket with client\) [\#12](https://github.com/nymtech/nym/issues/12)
|
||||
- Persistently store ledger with registered clients and their auth tokens [\#6](https://github.com/nymtech/nym/issues/6)
|
||||
- Persistent socket connection \(Websocket with client\) [\#17](https://github.com/nymtech/nym/issues/17)
|
||||
- Persistent socket connection \(TCP Socket with provider\) [\#18](https://github.com/nymtech/nym/issues/18)
|
||||
- Persistent socket connection \(Websocket with client\) [\#12](https://github.com/nymtech/nym/issues/12)
|
||||
- Persistent socket connection \(TCP Socket with client\) [\#13](https://github.com/nymtech/nym/issues/13)
|
||||
- WASM version of the Sphinx packet [\#19](https://github.com/nymtech/nym/issues/19)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
@@ -192,7 +628,6 @@ See the [changelog](https://github.com/nymtech/nym/blob/develop/CHANGELOG.md) fo
|
||||
- Feature/nym sphinx wasm [\#183](https://github.com/nymtech/nym/pull/183) ([futurechimp](https://github.com/futurechimp))
|
||||
- Improvements to sfw-provider - client communcation [\#180](https://github.com/nymtech/nym/pull/180) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Adding Apache 2 license headers to all files [\#178](https://github.com/nymtech/nym/pull/178) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/tcp client connection timeout [\#176](https://github.com/nymtech/nym/pull/176) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/service persistence [\#171](https://github.com/nymtech/nym/pull/171) ([futurechimp](https://github.com/futurechimp))
|
||||
|
||||
## [v0.6.0](https://github.com/nymtech/nym/tree/v0.6.0) (2020-04-07)
|
||||
@@ -221,6 +656,7 @@ This release fixes bugs in v0.5.0. All testnet node operators are advised to up
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Feature/tcp client connection timeout [\#176](https://github.com/nymtech/nym/pull/176) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/mixing stats logging [\#175](https://github.com/nymtech/nym/pull/175) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Preventing multiplication overflow for reconnection backoff [\#174](https://github.com/nymtech/nym/pull/174) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/non mandatory debug config [\#173](https://github.com/nymtech/nym/pull/173) ([jstuczyn](https://github.com/jstuczyn))
|
||||
@@ -284,11 +720,11 @@ This release fixes bugs in v0.5.0. All testnet node operators are advised to up
|
||||
- Fix incorrectly used Arcs [\#47](https://github.com/nymtech/nym/issues/47)
|
||||
- nym-mixnode mandatory host option [\#26](https://github.com/nymtech/nym/issues/26)
|
||||
- Create config struct for mixnode \(possibly also for client\) [\#21](https://github.com/nymtech/nym/issues/21)
|
||||
- Reuse TCP socket connection between client and mixnodes [\#20](https://github.com/nymtech/nym/issues/20)
|
||||
- Once implementation is available, wherever appropriate, replace `futures::lock::Mutex` with `futures::lock::RwLock` [\#9](https://github.com/nymtech/nym/issues/9)
|
||||
- Check if RwLock on MixProcessingData is still needed [\#8](https://github.com/nymtech/nym/issues/8)
|
||||
- Reuse TCP socket connection between mixnodes and providers [\#3](https://github.com/nymtech/nym/issues/3)
|
||||
- Once implementation is available, wherever appropriate, replace `futures::lock::Mutex` with `futures::lock::RwLock` [\#9](https://github.com/nymtech/nym/issues/9)
|
||||
- Persistent socket connection with other mixes [\#2](https://github.com/nymtech/nym/issues/2)
|
||||
- Reuse TCP socket connection between client and mixnodes [\#20](https://github.com/nymtech/nym/issues/20)
|
||||
- Reuse TCP socket connection between mixnodes and providers [\#3](https://github.com/nymtech/nym/issues/3)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
@@ -388,8 +824,8 @@ This release also integrates a health-checker and network topology refresh into
|
||||
- Messages returned by fetch are base64 encoded [\#55](https://github.com/nymtech/nym/issues/55)
|
||||
- Check layer 1 connectivity at client start [\#38](https://github.com/nymtech/nym/issues/38)
|
||||
- Check required sfw-provider args [\#27](https://github.com/nymtech/nym/issues/27)
|
||||
- Make Electron app work with new Rust mixnet client [\#16](https://github.com/nymtech/nym/issues/16)
|
||||
- Take version numbers into account when picking routes [\#14](https://github.com/nymtech/nym/issues/14)
|
||||
- Make Electron app work with new Rust mixnet client [\#16](https://github.com/nymtech/nym/issues/16)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
@@ -432,7 +868,7 @@ This release also integrates a health-checker and network topology refresh into
|
||||
**Merged pull requests:**
|
||||
|
||||
- Feature/client topology filtering [\#54](https://github.com/nymtech/nym/pull/54) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- print public key for nym client tools [\#53](https://github.com/nymtech/nym/pull/53) ([mileschet](https://github.com/mileschet))
|
||||
- print public key for nym client tools [\#53](https://github.com/nymtech/nym/pull/53) ([ghost](https://github.com/ghost))
|
||||
- Showing binding warning on binding to localhost, 0.0.0.0 or 127.0.0.1 [\#52](https://github.com/nymtech/nym/pull/52) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- validator: moving sample config files into sample configs directory [\#51](https://github.com/nymtech/nym/pull/51) ([futurechimp](https://github.com/futurechimp))
|
||||
- Feature/validator health checker [\#50](https://github.com/nymtech/nym/pull/50) ([jstuczyn](https://github.com/jstuczyn))
|
||||
@@ -455,7 +891,7 @@ This release also integrates a health-checker and network topology refresh into
|
||||
|
||||
## [0.2.0](https://github.com/nymtech/nym/tree/0.2.0) (2020-01-06)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/0.1.0...0.2.0)
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/3c64a2facd753f4f2f431e7f888e54842e2bc64e...0.2.0)
|
||||
|
||||
|
||||
|
||||
|
||||
Generated
+4849
-1467
File diff suppressed because it is too large
Load Diff
+29
-6
@@ -1,3 +1,6 @@
|
||||
# Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
@@ -8,34 +11,54 @@ panic = "abort"
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"clients/client-core",
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"clients/tauri-client/src-tauri",
|
||||
"clients/webassembly",
|
||||
"clients/client-core",
|
||||
"common/client-libs/directory-client",
|
||||
"common/client-libs/directory-client/models",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
"common/coconut-interface",
|
||||
"common/config",
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
"common/mixnet-contract",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nymsphinx",
|
||||
"common/nymsphinx/acknowledgements",
|
||||
"common/nymsphinx/addressing",
|
||||
"common/nymsphinx/anonymous-replies",
|
||||
"common/nymsphinx/chunking",
|
||||
"common/nymsphinx/cover",
|
||||
"common/nymsphinx/forwarding",
|
||||
"common/nymsphinx/framing",
|
||||
"common/nymsphinx/params",
|
||||
"common/nymsphinx/types",
|
||||
"common/pemstore",
|
||||
"common/socks5/requests",
|
||||
"common/socks5/proxy-helpers",
|
||||
"common/socks5/requests",
|
||||
"common/topology",
|
||||
"common/wasm-utils",
|
||||
"explorer-api",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"service-providers/sphinx-socks",
|
||||
"mixnode",
|
||||
"validator",
|
||||
"service-providers/network-requester",
|
||||
"validator-api",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
"clients/native",
|
||||
"clients/socks5",
|
||||
# "clients/webassembly",
|
||||
"gateway",
|
||||
"service-providers/network-requester",
|
||||
"mixnode",
|
||||
"validator-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts"]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
4. Limitations and Disclaimers.
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
|
||||
Standard License Header
|
||||
|
||||
There is no standard license header for the license
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Standard License Header
|
||||
|
||||
There is no standard license header for the license
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
<!--
|
||||
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
## The Nym Privacy Platform
|
||||
|
||||
This repository contains the full Nym platform.
|
||||
This repository contains the Nym mixnet.
|
||||
|
||||
The platform is composed of multiple Rust crates. Top-level executable binary crates include:
|
||||
|
||||
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
||||
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
||||
* nym-sfw-provider - a store-and-forward service provider. The provider acts sort of like a mailbox for mixnet messages.
|
||||
* nym-validator - currently just starting development. Handles consensus ordering of transactions, mixmining, and coconut credential generation and validation.
|
||||
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* nym-wallet (currently in development)- a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
|
||||
[](https://travis-ci.com/nymtech/nym)
|
||||
|
||||
### Building
|
||||
|
||||
@@ -22,3 +32,8 @@ There's a `.env.sample-dev` file provided which you can rename to `.env` if you
|
||||
### Developer chat
|
||||
|
||||
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
||||
|
||||
### Licensing and copyright information
|
||||
|
||||
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
|
||||
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
[package]
|
||||
build = "build.rs"
|
||||
name = "client-core"
|
||||
version = "0.8.0-dev"
|
||||
version = "0.11.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dirs = "2.0.2"
|
||||
futures = "0.3.1"
|
||||
dirs = "3.0"
|
||||
futures = "0.3"
|
||||
humantime-serde = "1.0"
|
||||
log = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
sled = "0.33"
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
url = "2.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sled = "0.34"
|
||||
tokio = { version = "1.4", features = ["macros"] }
|
||||
url = { version ="2.2", features = ["serde"] }
|
||||
|
||||
# internal
|
||||
config = { path = "../../common/config" }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
directory-client = { path = "../../common/client-libs/directory-client" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
topology = { path = "../../common/topology" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.4.3"
|
||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use built;
|
||||
|
||||
fn main() {
|
||||
built::write_built_file().expect("Failed to acquire build-time information");
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The file has been placed there by the build script.
|
||||
include!(concat!(env!("OUT_DIR"), "/built.rs"));
|
||||
@@ -1,18 +1,7 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::mix_traffic::{MixMessage, MixMessageSender};
|
||||
use crate::client::mix_traffic::BatchMixMessageSender;
|
||||
use crate::client::topology_control::TopologyAccessor;
|
||||
use futures::task::{Context, Poll};
|
||||
use futures::{Future, Stream, StreamExt};
|
||||
@@ -46,11 +35,11 @@ where
|
||||
|
||||
/// Internal state, determined by `average_message_sending_delay`,
|
||||
/// used to keep track of when a next packet should be sent out.
|
||||
next_delay: time::Delay,
|
||||
next_delay: Pin<Box<time::Sleep>>,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: MixMessageSender,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
/// Represents full address of this client.
|
||||
our_full_destination: Recipient,
|
||||
@@ -74,7 +63,7 @@ where
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
// it is not yet time to return a message
|
||||
if Pin::new(&mut self.next_delay).poll(cx).is_pending() {
|
||||
if self.next_delay.as_mut().poll(cx).is_pending() {
|
||||
return Poll::Pending;
|
||||
};
|
||||
|
||||
@@ -87,7 +76,7 @@ where
|
||||
// The next interval value is `next_poisson_delay` after the one that just
|
||||
// yielded.
|
||||
let next = now + next_poisson_delay;
|
||||
self.next_delay.reset(next);
|
||||
self.next_delay.as_mut().reset(next);
|
||||
|
||||
Poll::Ready(Some(()))
|
||||
}
|
||||
@@ -101,7 +90,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
average_ack_delay: time::Duration,
|
||||
average_packet_delay: time::Duration,
|
||||
average_cover_message_sending_delay: time::Duration,
|
||||
mix_tx: MixMessageSender,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
our_full_destination: Recipient,
|
||||
topology_access: TopologyAccessor,
|
||||
) -> Self {
|
||||
@@ -112,7 +101,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
average_ack_delay,
|
||||
average_packet_delay,
|
||||
average_cover_message_sending_delay,
|
||||
next_delay: time::delay_for(Default::default()),
|
||||
next_delay: Box::pin(time::sleep(Default::default())),
|
||||
mix_tx,
|
||||
our_full_destination,
|
||||
rng,
|
||||
@@ -152,9 +141,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
// - we run out of memory
|
||||
// - the receiver channel is closed
|
||||
// in either case there's no recovery and we can only panic
|
||||
self.mix_tx
|
||||
.unbounded_send(MixMessage::new(cover_message.0, cover_message.1))
|
||||
.unwrap();
|
||||
self.mix_tx.unbounded_send(vec![cover_message]).unwrap();
|
||||
|
||||
// TODO: I'm not entirely sure whether this is really required, because I'm not 100%
|
||||
// sure how `yield_now()` works - whether it just notifies the scheduler or whether it
|
||||
@@ -168,12 +155,12 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
|
||||
async fn run(&mut self) {
|
||||
// we should set initial delay only when we actually start the stream
|
||||
self.next_delay = time::delay_for(sample_poisson_duration(
|
||||
self.next_delay = Box::pin(time::sleep(sample_poisson_duration(
|
||||
&mut self.rng,
|
||||
self.average_cover_message_sending_delay,
|
||||
));
|
||||
)));
|
||||
|
||||
while let Some(_) = self.next().await {
|
||||
while self.next().await.is_some() {
|
||||
self.on_new_message().await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use futures::channel::mpsc;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
|
||||
pub type InputMessageSender = mpsc::UnboundedSender<InputMessage>;
|
||||
pub type InputMessageReceiver = mpsc::UnboundedReceiver<InputMessage>;
|
||||
@@ -13,7 +13,7 @@ pub enum InputMessage {
|
||||
with_reply_surb: bool,
|
||||
},
|
||||
Reply {
|
||||
reply_surb: ReplySURB,
|
||||
reply_surb: ReplySurb,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
}
|
||||
@@ -27,7 +27,7 @@ impl InputMessage {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_reply(reply_surb: ReplySURB, data: Vec<u8>) -> Self {
|
||||
pub fn new_reply(reply_surb: ReplySurb, data: Vec<u8>) -> Self {
|
||||
InputMessage::Reply { reply_surb, data }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
@@ -61,8 +50,8 @@ impl KeyManager {
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
KeyManager {
|
||||
identity_keypair: Arc::new(identity::KeyPair::new_with_rng(rng)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new_with_rng(rng)),
|
||||
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
gateway_shared_key: None,
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
}
|
||||
@@ -72,8 +61,8 @@ impl KeyManager {
|
||||
// I have absolutely no idea why the compiler insists it's unused. The call happens during client::init::execute
|
||||
#[allow(dead_code)]
|
||||
/// After shared key with the gateway is derived, puts its ownership to this instance of a [`KeyManager`].
|
||||
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: SharedKeys) {
|
||||
self.gateway_shared_key = Some(Arc::new(gateway_shared_key))
|
||||
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: Arc<SharedKeys>) {
|
||||
self.gateway_shared_key = Some(gateway_shared_key)
|
||||
}
|
||||
|
||||
/// Loads previously stored keys from the disk.
|
||||
@@ -127,12 +116,12 @@ impl KeyManager {
|
||||
),
|
||||
)?;
|
||||
|
||||
pemstore::store_key(self.ack_key.as_ref(), &client_pathfinder.ack_key())?;
|
||||
pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
|
||||
|
||||
match self.gateway_shared_key.as_ref() {
|
||||
None => warn!("No gateway shared key available to store!"),
|
||||
Some(gate_key) => {
|
||||
pemstore::store_key(gate_key.as_ref(), &client_pathfinder.gateway_shared_key())?
|
||||
pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,8 +143,7 @@ impl KeyManager {
|
||||
// hence it's up to us to ensure it's called in correct context
|
||||
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
|
||||
Arc::clone(
|
||||
&self
|
||||
.gateway_shared_key
|
||||
self.gateway_shared_key
|
||||
.as_ref()
|
||||
.expect("tried to unwrap empty gateway key!"),
|
||||
)
|
||||
|
||||
@@ -1,53 +1,35 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use gateway_client::GatewayClient;
|
||||
use log::*;
|
||||
use nymsphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
pub struct MixMessage(NymNodeRoutingAddress, SphinxPacket);
|
||||
pub type MixMessageSender = mpsc::UnboundedSender<MixMessage>;
|
||||
pub type MixMessageReceiver = mpsc::UnboundedReceiver<MixMessage>;
|
||||
|
||||
impl MixMessage {
|
||||
pub fn new(address: NymNodeRoutingAddress, packet: SphinxPacket) -> Self {
|
||||
MixMessage(address, packet)
|
||||
}
|
||||
}
|
||||
pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>;
|
||||
pub type BatchMixMessageReceiver = mpsc::UnboundedReceiver<Vec<MixPacket>>;
|
||||
|
||||
const MAX_FAILURE_COUNT: usize = 100;
|
||||
|
||||
pub struct MixTrafficController<'a> {
|
||||
pub struct MixTrafficController {
|
||||
// TODO: most likely to be replaced by some higher level construct as
|
||||
// later on gateway_client will need to be accessible by other entities
|
||||
gateway_client: GatewayClient<'a, url::Url>,
|
||||
mix_rx: MixMessageReceiver,
|
||||
gateway_client: GatewayClient,
|
||||
mix_rx: BatchMixMessageReceiver,
|
||||
|
||||
// TODO: this is temporary work-around.
|
||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||
consecutive_gateway_failure_count: usize,
|
||||
}
|
||||
|
||||
impl<'a> MixTrafficController<'static> {
|
||||
impl MixTrafficController {
|
||||
pub fn new(
|
||||
mix_rx: MixMessageReceiver,
|
||||
gateway_client: GatewayClient<'a, url::Url>,
|
||||
) -> MixTrafficController<'a> {
|
||||
mix_rx: BatchMixMessageReceiver,
|
||||
gateway_client: GatewayClient,
|
||||
) -> MixTrafficController {
|
||||
MixTrafficController {
|
||||
gateway_client,
|
||||
mix_rx,
|
||||
@@ -55,31 +37,38 @@ impl<'a> MixTrafficController<'static> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_message(&mut self, mix_message: MixMessage) {
|
||||
debug!("Got a mix_message for {:?}", mix_message.0);
|
||||
match self
|
||||
.gateway_client
|
||||
.send_sphinx_packet(mix_message.0, mix_message.1)
|
||||
.await
|
||||
{
|
||||
async fn on_messages(&mut self, mut mix_packets: Vec<MixPacket>) {
|
||||
debug_assert!(!mix_packets.is_empty());
|
||||
|
||||
let success = if mix_packets.len() == 1 {
|
||||
let mix_packet = mix_packets.pop().unwrap();
|
||||
self.gateway_client.send_mix_packet(mix_packet).await
|
||||
} else {
|
||||
self.gateway_client
|
||||
.batch_send_mix_packets(mix_packets)
|
||||
.await
|
||||
};
|
||||
|
||||
match success {
|
||||
Err(e) => {
|
||||
error!("Failed to send sphinx packet to the gateway! - {:?}", e);
|
||||
error!("Failed to send sphinx packet(s) to the gateway! - {:?}", e);
|
||||
self.consecutive_gateway_failure_count += 1;
|
||||
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
|
||||
// todo: in the future this should initiate a 'graceful' shutdown
|
||||
// todo: in the future this should initiate a 'graceful' shutdown or try
|
||||
// to reconnect?
|
||||
panic!("failed to send sphinx packet to the gateway {} times in a row - assuming the gateway is dead. Can't do anything about it yet :(", MAX_FAILURE_COUNT)
|
||||
}
|
||||
}
|
||||
Ok(_) => {
|
||||
trace!("We *might* have managed to forward sphinx packet to the gateway!");
|
||||
trace!("We *might* have managed to forward sphinx packet(s) to the gateway!");
|
||||
self.consecutive_gateway_failure_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
while let Some(mix_message) = self.mix_rx.next().await {
|
||||
self.on_message(mix_message).await;
|
||||
while let Some(mix_packets) = self.mix_rx.next().await {
|
||||
self.on_messages(mix_packets).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use futures::Stream;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll, Waker};
|
||||
use std::time::Duration;
|
||||
use tokio::time::{
|
||||
delay_queue::{self, Expired},
|
||||
DelayQueue,
|
||||
};
|
||||
|
||||
// works under assumption that it will be used inside a loop, where we never want a `None`
|
||||
// TODO: perhaps this should/could be renamed and moved to common/utils (and expose all inner methods?)
|
||||
pub struct AckDelayQueue<T> {
|
||||
inner: DelayQueue<T>,
|
||||
waker: Option<Waker>,
|
||||
}
|
||||
|
||||
// more methods of underlying DelayQueue will get exposed as we need them
|
||||
impl<T> AckDelayQueue<T> {
|
||||
pub fn new() -> Self {
|
||||
AckDelayQueue {
|
||||
inner: DelayQueue::new(),
|
||||
waker: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, value: T, timeout: Duration) -> delay_queue::Key {
|
||||
let key = self.inner.insert(value, timeout);
|
||||
if let Some(waker) = self.waker.take() {
|
||||
// we were waiting for an item - wake the executor!
|
||||
waker.wake()
|
||||
}
|
||||
key
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, key: &delay_queue::Key) -> Expired<T> {
|
||||
self.inner.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for AckDelayQueue<T> {
|
||||
type Item = <DelayQueue<T> as Stream>::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match Pin::new(&mut self.inner).poll_next(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Some(item)) => Poll::Ready(Some(item)),
|
||||
Poll::Ready(None) => {
|
||||
// we'll need to keep the waker to notify the executor once we get new item
|
||||
self.waker = Some(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-13
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::action_controller::{Action, ActionSender};
|
||||
use futures::StreamExt;
|
||||
|
||||
+7
-20
@@ -1,35 +1,22 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::PendingAcknowledgement;
|
||||
use crate::client::real_messages_control::acknowledgement_control::ack_delay_queue::AckDelayQueue;
|
||||
use crate::client::real_messages_control::acknowledgement_control::RetransmissionRequestSender;
|
||||
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey, TimerError};
|
||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nymsphinx::Delay as SphinxDelay;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio::time::delay_queue::{self, Expired};
|
||||
use tokio::time::Error as TimerError;
|
||||
|
||||
pub(crate) type ActionSender = UnboundedSender<Action>;
|
||||
|
||||
// The actual data being sent off as well as potential key to the delay queue
|
||||
type PendingAckEntry = (Arc<PendingAcknowledgement>, Option<delay_queue::Key>);
|
||||
type PendingAckEntry = (Arc<PendingAcknowledgement>, Option<QueueKey>);
|
||||
|
||||
// we can either:
|
||||
// - have a completely new set of packets we just sent and need to create entries for
|
||||
@@ -105,7 +92,7 @@ pub(super) struct ActionController {
|
||||
// previous version.
|
||||
/// DelayQueue with all `PendingAcknowledgement` that are waiting to be either received or
|
||||
/// retransmitted if their timer fires up.
|
||||
pending_acks_timers: AckDelayQueue<FragmentIdentifier>,
|
||||
pending_acks_timers: NonExhaustiveDelayQueue<FragmentIdentifier>,
|
||||
|
||||
/// Channel for receiving `Action`s from other modules.
|
||||
incoming_actions: UnboundedReceiver<Action>,
|
||||
@@ -124,7 +111,7 @@ impl ActionController {
|
||||
ActionController {
|
||||
config,
|
||||
pending_acks_data: HashMap::new(),
|
||||
pending_acks_timers: AckDelayQueue::new(),
|
||||
pending_acks_timers: NonExhaustiveDelayQueue::new(),
|
||||
incoming_actions: receiver,
|
||||
retransmission_sender,
|
||||
},
|
||||
|
||||
+27
-36
@@ -1,28 +1,17 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::action_controller::{Action, ActionSender};
|
||||
use super::PendingAcknowledgement;
|
||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||
use crate::client::{
|
||||
inbound_messages::{InputMessage, InputMessageReceiver},
|
||||
real_messages_control::real_traffic_stream::{RealMessage, RealMessageSender},
|
||||
real_messages_control::real_traffic_stream::{BatchRealMessageSender, RealMessage},
|
||||
topology_control::TopologyAccessor,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nymsphinx::preparer::MessagePreparer;
|
||||
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
||||
use rand::{CryptoRng, Rng};
|
||||
@@ -40,7 +29,7 @@ where
|
||||
input_receiver: InputMessageReceiver,
|
||||
message_preparer: MessagePreparer<R>,
|
||||
action_sender: ActionSender,
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
topology_access: TopologyAccessor,
|
||||
reply_key_storage: ReplyKeyStorage,
|
||||
}
|
||||
@@ -49,13 +38,16 @@ impl<R> InputMessageListener<R>
|
||||
where
|
||||
R: CryptoRng + Rng,
|
||||
{
|
||||
// at this point I'm not entirely sure how to deal with this warning without
|
||||
// some considerable refactoring
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn new(
|
||||
ack_key: Arc<AckKey>,
|
||||
ack_recipient: Recipient,
|
||||
input_receiver: InputMessageReceiver,
|
||||
message_preparer: MessagePreparer<R>,
|
||||
action_sender: ActionSender,
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
topology_access: TopologyAccessor,
|
||||
reply_key_storage: ReplyKeyStorage,
|
||||
) -> Self {
|
||||
@@ -72,7 +64,7 @@ where
|
||||
}
|
||||
|
||||
// we require topology for replies to generate surb_acks
|
||||
async fn handle_reply(&mut self, reply_surb: ReplySURB, data: Vec<u8>) -> Option<RealMessage> {
|
||||
async fn handle_reply(&mut self, reply_surb: ReplySurb, data: Vec<u8>) -> Option<RealMessage> {
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = match topology_permit.try_get_valid_topology_ref(&self.ack_recipient, None) {
|
||||
Some(topology_ref) => topology_ref,
|
||||
@@ -85,12 +77,13 @@ where
|
||||
match self
|
||||
.message_preparer
|
||||
.prepare_reply_for_use(data, reply_surb, topology, &self.ack_key)
|
||||
.await
|
||||
{
|
||||
Ok((reply_id, sphinx_packet, first_hop)) => {
|
||||
Ok((mix_packet, reply_id)) => {
|
||||
// TODO: later probably write pending ack here
|
||||
// and deal with them....
|
||||
// ... somehow
|
||||
Some(RealMessage::new(first_hop, sphinx_packet, reply_id))
|
||||
Some(RealMessage::new(mix_packet, reply_id))
|
||||
}
|
||||
Err(err) => {
|
||||
// TODO: should we have some mechanism to indicate to the user that the `reply_surb`
|
||||
@@ -106,7 +99,7 @@ where
|
||||
recipient: Recipient,
|
||||
content: Vec<u8>,
|
||||
with_reply_surb: bool,
|
||||
) -> Vec<RealMessage> {
|
||||
) -> Option<Vec<RealMessage>> {
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = match topology_permit
|
||||
.try_get_valid_topology_ref(&self.ack_recipient, Some(&recipient))
|
||||
@@ -114,7 +107,7 @@ where
|
||||
Some(topology_ref) => topology_ref,
|
||||
None => {
|
||||
warn!("Could not process the message - the network topology is invalid");
|
||||
return Vec::new();
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,18 +133,18 @@ where
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_chunk_for_sending(chunk_clone, topology, &self.ack_key, &recipient)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
real_messages.push(RealMessage::new(
|
||||
prepared_fragment.first_hop_address,
|
||||
prepared_fragment.sphinx_packet,
|
||||
prepared_fragment.mix_packet,
|
||||
message_chunk.fragment_identifier(),
|
||||
));
|
||||
|
||||
pending_acks.push(PendingAcknowledgement::new(
|
||||
message_chunk,
|
||||
prepared_fragment.total_delay,
|
||||
recipient.clone(),
|
||||
recipient,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -160,7 +153,7 @@ where
|
||||
.unbounded_send(Action::new_insert(pending_acks))
|
||||
.unwrap();
|
||||
|
||||
real_messages
|
||||
Some(real_messages)
|
||||
}
|
||||
|
||||
async fn on_input_message(&mut self, msg: InputMessage) {
|
||||
@@ -173,19 +166,17 @@ where
|
||||
self.handle_fresh_message(recipient, data, with_reply_surb)
|
||||
.await
|
||||
}
|
||||
InputMessage::Reply { reply_surb, data } => {
|
||||
if let Some(real_message) = self.handle_reply(reply_surb, data).await {
|
||||
vec![real_message]
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
InputMessage::Reply { reply_surb, data } => self
|
||||
.handle_reply(reply_surb, data)
|
||||
.await
|
||||
.map(|message| vec![message]),
|
||||
};
|
||||
|
||||
// tells real message sender (with the poisson timer) to send this to the mix network
|
||||
for real_message in real_messages {
|
||||
// there's no point in trying to send nothing
|
||||
if let Some(real_messages) = real_messages {
|
||||
// tells real message sender (with the poisson timer) to send this to the mix network
|
||||
self.real_message_sender
|
||||
.unbounded_send(real_message)
|
||||
.unbounded_send(real_messages)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-20
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use self::{
|
||||
acknowledgement_listener::AcknowledgementListener, action_controller::ActionController,
|
||||
@@ -18,7 +7,7 @@ use self::{
|
||||
retransmission_request_listener::RetransmissionRequestListener,
|
||||
sent_notification_listener::SentNotificationListener,
|
||||
};
|
||||
use super::real_traffic_stream::RealMessageSender;
|
||||
use super::real_traffic_stream::BatchRealMessageSender;
|
||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||
use crate::client::{inbound_messages::InputMessageReceiver, topology_control::TopologyAccessor};
|
||||
use futures::channel::mpsc;
|
||||
@@ -38,7 +27,6 @@ use std::{
|
||||
};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
mod ack_delay_queue;
|
||||
mod acknowledgement_listener;
|
||||
mod action_controller;
|
||||
mod input_message_listener;
|
||||
@@ -56,7 +44,7 @@ type RetransmissionRequestReceiver = mpsc::UnboundedReceiver<Weak<PendingAcknowl
|
||||
pub(super) type SentPacketNotificationSender = mpsc::UnboundedSender<FragmentIdentifier>;
|
||||
|
||||
/// Channel used for receiving signals about the particular `Fragment` (associated with the `FragmentIdentifier`)
|
||||
/// that it is about to be sent to tbe mix network and its timeout timer should be started.
|
||||
/// that it is about to be sent to the mix network and its timeout timer should be started.
|
||||
type SentPacketNotificationReceiver = mpsc::UnboundedReceiver<FragmentIdentifier>;
|
||||
|
||||
/// Structure representing a data `Fragment` that is on-route to the specified `Recipient`
|
||||
@@ -87,7 +75,7 @@ impl PendingAcknowledgement {
|
||||
pub(super) struct AcknowledgementControllerConnectors {
|
||||
/// Channel used for forwarding prepared sphinx messages into the poisson sender
|
||||
/// to be sent to the mix network.
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
|
||||
/// Channel used for receiving raw messages from a client. The messages need to be put
|
||||
/// into sphinx packets first.
|
||||
@@ -104,7 +92,7 @@ pub(super) struct AcknowledgementControllerConnectors {
|
||||
|
||||
impl AcknowledgementControllerConnectors {
|
||||
pub(super) fn new(
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
input_receiver: InputMessageReceiver,
|
||||
sent_notifier: SentPacketNotificationReceiver,
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
@@ -182,7 +170,7 @@ where
|
||||
|
||||
let message_preparer = MessagePreparer::new(
|
||||
rng,
|
||||
ack_recipient.clone(),
|
||||
ack_recipient,
|
||||
config.average_packet_delay,
|
||||
config.average_ack_delay,
|
||||
);
|
||||
@@ -197,7 +185,7 @@ where
|
||||
// will listen for any new messages from the client
|
||||
let input_message_listener = InputMessageListener::new(
|
||||
Arc::clone(&ack_key),
|
||||
ack_recipient.clone(),
|
||||
ack_recipient,
|
||||
connectors.input_receiver,
|
||||
message_preparer.clone(),
|
||||
action_sender.clone(),
|
||||
|
||||
+9
-20
@@ -1,22 +1,11 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::action_controller::{Action, ActionSender};
|
||||
use super::PendingAcknowledgement;
|
||||
use super::RetransmissionRequestReceiver;
|
||||
use crate::client::{
|
||||
real_messages_control::real_traffic_stream::{RealMessage, RealMessageSender},
|
||||
real_messages_control::real_traffic_stream::{BatchRealMessageSender, RealMessage},
|
||||
topology_control::TopologyAccessor,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
@@ -35,7 +24,7 @@ where
|
||||
ack_recipient: Recipient,
|
||||
message_preparer: MessagePreparer<R>,
|
||||
action_sender: ActionSender,
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
request_receiver: RetransmissionRequestReceiver,
|
||||
topology_access: TopologyAccessor,
|
||||
}
|
||||
@@ -49,7 +38,7 @@ where
|
||||
ack_recipient: Recipient,
|
||||
message_preparer: MessagePreparer<R>,
|
||||
action_sender: ActionSender,
|
||||
real_message_sender: RealMessageSender,
|
||||
real_message_sender: BatchRealMessageSender,
|
||||
request_receiver: RetransmissionRequestReceiver,
|
||||
topology_access: TopologyAccessor,
|
||||
) -> Self {
|
||||
@@ -94,6 +83,7 @@ where
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_chunk_for_sending(chunk_clone, topology_ref, &self.ack_key, packet_recipient)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// if we have the ONLY strong reference to the ack data, it means it was removed from the
|
||||
@@ -123,11 +113,10 @@ where
|
||||
|
||||
// send to `OutQueueControl` to eventually send to the mix network
|
||||
self.real_message_sender
|
||||
.unbounded_send(RealMessage::new(
|
||||
prepared_fragment.first_hop_address,
|
||||
prepared_fragment.sphinx_packet,
|
||||
.unbounded_send(vec![RealMessage::new(
|
||||
prepared_fragment.mix_packet,
|
||||
frag_id,
|
||||
))
|
||||
)])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
||||
+2
-13
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::action_controller::{Action, ActionSender};
|
||||
use super::SentPacketNotificationReceiver;
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// INPUT: InputMessage from user
|
||||
// INPUT2: Acks from mix
|
||||
@@ -22,7 +11,7 @@ use self::{
|
||||
use crate::client::real_messages_control::acknowledgement_control::AcknowledgementControllerConnectors;
|
||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||
use crate::client::{
|
||||
inbound_messages::InputMessageReceiver, mix_traffic::MixMessageSender,
|
||||
inbound_messages::InputMessageReceiver, mix_traffic::BatchMixMessageSender,
|
||||
topology_control::TopologyAccessor,
|
||||
};
|
||||
use futures::channel::mpsc;
|
||||
@@ -41,13 +30,26 @@ mod real_traffic_stream;
|
||||
|
||||
// TODO: ack_key and self_recipient shouldn't really be part of this config
|
||||
pub struct Config {
|
||||
/// Key used to decrypt contents of received SURBAcks
|
||||
ack_key: Arc<AckKey>,
|
||||
ack_wait_multiplier: f64,
|
||||
|
||||
/// Given ack timeout in the form a * BASE_DELAY + b, it specifies the additive part `b`
|
||||
ack_wait_addition: Duration,
|
||||
|
||||
/// Given ack timeout in the form a * BASE_DELAY + b, it specifies the multiplier `a`
|
||||
ack_wait_multiplier: f64,
|
||||
|
||||
/// Address of `this` client.
|
||||
self_recipient: Recipient,
|
||||
average_packet_delay_duration: Duration,
|
||||
average_ack_delay_duration: Duration,
|
||||
|
||||
/// Average delay between sending subsequent packets from this client.
|
||||
average_message_sending_delay: Duration,
|
||||
|
||||
/// Average delay a data packet is going to get delayed at a single mixnode.
|
||||
average_packet_delay_duration: Duration,
|
||||
|
||||
/// Average delay an acknowledgement packet is going to get delayed at a single mixnode.
|
||||
average_ack_delay_duration: Duration,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -62,12 +64,12 @@ impl Config {
|
||||
) -> Self {
|
||||
Config {
|
||||
ack_key,
|
||||
ack_wait_addition,
|
||||
ack_wait_multiplier,
|
||||
self_recipient,
|
||||
average_message_sending_delay,
|
||||
average_packet_delay_duration,
|
||||
average_ack_delay_duration,
|
||||
average_message_sending_delay,
|
||||
ack_wait_multiplier,
|
||||
ack_wait_addition,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +89,7 @@ impl RealMessagesController<OsRng> {
|
||||
config: Config,
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
input_receiver: InputMessageReceiver,
|
||||
mix_sender: MixMessageSender,
|
||||
mix_sender: BatchMixMessageSender,
|
||||
topology_access: TopologyAccessor,
|
||||
reply_key_storage: ReplyKeyStorage,
|
||||
) -> Self {
|
||||
@@ -115,7 +117,7 @@ impl RealMessagesController<OsRng> {
|
||||
rng,
|
||||
topology_access.clone(),
|
||||
Arc::clone(&config.ack_key),
|
||||
config.self_recipient.clone(),
|
||||
config.self_recipient,
|
||||
reply_key_storage,
|
||||
ack_controller_connectors,
|
||||
);
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::mix_traffic::{MixMessage, MixMessageSender};
|
||||
use crate::client::mix_traffic::BatchMixMessageSender;
|
||||
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
|
||||
use crate::client::topology_control::TopologyAccessor;
|
||||
use futures::channel::mpsc;
|
||||
@@ -20,12 +9,13 @@ use futures::task::{Context, Poll};
|
||||
use futures::{Future, Stream, StreamExt};
|
||||
use log::*;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::{clients::Recipient, nodes::NymNodeRoutingAddress};
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nymsphinx::cover::generate_loop_cover_packet;
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use nymsphinx::utils::sample_poisson_duration;
|
||||
use nymsphinx::SphinxPacket;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -72,15 +62,15 @@ where
|
||||
|
||||
/// Internal state, determined by `average_message_sending_delay`,
|
||||
/// used to keep track of when a next packet should be sent out.
|
||||
next_delay: time::Delay,
|
||||
next_delay: Pin<Box<time::Sleep>>,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: MixMessageSender,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
/// Channel used for receiving real, prepared, messages that must be first sufficiently delayed
|
||||
/// before being sent out into the network.
|
||||
real_receiver: RealMessageReceiver,
|
||||
real_receiver: BatchRealMessageReceiver,
|
||||
|
||||
/// Represents full address of this client.
|
||||
our_full_destination: Recipient,
|
||||
@@ -90,23 +80,20 @@ where
|
||||
|
||||
/// Accessor to the common instance of network topology.
|
||||
topology_access: TopologyAccessor,
|
||||
|
||||
/// Buffer containing all real messages received. It is first exhausted before more are pulled.
|
||||
received_buffer: VecDeque<RealMessage>,
|
||||
}
|
||||
|
||||
pub(crate) struct RealMessage {
|
||||
first_hop_address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
mix_packet: MixPacket,
|
||||
fragment_id: FragmentIdentifier,
|
||||
}
|
||||
|
||||
impl RealMessage {
|
||||
pub(crate) fn new(
|
||||
first_hop_address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
fragment_id: FragmentIdentifier,
|
||||
) -> Self {
|
||||
pub(crate) fn new(mix_packet: MixPacket, fragment_id: FragmentIdentifier) -> Self {
|
||||
RealMessage {
|
||||
first_hop_address,
|
||||
packet,
|
||||
mix_packet,
|
||||
fragment_id,
|
||||
}
|
||||
}
|
||||
@@ -114,12 +101,12 @@ impl RealMessage {
|
||||
|
||||
// messages are already prepared, etc. the real point of it is to forward it to mix_traffic
|
||||
// after sufficient delay
|
||||
pub(crate) type RealMessageSender = mpsc::UnboundedSender<RealMessage>;
|
||||
type RealMessageReceiver = mpsc::UnboundedReceiver<RealMessage>;
|
||||
pub(crate) type BatchRealMessageSender = mpsc::UnboundedSender<Vec<RealMessage>>;
|
||||
type BatchRealMessageReceiver = mpsc::UnboundedReceiver<Vec<RealMessage>>;
|
||||
|
||||
pub(crate) enum StreamMessage {
|
||||
Cover,
|
||||
Real(RealMessage),
|
||||
Real(Box<RealMessage>),
|
||||
}
|
||||
|
||||
impl<R> Stream for OutQueueControl<R>
|
||||
@@ -130,7 +117,7 @@ where
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
// it is not yet time to return a message
|
||||
if Pin::new(&mut self.next_delay).poll(cx).is_pending() {
|
||||
if self.next_delay.as_mut().poll(cx).is_pending() {
|
||||
return Poll::Pending;
|
||||
};
|
||||
|
||||
@@ -143,7 +130,12 @@ where
|
||||
// The next interval value is `next_poisson_delay` after the one that just
|
||||
// yielded.
|
||||
let next = now + next_poisson_delay;
|
||||
self.next_delay.reset(next);
|
||||
self.next_delay.as_mut().reset(next);
|
||||
|
||||
// check if we have anything immediately available
|
||||
if let Some(real_available) = self.received_buffer.pop_front() {
|
||||
return Poll::Ready(Some(StreamMessage::Real(Box::new(real_available))));
|
||||
}
|
||||
|
||||
// decide what kind of message to send
|
||||
match Pin::new(&mut self.real_receiver).poll_next(cx) {
|
||||
@@ -151,8 +143,14 @@ where
|
||||
// (and whoever is using the stream should panic)
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
|
||||
// if there's an actual message - return it
|
||||
Poll::Ready(Some(real_message)) => Poll::Ready(Some(StreamMessage::Real(real_message))),
|
||||
// if there are more messages available, return first one and store the rest
|
||||
Poll::Ready(Some(real_messages)) => {
|
||||
self.received_buffer = real_messages.into();
|
||||
// we MUST HAVE received at least ONE message
|
||||
Poll::Ready(Some(StreamMessage::Real(Box::new(
|
||||
self.received_buffer.pop_front().unwrap(),
|
||||
))))
|
||||
}
|
||||
|
||||
// otherwise construct a dummy one
|
||||
Poll::Pending => Poll::Ready(Some(StreamMessage::Cover)),
|
||||
@@ -164,12 +162,15 @@ impl<R> OutQueueControl<R>
|
||||
where
|
||||
R: CryptoRng + Rng + Unpin,
|
||||
{
|
||||
// at this point I'm not entirely sure how to deal with this warning without
|
||||
// some considerable refactoring
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
config: Config,
|
||||
ack_key: Arc<AckKey>,
|
||||
sent_notifier: SentPacketNotificationSender,
|
||||
mix_tx: MixMessageSender,
|
||||
real_receiver: RealMessageReceiver,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
real_receiver: BatchRealMessageReceiver,
|
||||
rng: R,
|
||||
our_full_destination: Recipient,
|
||||
topology_access: TopologyAccessor,
|
||||
@@ -178,15 +179,24 @@ where
|
||||
config,
|
||||
ack_key,
|
||||
sent_notifier,
|
||||
next_delay: time::delay_for(Default::default()),
|
||||
next_delay: Box::pin(time::sleep(Default::default())),
|
||||
mix_tx,
|
||||
real_receiver,
|
||||
our_full_destination,
|
||||
rng,
|
||||
topology_access,
|
||||
received_buffer: VecDeque::with_capacity(0), // we won't be putting any data into this guy directly
|
||||
}
|
||||
}
|
||||
|
||||
fn sent_notify(&self, frag_id: FragmentIdentifier) {
|
||||
// well technically the message was not sent just yet, but now it's up to internal
|
||||
// queues and client load rather than the required delay. So realistically we can treat
|
||||
// whatever is about to happen as negligible additional delay.
|
||||
trace!("{} is about to get sent to the mixnet", frag_id);
|
||||
self.sent_notifier.unbounded_send(frag_id).unwrap();
|
||||
}
|
||||
|
||||
async fn on_message(&mut self, next_message: StreamMessage) {
|
||||
trace!("created new message");
|
||||
|
||||
@@ -209,7 +219,7 @@ where
|
||||
}
|
||||
let topology_ref = topology_ref_option.unwrap();
|
||||
|
||||
let cover_message = generate_loop_cover_packet(
|
||||
generate_loop_cover_packet(
|
||||
&mut self.rng,
|
||||
topology_ref,
|
||||
&*self.ack_key,
|
||||
@@ -217,22 +227,11 @@ where
|
||||
self.config.average_ack_delay,
|
||||
self.config.average_packet_delay,
|
||||
)
|
||||
.expect("Somehow failed to generate a loop cover message with a valid topology");
|
||||
|
||||
MixMessage::new(cover_message.0, cover_message.1)
|
||||
.expect("Somehow failed to generate a loop cover message with a valid topology")
|
||||
}
|
||||
StreamMessage::Real(real_message) => {
|
||||
// well technically the message was not sent just yet, but now it's up to internal
|
||||
// queues and client load rather than the required delay. So realistically we can treat
|
||||
// whatever is about to happen as negligible additional delay.
|
||||
trace!(
|
||||
"{} is about to get sent to the mixnet",
|
||||
real_message.fragment_id
|
||||
);
|
||||
self.sent_notifier
|
||||
.unbounded_send(real_message.fragment_id)
|
||||
.unwrap();
|
||||
MixMessage::new(real_message.first_hop_address, real_message.packet)
|
||||
self.sent_notify(real_message.fragment_id);
|
||||
real_message.mix_packet
|
||||
}
|
||||
};
|
||||
|
||||
@@ -240,7 +239,7 @@ where
|
||||
// - we run out of memory
|
||||
// - the receiver channel is closed
|
||||
// in either case there's no recovery and we can only panic
|
||||
self.mix_tx.unbounded_send(next_message).unwrap();
|
||||
self.mix_tx.unbounded_send(vec![next_message]).unwrap();
|
||||
|
||||
// JS: Not entirely sure why or how it fixes stuff, but without the yield call,
|
||||
// the UnboundedReceiver [of mix_rx] will not get a chance to read anything
|
||||
@@ -250,16 +249,21 @@ where
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
pub(crate) async fn run_out_queue_control(&mut self) {
|
||||
// Send messages at certain rate and if no real traffic is available, send cover message.
|
||||
async fn run_normal_out_queue(&mut self) {
|
||||
// we should set initial delay only when we actually start the stream
|
||||
self.next_delay = time::delay_for(sample_poisson_duration(
|
||||
self.next_delay = Box::pin(time::sleep(sample_poisson_duration(
|
||||
&mut self.rng,
|
||||
self.config.average_message_sending_delay,
|
||||
));
|
||||
)));
|
||||
|
||||
debug!("Starting out queue controller...");
|
||||
while let Some(next_message) = self.next().await {
|
||||
self.on_message(next_message).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run_out_queue_control(&mut self) {
|
||||
debug!("Starting out queue controller...");
|
||||
self.run_normal_out_queue().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||
use crypto::asymmetric::encryption;
|
||||
@@ -21,8 +10,8 @@ use futures::lock::Mutex;
|
||||
use futures::StreamExt;
|
||||
use gateway_client::MixnetMessageReceiver;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SURBEncryptionKey};
|
||||
use nymsphinx::params::{ReplySURBEncryptionAlgorithm, ReplySURBKeyDigestAlgorithm};
|
||||
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
||||
use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
@@ -165,7 +154,7 @@ impl ReceivedMessagesBuffer {
|
||||
|
||||
// while we're at it, also empty the buffer if we happened to receive anything while
|
||||
// no sender was connected
|
||||
let stored_messages = std::mem::replace(&mut guard.messages, Vec::new());
|
||||
let stored_messages = std::mem::take(&mut guard.messages);
|
||||
if !stored_messages.is_empty() {
|
||||
if let Err(err) = sender.unbounded_send(stored_messages) {
|
||||
error!(
|
||||
@@ -191,12 +180,12 @@ impl ReceivedMessagesBuffer {
|
||||
|
||||
fn process_received_reply(
|
||||
reply_ciphertext: &[u8],
|
||||
reply_key: SURBEncryptionKey,
|
||||
reply_key: SurbEncryptionKey,
|
||||
) -> Option<ReconstructedMessage> {
|
||||
let zero_iv = stream_cipher::zero_iv::<ReplySURBEncryptionAlgorithm>();
|
||||
let zero_iv = stream_cipher::zero_iv::<ReplySurbEncryptionAlgorithm>();
|
||||
|
||||
let mut reply_msg = stream_cipher::decrypt::<ReplySURBEncryptionAlgorithm>(
|
||||
&reply_key.inner(),
|
||||
let mut reply_msg = stream_cipher::decrypt::<ReplySurbEncryptionAlgorithm>(
|
||||
reply_key.inner(),
|
||||
&zero_iv,
|
||||
reply_ciphertext,
|
||||
);
|
||||
@@ -221,7 +210,7 @@ impl ReceivedMessagesBuffer {
|
||||
let mut completed_messages = Vec::new();
|
||||
let mut inner_guard = self.inner.lock().await;
|
||||
|
||||
let reply_surb_digest_size = ReplySURBKeyDigestAlgorithm::output_size();
|
||||
let reply_surb_digest_size = ReplySurbKeyDigestAlgorithm::output_size();
|
||||
|
||||
// first check if this is a reply or a chunked message
|
||||
// TODO: verify with @AP if this way of doing it is safe or whether it could
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::{
|
||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SURBEncryptionKey,
|
||||
SURBEncryptionKeySize,
|
||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
|
||||
SurbEncryptionKeySize,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -29,7 +18,7 @@ pub enum ReplyKeyStorageError {
|
||||
/// Permanent storage for keys in all sent [`ReplySURB`]
|
||||
///
|
||||
/// Each sent out [`ReplySURB`] has a new key associated with it that is going to be used for
|
||||
/// payload encryption. In order to decrypt whatever reply we receive, we need to know which
|
||||
/// payload encryption. In order to -decrypt whatever reply we receive, we need to know which
|
||||
/// key to use for that purpose. We do it based on received `H(t)` which has to be included
|
||||
/// with each reply.
|
||||
/// Moreover, there is no restriction when the [`ReplySURB`] might get used so we need to
|
||||
@@ -49,24 +38,24 @@ impl ReplyKeyStorage {
|
||||
Ok(ReplyKeyStorage { db })
|
||||
}
|
||||
|
||||
fn read_encryption_key(&self, raw_key: sled::IVec) -> SURBEncryptionKey {
|
||||
fn read_encryption_key(&self, raw_key: sled::IVec) -> SurbEncryptionKey {
|
||||
let key_bytes_ref = raw_key.as_ref();
|
||||
// if this fails it means we have some database corruption and we
|
||||
// absolutely can't continue
|
||||
|
||||
if key_bytes_ref.len() != SURBEncryptionKeySize::to_usize() {
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
|
||||
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
}
|
||||
|
||||
// this can only fail if the bytes have invalid length but we already asserted it
|
||||
SURBEncryptionKey::try_from_bytes(key_bytes_ref).unwrap()
|
||||
SurbEncryptionKey::try_from_bytes(key_bytes_ref).unwrap()
|
||||
}
|
||||
|
||||
// TOOD: perhaps we could also store some part of original message here too?
|
||||
pub fn insert_encryption_key(
|
||||
&mut self,
|
||||
encryption_key: SURBEncryptionKey,
|
||||
encryption_key: SurbEncryptionKey,
|
||||
) -> Result<(), ReplyKeyStorageError> {
|
||||
let digest = encryption_key.compute_digest();
|
||||
|
||||
@@ -89,7 +78,7 @@ impl ReplyKeyStorage {
|
||||
pub fn get_and_remove_encryption_key(
|
||||
&self,
|
||||
key_digest: EncryptionKeyDigest,
|
||||
) -> Result<Option<SURBEncryptionKey>, ReplyKeyStorageError> {
|
||||
) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> {
|
||||
let removal_result = match self.db.remove(&key_digest.to_vec()) {
|
||||
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
|
||||
Ok(existing_key) => {
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::built_info;
|
||||
use directory_client::DirectoryClient;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use std::convert::TryInto;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
@@ -25,7 +13,8 @@ use std::time::Duration;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use tokio::task::JoinHandle;
|
||||
use topology::NymTopology;
|
||||
use topology::{nym_topology_from_bonds, NymTopology};
|
||||
use url::Url;
|
||||
|
||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||
#[derive(Debug)]
|
||||
@@ -74,9 +63,9 @@ impl<'a> TopologyReadPermit<'a> {
|
||||
Some(topology_ref) => {
|
||||
// see if it's possible to route the packet to both gateways
|
||||
if !topology_ref.can_construct_path_through(DEFAULT_NUM_MIX_HOPS)
|
||||
|| !topology_ref.gateway_exists(&ack_recipient.gateway())
|
||||
|| !topology_ref.gateway_exists(ack_recipient.gateway())
|
||||
|| if let Some(packet_recipient) = packet_recipient {
|
||||
!topology_ref.gateway_exists(&packet_recipient.gateway())
|
||||
!topology_ref.gateway_exists(packet_recipient.gateway())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -132,58 +121,108 @@ impl TopologyAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
directory_server: String,
|
||||
validator_api_urls: Vec<Url>,
|
||||
refresh_rate: time::Duration,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(directory_server: String, refresh_rate: time::Duration) -> Self {
|
||||
pub fn new(validator_api_urls: Vec<Url>, refresh_rate: time::Duration) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
directory_server,
|
||||
validator_api_urls,
|
||||
refresh_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
directory_client: directory_client::Client,
|
||||
validator_client: validator_client::ApiClient,
|
||||
|
||||
validator_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
refresh_rate: Duration,
|
||||
|
||||
currently_used_api: usize,
|
||||
was_latest_valid: bool,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new_directory_client(
|
||||
cfg: TopologyRefresherConfig,
|
||||
topology_accessor: TopologyAccessor,
|
||||
) -> Self {
|
||||
let directory_client_config = directory_client::Config::new(cfg.directory_server);
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||
cfg.validator_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
TopologyRefresher {
|
||||
directory_client,
|
||||
validator_client: validator_client::ApiClient::new(cfg.validator_api_urls[0].clone()),
|
||||
validator_api_urls: cfg.validator_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
currently_used_api: 0,
|
||||
was_latest_valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||
match self.directory_client.get_topology().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network topology! - {:?}", err);
|
||||
None
|
||||
}
|
||||
Ok(topology) => {
|
||||
let nym_topology: NymTopology = topology.try_into().ok()?;
|
||||
Some(nym_topology.filter_system_version(built_info::PKG_VERSION))
|
||||
}
|
||||
fn use_next_validator_api(&mut self) {
|
||||
if self.validator_api_urls.len() == 1 {
|
||||
warn!("There's only a single validator API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.validator_api_urls.len();
|
||||
self.validator_client
|
||||
.change_validator_api(self.validator_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
// TODO: optimization for the future:
|
||||
// only refresh mixnodes on timer and refresh gateways only when
|
||||
// we have to send to a new, unknown, gateway
|
||||
|
||||
let mixnodes = match self.validator_client.get_cached_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {}", err);
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {}", err);
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_bonds(mixnodes, gateways);
|
||||
|
||||
// TODO: I didn't want to change it now, but the expected system version should rather be put in config
|
||||
// rather than pulled from package version of `client_core`
|
||||
Some(topology.filter_system_version(env!("CARGO_PKG_VERSION")))
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
let new_topology = self.get_current_compatible_topology().await;
|
||||
|
||||
if new_topology.is_none() {
|
||||
self.use_next_validator_api();
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.was_latest_valid {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.was_latest_valid = false;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.was_latest_valid = true;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
@@ -196,7 +235,7 @@ impl TopologyRefresher {
|
||||
pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
|
||||
handle.spawn(async move {
|
||||
loop {
|
||||
tokio::time::delay_for(self.refresh_rate).await;
|
||||
tokio::time::sleep(self.refresh_rate).await;
|
||||
self.refresh().await;
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use config::defaults::*;
|
||||
use config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
use std::time;
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
pub mod persistence;
|
||||
|
||||
// 'CLIENT'
|
||||
const DEFAULT_DIRECTORY_SERVER: &str = "https://directory.nymtech.net";
|
||||
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
||||
|
||||
// 'DEBUG'
|
||||
// where applicable, the below are defined in milliseconds
|
||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
// all delays are in milliseconds
|
||||
const DEFAULT_ACK_WAIT_ADDITION: u64 = 800;
|
||||
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: u64 = 1000;
|
||||
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: u64 = 100;
|
||||
const DEFAULT_AVERAGE_PACKET_DELAY: u64 = 100;
|
||||
const DEFAULT_TOPOLOGY_REFRESH_RATE: u64 = 30_000;
|
||||
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: u64 = 5_000;
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: u64 = 1_500;
|
||||
const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
|
||||
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
||||
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
|
||||
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
||||
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
||||
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
|
||||
|
||||
pub fn missing_string_value() -> String {
|
||||
MISSING_VALUE.to_string()
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -118,14 +111,18 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.gateway_listener = gateway_listener.into();
|
||||
}
|
||||
|
||||
pub fn with_custom_directory<S: Into<String>>(&mut self, directory_server: S) {
|
||||
self.client.directory_server = directory_server.into();
|
||||
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
|
||||
self.client.validator_api_urls = validator_api_urls;
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.average_packet_delay = 10;
|
||||
self.debug.loop_cover_traffic_average_delay = 20; // 50 cover messages / s
|
||||
self.debug.message_sending_average_delay = 5; // 200 "real" messages / s
|
||||
self.debug.average_packet_delay = Duration::from_millis(10);
|
||||
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages
|
||||
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
|
||||
}
|
||||
|
||||
pub fn set_custom_version(&mut self, version: &str) {
|
||||
self.client.version = version.to_string();
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
@@ -164,8 +161,8 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.ack_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_directory_server(&self) -> String {
|
||||
self.client.directory_server.clone()
|
||||
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.validator_api_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
@@ -177,40 +174,44 @@ impl<T: NymConfig> Config<T> {
|
||||
}
|
||||
|
||||
// Debug getters
|
||||
pub fn get_average_packet_delay(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.average_packet_delay)
|
||||
pub fn get_average_packet_delay(&self) -> Duration {
|
||||
self.debug.average_packet_delay
|
||||
}
|
||||
|
||||
pub fn get_average_ack_delay(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.average_ack_delay)
|
||||
pub fn get_average_ack_delay(&self) -> Duration {
|
||||
self.debug.average_ack_delay
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_multiplier(&self) -> f64 {
|
||||
self.debug.ack_wait_multiplier
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_addition(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.ack_wait_addition)
|
||||
pub fn get_ack_wait_addition(&self) -> Duration {
|
||||
self.debug.ack_wait_addition
|
||||
}
|
||||
|
||||
pub fn get_loop_cover_traffic_average_delay(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.loop_cover_traffic_average_delay)
|
||||
pub fn get_loop_cover_traffic_average_delay(&self) -> Duration {
|
||||
self.debug.loop_cover_traffic_average_delay
|
||||
}
|
||||
|
||||
pub fn get_message_sending_average_delay(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.message_sending_average_delay)
|
||||
pub fn get_message_sending_average_delay(&self) -> Duration {
|
||||
self.debug.message_sending_average_delay
|
||||
}
|
||||
|
||||
pub fn get_gateway_response_timeout(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.gateway_response_timeout)
|
||||
pub fn get_gateway_response_timeout(&self) -> Duration {
|
||||
self.debug.gateway_response_timeout
|
||||
}
|
||||
|
||||
pub fn get_topology_refresh_rate(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.topology_refresh_rate)
|
||||
pub fn get_topology_refresh_rate(&self) -> Duration {
|
||||
self.debug.topology_refresh_rate
|
||||
}
|
||||
|
||||
pub fn get_topology_resolution_timeout(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.topology_resolution_timeout)
|
||||
pub fn get_topology_resolution_timeout(&self) -> Duration {
|
||||
self.debug.topology_resolution_timeout
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> &str {
|
||||
&self.client.version
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,13 +226,16 @@ impl<T: NymConfig> Default for Config<T> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
#[serde(default = "missing_string_value")]
|
||||
version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
id: String,
|
||||
|
||||
/// URL to the directory server.
|
||||
directory_server: String,
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls: Vec<Url>,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
private_identity_key_file: PathBuf,
|
||||
@@ -269,15 +273,16 @@ pub struct Client<T> {
|
||||
nym_root_directory: PathBuf,
|
||||
|
||||
#[serde(skip)]
|
||||
super_struct: PhantomData<T>,
|
||||
super_struct: PhantomData<*const T>,
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Client<T> {
|
||||
fn default() -> Self {
|
||||
// there must be explicit checks for whether id is not empty later
|
||||
Client {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
directory_server: DEFAULT_DIRECTORY_SERVER.to_string(),
|
||||
validator_api_urls: default_api_endpoints(),
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
private_encryption_key_file: Default::default(),
|
||||
@@ -340,15 +345,15 @@ pub struct Debug {
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
average_packet_delay: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
average_packet_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
average_ack_delay: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
average_ack_delay: Duration,
|
||||
|
||||
/// Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
@@ -358,36 +363,36 @@ pub struct Debug {
|
||||
/// Value added to the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 0.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
ack_wait_addition: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
ack_wait_addition: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
loop_cover_traffic_average_delay: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
message_sending_average_delay: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
message_sending_average_delay: Duration,
|
||||
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
gateway_response_timeout: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
gateway_response_timeout: Duration,
|
||||
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
topology_refresh_rate: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
topology_refresh_rate: Duration,
|
||||
|
||||
/// During topology refresh, test packets are sent through every single possible network
|
||||
/// path. This timeout determines waiting period until it is decided that the packet
|
||||
/// did not reach its destination.
|
||||
/// The provided value is interpreted as milliseconds.
|
||||
topology_resolution_timeout: u64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
topology_resolution_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for Debug {
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use config::NymConfig;
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod key_pathfinder;
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub(crate) fn config_template() -> &'static str {
|
||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||
// particular fields.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in mod.rs.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
##### main base client config options #####
|
||||
|
||||
[client]
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# URL to the directory server.
|
||||
directory_server = '{{ client.directory_server }}'
|
||||
|
||||
# Path to file containing private identity key.
|
||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||
|
||||
# Path to file containing public identity key.
|
||||
public_identity_key_file = '{{ client.public_identity_key_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
private_encryption_key_file = '{{ client.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
||||
|
||||
# Full path to file containing reply encryption keys of all reply-SURBs we have ever
|
||||
# sent but not received back.
|
||||
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
|
||||
# Path to file containing key used for encrypting and decrypting the content of an
|
||||
# acknowledgement so that nobody besides the client knows which packet it refers to.
|
||||
ack_key_file = '{{ client.ack_key_file }}'
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
[socket]
|
||||
|
||||
# allowed values are 'WebSocket' or 'None'
|
||||
socket_type = '{{ socket.socket_type }}'
|
||||
|
||||
# if applicable (for the case of 'WebSocket'), the port on which the client
|
||||
# will be listening for incoming requests
|
||||
listening_port = {{ socket.listening_port }}
|
||||
|
||||
|
||||
##### logging configuration options #####
|
||||
|
||||
[logging]
|
||||
|
||||
# TODO
|
||||
|
||||
|
||||
##### debug configuration options #####
|
||||
# The following options should not be modified unless you know EXACTLY what you are doing
|
||||
# as if set incorrectly, they may impact your anonymity.
|
||||
|
||||
[debug]
|
||||
|
||||
average_packet_delay = {{ debug.average_packet_delay }}
|
||||
average_ack_delay = {{ debug.average_ack_delay }}
|
||||
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
|
||||
message_sending_average_delay = {{ debug.message_sending_average_delay }}
|
||||
|
||||
"#
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod built_info;
|
||||
pub mod client;
|
||||
pub mod config;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[package]
|
||||
build = "build.rs"
|
||||
name = "nym-client"
|
||||
version = "0.8.0"
|
||||
version = "0.11.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -17,34 +16,31 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
||||
# the AsyncRead, AsyncWrite, Stream, Sink, etc. traits could be used from tokio
|
||||
# channels should really be replaced with crossbeam due to that implementation being more efficient
|
||||
# and the single instance of abortable we have should really be refactored anyway
|
||||
url = "2.1" # I think we should just replace it with String
|
||||
url = "2.2"
|
||||
|
||||
clap = "2.33.0" # for the command line arguments
|
||||
dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
||||
log = "0.4" # self explanatory
|
||||
pretty_env_logger = "0.3" # for formatting log messages
|
||||
pretty_env_logger = "0.4" # for formatting log messages
|
||||
rand = {version = "0.7.3", features = ["wasm-bindgen"]} # rng-related traits + some rng implementation to use
|
||||
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
|
||||
sled = "0.33" # for storage of replySURB decryption keys
|
||||
tokio = { version = "0.2", features = ["full"] } # async runtime
|
||||
tokio-tungstenite = "0.11.0" # websocket
|
||||
sled = "0.34" # for storage of replySURB decryption keys
|
||||
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||
tokio-tungstenite = "0.14" # websocket
|
||||
|
||||
## internal
|
||||
client-core = { path = "../client-core" }
|
||||
config = { path = "../../common/config" }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
directory-client = { path = "../../common/client-libs/directory-client" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
topology = { path = "../../common/topology" }
|
||||
websocket-requests = { path = "websocket-requests" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.4.3"
|
||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
version-checker = { path = "../../common/version-checker" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
serde_json = "1.0" # for the "textsend" example
|
||||
serde_json = "1.0" # for the "textsend" example
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use built;
|
||||
|
||||
fn main() {
|
||||
built::write_built_file().expect("Failed to acquire build-time information");
|
||||
}
|
||||
+18
-18
@@ -9,21 +9,21 @@ import (
|
||||
)
|
||||
|
||||
// request tags
|
||||
const SEND_REQUEST_TAG = 0x00
|
||||
const REPLY_REQUEST_TAG = 0x01
|
||||
const SELF_ADDRESS_REQUEST_TAG = 0x02
|
||||
const sendRequestTag = 0x00
|
||||
const replyRequestTag = 0x01
|
||||
const selfAddressRequestTag = 0x02
|
||||
|
||||
// response tags
|
||||
const ERROR_RESPONSE_TAG = 0x00
|
||||
const RECEIVED_RESPONSE_TAG = 0x01
|
||||
const SELF_ADDRESS_RESPONSE_TAG = 0x02
|
||||
const errorResponseTag = 0x00
|
||||
const receivedResponseTag = 0x01
|
||||
const selfAddressResponseTag = 0x02
|
||||
|
||||
func makeSelfAddressRequest() []byte {
|
||||
return []byte{SELF_ADDRESS_REQUEST_TAG}
|
||||
return []byte{selfAddressRequestTag}
|
||||
}
|
||||
|
||||
func parseSelfAddressResponse(rawResponse []byte) []byte {
|
||||
if len(rawResponse) != 97 || rawResponse[0] != SELF_ADDRESS_RESPONSE_TAG {
|
||||
if len(rawResponse) != 97 || rawResponse[0] != selfAddressResponseTag {
|
||||
panic("Received invalid response")
|
||||
}
|
||||
return rawResponse[1:]
|
||||
@@ -38,7 +38,7 @@ func makeSendRequest(recipient []byte, message []byte, withReplySurb bool) []byt
|
||||
surbByte = 1
|
||||
}
|
||||
|
||||
out := []byte{SEND_REQUEST_TAG, surbByte}
|
||||
out := []byte{sendRequestTag, surbByte}
|
||||
out = append(out, recipient...)
|
||||
out = append(out, messageLen...)
|
||||
out = append(out, message...)
|
||||
@@ -53,7 +53,7 @@ func makeReplyRequest(message []byte, replySURB []byte) []byte {
|
||||
surbLen := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(surbLen, uint64(len(replySURB)))
|
||||
|
||||
out := []byte{REPLY_REQUEST_TAG}
|
||||
out := []byte{replyRequestTag}
|
||||
out = append(out, surbLen...)
|
||||
out = append(out, replySURB...)
|
||||
out = append(out, messageLen...)
|
||||
@@ -63,7 +63,7 @@ func makeReplyRequest(message []byte, replySURB []byte) []byte {
|
||||
}
|
||||
|
||||
func parseReceived(rawResponse []byte) ([]byte, []byte) {
|
||||
if rawResponse[0] != RECEIVED_RESPONSE_TAG {
|
||||
if rawResponse[0] != receivedResponseTag {
|
||||
panic("Received invalid response!")
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func parseReceived(rawResponse []byte) ([]byte, []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func sendWithoutReply() {
|
||||
func sendBinaryWithoutReply() {
|
||||
uri := "ws://localhost:1977"
|
||||
|
||||
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
||||
@@ -122,12 +122,12 @@ func sendWithoutReply() {
|
||||
}
|
||||
selfAddress := parseSelfAddressResponse(receivedResponse)
|
||||
|
||||
read_data, err := ioutil.ReadFile("dummy_file")
|
||||
readData, err := ioutil.ReadFile("dummy_file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sendRequest := makeSendRequest(selfAddress, read_data, false)
|
||||
sendRequest := makeSendRequest(selfAddress, readData, false)
|
||||
fmt.Printf("sending content of 'dummy file' over the mix network...\n")
|
||||
if err = conn.WriteMessage(websocket.BinaryMessage, sendRequest); err != nil {
|
||||
panic(err)
|
||||
@@ -144,10 +144,10 @@ func sendWithoutReply() {
|
||||
panic("did not expect a replySURB!")
|
||||
}
|
||||
fmt.Printf("writing the file back to the disk!\n")
|
||||
ioutil.WriteFile("received_file_noreply", fileData, 0644)
|
||||
ioutil.WriteFile("received_file_no_reply", fileData, 0644)
|
||||
}
|
||||
|
||||
func sendWithReply() {
|
||||
func sendBinaryWithReply() {
|
||||
uri := "ws://localhost:1977"
|
||||
|
||||
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
||||
@@ -212,6 +212,6 @@ func sendWithReply() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// sendWithoutReply()
|
||||
sendWithReply()
|
||||
// sendBinaryWithoutReply()
|
||||
sendBinaryWithReply()
|
||||
}
|
||||
@@ -4,5 +4,5 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcutil v1.0.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis efficitur neque. Quisque aliquet vulputate ante, eget vehicula odio feugiat ac. Nulla ut mattis magna. Aenean tincidunt quis nulla eget eleifend. Cras in pretium sem. Nunc lorem metus, blandit sit amet egestas ut, feugiat quis tellus. Aenean tristique, enim a tincidunt condimentum, eros est blandit nunc, id viverra metus erat at nulla. Vivamus at tellus sodales, feugiat odio vel, laoreet neque. Vivamus posuere nulla ac sodales bibendum.
|
||||
|
||||
Vestibulum pulvinar nisi non ultricies egestas. Integer finibus ultrices justo vitae suscipit. Etiam interdum eu justo vel interdum. Morbi sagittis ac nisl quis consequat. Mauris dapibus ut risus ac facilisis. Pellentesque non tortor feugiat, consectetur arcu vel, ullamcorper sapien. Proin sodales purus non orci bibendum, sit amet ultrices justo ullamcorper. Nullam ac risus ac justo ultricies efficitur auctor nec arcu. Etiam sed finibus felis. Suspendisse potenti. Phasellus malesuada velit ac ullamcorper egestas. Sed elementum diam ut est gravida ultricies.
|
||||
|
||||
Pellentesque sed metus massa. Cras imperdiet lacus sit amet dolor aliquam, luctus posuere justo hendrerit. Morbi augue ex, gravida a metus sed, scelerisque euismod lacus. Nam consequat sapien ac pellentesque sagittis. Morbi a ultrices massa, vel aliquet ex. Maecenas ac sem diam. Nunc sed erat et ipsum volutpat auctor. Etiam elit felis, commodo vitae ipsum ac, fermentum lobortis arcu. Aliquam eu tempus enim. Curabitur vulputate imperdiet aliquam. Morbi iaculis rhoncus risus at malesuada. Donec accumsan feugiat ligula ut facilisis. Nunc porttitor sit amet est eget malesuada. Sed sed consectetur augue, non dapibus orci. Mauris aliquam pellentesque quam, sit amet pellentesque velit cursus vitae. Morbi sit amet molestie risus.
|
||||
|
||||
Nam gravida non ligula a egestas. Fusce sodales, purus id rhoncus mattis, purus est vehicula urna, vel finibus augue velit et est. Donec dictum erat eleifend lobortis iaculis. Praesent id venenatis ante. Donec feugiat, ipsum eget porttitor pulvinar, nisl odio posuere lorem, ut placerat elit nulla a ligula. Suspendisse nec nibh tincidunt, sollicitudin mi a, volutpat ligula. In maximus quam lacus, eget semper dolor sagittis sit amet.
|
||||
|
||||
In vitae hendrerit est, quis facilisis dui. In eu ante enim. Nullam hendrerit odio sit amet odio tincidunt eleifend. Aliquam erat volutpat. Curabitur commodo, purus pharetra lobortis rhoncus, tortor massa imperdiet nisl, vel dignissim tortor sem at orci. Aliquam maximus lobortis lacus, eu porttitor purus dapibus ut. Praesent at dapibus felis, efficitur blandit tortor. In hac habitasse platea dictumst. Aenean ultrices, nisl a pretium sagittis, tellus sapien mollis erat, eu consectetur erat mauris sed libero. Duis feugiat dapibus mi, vel ornare velit vehicula mattis. Ut suscipit pharetra leo et sollicitudin.
|
||||
+7
-7
@@ -26,7 +26,7 @@ func getSelfAddress(conn *websocket.Conn) string {
|
||||
return responseJSON["address"].(string)
|
||||
}
|
||||
|
||||
func sendWithoutReply() {
|
||||
func sendTextWithoutReply() {
|
||||
message := "Hello Nym!"
|
||||
|
||||
uri := "ws://localhost:1977"
|
||||
@@ -62,7 +62,7 @@ func sendWithoutReply() {
|
||||
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
||||
}
|
||||
|
||||
func sendWithReply() {
|
||||
func sendTextWithReply() {
|
||||
message := "Hello Nym!"
|
||||
|
||||
uri := "ws://localhost:1977"
|
||||
@@ -97,13 +97,13 @@ func sendWithReply() {
|
||||
}
|
||||
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
||||
|
||||
receivedMessageJson := make(map[string]interface{})
|
||||
if err := json.Unmarshal(receivedMessage, &receivedMessageJson); err != nil {
|
||||
receivedMessageJSON := make(map[string]interface{})
|
||||
if err := json.Unmarshal(receivedMessage, &receivedMessageJSON); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// use the received surb to send an anonymous reply!
|
||||
replySurb := receivedMessageJson["replySurb"]
|
||||
replySurb := receivedMessageJSON["replySurb"]
|
||||
replyMessage := "hello from reply SURB!"
|
||||
|
||||
reply, err := json.Marshal(map[string]interface{}{
|
||||
@@ -129,6 +129,6 @@ func sendWithReply() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// sendWithoutReply()
|
||||
sendWithReply()
|
||||
// sendTextWithoutReply()
|
||||
sendTextWithReply()
|
||||
}
|
||||
+7913
-1181
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
"author": "Dave Hrycyszyn",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.8.0",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"webpack": "^4.42.1",
|
||||
"webpack-cli": "^3.3.11",
|
||||
|
||||
+34
-23
@@ -36,31 +36,42 @@
|
||||
},
|
||||
"websockets": {
|
||||
"hashes": [
|
||||
"sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5",
|
||||
"sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5",
|
||||
"sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308",
|
||||
"sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb",
|
||||
"sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a",
|
||||
"sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c",
|
||||
"sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170",
|
||||
"sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422",
|
||||
"sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8",
|
||||
"sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485",
|
||||
"sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f",
|
||||
"sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8",
|
||||
"sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc",
|
||||
"sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779",
|
||||
"sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989",
|
||||
"sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1",
|
||||
"sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092",
|
||||
"sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824",
|
||||
"sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d",
|
||||
"sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55",
|
||||
"sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36",
|
||||
"sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"
|
||||
"sha256:0dd4eb8e0bbf365d6f652711ce21b8fd2b596f873d32aabb0fbb53ec604418cc",
|
||||
"sha256:1d0971cc7251aeff955aa742ec541ee8aaea4bb2ebf0245748fbec62f744a37e",
|
||||
"sha256:1d6b4fddb12ab9adf87b843cd4316c4bd602db8d5efd2fb83147f0458fe85135",
|
||||
"sha256:230a3506df6b5f446fed2398e58dcaafdff12d67fe1397dff196411a9e820d02",
|
||||
"sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3",
|
||||
"sha256:2cf04601633a4ec176b9cc3d3e73789c037641001dbfaf7c411f89cd3e04fcaf",
|
||||
"sha256:3ddff38894c7857c476feb3538dd847514379d6dc844961dc99f04b0384b1b1b",
|
||||
"sha256:48c222feb3ced18f3dc61168ca18952a22fb88e5eb8902d2bf1b50faefdc34a2",
|
||||
"sha256:51d04df04ed9d08077d10ccbe21e6805791b78eac49d16d30a1f1fe2e44ba0af",
|
||||
"sha256:597c28f3aa7a09e8c070a86b03107094ee5cdafcc0d55f2f2eac92faac8dc67d",
|
||||
"sha256:5c8f0d82ea2468282e08b0cf5307f3ad022290ed50c45d5cb7767957ca782880",
|
||||
"sha256:7189e51955f9268b2bdd6cc537e0faa06f8fffda7fb386e5922c6391de51b077",
|
||||
"sha256:7df3596838b2a0c07c6f6d67752c53859a54993d4f062689fdf547cb56d0f84f",
|
||||
"sha256:826ccf85d4514609219725ba4a7abd569228c2c9f1968e8be05be366f68291ec",
|
||||
"sha256:836d14eb53b500fd92bd5db2fc5894f7c72b634f9c2a28f546f75967503d8e25",
|
||||
"sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0",
|
||||
"sha256:85e701a6c316b7067f1e8675c638036a796fe5116783a4c932e7eb8e305a3ffe",
|
||||
"sha256:900589e19200be76dd7cbaa95e9771605b5ce3f62512d039fb3bc5da9014912a",
|
||||
"sha256:9147868bb0cc01e6846606cd65cbf9c58598f187b96d14dd1ca17338b08793bb",
|
||||
"sha256:9e7fdc775fe7403dbd8bc883ba59576a6232eac96dacb56512daacf7af5d618d",
|
||||
"sha256:ab5ee15d3462198c794c49ccd31773d8a2b8c17d622aa184f669d2b98c2f0857",
|
||||
"sha256:ad893d889bc700a5835e0a95a3e4f2c39e91577ab232a3dc03c262a0f8fc4b5c",
|
||||
"sha256:b2e71c4670ebe1067fa8632f0d081e47254ee2d3d409de54168b43b0ba9147e0",
|
||||
"sha256:b43b13e5622c5a53ab12f3272e6f42f1ce37cd5b6684b2676cb365403295cd40",
|
||||
"sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4",
|
||||
"sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20",
|
||||
"sha256:caa68c95bc1776d3521f81eeb4d5b9438be92514ec2a79fececda814099c8314",
|
||||
"sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da",
|
||||
"sha256:d2c2d9b24d3c65b5a02cac12cbb4e4194e590314519ed49db2f67ef561c3cf58",
|
||||
"sha256:e9e5fd6dbdf95d99bc03732ded1fc8ef22ebbc05999ac7e0c7bf57fe6e4e5ae2",
|
||||
"sha256:ebf459a1c069f9866d8569439c06193c586e72c9330db1390af7c6a0a32c4afd",
|
||||
"sha256:f31722f1c033c198aa4a39a01905951c00bd1c74f922e8afc1b1c62adbcdd56a",
|
||||
"sha256:f68c352a68e5fdf1e97288d5cec9296664c590c25932a8476224124aaf90dbcd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==8.1"
|
||||
"version": "==9.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocketStream};
|
||||
use tokio_tungstenite::{
|
||||
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||
};
|
||||
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
|
||||
// just helpers functions that work in this very particular context because we are sending to ourselves
|
||||
// and hence will always get a response back (i.e. the message we sent)
|
||||
async fn send_message_and_get_response(
|
||||
ws_stream: &mut WebSocketStream<TcpStream>,
|
||||
ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
req: Vec<u8>,
|
||||
) -> ServerResponse {
|
||||
ws_stream.send(Message::Binary(req)).await.unwrap();
|
||||
@@ -18,7 +20,7 @@ async fn send_message_and_get_response(
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_self_address(ws_stream: &mut WebSocketStream<TcpStream>) -> Recipient {
|
||||
async fn get_self_address(ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>) -> Recipient {
|
||||
let self_address_request = ClientRequest::SelfAddress.serialize();
|
||||
let response = send_message_and_get_response(ws_stream, self_address_request).await;
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use serde_json::json;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocketStream};
|
||||
use tokio_tungstenite::{
|
||||
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||
};
|
||||
|
||||
// PREFACE: in practice I don't see why you would ever want to use text api while in Rust, but example
|
||||
// is here for the completion sake
|
||||
@@ -9,7 +11,7 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocket
|
||||
// just helpers functions that work in this very particular context because we are sending to ourselves
|
||||
// and hence will always get a response back (i.e. the message we sent)
|
||||
async fn send_message_and_get_json_response(
|
||||
ws_stream: &mut WebSocketStream<TcpStream>,
|
||||
ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
text_req: String,
|
||||
) -> serde_json::Value {
|
||||
ws_stream.send(Message::Text(text_req)).await.unwrap();
|
||||
@@ -20,7 +22,7 @@ async fn send_message_and_get_json_response(
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_self_address(ws_stream: &mut WebSocketStream<TcpStream>) -> String {
|
||||
async fn get_self_address(ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>) -> String {
|
||||
let self_address_request = json!({ "type": "selfAddress" }).to_string();
|
||||
let response = send_message_and_get_json_response(ws_stream, self_address_request).await;
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The file has been placed there by the build script.
|
||||
include!(concat!(env!("OUT_DIR"), "/built.rs"));
|
||||
@@ -1,27 +1,16 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
use config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod template;
|
||||
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1977;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
@@ -54,10 +43,6 @@ impl NymConfig for Config {
|
||||
config_template()
|
||||
}
|
||||
|
||||
fn config_file_name() -> String {
|
||||
"config.toml".to_string()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
@@ -131,27 +116,7 @@ impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket {
|
||||
socket_type: SocketType::WebSocket,
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_config {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn after_saving_default_config_the_loaded_one_is_identical() {
|
||||
// need to figure out how to do something similar but without touching the disk
|
||||
// or the file system at all...
|
||||
let temp_location = tempfile::tempdir().unwrap().path().join("config.toml");
|
||||
let default_config = Config::new("foomp".to_string());
|
||||
default_config
|
||||
.save_to_file(Some(temp_location.clone()))
|
||||
.unwrap();
|
||||
|
||||
let loaded_config = Config::load_from_file(Some(temp_location), None).unwrap();
|
||||
|
||||
assert_eq!(default_config, loaded_config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub(crate) fn config_template() -> &'static str {
|
||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||
// particular fields.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in mod.rs.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
@@ -24,11 +13,18 @@ pub(crate) fn config_template() -> &'static str {
|
||||
##### main base client config options #####
|
||||
|
||||
[client]
|
||||
# Version of the client for which this configuration was created.
|
||||
version = '{{ client.version }}'
|
||||
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# URL to the directory server.
|
||||
directory_server = '{{ client.directory_server }}'
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||
@@ -93,10 +89,10 @@ listening_port = {{ socket.listening_port }}
|
||||
|
||||
[debug]
|
||||
|
||||
average_packet_delay = {{ debug.average_packet_delay }}
|
||||
average_ack_delay = {{ debug.average_ack_delay }}
|
||||
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
|
||||
message_sending_average_delay = {{ debug.message_sending_average_delay }}
|
||||
average_packet_delay = '{{ debug.average_packet_delay }}'
|
||||
average_ack_delay = '{{ debug.average_ack_delay }}'
|
||||
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
|
||||
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, SocketType};
|
||||
use crate::websocket;
|
||||
@@ -20,7 +9,7 @@ use client_core::client::inbound_messages::{
|
||||
};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::client::mix_traffic::{
|
||||
MixMessageReceiver, MixMessageSender, MixTrafficController,
|
||||
BatchMixMessageReceiver, BatchMixMessageSender, MixTrafficController,
|
||||
};
|
||||
use client_core::client::real_messages_control;
|
||||
use client_core::client::real_messages_control::RealMessagesController;
|
||||
@@ -42,7 +31,7 @@ use gateway_client::{
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
@@ -88,7 +77,7 @@ impl NymClient {
|
||||
pub fn as_mix_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*self.key_manager.identity_keypair().public_key(),
|
||||
self.key_manager.encryption_keypair().public_key().clone(),
|
||||
*self.key_manager.encryption_keypair().public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(self.config.get_base().get_gateway_id()).unwrap(),
|
||||
@@ -100,26 +89,25 @@ impl NymClient {
|
||||
fn start_cover_traffic_stream(
|
||||
&self,
|
||||
topology_accessor: TopologyAccessor,
|
||||
mix_tx: MixMessageSender,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
) {
|
||||
info!("Starting loop cover traffic stream...");
|
||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||
// set in the constructor which HAS TO be called within context of a tokio runtime
|
||||
self.runtime
|
||||
.enter(|| {
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
)
|
||||
})
|
||||
.start(self.runtime.handle());
|
||||
let _guard = self.runtime.enter();
|
||||
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
)
|
||||
.start(self.runtime.handle());
|
||||
}
|
||||
|
||||
fn start_real_traffic_controller(
|
||||
@@ -128,7 +116,7 @@ impl NymClient {
|
||||
reply_key_storage: ReplyKeyStorage,
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
input_receiver: InputMessageReceiver,
|
||||
mix_sender: MixMessageSender,
|
||||
mix_sender: BatchMixMessageSender,
|
||||
) {
|
||||
let controller_config = real_messages_control::Config::new(
|
||||
self.key_manager.ack_key(),
|
||||
@@ -144,17 +132,17 @@ impl NymClient {
|
||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
||||
// When refactoring this restriction should definitely be removed.
|
||||
let real_messages_controller = self.runtime.enter(|| {
|
||||
RealMessagesController::new(
|
||||
controller_config,
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
mix_sender,
|
||||
topology_accessor,
|
||||
reply_key_storage,
|
||||
)
|
||||
});
|
||||
real_messages_controller.start(self.runtime.handle());
|
||||
let _guard = self.runtime.enter();
|
||||
|
||||
RealMessagesController::new(
|
||||
controller_config,
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
mix_sender,
|
||||
topology_accessor,
|
||||
reply_key_storage,
|
||||
)
|
||||
.start(self.runtime.handle());
|
||||
}
|
||||
|
||||
// buffer controlling all messages fetched from provider
|
||||
@@ -179,59 +167,51 @@ impl NymClient {
|
||||
&mut self,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
) -> GatewayClient<'static, url::Url> {
|
||||
) -> GatewayClient {
|
||||
let gateway_id = self.config.get_base().get_gateway_id();
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address_str = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address_str.is_empty() {
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
.expect("provided gateway id is invalid!");
|
||||
|
||||
// TODO: since we presumably now get something valid-ish from the `init`, can we just
|
||||
// ditch url::Url and operate on `String`?
|
||||
let gateway_address =
|
||||
url::Url::parse(&gateway_address_str).expect("provided gateway address is invalid!");
|
||||
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
self.runtime.block_on(async {
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
.await
|
||||
.expect("could not authenticate and start up the gateway connection")
|
||||
});
|
||||
.expect("could not authenticate and start up the gateway connection");
|
||||
|
||||
gateway_client
|
||||
gateway_client
|
||||
})
|
||||
}
|
||||
|
||||
// future responsible for periodically polling directory server and updating
|
||||
// the current global view of topology
|
||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_base().get_directory_server(),
|
||||
self.config.get_base().get_validator_api_endpoints(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new_directory_client(topology_refresher_config, topology_accessor);
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
// before returning, block entire runtime to refresh the current network view so that any
|
||||
// components depending on topology would see a non-empty view
|
||||
info!(
|
||||
"Obtaining initial network topology from {}",
|
||||
self.config.get_base().get_directory_server()
|
||||
);
|
||||
info!("Obtaining initial network topology");
|
||||
self.runtime.block_on(topology_refresher.refresh());
|
||||
|
||||
// TODO: a slightly more graceful termination here
|
||||
@@ -255,8 +235,8 @@ impl NymClient {
|
||||
// requests?
|
||||
fn start_mix_traffic_controller(
|
||||
&mut self,
|
||||
mix_rx: MixMessageReceiver,
|
||||
gateway_client: GatewayClient<'static, url::Url>,
|
||||
mix_rx: BatchMixMessageReceiver,
|
||||
gateway_client: GatewayClient,
|
||||
) {
|
||||
info!("Starting mix traffic controller...");
|
||||
MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
|
||||
@@ -292,7 +272,7 @@ impl NymClient {
|
||||
/// EXPERIMENTAL DIRECT RUST API
|
||||
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
||||
/// well enough in local tests)
|
||||
pub fn send_reply(&mut self, reply_surb: ReplySURB, message: Vec<u8>) {
|
||||
pub fn send_reply(&mut self, reply_surb: ReplySurb, message: Vec<u8>) {
|
||||
let input_msg = InputMessage::new_reply(reply_surb, message);
|
||||
|
||||
self.input_tx
|
||||
@@ -330,7 +310,7 @@ impl NymClient {
|
||||
}
|
||||
|
||||
println!(
|
||||
"Received SIGINT - the client will terminate now (threads are not YET nicely stopped)"
|
||||
"Received SIGINT - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -383,6 +363,7 @@ impl NymClient {
|
||||
input_receiver,
|
||||
sphinx_message_sender.clone(),
|
||||
);
|
||||
|
||||
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||
|
||||
match self.config.get_socket_type() {
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::built_info;
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
use directory_client::DirectoryClient;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{gateway, NymTopology};
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("init")
|
||||
@@ -40,14 +32,13 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
.help("Id of the gateway we are going to connect to. If unsure what to put here - 'D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr' is a safe choice for the testnet")
|
||||
.help("Id of the gateway we are going to connect to.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
.takes_value(true),
|
||||
.arg(Arg::with_name("validators")
|
||||
.long("validators")
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("disable-socket")
|
||||
.long("disable-socket")
|
||||
@@ -69,10 +60,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> SharedKeys {
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
@@ -82,75 +73,148 @@ async fn register_with_gateway(
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.register()
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.to_string());
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
|
||||
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
|
||||
async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
version_filtered_topology
|
||||
.gateways()
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
println!("Initialising client...");
|
||||
|
||||
let id = matches.value_of("id").unwrap(); // required for now
|
||||
|
||||
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||
println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut config = Config::new(id);
|
||||
|
||||
let mut rng = OsRng;
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
// if client was already initialised, don't generate new keys, not re-register with gateway
|
||||
// (because this would create new shared key)
|
||||
if !already_init {
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
let gateway_id = matches.value_of("gateway").unwrap();
|
||||
let chosen_gateway_id = matches.value_of("gateway");
|
||||
|
||||
let registration_fut = async {
|
||||
let gate_details =
|
||||
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
};
|
||||
let registration_fut = async {
|
||||
let gate_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.clients_address())
|
||||
};
|
||||
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||
println!("Client configuration completed.\n\n\n");
|
||||
|
||||
println!(
|
||||
"Unless overridden in all `nym-client run` we will be talking to the following gateway: {}...",
|
||||
config.get_base().get_gateway_id(),
|
||||
);
|
||||
|
||||
println!("Client configuration completed.\n\n\n")
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, SocketType};
|
||||
use clap::ArgMatches;
|
||||
use url::Url;
|
||||
|
||||
pub mod init;
|
||||
pub mod run;
|
||||
pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| {
|
||||
raw_validator
|
||||
.trim()
|
||||
.parse()
|
||||
.expect("one of the provided validator api urls is invalid")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
if let Some(directory) = matches.value_of("directory") {
|
||||
config.get_base_mut().with_custom_directory(directory);
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||
}
|
||||
|
||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
use version_checker::is_minor_version_compatible;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("run")
|
||||
@@ -28,15 +19,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.required(true)
|
||||
)
|
||||
// the rest of arguments are optional, they are used to override settings in config file
|
||||
.arg(Arg::with_name("config")
|
||||
.long("config")
|
||||
.help("Custom path to the nym-mixnet-client configuration file")
|
||||
.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("validators")
|
||||
.long("validators")
|
||||
.help("Comma separated list rest rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
@@ -55,14 +41,42 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
}
|
||||
|
||||
// this only checks compatibility between config the binary. It does not take into consideration
|
||||
// network version. It might do so in the future.
|
||||
fn version_check(cfg: &Config) -> bool {
|
||||
let binary_version = env!("CARGO_PKG_VERSION");
|
||||
let config_version = cfg.get_base().get_version();
|
||||
if binary_version != config_version {
|
||||
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||
if is_minor_version_compatible(binary_version, config_version) {
|
||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||
true
|
||||
} else {
|
||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
let mut config =
|
||||
Config::load_from_file(matches.value_of("config").map(|path| path.into()), Some(id))
|
||||
.expect("Failed to load config file");
|
||||
let mut config = match Config::load_from_file(Some(id)) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
config = override_config(config, matches);
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return;
|
||||
}
|
||||
|
||||
NymClient::new(config).run_forever();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, MISSING_VALUE};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::defaults::default_api_endpoints;
|
||||
use config::NymConfig;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
use version_checker::Version;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"\n==================\nTrying to upgrade client from {} to {} ...",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!(
|
||||
"Upgrade from {} to {} failed!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"Upgrade from {} to {} was successful!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!(
|
||||
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||
config_version, package_version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-client we want to upgrade")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {:?}", err);
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_matches: &ArgMatches,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||
package_version.clone()
|
||||
} else {
|
||||
Version::new(0, 12, 0)
|
||||
};
|
||||
|
||||
print_start_upgrade(&config_version, &to_version);
|
||||
|
||||
println!(
|
||||
"Setting validator API endpoints to {:?}",
|
||||
default_api_endpoints()
|
||||
);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(default_api_endpoints());
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_version(to_version.to_string().as_ref());
|
||||
|
||||
config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
if config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {:?}", err);
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.get_base().get_version() == MISSING_VALUE {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||
do_upgrade(existing_config, matches, package_version)
|
||||
}
|
||||
@@ -1,17 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod built_info;
|
||||
pub mod client;
|
||||
pub mod websocket;
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, ArgMatches};
|
||||
|
||||
pub mod built_info;
|
||||
pub mod client;
|
||||
pub mod commands;
|
||||
pub mod websocket;
|
||||
@@ -23,14 +11,14 @@ fn main() {
|
||||
dotenv::dotenv().ok();
|
||||
setup_logging();
|
||||
println!("{}", banner());
|
||||
println!("\n\nIf unsure which gateway to choose - 'D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr' is a safe choice for the testnet\n\n");
|
||||
|
||||
let arg_matches = App::new("Nym Client")
|
||||
.version(built_info::PKG_VERSION)
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author("Nymtech")
|
||||
.about("Implementation of the Nym Client")
|
||||
.subcommand(commands::init::command_args())
|
||||
.subcommand(commands::run::command_args())
|
||||
.subcommand(commands::upgrade::command_args())
|
||||
.get_matches();
|
||||
|
||||
execute(arg_matches);
|
||||
@@ -40,6 +28,7 @@ fn execute(matches: ArgMatches) {
|
||||
match matches.subcommand() {
|
||||
("init", Some(m)) => commands::init::execute(m),
|
||||
("run", Some(m)) => commands::run::execute(m),
|
||||
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
||||
_ => println!("{}", usage()),
|
||||
}
|
||||
}
|
||||
@@ -61,7 +50,7 @@ fn banner() -> String {
|
||||
(client - version {:})
|
||||
|
||||
"#,
|
||||
built_info::PKG_VERSION
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use client_core::client::{
|
||||
inbound_messages::{InputMessage, InputMessageSender},
|
||||
@@ -22,7 +11,7 @@ use futures::channel::mpsc;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{
|
||||
@@ -57,7 +46,7 @@ impl Clone for Handler {
|
||||
Handler {
|
||||
msg_input: self.msg_input.clone(),
|
||||
buffer_requester: self.buffer_requester.clone(),
|
||||
self_full_address: self.self_full_address.clone(),
|
||||
self_full_address: self.self_full_address,
|
||||
socket: None,
|
||||
received_response_type: Default::default(),
|
||||
}
|
||||
@@ -100,9 +89,9 @@ impl Handler {
|
||||
None
|
||||
}
|
||||
|
||||
fn handle_reply(&mut self, reply_surb: ReplySURB, message: Vec<u8>) -> Option<ServerResponse> {
|
||||
if message.len() > ReplySURB::max_msg_len(Default::default()) {
|
||||
return Some(ServerResponse::new_error(format!("too long message to put inside a reply SURB. Received: {} bytes and maximum is {} bytes", message.len(), ReplySURB::max_msg_len(Default::default()))));
|
||||
fn handle_reply(&mut self, reply_surb: ReplySurb, message: Vec<u8>) -> Option<ServerResponse> {
|
||||
if message.len() > ReplySurb::max_msg_len(Default::default()) {
|
||||
return Some(ServerResponse::new_error(format!("too long message to put inside a reply SURB. Received: {} bytes and maximum is {} bytes", message.len(), ReplySurb::max_msg_len(Default::default()))));
|
||||
}
|
||||
|
||||
let input_msg = InputMessage::new_reply(reply_surb, message);
|
||||
@@ -112,7 +101,7 @@ impl Handler {
|
||||
}
|
||||
|
||||
fn handle_self_address(&self) -> ServerResponse {
|
||||
ServerResponse::SelfAddress(self.self_full_address.clone())
|
||||
ServerResponse::SelfAddress(self.self_full_address)
|
||||
}
|
||||
|
||||
fn handle_request(&mut self, request: ClientRequest) -> Option<ServerResponse> {
|
||||
|
||||
@@ -1,23 +1,10 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::handler::Handler;
|
||||
use log::*;
|
||||
use std::{
|
||||
net::{Shutdown, SocketAddr},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{net::SocketAddr, process, sync::Arc};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::runtime;
|
||||
use tokio::{sync::Notify, task::JoinHandle};
|
||||
|
||||
@@ -28,10 +15,7 @@ enum State {
|
||||
|
||||
impl State {
|
||||
fn is_connected(&self) -> bool {
|
||||
match self {
|
||||
State::Connected => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, State::Connected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +34,13 @@ impl Listener {
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&mut self, handler: Handler) {
|
||||
let mut tcp_listener = tokio::net::TcpListener::bind(self.address)
|
||||
.await
|
||||
.expect("Failed to start websocket listener");
|
||||
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
|
||||
Ok(listener) => listener,
|
||||
Err(err) => {
|
||||
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let notify = Arc::new(Notify::new());
|
||||
|
||||
@@ -64,7 +52,7 @@ impl Listener {
|
||||
}
|
||||
new_conn = tcp_listener.accept() => {
|
||||
match new_conn {
|
||||
Ok((socket, remote_addr)) => {
|
||||
Ok((mut socket, remote_addr)) => {
|
||||
debug!("Received connection from {:?}", remote_addr);
|
||||
if self.state.is_connected() {
|
||||
warn!("tried to duplicate!");
|
||||
@@ -73,7 +61,7 @@ impl Listener {
|
||||
// while we only ever want to accept a single connection, we don't want
|
||||
// to leave clients hanging (and also allow for reconnection if it somehow
|
||||
// was dropped)
|
||||
match socket.shutdown(Shutdown::Both) {
|
||||
match socket.shutdown().await {
|
||||
Ok(_) => trace!(
|
||||
"closed the connection between attempting websocket handshake"
|
||||
),
|
||||
@@ -87,7 +75,7 @@ impl Listener {
|
||||
let fresh_handler = handler.clone();
|
||||
tokio::spawn(async move {
|
||||
fresh_handler.handle_connection(socket).await;
|
||||
notify_clone.notify();
|
||||
notify_clone.notify_one();
|
||||
});
|
||||
self.state = State::Connected;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub(crate) mod handler;
|
||||
pub(crate) mod listener;
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@@ -55,7 +44,7 @@ pub enum ErrorKind {
|
||||
/// The received request is malformed.
|
||||
MalformedRequest = 0x04,
|
||||
|
||||
// that's an arbitrary division but lets keep 1-127 (hex 0x01 - 0x7F) values request-specific
|
||||
// that's an arbitrary division but let's keep 1-127 (hex 0x01 - 0x7F) values request-specific
|
||||
// and 128-254 (hex 0x80 - 0xFE) for responses
|
||||
/// The received response contained no data.
|
||||
EmptyResponse = 0x80,
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod error;
|
||||
pub mod requests;
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// all variable size data is always prefixed with u64 length
|
||||
// tags are u8
|
||||
@@ -18,7 +7,7 @@
|
||||
use crate::error::{self, ErrorKind};
|
||||
use crate::text::ClientRequestText;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::mem::size_of;
|
||||
|
||||
@@ -42,7 +31,7 @@ pub enum ClientRequest {
|
||||
},
|
||||
Reply {
|
||||
message: Vec<u8>,
|
||||
reply_surb: ReplySURB,
|
||||
reply_surb: ReplySurb,
|
||||
},
|
||||
SelfAddress,
|
||||
}
|
||||
@@ -119,7 +108,7 @@ impl ClientRequest {
|
||||
}
|
||||
|
||||
// REPLY_REQUEST_TAG || surb_len || surb || message_len || message
|
||||
fn serialize_reply(message: Vec<u8>, reply_surb: ReplySURB) -> Vec<u8> {
|
||||
fn serialize_reply(message: Vec<u8>, reply_surb: ReplySurb) -> Vec<u8> {
|
||||
let reply_surb_bytes = reply_surb.to_bytes();
|
||||
let surb_len_bytes = (reply_surb_bytes.len() as u64).to_be_bytes();
|
||||
let message_len_bytes = (message.len() as u64).to_be_bytes();
|
||||
@@ -164,7 +153,7 @@ impl ClientRequest {
|
||||
let surb_bound = 1 + size_of::<u64>() + reply_surb_len as usize;
|
||||
|
||||
let reply_surb_bytes = &b[1 + size_of::<u64>()..surb_bound];
|
||||
let reply_surb = match ReplySURB::from_bytes(reply_surb_bytes) {
|
||||
let reply_surb = match ReplySurb::from_bytes(reply_surb_bytes) {
|
||||
Ok(reply_surb) => reply_surb,
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
@@ -206,11 +195,11 @@ impl ClientRequest {
|
||||
}
|
||||
|
||||
// SELF_ADDRESS_REQUEST_TAG
|
||||
fn deserialize_self_address(b: &[u8]) -> Result<Self, error::Error> {
|
||||
fn deserialize_self_address(b: &[u8]) -> Self {
|
||||
// this MUST match because it was called by 'deserialize'
|
||||
debug_assert_eq!(b[0], SELF_ADDRESS_REQUEST_TAG);
|
||||
|
||||
Ok(ClientRequest::SelfAddress)
|
||||
ClientRequest::SelfAddress
|
||||
}
|
||||
|
||||
pub fn serialize(self) -> Vec<u8> {
|
||||
@@ -255,7 +244,7 @@ impl ClientRequest {
|
||||
match request_tag {
|
||||
SEND_REQUEST_TAG => Self::deserialize_send(b),
|
||||
REPLY_REQUEST_TAG => Self::deserialize_reply(b),
|
||||
SELF_ADDRESS_REQUEST_TAG => Self::deserialize_self_address(b),
|
||||
SELF_ADDRESS_REQUEST_TAG => Ok(Self::deserialize_self_address(b)),
|
||||
n => Err(error::Error::new(
|
||||
ErrorKind::UnknownRequest,
|
||||
format!("type {}", n),
|
||||
@@ -288,7 +277,7 @@ mod tests {
|
||||
let recipient_string = recipient.to_string();
|
||||
|
||||
let send_request_no_surb = ClientRequest::Send {
|
||||
recipient: recipient.clone(),
|
||||
recipient,
|
||||
message: b"foomp".to_vec(),
|
||||
with_reply_surb: false,
|
||||
};
|
||||
@@ -333,7 +322,7 @@ mod tests {
|
||||
#[test]
|
||||
fn reply_request_serialization_works() {
|
||||
let reply_surb_string = "CjfVbHbfAjbC3W1BvNHGXmM8KNAnDNYGaHMLqVDxRYeo352csAihstup9bvqXam4dTWgfHak6KYwL9STaxWJ47E8XFZbSEvs7hEsfCkxr6K9WJuSBPK84GDDEvad8ZAuMCoaXsAd5S2Lj9a5eYyzG4SL1jHzhSMni55LyJwumxo1ZTGZNXggxw1RREosvyzNrW9Rsi3owyPqLCwXpiei2tHZty8w8midVvg8vDa7ZEJD842CLv8D4ohynSG7gDpqTrhkRaqYAuz7dzqNbMXLJRM7v823Jn16fA1L7YQxmcaUdUigyRSgTdb4i9ebiLGSyJ1iDe6Acz613PQZh6Ua3bZ2zVKq3dSycpDm9ngarRK4zJrAaUxRkdih8YzW3BY4nL9eqkfKA4N1TWCLaRU7zpSaf8yMEwrAZReU3d5zLV8c5KBfa2w8R5anhQeBojduZEGEad8kkHuKU52Zg93FeWHvH1qgZaEJMHH4nN7gKXz9mvWDhYwyF4vt3Uy2NhCHC3N5pL1gMme27YcoPcTEia1fxKZtnt6rtEozzTrAgCJGswigkFbkafiV5QaJwLKTUxtzhkZ57eEuLPte9UvJHzhhXUQ2CV7R2BUkJjYZy3Zsx6YYvdYWiAFFkWUwNEGA4QpShUHciBfsQVHQ7pN41YcyYUhbywQDFnTVgEmdUZ1XCBi3gyK5U3tDQmFzP1u9m3mWrUA8qB9mRDE7ptNDm5c3c1458L6uXLUth7sdMaa1Was5LCmCdmNDtvNpCDAEt1in6q6mrZFR85aCSU9b1baNGwZoCqPpPvydkVe63gXWoi8ebvdyxARrqACFrSB3ZdY3uJBw8CTMNkKK6MvcefMkSVVsbLd36TQAtYSCqrpiMc5dQuKcEu5QfciwvWYXYx8WFNAgKwP2mv49KCTvfozNDUCbjzDwSx92Zv5zjG8HbFpB13bY9UZGeyTPvv7gGxCzjGjJGbW6FRAheRQaaje5fUgCNM95Tv7wBmAMRHHFgWafeK1sdFH7dtCX9u898HucGTaboSKLsVh8J78gbbkHErwjMh7y9YRkceq5TTYS5da4kHnyNKYWSbxgZrmFg44XGKoeYcqoHB3XTZrdsf7F5fFeNwnihkmADvhAcaxXUmVqq4rQFZH84a1iC3WBWXYcqiZH2L7ujGWV7mMDT4HBEerDYjc8rNY4xGTPfivCrBCJW1i14aqW8xRdsdgTM88eTksvC3WPJLJ7iMzfKXeL7fMW1Ek6QGyQtLBW98vEESpdcDg6DeZ5rMz6VqjTGGqcCaFGfHoqtfxMDaBAEsyQ8h7XDX6dg1wq9wH6j4Tw7Tj1MEv1b8uj5NJkozZdzVdYA2QyE2Dp8vuurQG6uVdTDNww2d88RBQ8sVgjxN8gR45y4woJLhFAaNTAtrY6wDTxyXST13ni6oyqdYxjFVk9Am4v3DzH7Y2K8iRVSHfTk4FRbPULyaeK6wt2anvMJH1XdvVRgc14h67MnBxMgMD1UFk8AErN7CDj26fppe3c5G6KozJe4cSqQUGbBjVzBnrHCruqrfZBn5hNZHTV37bQiomqhRQXohxhuKEnNrGbAe1xNvJr9X";
|
||||
let reply_surb = ReplySURB::from_base58_string(reply_surb_string).unwrap();
|
||||
let reply_surb = ReplySurb::from_base58_string(reply_surb_string).unwrap();
|
||||
let reply_request = ClientRequest::Reply {
|
||||
message: b"foomp".to_vec(),
|
||||
reply_surb,
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// all variable size data is always prefixed with u64 length
|
||||
// tags are u8
|
||||
|
||||
#![allow(unknown_lints)] // due to using `clippy::branches_sharing_code` which does not exist on `stable` just yet
|
||||
|
||||
use crate::error::{self, ErrorKind};
|
||||
use crate::text::ServerResponseText;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use std::convert::TryInto;
|
||||
use std::mem::size_of;
|
||||
@@ -96,6 +87,8 @@ impl ServerResponse {
|
||||
}
|
||||
};
|
||||
|
||||
// this is a false positive as even though the code is the same, it refers to different things
|
||||
#[allow(clippy::branches_sharing_code)]
|
||||
if with_reply_surb {
|
||||
let reply_surb_len =
|
||||
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
|
||||
@@ -111,7 +104,7 @@ impl ServerResponse {
|
||||
let surb_bound = 2 + size_of::<u64>() + reply_surb_len as usize;
|
||||
|
||||
let reply_surb_bytes = &b[2 + size_of::<u64>()..surb_bound];
|
||||
let reply_surb = match ReplySURB::from_bytes(reply_surb_bytes) {
|
||||
let reply_surb = match ReplySurb::from_bytes(reply_surb_bytes) {
|
||||
Ok(reply_surb) => reply_surb,
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
@@ -310,12 +303,10 @@ impl ServerResponse {
|
||||
RECEIVED_RESPONSE_TAG => Self::deserialize_received(b),
|
||||
SELF_ADDRESS_RESPONSE_TAG => Self::deserialize_self_address(b),
|
||||
ERROR_RESPONSE_TAG => Self::deserialize_error(b),
|
||||
n => {
|
||||
return Err(error::Error::new(
|
||||
ErrorKind::UnknownResponse,
|
||||
format!("type {}", n),
|
||||
))
|
||||
}
|
||||
n => Err(error::Error::new(
|
||||
ErrorKind::UnknownResponse,
|
||||
format!("type {}", n),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +332,7 @@ mod tests {
|
||||
|
||||
let received_with_surb = ServerResponse::Received(ReconstructedMessage {
|
||||
message: b"foomp".to_vec(),
|
||||
reply_surb: Some(ReplySURB::from_base58_string(reply_surb_string).unwrap()),
|
||||
reply_surb: Some(ReplySurb::from_base58_string(reply_surb_string).unwrap()),
|
||||
});
|
||||
let bytes = received_with_surb.serialize();
|
||||
let recovered = ServerResponse::deserialize(&bytes).unwrap();
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::ErrorKind;
|
||||
use crate::requests::ClientRequest;
|
||||
use crate::responses::ServerResponse;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
@@ -75,7 +64,7 @@ impl TryInto<ClientRequest> for ClientRequestText {
|
||||
reply_surb,
|
||||
} => {
|
||||
let message_bytes = message.into_bytes();
|
||||
let reply_surb = ReplySURB::from_base58_string(reply_surb).map_err(|err| {
|
||||
let reply_surb = ReplySurb::from_base58_string(reply_surb).map_err(|err| {
|
||||
Self::Error::new(ErrorKind::MalformedRequest, err.to_string())
|
||||
})?;
|
||||
|
||||
@@ -115,15 +104,15 @@ impl TryFrom<String> for ServerResponseText {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for ServerResponseText {
|
||||
fn into(self) -> String {
|
||||
impl From<ServerResponseText> for String {
|
||||
fn from(res: ServerResponseText) -> Self {
|
||||
// per serde_json docs:
|
||||
/*
|
||||
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
|
||||
/// fail, or if `T` contains a map with non-string keys.
|
||||
*/
|
||||
// this is not the case here.
|
||||
serde_json::to_string(&self).unwrap()
|
||||
serde_json::to_string(&res).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[package]
|
||||
build = "build.rs"
|
||||
name = "nym-socks5-client"
|
||||
version = "0.8.0"
|
||||
version = "0.11.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -15,29 +14,25 @@ dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0"
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
pin-project = "0.4"
|
||||
pretty_env_logger = "0.3"
|
||||
pin-project = "1.0"
|
||||
pretty_env_logger = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization
|
||||
snafu = "0.4.1"
|
||||
tokio = { version = "0.2", features = ["rt-threaded"] }
|
||||
url = "2.1"
|
||||
snafu = "0.6"
|
||||
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] }
|
||||
url = "2.2"
|
||||
|
||||
# internal
|
||||
client-core = { path = "../client-core" }
|
||||
config = { path = "../../common/config" }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
directory-client = { path = "../../common/client-libs/directory-client" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
ordered-buffer = {path = "../../common/socks5/ordered-buffer"}
|
||||
socks5-requests = { path = "../../common/socks5/requests" }
|
||||
topology = { path = "../../common/topology" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
version-checker = { path = "../../common/version-checker" }
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use built;
|
||||
|
||||
fn main() {
|
||||
built::write_built_file().expect("Failed to acquire build-time information");
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The file has been placed there by the build script.
|
||||
include!(concat!(env!("OUT_DIR"), "/built.rs"));
|
||||
@@ -1,19 +1,10 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
use config::defaults::DEFAULT_SOCKS5_LISTENING_PORT;
|
||||
use config::NymConfig;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -21,8 +12,6 @@ use std::path::PathBuf;
|
||||
|
||||
mod template;
|
||||
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1080;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
@@ -37,10 +26,6 @@ impl NymConfig for Config {
|
||||
config_template()
|
||||
}
|
||||
|
||||
fn config_file_name() -> String {
|
||||
"config.toml".to_string()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
@@ -117,7 +102,7 @@ pub struct Socks5 {
|
||||
impl Socks5 {
|
||||
pub fn new<S: Into<String>>(provider_mix_address: S) -> Self {
|
||||
Socks5 {
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
listening_port: DEFAULT_SOCKS5_LISTENING_PORT,
|
||||
provider_mix_address: provider_mix_address.into(),
|
||||
}
|
||||
}
|
||||
@@ -126,29 +111,8 @@ impl Socks5 {
|
||||
impl Default for Socks5 {
|
||||
fn default() -> Self {
|
||||
Socks5 {
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
listening_port: DEFAULT_SOCKS5_LISTENING_PORT,
|
||||
provider_mix_address: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_config {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn after_saving_default_config_the_loaded_one_is_identical() {
|
||||
// need to figure out how to do something similar but without touching the disk
|
||||
// or the file system at all...
|
||||
let temp_location = tempfile::tempdir().unwrap().path().join("config.toml");
|
||||
let fake_address = "CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@FioFa8nMmPpQnYi7JyojoTuwGLeyNS8BF4ChPr29zUML";
|
||||
let default_config = Config::new("foomp", fake_address);
|
||||
default_config
|
||||
.save_to_file(Some(temp_location.clone()))
|
||||
.unwrap();
|
||||
|
||||
let loaded_config = Config::load_from_file(Some(temp_location), None).unwrap();
|
||||
|
||||
assert_eq!(default_config, loaded_config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub(crate) fn config_template() -> &'static str {
|
||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||
// particular fields.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in mod.rs.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
@@ -24,11 +13,18 @@ pub(crate) fn config_template() -> &'static str {
|
||||
##### main base client config options #####
|
||||
|
||||
[client]
|
||||
# Version of the client for which this configuration was created.
|
||||
version = '{{ client.version }}'
|
||||
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# URL to the directory server.
|
||||
directory_server = '{{ client.directory_server }}'
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||
@@ -92,10 +88,10 @@ listening_port = {{ socks5.listening_port }}
|
||||
|
||||
[debug]
|
||||
|
||||
average_packet_delay = {{ debug.average_packet_delay }}
|
||||
average_ack_delay = {{ debug.average_ack_delay }}
|
||||
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
|
||||
message_sending_average_delay = {{ debug.message_sending_average_delay }}
|
||||
average_packet_delay = '{{ debug.average_packet_delay }}'
|
||||
average_ack_delay = '{{ debug.average_ack_delay }}'
|
||||
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
|
||||
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::socks::{
|
||||
@@ -23,7 +12,7 @@ use client_core::client::inbound_messages::{
|
||||
};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::client::mix_traffic::{
|
||||
MixMessageReceiver, MixMessageSender, MixTrafficController,
|
||||
BatchMixMessageReceiver, BatchMixMessageSender, MixTrafficController,
|
||||
};
|
||||
use client_core::client::real_messages_control::RealMessagesController;
|
||||
use client_core::client::received_buffer::{
|
||||
@@ -76,7 +65,7 @@ impl NymClient {
|
||||
pub fn as_mix_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*self.key_manager.identity_keypair().public_key(),
|
||||
self.key_manager.encryption_keypair().public_key().clone(),
|
||||
*self.key_manager.encryption_keypair().public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(self.config.get_base().get_gateway_id()).unwrap(),
|
||||
@@ -88,26 +77,25 @@ impl NymClient {
|
||||
fn start_cover_traffic_stream(
|
||||
&self,
|
||||
topology_accessor: TopologyAccessor,
|
||||
mix_tx: MixMessageSender,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
) {
|
||||
info!("Starting loop cover traffic stream...");
|
||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||
// set in the constructor which HAS TO be called within context of a tokio runtime
|
||||
self.runtime
|
||||
.enter(|| {
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
)
|
||||
})
|
||||
.start(self.runtime.handle());
|
||||
let _guard = self.runtime.enter();
|
||||
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
)
|
||||
.start(self.runtime.handle());
|
||||
}
|
||||
|
||||
fn start_real_traffic_controller(
|
||||
@@ -116,7 +104,7 @@ impl NymClient {
|
||||
reply_key_storage: ReplyKeyStorage,
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
input_receiver: InputMessageReceiver,
|
||||
mix_sender: MixMessageSender,
|
||||
mix_sender: BatchMixMessageSender,
|
||||
) {
|
||||
let controller_config = client_core::client::real_messages_control::Config::new(
|
||||
self.key_manager.ack_key(),
|
||||
@@ -132,17 +120,17 @@ impl NymClient {
|
||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
||||
// When refactoring this restriction should definitely be removed.
|
||||
let real_messages_controller = self.runtime.enter(|| {
|
||||
RealMessagesController::new(
|
||||
controller_config,
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
mix_sender,
|
||||
topology_accessor,
|
||||
reply_key_storage,
|
||||
)
|
||||
});
|
||||
real_messages_controller.start(self.runtime.handle());
|
||||
let _guard = self.runtime.enter();
|
||||
|
||||
RealMessagesController::new(
|
||||
controller_config,
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
mix_sender,
|
||||
topology_accessor,
|
||||
reply_key_storage,
|
||||
)
|
||||
.start(self.runtime.handle());
|
||||
}
|
||||
|
||||
// buffer controlling all messages fetched from provider
|
||||
@@ -167,59 +155,51 @@ impl NymClient {
|
||||
&mut self,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
) -> GatewayClient<'static, url::Url> {
|
||||
) -> GatewayClient {
|
||||
let gateway_id = self.config.get_base().get_gateway_id();
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address_str = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address_str.is_empty() {
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
.expect("provided gateway id is invalid!");
|
||||
|
||||
// TODO: since we presumably now get something valid-ish from the `init`, can we just
|
||||
// ditch url::Url and operate on `String`?
|
||||
let gateway_address =
|
||||
url::Url::parse(&gateway_address_str).expect("provided gateway address is invalid!");
|
||||
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
self.runtime.block_on(async {
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
.await
|
||||
.expect("could not authenticate and start up the gateway connection")
|
||||
});
|
||||
.expect("could not authenticate and start up the gateway connection");
|
||||
|
||||
gateway_client
|
||||
gateway_client
|
||||
})
|
||||
}
|
||||
|
||||
// future responsible for periodically polling directory server and updating
|
||||
// the current global view of topology
|
||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_base().get_directory_server(),
|
||||
self.config.get_base().get_validator_api_endpoints(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new_directory_client(topology_refresher_config, topology_accessor);
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
// before returning, block entire runtime to refresh the current network view so that any
|
||||
// components depending on topology would see a non-empty view
|
||||
info!(
|
||||
"Obtaining initial network topology from {}",
|
||||
self.config.get_base().get_directory_server()
|
||||
);
|
||||
info!("Obtaining initial network topology");
|
||||
self.runtime.block_on(topology_refresher.refresh());
|
||||
|
||||
// TODO: a slightly more graceful termination here
|
||||
@@ -243,8 +223,8 @@ impl NymClient {
|
||||
// requests?
|
||||
fn start_mix_traffic_controller(
|
||||
&mut self,
|
||||
mix_rx: MixMessageReceiver,
|
||||
gateway_client: GatewayClient<'static, url::Url>,
|
||||
mix_rx: BatchMixMessageReceiver,
|
||||
gateway_client: GatewayClient,
|
||||
) {
|
||||
info!("Starting mix traffic controller...");
|
||||
MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
|
||||
@@ -256,8 +236,7 @@ impl NymClient {
|
||||
msg_input: InputMessageSender,
|
||||
) {
|
||||
info!("Starting socks5 listener...");
|
||||
let mut auth_methods: Vec<u8> = Vec::new();
|
||||
auth_methods.push(AuthenticationMethods::NoAuth as u8);
|
||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||
let allowed_users: Vec<User> = Vec::new();
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
@@ -282,7 +261,7 @@ impl NymClient {
|
||||
}
|
||||
|
||||
println!(
|
||||
"Received SIGINT - the client will terminate now (threads are not YET nicely stopped)"
|
||||
"Received SIGINT - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -335,6 +314,7 @@ impl NymClient {
|
||||
input_receiver,
|
||||
sphinx_message_sender.clone(),
|
||||
);
|
||||
|
||||
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||
self.start_socks5_listener(received_buffer_request_sender, input_sender);
|
||||
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::built_info;
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
use directory_client::DirectoryClient;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use rand::rngs::OsRng;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{gateway, NymTopology};
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("init")
|
||||
@@ -46,14 +36,13 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
.help("Id of the gateway we are going to connect to. If unsure what to put here - 'D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr' is a safe choice for the testnet")
|
||||
.help("Id of the gateway we are going to connect to.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
.takes_value(true),
|
||||
.arg(Arg::with_name("validators")
|
||||
.long("validators")
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("port")
|
||||
.short("p")
|
||||
@@ -71,10 +60,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> SharedKeys {
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
@@ -84,24 +73,79 @@ async fn register_with_gateway(
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.register()
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.to_string());
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
|
||||
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
|
||||
async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
version_filtered_topology
|
||||
.gateways()
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
@@ -110,51 +154,68 @@ pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap(); // required for now
|
||||
let provider_address = matches.value_of("provider").unwrap();
|
||||
|
||||
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||
println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut config = Config::new(id, provider_address);
|
||||
|
||||
let mut rng = OsRng;
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
// if client was already initialised, don't generate new keys, not re-register with gateway
|
||||
// (because this would create new shared key)
|
||||
if !already_init {
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
let gateway_id = matches.value_of("gateway").unwrap();
|
||||
let chosen_gateway_id = matches.value_of("gateway");
|
||||
|
||||
let registration_fut = async {
|
||||
let gate_details =
|
||||
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
};
|
||||
let registration_fut = async {
|
||||
let gate_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.clients_address())
|
||||
};
|
||||
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||
println!("Client configuration completed.\n\n\n");
|
||||
|
||||
println!(
|
||||
"Unless overridden in all `nym-socks5-client run` we will be talking to the following gateway: {}...",
|
||||
config.get_base().get_gateway_id(),
|
||||
);
|
||||
|
||||
println!("Client configuration completed.\n\n\n")
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use clap::ArgMatches;
|
||||
use url::Url;
|
||||
|
||||
pub mod init;
|
||||
pub mod run;
|
||||
pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| {
|
||||
raw_validator
|
||||
.trim()
|
||||
.parse()
|
||||
.expect("one of the provided validator api urls is invalid")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
if let Some(directory) = matches.value_of("directory") {
|
||||
config.get_base_mut().with_custom_directory(directory);
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||
}
|
||||
|
||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
use version_checker::is_minor_version_compatible;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("run")
|
||||
@@ -38,10 +29,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Address of the socks5 provider to send messages to.")
|
||||
.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("validators")
|
||||
.long("validators")
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
@@ -56,14 +47,42 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
}
|
||||
|
||||
// this only checks compatibility between config the binary. It does not take into consideration
|
||||
// network version. It might do so in the future.
|
||||
fn version_check(cfg: &Config) -> bool {
|
||||
let binary_version = env!("CARGO_PKG_VERSION");
|
||||
let config_version = cfg.get_base().get_version();
|
||||
if binary_version != config_version {
|
||||
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||
if is_minor_version_compatible(binary_version, config_version) {
|
||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||
true
|
||||
} else {
|
||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
let mut config =
|
||||
Config::load_from_file(matches.value_of("config").map(|path| path.into()), Some(id))
|
||||
.expect("Failed to load config file");
|
||||
let mut config = match Config::load_from_file(Some(id)) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
config = override_config(config, matches);
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return;
|
||||
}
|
||||
|
||||
NymClient::new(config).run_forever();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, MISSING_VALUE};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::defaults::default_api_endpoints;
|
||||
use config::NymConfig;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
use version_checker::Version;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"\n==================\nTrying to upgrade client from {} to {} ...",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!(
|
||||
"Upgrade from {} to {} failed!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"Upgrade from {} to {} was successful!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!(
|
||||
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||
config_version, package_version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
.help("Id of the nym-client we want to upgrade")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {:?}", err);
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_matches: &ArgMatches,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||
package_version.clone()
|
||||
} else {
|
||||
Version::new(0, 12, 0)
|
||||
};
|
||||
|
||||
print_start_upgrade(&config_version, &to_version);
|
||||
|
||||
println!(
|
||||
"Setting validator API endpoints to {:?}",
|
||||
default_api_endpoints()
|
||||
);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(default_api_endpoints());
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_version(to_version.to_string().as_ref());
|
||||
|
||||
config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
if config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {:?}", err);
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.get_base().get_version() == MISSING_VALUE {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||
do_upgrade(existing_config, matches, package_version)
|
||||
}
|
||||
@@ -1,16 +1,5 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
pub mod built_info;
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod client;
|
||||
pub mod socks;
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, ArgMatches};
|
||||
|
||||
pub mod built_info;
|
||||
pub mod client;
|
||||
mod commands;
|
||||
pub mod socks;
|
||||
@@ -23,14 +11,14 @@ fn main() {
|
||||
dotenv::dotenv().ok();
|
||||
setup_logging();
|
||||
println!("{}", banner());
|
||||
println!("\n\nIf unsure which gateway to choose - 'D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr' is a safe choice for the testnet\n\n");
|
||||
|
||||
let arg_matches = App::new("Nym Socks5 Proxy")
|
||||
.version(built_info::PKG_VERSION)
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author("Nymtech")
|
||||
.about("A Socks5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address")
|
||||
.subcommand(commands::init::command_args())
|
||||
.subcommand(commands::run::command_args())
|
||||
.subcommand(commands::upgrade::command_args())
|
||||
.get_matches();
|
||||
|
||||
execute(arg_matches);
|
||||
@@ -40,6 +28,7 @@ fn execute(matches: ArgMatches) {
|
||||
match matches.subcommand() {
|
||||
("init", Some(m)) => commands::init::execute(m),
|
||||
("run", Some(m)) => commands::run::execute(m),
|
||||
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
||||
_ => println!("{}", usage()),
|
||||
}
|
||||
}
|
||||
@@ -61,7 +50,7 @@ fn banner() -> String {
|
||||
(socks5 proxy - version {:})
|
||||
|
||||
"#,
|
||||
built_info::PKG_VERSION
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn constructor_works() {
|
||||
let mut auth_methods: Vec<u8> = Vec::new();
|
||||
auth_methods.push(AuthenticationMethods::NoAuth as u8);
|
||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
||||
let auth_methods = vec![
|
||||
AuthenticationMethods::NoAuth as u8,
|
||||
AuthenticationMethods::UserPass as u8,
|
||||
];
|
||||
|
||||
let admin = User {
|
||||
username: "foo".to_string(),
|
||||
@@ -98,8 +99,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn allowed_user_passes_authentication_check() {
|
||||
let mut auth_methods: Vec<u8> = Vec::new();
|
||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
||||
let auth_methods = vec![AuthenticationMethods::UserPass as u8];
|
||||
|
||||
let admin = User {
|
||||
username: "foo".to_string(),
|
||||
@@ -115,8 +115,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn disallowed_user_fails_authentication_check() {
|
||||
let mut auth_methods: Vec<u8> = Vec::new();
|
||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
||||
let auth_methods = vec![AuthenticationMethods::UserPass as u8];
|
||||
|
||||
let bad_user = User {
|
||||
username: "ashy".to_string(),
|
||||
|
||||
@@ -7,21 +7,20 @@ use super::{RESERVED, SOCKS_VERSION};
|
||||
use client_core::client::inbound_messages::InputMessage;
|
||||
use client_core::client::inbound_messages::InputMessageSender;
|
||||
use futures::channel::mpsc;
|
||||
use futures::core_reexport::pin::Pin;
|
||||
use futures::task::{Context, Poll};
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use ordered_buffer::{OrderedMessageBuffer, OrderedMessageSender};
|
||||
use pin_project::pin_project;
|
||||
use proxy_helpers::available_reader::AvailableReader;
|
||||
use proxy_helpers::connection_controller::{
|
||||
ConnectionReceiver, ControllerCommand, ControllerSender,
|
||||
};
|
||||
use proxy_helpers::proxy_runner::ProxyRunner;
|
||||
use rand::RngCore;
|
||||
use socks5_requests::{ConnectionId, Request};
|
||||
use std::net::{Shutdown, SocketAddr};
|
||||
use tokio::prelude::*;
|
||||
use socks5_requests::{ConnectionId, RemoteAddress, Request};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||
use tokio::{self, net::TcpStream};
|
||||
|
||||
#[pin_project(project = StateProject)]
|
||||
@@ -63,12 +62,12 @@ impl StreamState {
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
||||
async fn shutdown(&mut self) -> io::Result<()> {
|
||||
// shutdown should only be called if proxy is not being run. If it is, there's some bug
|
||||
// somewhere
|
||||
match self {
|
||||
StreamState::RunningProxy => panic!("Tried to shutdown stream while proxy is running"),
|
||||
StreamState::Available(ref stream) => TcpStream::shutdown(stream, how),
|
||||
StreamState::Available(ref mut stream) => TcpStream::shutdown(stream).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,8 +77,8 @@ impl AsyncRead for StreamState {
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
match self.project() {
|
||||
StateProject::RunningProxy => Poll::Ready(Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
@@ -140,16 +139,18 @@ pub(crate) struct SocksClient {
|
||||
connection_id: ConnectionId,
|
||||
service_provider: Recipient,
|
||||
self_address: Recipient,
|
||||
started_proxy: bool,
|
||||
}
|
||||
|
||||
impl Drop for SocksClient {
|
||||
fn drop(&mut self) {
|
||||
// TODO: decrease to debug/trace
|
||||
info!("socksclient is going out of scope - the stream is getting dropped!");
|
||||
info!("Connection {} is getting closed", self.connection_id);
|
||||
self.controller_sender
|
||||
.unbounded_send(ControllerCommand::Remove(self.connection_id))
|
||||
.unwrap();
|
||||
debug!("Connection {} is getting closed", self.connection_id);
|
||||
// if we never managed to start a proxy, the entry will not exist in the controller
|
||||
if self.started_proxy {
|
||||
self.controller_sender
|
||||
.unbounded_send(ControllerCommand::Remove(self.connection_id))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +175,7 @@ impl SocksClient {
|
||||
input_sender,
|
||||
service_provider,
|
||||
self_address,
|
||||
started_proxy: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +191,9 @@ impl SocksClient {
|
||||
}
|
||||
|
||||
/// Shutdown the TcpStream to the client and end the session
|
||||
pub fn shutdown(&mut self) -> Result<(), SocksProxyError> {
|
||||
pub async fn shutdown(&mut self) -> Result<(), SocksProxyError> {
|
||||
info!("client is shutting down its TCP stream");
|
||||
self.stream.shutdown(Shutdown::Both)?;
|
||||
self.stream.shutdown().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -209,39 +211,44 @@ impl SocksClient {
|
||||
// Handle SOCKS4 requests
|
||||
if header[0] != SOCKS_VERSION {
|
||||
warn!("Init: Unsupported version: SOCKS{}", self.socks_version);
|
||||
self.shutdown()?;
|
||||
self.shutdown().await
|
||||
}
|
||||
// Valid SOCKS5
|
||||
else {
|
||||
// Authenticate w/ client
|
||||
self.authenticate().await?;
|
||||
// Handle requests
|
||||
self.handle_request().await?;
|
||||
self.handle_request().await
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_request_to_mixnet(&mut self, request: Request) {
|
||||
self.send_to_mixnet(request.into_bytes()).await;
|
||||
async fn send_connect_to_mixnet(&mut self, remote_address: RemoteAddress) {
|
||||
let req = Request::new_connect(self.connection_id, remote_address, self.self_address);
|
||||
|
||||
let input_message = InputMessage::new_fresh(self.service_provider, req.into_bytes(), false);
|
||||
self.input_sender.unbounded_send(input_message).unwrap();
|
||||
}
|
||||
|
||||
async fn run_proxy(
|
||||
&mut self,
|
||||
conn_receiver: ConnectionReceiver,
|
||||
message_sender: OrderedMessageSender,
|
||||
) {
|
||||
async fn run_proxy(&mut self, conn_receiver: ConnectionReceiver, remote_proxy_target: String) {
|
||||
self.send_connect_to_mixnet(remote_proxy_target.clone())
|
||||
.await;
|
||||
|
||||
let stream = self.stream.run_proxy();
|
||||
let local_stream_remote = stream
|
||||
.peer_addr()
|
||||
.expect("failed to extract peer address")
|
||||
.to_string();
|
||||
let connection_id = self.connection_id;
|
||||
let input_sender = self.input_sender.clone();
|
||||
|
||||
let recipient = self.service_provider.clone();
|
||||
let recipient = self.service_provider;
|
||||
let (stream, _) = ProxyRunner::new(
|
||||
stream,
|
||||
local_stream_remote,
|
||||
remote_proxy_target,
|
||||
conn_receiver,
|
||||
input_sender,
|
||||
connection_id,
|
||||
message_sender,
|
||||
)
|
||||
.run(move |conn_id, read_data, socket_closed| {
|
||||
let provider_request = Request::new_send(conn_id, read_data, socket_closed);
|
||||
@@ -262,15 +269,6 @@ impl SocksClient {
|
||||
|
||||
// setup for receiving from the mixnet
|
||||
let (mix_sender, mix_receiver) = mpsc::unbounded();
|
||||
let ordered_buffer = OrderedMessageBuffer::new();
|
||||
|
||||
self.controller_sender
|
||||
.unbounded_send(ControllerCommand::Insert(
|
||||
self.connection_id,
|
||||
mix_sender,
|
||||
ordered_buffer,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
match request.command {
|
||||
// Use the Proxy to connect to the specified addr/port
|
||||
@@ -278,26 +276,21 @@ impl SocksClient {
|
||||
trace!("Connecting to: {:?}", remote_address.clone());
|
||||
self.acknowledge_socks5().await;
|
||||
|
||||
let mut message_sender = OrderedMessageSender::new();
|
||||
// 'connect' needs to be handled manually due to different structure,
|
||||
// but still needs to have correct sequence number on it!
|
||||
self.started_proxy = true;
|
||||
self.controller_sender
|
||||
.unbounded_send(ControllerCommand::Insert(self.connection_id, mix_sender))
|
||||
.unwrap();
|
||||
|
||||
// read whatever we can
|
||||
let available_reader = AvailableReader::new(&mut self.stream);
|
||||
let (request_data_bytes, _) = available_reader.await?;
|
||||
let ordered_message = message_sender.wrap_message(request_data_bytes.to_vec());
|
||||
|
||||
let socks_provider_request = Request::new_connect(
|
||||
self.connection_id,
|
||||
info!(
|
||||
"Starting proxy for {} (id: {})",
|
||||
remote_address.clone(),
|
||||
ordered_message,
|
||||
self.self_address.clone(),
|
||||
self.connection_id
|
||||
);
|
||||
self.run_proxy(mix_receiver, remote_address.clone()).await;
|
||||
info!(
|
||||
"Proxy for {} is finished (id: {})",
|
||||
remote_address, self.connection_id
|
||||
);
|
||||
|
||||
self.send_request_to_mixnet(socks_provider_request).await;
|
||||
info!("Starting proxy for {}", remote_address.clone());
|
||||
self.run_proxy(mix_receiver, message_sender).await;
|
||||
info!("Proxy for {} is finished", remote_address);
|
||||
}
|
||||
|
||||
SocksCommand::Bind => unimplemented!(), // not handled
|
||||
@@ -307,16 +300,6 @@ impl SocksClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send serialized Socks5 request bytes to the mixnet. The request stream
|
||||
/// will be chunked up into a series of one or more Sphinx packets and
|
||||
/// reassembled at the destination service provider at the other end, then
|
||||
/// sent onwards anonymously.
|
||||
async fn send_to_mixnet(&self, request_bytes: Vec<u8>) {
|
||||
let input_message =
|
||||
InputMessage::new_fresh(self.service_provider.clone(), request_bytes, false);
|
||||
self.input_sender.unbounded_send(input_message).unwrap();
|
||||
}
|
||||
|
||||
/// Writes a Socks5 header back to the requesting client's TCP stream,
|
||||
/// basically saying "I acknowledge your request and am dealing with it".
|
||||
async fn acknowledge_socks5(&mut self) {
|
||||
@@ -342,7 +325,7 @@ impl SocksClient {
|
||||
/// username and password from the stream, then check with the Authenticator
|
||||
/// to see if the resulting user is allowed.
|
||||
///
|
||||
/// A lot of this could probably be put into the the `SocksRequest::from_stream()`
|
||||
/// A lot of this could probably be put into the `SocksRequest::from_stream()`
|
||||
/// constructor, and/or cleaned up with tokio::codec. It's mostly just
|
||||
/// read-a-byte-or-two. The bytes being extracted look like this:
|
||||
///
|
||||
@@ -381,27 +364,12 @@ impl SocksClient {
|
||||
|
||||
// Username parsing
|
||||
let ulen = header[1];
|
||||
|
||||
let mut username = Vec::with_capacity(ulen as usize);
|
||||
|
||||
// For some reason the vector needs to actually be full
|
||||
for _ in 0..ulen {
|
||||
username.push(0);
|
||||
}
|
||||
|
||||
let mut username = vec![0; ulen as usize];
|
||||
self.stream.read_exact(&mut username).await?;
|
||||
|
||||
// Password Parsing
|
||||
let mut plen = [0u8; 1];
|
||||
self.stream.read_exact(&mut plen).await?;
|
||||
|
||||
let mut password = Vec::with_capacity(plen[0] as usize);
|
||||
|
||||
// For some reason the vector needs to actually be full
|
||||
for _ in 0..plen[0] {
|
||||
password.push(0);
|
||||
}
|
||||
|
||||
let plen = self.stream.read_u8().await?;
|
||||
let mut password = vec![0; plen as usize];
|
||||
self.stream.read_exact(&mut password).await?;
|
||||
|
||||
let username_str = String::from_utf8(username)?;
|
||||
@@ -423,7 +391,7 @@ impl SocksClient {
|
||||
self.stream.write_all(&response).await?;
|
||||
|
||||
// Shutdown
|
||||
self.shutdown()?;
|
||||
self.shutdown().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -437,7 +405,7 @@ impl SocksClient {
|
||||
warn!("Client has no suitable authentication methods!");
|
||||
response[1] = AuthenticationMethods::NoMethods as u8;
|
||||
self.stream.write_all(&response).await?;
|
||||
self.shutdown()?;
|
||||
self.shutdown().await?;
|
||||
Err(ResponseCode::Failure.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ impl MixnetResponseListener {
|
||||
.unwrap();
|
||||
|
||||
MixnetResponseListener {
|
||||
controller_sender,
|
||||
buffer_requester,
|
||||
mix_response_receiver,
|
||||
controller_sender,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use super::types::{AddrType, ResponseCode, SocksProxyError};
|
||||
use super::{utils as socks_utils, SOCKS_VERSION};
|
||||
use log::*;
|
||||
use tokio::prelude::*;
|
||||
use std::fmt::{self, Display};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||
|
||||
/// A Socks5 request hitting the proxy.
|
||||
pub(crate) struct SocksRequest {
|
||||
#[allow(dead_code)]
|
||||
pub version: u8,
|
||||
pub command: SocksCommand,
|
||||
pub addr_type: AddrType,
|
||||
@@ -95,12 +97,14 @@ impl SocksRequest {
|
||||
port,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SocksRequest {
|
||||
/// Print out the address and port to a String.
|
||||
/// This might return domain:port, ipv6:port, or ipv4:port.
|
||||
pub(crate) fn to_string(&self) -> String {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let address = socks_utils::pretty_print_addr(&self.addr_type, &self.addr);
|
||||
format!("{}:{}", address, self.port)
|
||||
write!(f, "{}:{}", address, self.port)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ impl SphinxSocksServer {
|
||||
input_sender: InputMessageSender,
|
||||
buffer_requester: ReceivedBufferRequestSender,
|
||||
) -> Result<(), SocksProxyError> {
|
||||
let mut listener = TcpListener::bind(self.listening_address).await.unwrap();
|
||||
let listener = TcpListener::bind(self.listening_address).await.unwrap();
|
||||
info!("Serving Connections...");
|
||||
|
||||
// controller for managing all active connections
|
||||
@@ -72,9 +72,9 @@ impl SphinxSocksServer {
|
||||
stream,
|
||||
self.authenticator.clone(),
|
||||
input_sender.clone(),
|
||||
self.service_provider.clone(),
|
||||
self.service_provider,
|
||||
controller_sender.clone(),
|
||||
self.self_address.clone(),
|
||||
self.self_address,
|
||||
);
|
||||
|
||||
tokio::spawn(async move {
|
||||
@@ -100,7 +100,7 @@ impl SphinxSocksServer {
|
||||
if client.error(response).await.is_err() {
|
||||
warn!("Failed to send error code");
|
||||
};
|
||||
if client.shutdown().is_err() {
|
||||
if client.shutdown().await.is_err() {
|
||||
warn!("Failed to shutdown TcpStream");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.DS_Store
|
||||
/node_modules/
|
||||
/src/node_modules/@sapper/
|
||||
yarn-error.log
|
||||
/__sapper__/
|
||||
@@ -0,0 +1,33 @@
|
||||
## Prerequisites
|
||||
|
||||
On Ubuntu-ish systems (not tested on Debian but may work):
|
||||
|
||||
```
|
||||
sudo apt update && sudo apt install libwebkit2gtk-4.0-dev \
|
||||
build-essential \
|
||||
curl \
|
||||
wget \
|
||||
libssl-dev \
|
||||
libgtk-3-dev \
|
||||
libappindicator3-dev \
|
||||
patchelf \
|
||||
librsvg2-dev```
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Start Sapper([docs](https://sapper.svelte.dev/docs/)) -> `yarn run dev`
|
||||
2. Start Tauri([docs](https://tauri.studio/en/)) in another terminal -> `yarn tauri dev`
|
||||
3. Start validator-api locally, or override `validator-urls` in `index.svelte`
|
||||
|
||||
## Getting around
|
||||
|
||||
+ Frontend -> `tauri-client/`
|
||||
+ logic -> `tauri-client/src/routes/index.svelte`
|
||||
+ assets -> `tauri-client/static`
|
||||
+ Backend -> `tauri-client/src/src-tauri`
|
||||
|
||||
## Build standalone app
|
||||
|
||||
+ yarn tauri build [--debug]
|
||||
Generated
+14875
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "TODO",
|
||||
"description": "TODO",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "sapper dev",
|
||||
"build": "sapper build --legacy",
|
||||
"export": "sapper export --legacy",
|
||||
"start": "node __sapper__/build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.0.0-beta.4",
|
||||
"compression": "^1.7.1",
|
||||
"polka": "next",
|
||||
"qrious": "^4.0.2",
|
||||
"sirv": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@rollup/plugin-babel": "^5.0.0",
|
||||
"@rollup/plugin-commonjs": "^14.0.0",
|
||||
"@rollup/plugin-node-resolve": "^8.0.0",
|
||||
"@rollup/plugin-replace": "^2.4.0",
|
||||
"@rollup/plugin-url": "^5.0.0",
|
||||
"@tauri-apps/cli": "^1.0.0-beta.5",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"sapper": "^0.28.0",
|
||||
"sass": "^1.35.2",
|
||||
"svelte": "^3.17.3",
|
||||
"svelte-preprocess": "^4.7.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import path from "path";
|
||||
import resolve from "@rollup/plugin-node-resolve";
|
||||
import replace from "@rollup/plugin-replace";
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import url from "@rollup/plugin-url";
|
||||
import svelte from "rollup-plugin-svelte";
|
||||
import babel from "@rollup/plugin-babel";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
import config from "sapper/config/rollup.js";
|
||||
import pkg from "./package.json";
|
||||
import sveltePreprocess from "svelte-preprocess";
|
||||
|
||||
const mode = process.env.NODE_ENV;
|
||||
const dev = mode === "development";
|
||||
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
|
||||
|
||||
const onwarn = (warning, onwarn) =>
|
||||
(warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) ||
|
||||
(warning.code === "CIRCULAR_DEPENDENCY" &&
|
||||
/[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||
onwarn(warning);
|
||||
|
||||
export default {
|
||||
client: {
|
||||
input: config.client.input(),
|
||||
output: config.client.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
values: {
|
||||
"process.browser": true,
|
||||
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||
},
|
||||
}),
|
||||
svelte({
|
||||
compilerOptions: {
|
||||
dev,
|
||||
hydratable: true,
|
||||
},
|
||||
preprocess: sveltePreprocess(),
|
||||
}),
|
||||
url({
|
||||
sourceDir: path.resolve(__dirname, "src/node_modules/images"),
|
||||
publicPath: "/client/",
|
||||
}),
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: ["svelte"],
|
||||
}),
|
||||
commonjs(),
|
||||
|
||||
legacy &&
|
||||
babel({
|
||||
extensions: [".js", ".mjs", ".html", ".svelte"],
|
||||
babelHelpers: "runtime",
|
||||
exclude: ["node_modules/@babel/**"],
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
targets: "> 0.25%, not dead",
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
useESModules: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
}),
|
||||
|
||||
!dev &&
|
||||
terser({
|
||||
module: true,
|
||||
}),
|
||||
],
|
||||
|
||||
preserveEntrySignatures: false,
|
||||
onwarn,
|
||||
},
|
||||
|
||||
server: {
|
||||
input: config.server.input(),
|
||||
output: config.server.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
values: {
|
||||
"process.browser": false,
|
||||
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||
},
|
||||
}),
|
||||
svelte({
|
||||
compilerOptions: {
|
||||
dev,
|
||||
generate: "ssr",
|
||||
hydratable: true,
|
||||
},
|
||||
emitCss: false,
|
||||
}),
|
||||
url({
|
||||
sourceDir: path.resolve(__dirname, "src/node_modules/images"),
|
||||
publicPath: "/client/",
|
||||
emitFiles: false, // already emitted by client build
|
||||
}),
|
||||
resolve({
|
||||
dedupe: ["svelte"],
|
||||
}),
|
||||
commonjs(),
|
||||
],
|
||||
external: Object.keys(pkg.dependencies).concat(
|
||||
require("module").builtinModules
|
||||
),
|
||||
preserveEntrySignatures: "strict",
|
||||
onwarn,
|
||||
},
|
||||
|
||||
serviceworker: {
|
||||
input: config.serviceworker.input(),
|
||||
output: config.serviceworker.output(),
|
||||
plugins: [
|
||||
resolve(),
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
values: {
|
||||
"process.browser": true,
|
||||
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||
},
|
||||
}),
|
||||
commonjs(),
|
||||
!dev && terser(),
|
||||
],
|
||||
preserveEntrySignatures: false,
|
||||
onwarn,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* Run this script to convert the project to TypeScript. This is only guaranteed to work
|
||||
* on the unmodified default template; if you have done code changes you are likely need
|
||||
* to touch up the generated project manually.
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { argv } = require('process');
|
||||
|
||||
const projectRoot = argv[2] || path.join(__dirname, '..');
|
||||
|
||||
const isRollup = fs.existsSync(path.join(projectRoot, "rollup.config.js"));
|
||||
|
||||
function warn(message) {
|
||||
console.warn('Warning: ' + message);
|
||||
}
|
||||
|
||||
function replaceInFile(fileName, replacements) {
|
||||
if (fs.existsSync(fileName)) {
|
||||
let contents = fs.readFileSync(fileName, 'utf8');
|
||||
let hadUpdates = false;
|
||||
|
||||
replacements.forEach(([from, to]) => {
|
||||
const newContents = contents.replace(from, to);
|
||||
|
||||
const isAlreadyApplied = typeof to !== 'string' || contents.includes(to);
|
||||
|
||||
if (newContents !== contents) {
|
||||
contents = newContents;
|
||||
hadUpdates = true;
|
||||
} else if (!isAlreadyApplied) {
|
||||
warn(`Wanted to update "${from}" in ${fileName}, but did not find it.`);
|
||||
}
|
||||
});
|
||||
|
||||
if (hadUpdates) {
|
||||
fs.writeFileSync(fileName, contents);
|
||||
} else {
|
||||
console.log(`${fileName} had already been updated.`);
|
||||
}
|
||||
} else {
|
||||
warn(`Wanted to update ${fileName} but the file did not exist.`);
|
||||
}
|
||||
}
|
||||
|
||||
function createFile(fileName, contents) {
|
||||
if (fs.existsSync(fileName)) {
|
||||
warn(`Wanted to create ${fileName}, but it already existed. Leaving existing file.`);
|
||||
} else {
|
||||
fs.writeFileSync(fileName, contents);
|
||||
}
|
||||
}
|
||||
|
||||
function addDepsToPackageJson() {
|
||||
const pkgJSONPath = path.join(projectRoot, 'package.json');
|
||||
const packageJSON = JSON.parse(fs.readFileSync(pkgJSONPath, 'utf8'));
|
||||
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
|
||||
...(isRollup ? { '@rollup/plugin-typescript': '^6.0.0' } : { 'ts-loader': '^8.0.4' }),
|
||||
'@tsconfig/svelte': '^1.0.10',
|
||||
'@types/compression': '^1.7.0',
|
||||
'@types/node': '^14.11.1',
|
||||
'@types/polka': '^0.5.1',
|
||||
'svelte-check': '^1.0.46',
|
||||
'svelte-preprocess': '^4.3.0',
|
||||
tslib: '^2.0.1',
|
||||
typescript: '^4.0.3'
|
||||
});
|
||||
|
||||
// Add script for checking
|
||||
packageJSON.scripts = Object.assign(packageJSON.scripts, {
|
||||
validate: 'svelte-check --ignore src/node_modules/@sapper'
|
||||
});
|
||||
|
||||
// Write the package JSON
|
||||
fs.writeFileSync(pkgJSONPath, JSON.stringify(packageJSON, null, ' '));
|
||||
}
|
||||
|
||||
function changeJsExtensionToTs(dir) {
|
||||
const elements = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
if (elements[i].isDirectory()) {
|
||||
changeJsExtensionToTs(path.join(dir, elements[i].name));
|
||||
} else if (elements[i].name.match(/^[^_]((?!json).)*js$/)) {
|
||||
fs.renameSync(path.join(dir, elements[i].name), path.join(dir, elements[i].name).replace('.js', '.ts'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateSingleSvelteFile({ view, vars, contextModule }) {
|
||||
replaceInFile(path.join(projectRoot, 'src', `${view}.svelte`), [
|
||||
[/(?:<script)(( .*?)*?)>/gm, (m, attrs) => `<script${attrs}${!attrs.includes('lang="ts"') ? ' lang="ts"' : ''}>`],
|
||||
...(vars ? vars.map(({ name, type }) => [`export let ${name};`, `export let ${name}: ${type};`]) : []),
|
||||
...(contextModule ? contextModule.map(({ js, ts }) => [js, ts]) : [])
|
||||
]);
|
||||
}
|
||||
|
||||
// Switch the *.svelte file to use TS
|
||||
function updateSvelteFiles() {
|
||||
[
|
||||
{
|
||||
view: 'components/Nav',
|
||||
vars: [{ name: 'segment', type: 'string' }]
|
||||
},
|
||||
{
|
||||
view: 'routes/_layout',
|
||||
vars: [{ name: 'segment', type: 'string' }]
|
||||
},
|
||||
{
|
||||
view: 'routes/_error',
|
||||
vars: [
|
||||
{ name: 'status', type: 'number' },
|
||||
{ name: 'error', type: 'Error' }
|
||||
]
|
||||
},
|
||||
{
|
||||
view: 'routes/blog/index',
|
||||
vars: [{ name: 'posts', type: '{ slug: string; title: string, html: any }[]' }],
|
||||
contextModule: [
|
||||
{
|
||||
js: '.then(r => r.json())',
|
||||
ts: '.then((r: { json: () => any; }) => r.json())'
|
||||
},
|
||||
{
|
||||
js: '.then(posts => {',
|
||||
ts: '.then((posts: { slug: string; title: string, html: any }[]) => {'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
view: 'routes/blog/[slug]',
|
||||
vars: [{ name: 'post', type: '{ slug: string; title: string, html: any }' }]
|
||||
}
|
||||
].forEach(updateSingleSvelteFile);
|
||||
}
|
||||
|
||||
function updateRollupConfig() {
|
||||
// Edit rollup config
|
||||
replaceInFile(path.join(projectRoot, 'rollup.config.js'), [
|
||||
// Edit imports
|
||||
[
|
||||
/'rollup-plugin-terser';\n(?!import sveltePreprocess)/,
|
||||
`'rollup-plugin-terser';
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
`
|
||||
],
|
||||
// Edit inputs
|
||||
[
|
||||
/(?<!THIS_IS_UNDEFINED[^\n]*\n\s*)onwarn\(warning\);/,
|
||||
`(warning.code === 'THIS_IS_UNDEFINED') ||\n\tonwarn(warning);`
|
||||
],
|
||||
[/input: config.client.input\(\)(?!\.replace)/, `input: config.client.input().replace(/\\.js$/, '.ts')`],
|
||||
[
|
||||
/input: config.server.input\(\)(?!\.replace)/,
|
||||
`input: { server: config.server.input().server.replace(/\\.js$/, ".ts") }`
|
||||
],
|
||||
[
|
||||
/input: config.serviceworker.input\(\)(?!\.replace)/,
|
||||
`input: config.serviceworker.input().replace(/\\.js$/, '.ts')`
|
||||
],
|
||||
// Add preprocess
|
||||
[/compilerOptions/g, 'preprocess: sveltePreprocess({ sourceMap: dev }),\n\t\t\t\tcompilerOptions'],
|
||||
// Add TypeScript
|
||||
[/commonjs\(\)(?!,\n\s*typescript)/g, 'commonjs(),\n\t\t\ttypescript({ sourceMap: dev })']
|
||||
]);
|
||||
}
|
||||
|
||||
function updateWebpackConfig() {
|
||||
// Edit webpack config
|
||||
replaceInFile(path.join(projectRoot, 'webpack.config.js'), [
|
||||
// Edit imports
|
||||
[
|
||||
/require\('webpack-modules'\);\n(?!const sveltePreprocess)/,
|
||||
`require('webpack-modules');\nconst sveltePreprocess = require('svelte-preprocess');\n`
|
||||
],
|
||||
// Edit extensions
|
||||
[
|
||||
/\['\.mjs', '\.js', '\.json', '\.svelte', '\.html'\]/,
|
||||
`['.mjs', '.js', '.ts', '.json', '.svelte', '.html']`
|
||||
],
|
||||
// Edit entries
|
||||
[
|
||||
/entry: config\.client\.entry\(\)/,
|
||||
`entry: { main: config.client.entry().main.replace(/\\.js$/, '.ts') }`
|
||||
],
|
||||
[
|
||||
/entry: config\.server\.entry\(\)/,
|
||||
`entry: { server: config.server.entry().server.replace(/\\.js$/, '.ts') }`
|
||||
],
|
||||
[
|
||||
/entry: config\.serviceworker\.entry\(\)/,
|
||||
`entry: { 'service-worker': config.serviceworker.entry()['service-worker'].replace(/\\.js$/, '.ts') }`
|
||||
],
|
||||
[
|
||||
/loader: 'svelte-loader',\n\t\t\t\t\t\toptions: {/g,
|
||||
'loader: \'svelte-loader\',\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tpreprocess: sveltePreprocess({ sourceMap: dev }),'
|
||||
],
|
||||
// Add TypeScript rules for client and server
|
||||
[
|
||||
/module: {\n\s*rules: \[\n\s*(?!{\n\s*test: \/\\\.ts\$\/)/g,
|
||||
`module: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t},\n\t\t\t\t`
|
||||
],
|
||||
// Add TypeScript rules for serviceworker
|
||||
[
|
||||
/output: config\.serviceworker\.output\(\),\n\s*(?!module)/,
|
||||
`output: config.serviceworker.output(),\n\t\tmodule: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t`
|
||||
],
|
||||
// Edit outputs
|
||||
[
|
||||
/output: config\.serviceworker\.output\(\),\n\s*(?!resolve)/,
|
||||
`output: config.serviceworker.output(),\n\t\tresolve: { extensions: ['.mjs', '.js', '.ts', '.json'] },\n\t\t`
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
function updateServiceWorker() {
|
||||
replaceInFile(path.join(projectRoot, 'src', 'service-worker.ts'), [
|
||||
[`shell.concat(files);`, `(shell as string[]).concat(files as string[]);`],
|
||||
[`self.skipWaiting();`, `((self as any) as ServiceWorkerGlobalScope).skipWaiting();`],
|
||||
[`self.clients.claim();`, `((self as any) as ServiceWorkerGlobalScope).clients.claim();`],
|
||||
[`fetchAndCache(request)`, `fetchAndCache(request: Request)`],
|
||||
[`self.addEventListener('activate', event =>`, `self.addEventListener('activate', (event: ExtendableEvent) =>`],
|
||||
[`self.addEventListener('install', event =>`, `self.addEventListener('install', (event: ExtendableEvent) =>`],
|
||||
[`addEventListener('fetch', event =>`, `addEventListener('fetch', (event: FetchEvent) =>`],
|
||||
]);
|
||||
}
|
||||
|
||||
function createTsConfig() {
|
||||
const tsconfig = `{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "ES2017", "WebWorker"]
|
||||
},
|
||||
"include": ["src/**/*", "src/node_modules/**/*"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "static/*"]
|
||||
}`;
|
||||
|
||||
createFile(path.join(projectRoot, 'tsconfig.json'), tsconfig);
|
||||
}
|
||||
|
||||
// Adds the extension recommendation
|
||||
function configureVsCode() {
|
||||
const dir = path.join(projectRoot, '.vscode');
|
||||
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
|
||||
createFile(path.join(projectRoot, '.vscode', 'extensions.json'), `{"recommendations": ["svelte.svelte-vscode"]}`);
|
||||
}
|
||||
|
||||
function deleteThisScript() {
|
||||
fs.unlinkSync(path.join(__filename));
|
||||
|
||||
// Check for Mac's DS_store file, and if it's the only one left remove it
|
||||
const remainingFiles = fs.readdirSync(path.join(__dirname));
|
||||
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
|
||||
fs.unlinkSync(path.join(__dirname, '.DS_store'));
|
||||
}
|
||||
|
||||
// Check if the scripts folder is empty
|
||||
if (fs.readdirSync(path.join(__dirname)).length === 0) {
|
||||
// Remove the scripts folder
|
||||
fs.rmdirSync(path.join(__dirname));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Adding TypeScript with ${isRollup ? "Rollup" : "webpack" }...`);
|
||||
|
||||
addDepsToPackageJson();
|
||||
|
||||
changeJsExtensionToTs(path.join(projectRoot, 'src'));
|
||||
|
||||
updateSvelteFiles();
|
||||
|
||||
if (isRollup) {
|
||||
updateRollupConfig();
|
||||
} else {
|
||||
updateWebpackConfig();
|
||||
}
|
||||
|
||||
updateServiceWorker();
|
||||
|
||||
createTsConfig();
|
||||
|
||||
configureVsCode();
|
||||
|
||||
// Delete this script, but not during testing
|
||||
if (!argv[2]) {
|
||||
deleteThisScript();
|
||||
}
|
||||
|
||||
console.log('Converted to TypeScript.');
|
||||
|
||||
if (fs.existsSync(path.join(projectRoot, 'node_modules'))) {
|
||||
console.log(`
|
||||
Next:
|
||||
1. run 'npm install' again to install TypeScript dependencies
|
||||
2. run 'npm run build' for the @sapper imports in your project to work
|
||||
`);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
WixTools
|
||||
+3203
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.0.0-beta.2" }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.0.0-beta.4", features = [] }
|
||||
tokio = "1.4"
|
||||
url = "2.2"
|
||||
|
||||
coconut-interface = { path = "../../../common/coconut-interface" }
|
||||
credentials = { path = "../../../common/credentials" }
|
||||
validator-client = {path = "../../../common/client-libs/validator-client"}
|
||||
|
||||
[features]
|
||||
default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user