Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bc7448b08 |
@@ -49,7 +49,7 @@ jobs:
|
||||
"build-tools;$SDK_BUILDTOOLS_VERSION"
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@1.70.0
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install rust android targets
|
||||
run: |
|
||||
@@ -60,7 +60,6 @@ jobs:
|
||||
working-directory: sdk/lib/socks5-listener/
|
||||
env:
|
||||
RELEASE: true
|
||||
RUSTFLAGS: "-C link-args=-Wl,--hash-style=gnu"
|
||||
# build for arm64 and x86_64
|
||||
run: ./build-android.sh aarch64 x86_64
|
||||
|
||||
@@ -69,24 +68,19 @@ jobs:
|
||||
env:
|
||||
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
|
||||
# build for arm64 and x86_64
|
||||
run: |
|
||||
./gradlew :app:assembleArch64Debug
|
||||
./gradlew :app:assembleArch64Release
|
||||
run: ./gradlew :app:assembleArch64Release
|
||||
|
||||
- name: Prepare APKs
|
||||
run: |
|
||||
mkdir apk
|
||||
mv nym-connect/native/android/app/build/outputs/apk/arch64/debug/app-arch64-debug.apk \
|
||||
apk/nyms5-arch64-debug.apk
|
||||
mv nym-connect/native/android/app/build/outputs/apk/arch64/release/app-arch64-release-unsigned.apk \
|
||||
apk/nyms5-arch64-release.apk
|
||||
|
||||
- name: Upload APKs
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nyms5-apk-arch64
|
||||
name: nyms5-apk-arch64-release
|
||||
path: |
|
||||
apk/nyms5-arch64-debug.apk
|
||||
apk/nyms5-arch64-release.apk
|
||||
|
||||
gh-release:
|
||||
@@ -99,12 +93,10 @@ jobs:
|
||||
- name: Download binary artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: nyms5-apk-arch64
|
||||
name: nyms5-apk-arch64-release
|
||||
path: apk
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
apk/nyms5-arch64-debug.apk
|
||||
apk/nyms5-arch64-release.apk
|
||||
files: apk/nyms5-arch64-release.apk
|
||||
|
||||
|
||||
@@ -4,39 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.22] (2023-06-20)
|
||||
|
||||
- CLI tool for querying network-requesters ([#3539])
|
||||
- Statically link OpenSSL ([#3510])
|
||||
- NymConnect - add sentry.io reporting ([#3421])
|
||||
- init command does not change version number in config.toml ([#3336])
|
||||
- [Bug] Config version does not correspond to binary version ([#3434])
|
||||
|
||||
[#3539]: https://github.com/nymtech/nym/issues/3539
|
||||
[#3510]: https://github.com/nymtech/nym/issues/3510
|
||||
[#3421]: https://github.com/nymtech/nym/issues/3421
|
||||
[#3336]: https://github.com/nymtech/nym/issues/3336
|
||||
[#3434]: https://github.com/nymtech/nym/issues/3434
|
||||
|
||||
## [v1.1.21] (2023-06-13)
|
||||
|
||||
- mixFetch: Change socks5 `SendRequest` to include OrderedMessage index as a field rather than making it serialized inside the `data` field
|
||||
([#3534])
|
||||
- Explorer - add more data columns to the Service Provider section: ([#3474])
|
||||
- network-requester: support report if they run an open proxy using `ControlRequest` API ([#3461])
|
||||
- Refactor client configs (London discussion) ([#3444])
|
||||
- Increase `DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE` to 2000 to improve reliability ([#3433])
|
||||
- socks5: sender waits for lanes to clear even though the connection is closed ([#3366])
|
||||
- version bump for variables ([#3545])
|
||||
|
||||
[#3534]: https://github.com/nymtech/nym/issues/3534
|
||||
[#3474]: https://github.com/nymtech/nym/issues/3474
|
||||
[#3461]: https://github.com/nymtech/nym/issues/3461
|
||||
[#3444]: https://github.com/nymtech/nym/issues/3444
|
||||
[#3433]: https://github.com/nymtech/nym/issues/3433
|
||||
[#3366]: https://github.com/nymtech/nym/issues/3366
|
||||
[#3545]: https://github.com/nymtech/nym/pull/3545
|
||||
|
||||
## [v1.1.20] (2023-06-06)
|
||||
|
||||
- Explorer - Fix SP supported apps list ([#3458])
|
||||
|
||||
Generated
+57
-407
@@ -68,7 +68,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
@@ -204,17 +204,6 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-file-watcher"
|
||||
version = "0.1.0"
|
||||
@@ -373,9 +362,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@@ -389,15 +378,6 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bip32"
|
||||
version = "0.3.0"
|
||||
@@ -581,12 +561,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
@@ -836,15 +810,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.5.0"
|
||||
@@ -946,7 +911,7 @@ dependencies = [
|
||||
"cosmos-sdk-proto",
|
||||
"ecdsa",
|
||||
"eyre",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"k256",
|
||||
"prost 0.10.4",
|
||||
"prost-types 0.10.1",
|
||||
@@ -1264,36 +1229,6 @@ dependencies = [
|
||||
"rustc_version 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.63+curl-8.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "3.2.0"
|
||||
@@ -1516,16 +1451,7 @@ version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1539,18 +1465,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@@ -1732,7 +1646,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.2.7",
|
||||
@@ -1841,7 +1755,7 @@ dependencies = [
|
||||
"atomic",
|
||||
"pear",
|
||||
"serde",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"uncased",
|
||||
"version_check",
|
||||
]
|
||||
@@ -2006,21 +1920,6 @@ version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.28"
|
||||
@@ -2117,9 +2016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -2724,12 +2623,6 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "integer-encoding"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02"
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.1.11"
|
||||
@@ -2799,31 +2692,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isahc"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"castaway",
|
||||
"crossbeam-utils",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"http",
|
||||
"log",
|
||||
"once_cell",
|
||||
"polling",
|
||||
"slab",
|
||||
"sluice",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
"url",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isocountry"
|
||||
version = "0.3.2"
|
||||
@@ -3322,7 +3190,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.23"
|
||||
version = "1.1.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3335,7 +3203,7 @@ dependencies = [
|
||||
"cw-utils",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"getset",
|
||||
"humantime-serde",
|
||||
@@ -3387,7 +3255,6 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3423,20 +3290,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-bin-common"
|
||||
version = "0.6.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"clap 4.2.7",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
"log",
|
||||
"opentelemetry",
|
||||
"opentelemetry-jaeger",
|
||||
"pretty_env_logger",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
"vergen",
|
||||
@@ -3459,7 +3324,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -3517,16 +3382,16 @@ dependencies = [
|
||||
"tap",
|
||||
"thiserror",
|
||||
"time 0.3.21",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"clap 4.2.7",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@@ -3559,12 +3424,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client-core"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.21.2",
|
||||
"dashmap 5.4.0",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"gloo-timers",
|
||||
"humantime-serde",
|
||||
@@ -3585,7 +3449,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.6",
|
||||
"sqlx 0.6.3",
|
||||
"tap",
|
||||
"tempfile",
|
||||
@@ -3622,7 +3485,7 @@ dependencies = [
|
||||
"digest 0.9.0",
|
||||
"doc-comment",
|
||||
"ff 0.11.1",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"group 0.11.0",
|
||||
"itertools",
|
||||
"nym-dkg",
|
||||
@@ -3672,12 +3535,12 @@ dependencies = [
|
||||
name = "nym-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs 5.0.1",
|
||||
"cfg-if",
|
||||
"handlebars",
|
||||
"log",
|
||||
"nym-network-defaults",
|
||||
"serde",
|
||||
"toml 0.7.4",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -3701,7 +3564,6 @@ dependencies = [
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
"nym-credentials",
|
||||
@@ -3797,7 +3659,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3807,7 +3669,7 @@ dependencies = [
|
||||
"clap 4.2.7",
|
||||
"colored",
|
||||
"dashmap 4.0.2",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"dotenvy",
|
||||
"futures",
|
||||
"humantime-serde",
|
||||
@@ -3850,7 +3712,7 @@ name = "nym-gateway-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-coconut-interface",
|
||||
@@ -3948,7 +3810,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.23"
|
||||
version = "1.1.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
@@ -3957,7 +3819,7 @@ dependencies = [
|
||||
"colored",
|
||||
"cpu-cycles",
|
||||
"cupid",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"humantime-serde",
|
||||
"lazy_static",
|
||||
@@ -3986,7 +3848,7 @@ dependencies = [
|
||||
"sysinfo",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
@@ -4058,14 +3920,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-file-watcher",
|
||||
"async-trait",
|
||||
"bs58",
|
||||
"clap 4.2.7",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"humantime-serde",
|
||||
"ipnetwork 0.20.0",
|
||||
@@ -4104,9 +3965,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-statistics-common",
|
||||
@@ -4150,22 +4011,6 @@ dependencies = [
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-nr-query"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.2.7",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-network-defaults",
|
||||
"nym-sdk",
|
||||
"nym-service-providers-common",
|
||||
"nym-socks5-requests",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-ordered-buffer"
|
||||
version = "0.1.0"
|
||||
@@ -4184,7 +4029,7 @@ dependencies = [
|
||||
"criterion",
|
||||
"curve25519-dalek",
|
||||
"fastrand",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
@@ -4227,7 +4072,7 @@ dependencies = [
|
||||
"tap",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -4253,7 +4098,6 @@ dependencies = [
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-sdk",
|
||||
"nym-socks5-requests",
|
||||
"nym-sphinx-anonymous-replies",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4263,7 +4107,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
dependencies = [
|
||||
"clap 4.2.7",
|
||||
"lazy_static",
|
||||
@@ -4295,7 +4139,7 @@ dependencies = [
|
||||
name = "nym-socks5-client-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
@@ -4336,7 +4180,6 @@ dependencies = [
|
||||
"openssl",
|
||||
"rand 0.7.3",
|
||||
"safer-ffi",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -4359,13 +4202,10 @@ dependencies = [
|
||||
name = "nym-socks5-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"log",
|
||||
"nym-service-providers-common",
|
||||
"nym-sphinx-addressing",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -4537,7 +4377,7 @@ dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2",
|
||||
"generic-array 0.14.7",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4631,7 +4471,6 @@ dependencies = [
|
||||
"nym-service-provider-directory-common",
|
||||
"nym-vesting-contract",
|
||||
"nym-vesting-contract-common",
|
||||
"openssl",
|
||||
"prost 0.10.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
@@ -4794,55 +4633,12 @@ dependencies = [
|
||||
"opentelemetry_sdk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-http"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"http",
|
||||
"isahc",
|
||||
"opentelemetry_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-jaeger"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08e028dc9f4f304e9320ce38c80e7cf74067415b1ad5a8750a38bae54a4d450d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
"futures-executor",
|
||||
"http",
|
||||
"isahc",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry-http",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"thiserror",
|
||||
"thrift",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24e33428e6bf08c6f7fcea4ddb8e358fab0fe48ab877a87c70c6ebe20f673ce5"
|
||||
dependencies = [
|
||||
"opentelemetry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_api"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"indexmap",
|
||||
@@ -4860,8 +4656,6 @@ checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"crossbeam-channel",
|
||||
"dashmap 5.4.0",
|
||||
"fnv",
|
||||
"futures-channel",
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
@@ -4870,23 +4664,6 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4919,12 +4696,6 @@ dependencies = [
|
||||
"group 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
@@ -5187,22 +4958,6 @@ dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
@@ -5517,7 +5272,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5674,7 +5429,7 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"redox_syscall 0.2.16",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -5737,7 +5492,7 @@ version = "0.11.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@@ -6007,7 +5762,7 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6284,15 +6039,6 @@ dependencies = [
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -6434,17 +6180,6 @@ dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sluice"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
@@ -6932,7 +6667,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tendermint",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -6964,7 +6699,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"flex-error",
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-proxy",
|
||||
@@ -7032,28 +6767,6 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpool"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||
dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thrift"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"integer-encoding",
|
||||
"log",
|
||||
"ordered-float",
|
||||
"threadpool",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
@@ -7277,40 +6990,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.9.2"
|
||||
@@ -7319,7 +6998,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -7378,12 +7057,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-appender"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"time 0.3.21",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.24"
|
||||
@@ -7405,16 +7094,6 @@ dependencies = [
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
@@ -7426,20 +7105,6 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-opentelemetry"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
@@ -7734,7 +7399,7 @@ version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -7773,12 +7438,6 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.3"
|
||||
@@ -7902,7 +7561,7 @@ name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"indexed_db_futures",
|
||||
"js-sys",
|
||||
"nym-store-cipher",
|
||||
@@ -8150,15 +7809,6 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
||||
+2
-4
@@ -87,7 +87,6 @@ members = [
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-outfox",
|
||||
"tools/nym-cli",
|
||||
"tools/nym-nr-query",
|
||||
"tools/ts-rs-cli"
|
||||
]
|
||||
|
||||
@@ -102,7 +101,7 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles", "lib-25519"]
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
@@ -113,8 +112,8 @@ edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.71"
|
||||
async-trait = "0.1.64"
|
||||
anyhow = "1.0.71"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
cosmwasm-derive = "=1.0.0"
|
||||
@@ -130,7 +129,6 @@ cw3-fixed-multisig = { version = "=0.13.4" }
|
||||
cw4 = { version = "=0.13.4" }
|
||||
dotenvy = "0.15.6"
|
||||
generic-array = "0.14.7"
|
||||
getrandom = "0.2.10"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
|
||||
@@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
|
||||
### Building
|
||||
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/build-nym.html).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/building-nym.html).
|
||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
|
||||
### Developing
|
||||
|
||||
@@ -12,9 +12,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||
|
||||
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-client-core = { path = "../../common/client-core" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
mod commands;
|
||||
@@ -9,14 +9,13 @@ use commands::*;
|
||||
use error::Result;
|
||||
use log::*;
|
||||
use nym_bin_common::completions::fig_generate;
|
||||
use nym_config::DEFAULT_DATA_DIR;
|
||||
use nym_config::{CRED_DB_FILE_NAME, DATA_DIR};
|
||||
use nym_network_defaults::{setup_env, NymNetworkDetails};
|
||||
use std::process::exit;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use clap::{CommandFactory, Parser};
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||
use nym_validator_client::Config;
|
||||
@@ -72,11 +71,10 @@ async fn main() -> Result<()> {
|
||||
|
||||
match args.command {
|
||||
Command::Run(r) => {
|
||||
// we assume the structure of <home-dir>/data
|
||||
let data_dir = r.client_home_directory.join(DEFAULT_DATA_DIR);
|
||||
let paths = CommonClientPaths::new_default(data_dir);
|
||||
let db_path = paths.credentials_database;
|
||||
|
||||
let db_path = r
|
||||
.client_home_directory
|
||||
.join(DATA_DIR)
|
||||
.join(CRED_DB_FILE_NAME);
|
||||
let shared_storage =
|
||||
nym_credential_storage::initialise_persistent_storage(db_path).await;
|
||||
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,104 +1,99 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::persistence::ClientPaths;
|
||||
use crate::client::config::template::CONFIG_TEMPLATE;
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use crate::client::config::template::config_template;
|
||||
use nym_client_core::config::ClientCoreConfigTrait;
|
||||
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use nym_config::{
|
||||
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
|
||||
OptionalSet, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
|
||||
};
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use nym_client_core::config::Config as BaseClientConfig;
|
||||
pub use nym_client_core::config::Config as BaseConfig;
|
||||
pub use nym_client_core::config::MISSING_VALUE;
|
||||
pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig};
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
pub mod old_config_v1_1_20;
|
||||
pub mod old_config_v1_1_20_2;
|
||||
mod persistence;
|
||||
mod template;
|
||||
|
||||
const DEFAULT_CLIENTS_DIR: &str = "clients";
|
||||
|
||||
/// Derive default path to clients's config directory.
|
||||
/// It should get resolved to `$HOME/.nym/mixnodes/<id>/config`
|
||||
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_CLIENTS_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_CONFIG_DIR)
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
/// Derive default path to client's config file.
|
||||
/// It should get resolved to `$HOME/.nym/clients/<id>/config/config.toml`
|
||||
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
|
||||
impl SocketType {
|
||||
pub fn from_string<S: Into<String>>(val: S) -> Self {
|
||||
let mut upper = val.into();
|
||||
upper.make_ascii_uppercase();
|
||||
match upper.as_ref() {
|
||||
"WEBSOCKET" | "WS" => SocketType::WebSocket,
|
||||
_ => SocketType::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_websocket(&self) -> bool {
|
||||
matches!(self, SocketType::WebSocket)
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive default path to client's data directory where files, such as keys, are stored.
|
||||
/// It should get resolved to `$HOME/.nym/clients/<id>/data`
|
||||
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_CLIENTS_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_DATA_DIR)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseClientConfig,
|
||||
base: BaseConfig<Config>,
|
||||
|
||||
pub socket: Socket,
|
||||
|
||||
// pub paths: CommonClientPathfinder,
|
||||
pub storage_paths: ClientPaths,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
socket: Socket,
|
||||
}
|
||||
|
||||
impl NymConfigTemplate for Config {
|
||||
impl NymConfig for Config {
|
||||
fn template() -> &'static str {
|
||||
CONFIG_TEMPLATE
|
||||
config_template()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
.join(".nym")
|
||||
.join("clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.get_nym_root_directory()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(self.base.get_id())
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory().join(self.base.get_id()).join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientCoreConfigTrait for Config {
|
||||
fn get_gateway_endpoint(&self) -> &nym_client_core::config::GatewayEndpointConfig {
|
||||
self.base.get_gateway_endpoint()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: AsRef<str>>(id: S) -> Self {
|
||||
pub fn new<S: Into<String>>(id: S) -> Self {
|
||||
Config {
|
||||
base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")),
|
||||
storage_paths: ClientPaths::new_default(default_data_directory(id.as_ref())),
|
||||
logging: Default::default(),
|
||||
base: BaseConfig::new(id),
|
||||
socket: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
pub fn default_location(&self) -> PathBuf {
|
||||
default_config_filepath(&self.base.client.id)
|
||||
}
|
||||
|
||||
pub fn save_to_default_location(&self) -> io::Result<()> {
|
||||
let config_save_location: PathBuf = self.default_location();
|
||||
save_formatted_config_to_file(self, config_save_location)
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.base.validate()
|
||||
@@ -128,10 +123,39 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
// getters
|
||||
pub fn get_config_file_save_location(&self) -> PathBuf {
|
||||
self.config_directory().join(Self::config_file_name())
|
||||
}
|
||||
|
||||
pub fn get_base(&self) -> &BaseConfig<Self> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
pub fn get_base_mut(&mut self) -> &mut BaseConfig<Self> {
|
||||
&mut self.base
|
||||
}
|
||||
|
||||
pub fn get_debug_settings(&self) -> &DebugConfig {
|
||||
self.get_base().get_debug_config()
|
||||
}
|
||||
|
||||
pub fn get_socket_type(&self) -> SocketType {
|
||||
self.socket.socket_type
|
||||
}
|
||||
|
||||
pub fn get_listening_ip(&self) -> IpAddr {
|
||||
self.socket.host
|
||||
}
|
||||
|
||||
pub fn get_listening_port(&self) -> u16 {
|
||||
self.socket.listening_port
|
||||
}
|
||||
|
||||
// poor man's 'builder' method
|
||||
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
{
|
||||
self.base = f(self.base, val);
|
||||
self
|
||||
@@ -141,7 +165,7 @@ impl Config {
|
||||
// (plz, lets refactor it)
|
||||
pub fn with_optional_ext<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
{
|
||||
self.base = self.base.with_optional(f, val);
|
||||
self
|
||||
@@ -149,7 +173,7 @@ impl Config {
|
||||
|
||||
pub fn with_optional_env_ext<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
@@ -165,7 +189,7 @@ impl Config {
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
G: Fn(&str) -> T,
|
||||
{
|
||||
self.base = self.base.with_optional_custom_env(f, val, env_var, parser);
|
||||
@@ -173,34 +197,19 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
// define_optional_set_inner!(Config, base, BaseClientConfig);
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
impl SocketType {
|
||||
pub fn is_websocket(&self) -> bool {
|
||||
matches!(self, SocketType::WebSocket)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Socket {
|
||||
pub socket_type: SocketType,
|
||||
pub host: IpAddr,
|
||||
pub listening_port: u16,
|
||||
socket_type: SocketType,
|
||||
host: IpAddr,
|
||||
listening_port: u16,
|
||||
}
|
||||
|
||||
impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket {
|
||||
socket_type: SocketType::WebSocket,
|
||||
host: IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,58 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_20::{ConfigV1_1_20, SocketV1_1_20};
|
||||
use crate::client::config::{Config, Socket};
|
||||
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
pub base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
pub socket: SocketV1_1_20,
|
||||
socket: Socket,
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for OldConfigV1_1_13 {
|
||||
impl NymConfig for OldConfigV1_1_13 {
|
||||
fn template() -> &'static str {
|
||||
// not intended to be used
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
.join(".nym")
|
||||
.join("clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for ConfigV1_1_20 {
|
||||
impl From<OldConfigV1_1_13> for Config {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
ConfigV1_1_20 {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socket: value.socket,
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_20_2::{
|
||||
ClientPathsV1_1_20_2, ConfigV1_1_20_2, SocketTypeV1_1_20_2, SocketV1_1_20_2,
|
||||
};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
|
||||
use nym_client_core::config::old_config_v1_1_20_2::{
|
||||
ClientV1_1_20_2, ConfigV1_1_20_2 as BaseConfigV1_1_20_2,
|
||||
};
|
||||
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketTypeV1_1_20 {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<SocketTypeV1_1_20> for SocketTypeV1_1_20_2 {
|
||||
fn from(value: SocketTypeV1_1_20) -> Self {
|
||||
match value {
|
||||
SocketTypeV1_1_20::WebSocket => SocketTypeV1_1_20_2::WebSocket,
|
||||
SocketTypeV1_1_20::None => SocketTypeV1_1_20_2::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20 {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseConfigV1_1_20<ConfigV1_1_20>,
|
||||
|
||||
pub socket: SocketV1_1_20,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
|
||||
fn from(value: ConfigV1_1_20) -> Self {
|
||||
ConfigV1_1_20_2 {
|
||||
base: BaseConfigV1_1_20_2 {
|
||||
client: ClientV1_1_20_2 {
|
||||
version: value.base.client.version,
|
||||
id: value.base.client.id,
|
||||
disabled_credentials_mode: value.base.client.disabled_credentials_mode,
|
||||
nyxd_urls: value.base.client.nyxd_urls,
|
||||
nym_api_urls: value.base.client.nym_api_urls,
|
||||
gateway_endpoint: value.base.client.gateway_endpoint.into(),
|
||||
},
|
||||
debug: value.base.debug.into(),
|
||||
},
|
||||
socket: value.socket.into(),
|
||||
storage_paths: ClientPathsV1_1_20_2 {
|
||||
common_paths: CommonClientPathsV1_1_20_2 {
|
||||
keys: ClientKeysPaths {
|
||||
private_identity_key_file: value.base.client.private_identity_key_file,
|
||||
public_identity_key_file: value.base.client.public_identity_key_file,
|
||||
private_encryption_key_file: value.base.client.private_encryption_key_file,
|
||||
public_encryption_key_file: value.base.client.public_encryption_key_file,
|
||||
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
|
||||
ack_key_file: value.base.client.ack_key_file,
|
||||
},
|
||||
credentials_database: value.base.client.database_path,
|
||||
reply_surb_database: value.base.client.reply_surb_database_path,
|
||||
},
|
||||
},
|
||||
logging: LoggingSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for ConfigV1_1_20 {
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
.join(".nym")
|
||||
.join("clients")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct SocketV1_1_20 {
|
||||
socket_type: SocketTypeV1_1_20,
|
||||
host: IpAddr,
|
||||
listening_port: u16,
|
||||
}
|
||||
|
||||
impl From<SocketV1_1_20> for SocketV1_1_20_2 {
|
||||
fn from(value: SocketV1_1_20) -> Self {
|
||||
SocketV1_1_20_2 {
|
||||
socket_type: value.socket_type.into(),
|
||||
host: value.host,
|
||||
listening_port: value.listening_port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SocketV1_1_20 {
|
||||
fn default() -> Self {
|
||||
SocketV1_1_20 {
|
||||
socket_type: SocketTypeV1_1_20::WebSocket,
|
||||
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::persistence::ClientPaths;
|
||||
use crate::client::config::{default_config_filepath, Config, Socket, SocketType};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_config::read_config_from_toml_file;
|
||||
use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct ClientPathsV1_1_20_2 {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPathsV1_1_20_2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseConfigV1_1_20_2,
|
||||
|
||||
pub socket: SocketV1_1_20_2,
|
||||
|
||||
pub storage_paths: ClientPathsV1_1_20_2,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
}
|
||||
|
||||
impl ConfigV1_1_20_2 {
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
// in this upgrade, gateway endpoint configuration was moved out of the config file,
|
||||
// so its returned to be stored elsewhere.
|
||||
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
|
||||
let gateway_details = self.base.client.gateway_endpoint.clone().into();
|
||||
let config = Config {
|
||||
base: self.base.into(),
|
||||
socket: self.socket.into(),
|
||||
storage_paths: ClientPaths {
|
||||
common_paths: self.storage_paths.common_paths.upgrade_default(),
|
||||
},
|
||||
logging: self.logging,
|
||||
};
|
||||
|
||||
(config, gateway_details)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketTypeV1_1_20_2 {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<SocketTypeV1_1_20_2> for SocketType {
|
||||
fn from(value: SocketTypeV1_1_20_2) -> Self {
|
||||
match value {
|
||||
SocketTypeV1_1_20_2::WebSocket => SocketType::WebSocket,
|
||||
SocketTypeV1_1_20_2::None => SocketType::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct SocketV1_1_20_2 {
|
||||
pub socket_type: SocketTypeV1_1_20_2,
|
||||
pub host: IpAddr,
|
||||
pub listening_port: u16,
|
||||
}
|
||||
|
||||
impl From<SocketV1_1_20_2> for Socket {
|
||||
fn from(value: SocketV1_1_20_2) -> Self {
|
||||
Socket {
|
||||
socket_type: value.socket_type.into(),
|
||||
host: value.host,
|
||||
listening_port: value.listening_port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SocketV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
SocketV1_1_20_2 {
|
||||
socket_type: SocketTypeV1_1_20_2::WebSocket,
|
||||
host: IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct ClientPaths {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPaths,
|
||||
}
|
||||
|
||||
impl ClientPaths {
|
||||
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
ClientPaths {
|
||||
common_paths: CommonClientPaths::new_default(base_data_directory),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// 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.
|
||||
pub(crate) const CONFIG_TEMPLATE: &str = r#"
|
||||
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.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
@@ -36,37 +37,50 @@ nym_api_urls = [
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
[storage_paths]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
|
||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||
|
||||
# Path to file containing public identity key.
|
||||
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
|
||||
public_identity_key_file = '{{ client.public_identity_key_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
|
||||
private_encryption_key_file = '{{ client.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
|
||||
public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
||||
|
||||
# Path to the database containing bandwidth credentials
|
||||
database_path = '{{ client.database_path }}'
|
||||
|
||||
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
reply_surb_database_path = '{{ client.reply_surb_database_path }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}'
|
||||
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.
|
||||
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
|
||||
ack_key_file = '{{ client.ack_key_file }}'
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Path to the database containing bandwidth credentials
|
||||
credentials_database = '{{ storage_paths.credentials_database }}'
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
|
||||
|
||||
# Path to the file containing information about gateway used by this client,
|
||||
# i.e. details such as its public key, owner address or the network information.
|
||||
gateway_details = '{{ storage_paths.gateway_details }}'
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
@@ -106,5 +120,5 @@ average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
|
||||
[debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
|
||||
|
||||
"#;
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
@@ -6,15 +6,19 @@ use crate::error::ClientError;
|
||||
use crate::websocket;
|
||||
use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config;
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core::client::base_client::non_wasm_helpers::create_bandwidth_controller;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_client_core::client::base_client::{
|
||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
};
|
||||
use nym_client_core::client::inbound_messages::InputMessage;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::client::received_buffer::{
|
||||
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
|
||||
};
|
||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
@@ -42,6 +46,17 @@ impl SocketClient {
|
||||
SocketClient { config }
|
||||
}
|
||||
|
||||
async fn create_bandwidth_controller(
|
||||
config: &Config,
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, PersistentStorage> {
|
||||
let storage = nym_credential_storage::initialise_persistent_storage(
|
||||
config.get_base().get_database_path(),
|
||||
)
|
||||
.await;
|
||||
|
||||
create_bandwidth_controller(config.get_base(), storage)
|
||||
}
|
||||
|
||||
fn start_websocket_listener(
|
||||
config: &Config,
|
||||
client_input: ClientInput,
|
||||
@@ -78,7 +93,7 @@ impl SocketClient {
|
||||
Some(packet_type),
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.socket.host, config.socket.listening_port)
|
||||
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
||||
.start(websocket_handler, shutdown);
|
||||
}
|
||||
|
||||
@@ -91,38 +106,42 @@ impl SocketClient {
|
||||
res
|
||||
}
|
||||
|
||||
async fn initialise_storage(&self) -> Result<OnDiskPersistent, ClientError> {
|
||||
Ok(OnDiskPersistent::from_paths(
|
||||
self.config.storage_paths.common_paths.clone(),
|
||||
&self.config.base.debug,
|
||||
)
|
||||
.await?)
|
||||
fn key_store(&self) -> OnDiskKeys {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(self.config.get_base());
|
||||
OnDiskKeys::new(pathfinder)
|
||||
}
|
||||
|
||||
// TODO: see if this could also be shared with socks5 client / nym-sdk maybe
|
||||
async fn create_base_client_builder(&self) -> Result<NativeClientBuilder, ClientError> {
|
||||
// don't create dkg client for the bandwidth controller if credentials are disabled
|
||||
let dkg_query_client = if self.config.base.client.disabled_credentials_mode {
|
||||
// don't create bandwidth controller if credentials are disabled
|
||||
let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() {
|
||||
None
|
||||
} else {
|
||||
Some(default_query_dkg_client_from_config(&self.config.base))
|
||||
Some(Self::create_bandwidth_controller(&self.config).await)
|
||||
};
|
||||
|
||||
let storage = self.initialise_storage().await?;
|
||||
|
||||
let base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
|
||||
let base_client = BaseClientBuilder::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_store(),
|
||||
bandwidth_controller,
|
||||
non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||
self.config.get_base().get_reply_surb_database_path(),
|
||||
&self.config.get_debug_settings().reply_surbs,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
Ok(base_client)
|
||||
}
|
||||
|
||||
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
|
||||
if !self.config.socket.socket_type.is_websocket() {
|
||||
if !self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let packet_type = self.config.base.debug.traffic.packet_type;
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
@@ -145,13 +164,13 @@ impl SocketClient {
|
||||
}
|
||||
|
||||
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
|
||||
if self.config.socket.socket_type.is_websocket() {
|
||||
if self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let packet_type = self.config.base.debug.traffic.packet_type;
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{
|
||||
default_config_directory, default_config_filepath, default_data_directory,
|
||||
};
|
||||
use crate::commands::try_upgrade_config;
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::config::Config,
|
||||
commands::{override_config, OverrideConfig},
|
||||
@@ -12,16 +9,13 @@ use crate::{
|
||||
};
|
||||
use clap::Args;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::Serialize;
|
||||
use std::fmt::Display;
|
||||
use std::net::IpAddr;
|
||||
use std::{fs, io};
|
||||
use tap::TapFallible;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
@@ -103,15 +97,15 @@ impl From<Init> for OverrideConfig {
|
||||
pub struct InitResults {
|
||||
#[serde(flatten)]
|
||||
client_core: nym_client_core::init::InitResults,
|
||||
client_listening_port: u16,
|
||||
client_listening_port: String,
|
||||
client_address: String,
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
|
||||
fn new(config: &Config, address: &Recipient) -> Self {
|
||||
Self {
|
||||
client_core: nym_client_core::init::InitResults::new(&config.base, address, gateway),
|
||||
client_listening_port: config.socket.listening_port,
|
||||
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
|
||||
client_listening_port: config.get_listening_port().to_string(),
|
||||
client_address: address.to_string(),
|
||||
}
|
||||
}
|
||||
@@ -125,26 +119,18 @@ impl Display for InitResults {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_paths(id: &str) -> io::Result<()> {
|
||||
fs::create_dir_all(default_data_directory(id))?;
|
||||
fs::create_dir_all(default_config_directory(id))
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
eprintln!("Initialising client...");
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let already_init = if default_config_filepath(id).exists() {
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_config(id)?;
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
eprintln!("Client \"{id}\" was already initialised before");
|
||||
true
|
||||
} else {
|
||||
init_paths(id)?;
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
@@ -160,44 +146,48 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = args.gateway;
|
||||
let gateway_setup = GatewaySetup::new_fresh(
|
||||
user_chosen_gateway_id.map(|id| id.to_base58_string()),
|
||||
Some(args.latency_based_selection),
|
||||
);
|
||||
|
||||
// Load and potentially override config
|
||||
let config = override_config(Config::new(id), OverrideConfig::from(args.clone()));
|
||||
let mut config = override_config(Config::new(id), OverrideConfig::from(args.clone()));
|
||||
|
||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||
// one but with keys kept, or reusing the gateway configuration.
|
||||
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let init_details = nym_client_core::init::setup_gateway(
|
||||
&gateway_setup,
|
||||
let key_store = OnDiskKeys::from_config(config.get_base());
|
||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
|
||||
&key_store,
|
||||
&details_store,
|
||||
register_gateway,
|
||||
Some(&config.base.client.nym_api_urls),
|
||||
user_chosen_gateway_id,
|
||||
config.get_base(),
|
||||
args.latency_based_selection,
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
|
||||
let config_save_location = config.default_location();
|
||||
config.save_to_default_location().tap_err(|_| {
|
||||
config.get_base_mut().set_gateway_endpoint(gateway);
|
||||
|
||||
config.save_to_file(None).tap_err(|_| {
|
||||
log::error!("Failed to save the config file");
|
||||
})?;
|
||||
eprintln!(
|
||||
"Saved configuration file to {}",
|
||||
config_save_location.display()
|
||||
);
|
||||
|
||||
let address = init_details.client_address()?;
|
||||
print_saved_config(&config);
|
||||
|
||||
eprintln!("Client configuration completed.\n");
|
||||
|
||||
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
|
||||
let address =
|
||||
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
|
||||
let init_results = InitResults::new(&config, &address);
|
||||
println!("{}", args.output.format(&init_results));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_saved_config(config: &Config) {
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
eprintln!("Saved configuration file to {config_save_location:?}");
|
||||
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
|
||||
log::debug!(
|
||||
"Gateway listener: {}",
|
||||
config.get_base().get_gateway_listener()
|
||||
);
|
||||
eprintln!("Client configuration completed.\n");
|
||||
}
|
||||
|
||||
@@ -2,23 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::client::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
|
||||
use crate::client::config::{BaseClientConfig, Config};
|
||||
use crate::error::ClientError;
|
||||
use crate::client::config::{BaseConfig, Config};
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info};
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
@@ -91,151 +82,40 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
config
|
||||
.with_optional(Config::with_disabled_socket, args.disable_socket)
|
||||
.with_base(
|
||||
BaseClientConfig::with_high_default_traffic_volume,
|
||||
args.fastmode,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
||||
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
.with_optional(Config::with_host, args.host)
|
||||
.with_optional_custom_env_ext(
|
||||
BaseClientConfig::with_custom_nym_apis,
|
||||
BaseConfig::with_custom_nym_apis,
|
||||
args.nym_apis,
|
||||
nym_network_defaults::var_names::NYM_API,
|
||||
nym_config::parse_urls,
|
||||
)
|
||||
.with_optional_custom_env_ext(
|
||||
BaseClientConfig::with_custom_nyxd,
|
||||
BaseConfig::with_custom_nyxd,
|
||||
args.nyxd_urls,
|
||||
nym_network_defaults::var_names::NYXD,
|
||||
nym_config::parse_urls,
|
||||
)
|
||||
.with_optional_ext(
|
||||
BaseClientConfig::with_disabled_credentials,
|
||||
BaseConfig::with_disabled_credentials,
|
||||
args.enabled_credentials_mode.map(|b| !b),
|
||||
)
|
||||
}
|
||||
|
||||
fn persist_gateway_details(
|
||||
config: &Config,
|
||||
details: GatewayEndpointConfig,
|
||||
) -> Result<(), ClientError> {
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
|
||||
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
|
||||
ClientError::ClientCoreError(ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
})?;
|
||||
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
|
||||
details_store
|
||||
.store_to_disk(&persisted_details)
|
||||
.map_err(|source| {
|
||||
ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, ClientError> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20 = old_config.into();
|
||||
let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
|
||||
let (updated, gateway_config) = updated_step2.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, ClientError> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20_2 = old_config.into();
|
||||
let (updated, gateway_config) = updated_step1.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, ClientError> {
|
||||
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20_2 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let (updated, gateway_config) = old_config.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_config(id: &str) -> Result<(), ClientError> {
|
||||
if try_upgrade_v1_1_13_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_2_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_load_current_config(id: &str) -> Result<Config, ClientError> {
|
||||
// try to load the config as is
|
||||
if let Ok(cfg) = Config::read_from_default_path(id) {
|
||||
return if !cfg.validate() {
|
||||
Err(ClientError::ConfigValidationFailure)
|
||||
} else {
|
||||
Ok(cfg)
|
||||
};
|
||||
}
|
||||
|
||||
// we couldn't load it - try upgrading it from older revisions
|
||||
try_upgrade_config(id)?;
|
||||
|
||||
let config = match Config::read_from_default_path(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
|
||||
return Err(ClientError::FailedToLoadConfig(id.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(ClientError::ConfigValidationFailure);
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::{config::Config, SocketClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
@@ -10,9 +13,8 @@ use crate::{
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Run {
|
||||
@@ -80,7 +82,7 @@ impl From<Run> for OverrideConfig {
|
||||
// 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.base.client.version;
|
||||
let config_version = cfg.get_base().get_version();
|
||||
if binary_version == config_version {
|
||||
true
|
||||
} else {
|
||||
@@ -96,10 +98,30 @@ fn version_check(cfg: &Config) -> bool {
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
eprintln!("Starting client {}...", args.id);
|
||||
let id = &args.id;
|
||||
|
||||
let mut config = try_load_current_config(&args.id)?;
|
||||
config = override_config(config, OverrideConfig::from(args.clone()));
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
|
||||
return Err(Box::new(ClientError::FailedToLoadConfig(id.to_string())));
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(Box::new(ClientError::ConfigValidationFailure));
|
||||
}
|
||||
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
if config.get_base_mut().set_empty_fields_to_defaults() {
|
||||
warn!("some of the core config options were left unset. the default values are going to get used instead.");
|
||||
}
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
|
||||
@@ -1,14 +1,42 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::try_load_current_config;
|
||||
use clap::Args;
|
||||
use crate::client::config::{Config, MISSING_VALUE};
|
||||
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use nym_config::NymConfig;
|
||||
|
||||
use clap::Args;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
|
||||
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
|
||||
#[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 {from} to {to} ...");
|
||||
}
|
||||
|
||||
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!("Upgrade from {from} to {to} failed!\n==================\n");
|
||||
}
|
||||
|
||||
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!("Upgrade from {from} to {to} was successful!\n==================\n");
|
||||
}
|
||||
|
||||
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!(
|
||||
"Cannot perform upgrade from {config_version} to {package_version}. Your version is too old to perform the upgrade.!"
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {current_version}. Please let the developers know about this issue if you expected it to work!");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
@@ -20,7 +48,7 @@ pub(crate) struct Upgrade {
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.base.client.version).unwrap_or_else(|err| {
|
||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
@@ -49,14 +77,53 @@ fn parse_package_version() -> Version {
|
||||
version
|
||||
}
|
||||
|
||||
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
|
||||
let config_version = parse_config_version(&config);
|
||||
if &config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_matches: &Upgrade,
|
||||
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)
|
||||
};
|
||||
|
||||
unimplemented_upgrade(package_version, &config_version)
|
||||
print_start_upgrade(config_version, &to_version);
|
||||
|
||||
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, args: &Upgrade, 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, args, &config_version, package_version),
|
||||
_ => unsupported_upgrade(&config_version, package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: &Upgrade) {
|
||||
@@ -64,15 +131,16 @@ pub(crate) fn execute(args: &Upgrade) {
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
|
||||
let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.base.client.version.is_empty() {
|
||||
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, args, &package_version)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.22"
|
||||
version = "1.1.20"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_config;
|
||||
use crate::config::{
|
||||
default_config_directory, default_config_filepath, default_data_directory, Config,
|
||||
};
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
};
|
||||
use clap::Args;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_socks5_client_core::config::Config;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::Serialize;
|
||||
use std::fmt::Display;
|
||||
use std::{fs, io};
|
||||
use tap::TapFallible;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
@@ -105,19 +100,15 @@ impl From<Init> for OverrideConfig {
|
||||
pub struct InitResults {
|
||||
#[serde(flatten)]
|
||||
client_core: nym_client_core::init::InitResults,
|
||||
socks5_listening_port: u16,
|
||||
socks5_listening_port: String,
|
||||
client_address: String,
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
|
||||
fn new(config: &Config, address: &Recipient) -> Self {
|
||||
Self {
|
||||
client_core: nym_client_core::init::InitResults::new(
|
||||
&config.core.base,
|
||||
address,
|
||||
gateway,
|
||||
),
|
||||
socks5_listening_port: config.core.socks5.listening_port,
|
||||
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
|
||||
socks5_listening_port: config.get_socks5().get_listening_port().to_string(),
|
||||
client_address: address.to_string(),
|
||||
}
|
||||
}
|
||||
@@ -131,27 +122,19 @@ impl Display for InitResults {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_paths(id: &str) -> io::Result<()> {
|
||||
fs::create_dir_all(default_data_directory(id))?;
|
||||
fs::create_dir_all(default_config_directory(id))
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
eprintln!("Initialising client...");
|
||||
|
||||
let id = &args.id;
|
||||
let provider_address = &args.provider;
|
||||
|
||||
let already_init = if default_config_filepath(id).exists() {
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_config(id)?;
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
eprintln!("SOCKS5 client \"{id}\" was already initialised before");
|
||||
true
|
||||
} else {
|
||||
init_paths(id)?;
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
@@ -167,47 +150,53 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = args.gateway;
|
||||
let gateway_setup = GatewaySetup::new_fresh(
|
||||
user_chosen_gateway_id.map(|id| id.to_base58_string()),
|
||||
Some(args.latency_based_selection),
|
||||
);
|
||||
|
||||
// Load and potentially override config
|
||||
let config = override_config(
|
||||
let mut config = override_config(
|
||||
Config::new(id, &provider_address.to_string()),
|
||||
OverrideConfig::from(args.clone()),
|
||||
);
|
||||
|
||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||
// one but with keys kept, or reusing the gateway configuration.
|
||||
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let init_details = nym_client_core::init::setup_gateway(
|
||||
&gateway_setup,
|
||||
let key_store = OnDiskKeys::from_config(config.get_base());
|
||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
|
||||
&key_store,
|
||||
&details_store,
|
||||
register_gateway,
|
||||
Some(&config.core.base.client.nym_api_urls),
|
||||
user_chosen_gateway_id,
|
||||
config.get_base(),
|
||||
args.latency_based_selection,
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
|
||||
config.get_base_mut().set_gateway_endpoint(gateway);
|
||||
|
||||
// TODO: ask the service provider we specified for its interface version and set it in the config
|
||||
|
||||
let config_save_location = config.default_location();
|
||||
config.save_to_default_location().tap_err(|_| {
|
||||
config.save_to_file(None).tap_err(|_| {
|
||||
log::error!("Failed to save the config file");
|
||||
})?;
|
||||
eprintln!(
|
||||
"Saved configuration file to {}",
|
||||
config_save_location.display()
|
||||
);
|
||||
|
||||
let address = init_details.client_address()?;
|
||||
print_saved_config(&config);
|
||||
|
||||
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
|
||||
let address =
|
||||
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
|
||||
let init_results = InitResults::new(&config, &address);
|
||||
println!("{}", args.output.format(&init_results));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_saved_config(config: &Config) {
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
eprintln!("Saved configuration file to {:?}", config_save_location);
|
||||
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
|
||||
log::debug!(
|
||||
"Gateway listener: {}",
|
||||
config.get_base().get_gateway_listener()
|
||||
);
|
||||
eprintln!("Client configuration completed.\n");
|
||||
}
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
|
||||
use crate::config::{BaseClientConfig, Config};
|
||||
use crate::error::Socks5ClientError;
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info};
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use nym_socks5_client_core::config::{BaseConfig, Config};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use std::error::Error;
|
||||
|
||||
@@ -97,152 +88,41 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
PacketType::Mix
|
||||
};
|
||||
config
|
||||
.with_base(
|
||||
BaseClientConfig::with_high_default_traffic_volume,
|
||||
args.fastmode,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
||||
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
.with_optional_base_custom_env(
|
||||
BaseClientConfig::with_custom_nym_apis,
|
||||
.with_optional_custom_env_ext(
|
||||
BaseConfig::with_custom_nym_apis,
|
||||
args.nym_apis,
|
||||
nym_network_defaults::var_names::NYM_API,
|
||||
nym_config::parse_urls,
|
||||
)
|
||||
.with_optional_base_custom_env(
|
||||
BaseClientConfig::with_custom_nyxd,
|
||||
.with_optional_custom_env_ext(
|
||||
BaseConfig::with_custom_nyxd,
|
||||
args.nyxd_urls,
|
||||
nym_network_defaults::var_names::NYXD,
|
||||
nym_config::parse_urls,
|
||||
)
|
||||
.with_optional_base(
|
||||
BaseClientConfig::with_disabled_credentials,
|
||||
.with_optional_ext(
|
||||
BaseConfig::with_disabled_credentials,
|
||||
args.enabled_credentials_mode.map(|b| !b),
|
||||
)
|
||||
}
|
||||
|
||||
fn persist_gateway_details(
|
||||
config: &Config,
|
||||
details: GatewayEndpointConfig,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
|
||||
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
|
||||
Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
})?;
|
||||
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
|
||||
details_store
|
||||
.store_to_disk(&persisted_details)
|
||||
.map_err(|source| {
|
||||
Socks5ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20 = old_config.into();
|
||||
let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
|
||||
let (updated, gateway_config) = updated_step2.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, Socks5ClientError> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20_2 = old_config.into();
|
||||
let (updated, gateway_config) = updated_step1.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, Socks5ClientError> {
|
||||
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20_2 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let (updated, gateway_config) = old_config.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> {
|
||||
if try_upgrade_v1_1_13_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_2_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_load_current_config(id: &str) -> Result<Config, Socks5ClientError> {
|
||||
// try to load the config as is
|
||||
if let Ok(cfg) = Config::read_from_default_path(id) {
|
||||
return if !cfg.validate() {
|
||||
Err(Socks5ClientError::ConfigValidationFailure)
|
||||
} else {
|
||||
Ok(cfg)
|
||||
};
|
||||
}
|
||||
|
||||
// we couldn't load it - try upgrading it from older revisions
|
||||
try_upgrade_config(id)?;
|
||||
|
||||
let config = match Config::read_from_default_path(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
|
||||
return Err(Socks5ClientError::FailedToLoadConfig(id.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(Socks5ClientError::ConfigValidationFailure);
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use crate::config::Config;
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
@@ -11,8 +10,9 @@ use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_socks5_client_core::NymClient;
|
||||
use nym_socks5_client_core::{config::Config, NymClient};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
@@ -21,6 +21,10 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
id: String,
|
||||
|
||||
/// Custom path to the nym-mixnet-client configuration file
|
||||
#[clap(long)]
|
||||
config: Option<String>,
|
||||
|
||||
/// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
|
||||
/// While this is going to hide its actual address information, it will make the actual communication
|
||||
/// slower and consume nearly double the bandwidth as it will require sending reply SURBs.
|
||||
@@ -88,12 +92,13 @@ impl From<Run> for OverrideConfig {
|
||||
// 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.core.base.client.version;
|
||||
let config_version = cfg.get_base().get_version();
|
||||
if binary_version == config_version {
|
||||
true
|
||||
} else {
|
||||
warn!(
|
||||
"The socks5-client binary has different version than what is specified in config file! {binary_version} and {config_version}",
|
||||
"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");
|
||||
@@ -106,18 +111,38 @@ fn version_check(cfg: &Config) -> bool {
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
eprintln!("Starting client {}...", args.id);
|
||||
let id = &args.id;
|
||||
|
||||
let mut config = try_load_current_config(&args.id)?;
|
||||
config = override_config(config, OverrideConfig::from(args.clone()));
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
|
||||
return Err(Box::new(Socks5ClientError::FailedToLoadConfig(
|
||||
id.to_string(),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(Box::new(Socks5ClientError::ConfigValidationFailure));
|
||||
}
|
||||
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
if config.get_base_mut().set_empty_fields_to_defaults() {
|
||||
warn!("some of the core config options were left unset. the default values are going to get used instead.");
|
||||
}
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
let storage =
|
||||
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
|
||||
.await?;
|
||||
NymClient::new(config.core, storage).run_forever().await
|
||||
let storage = OnDiskPersistent::from_config(config.get_base()).await?;
|
||||
NymClient::new(config, storage).run_forever().await
|
||||
}
|
||||
|
||||
@@ -1,14 +1,50 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use crate::config::Config;
|
||||
use clap::Args;
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use std::process;
|
||||
use nym_config::NymConfig;
|
||||
use nym_socks5_client_core::config::{Config, MISSING_VALUE};
|
||||
|
||||
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
|
||||
use clap::Args;
|
||||
use std::{fmt::Display, process};
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
@@ -20,14 +56,15 @@ pub(crate) struct Upgrade {
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.core.base.client.version).unwrap_or_else(|err| {
|
||||
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 {version}. This is not supported!"
|
||||
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
@@ -42,21 +79,63 @@ fn parse_package_version() -> Version {
|
||||
// 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 {version}. This is not supported!");
|
||||
eprintln!(
|
||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
|
||||
let config_version = parse_config_version(&config);
|
||||
if &config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_args: &Upgrade,
|
||||
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)
|
||||
};
|
||||
|
||||
unimplemented_upgrade(package_version, &config_version)
|
||||
print_start_upgrade(config_version, &to_version);
|
||||
|
||||
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, args: &Upgrade, 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, args, &config_version, package_version),
|
||||
_ => unsupported_upgrade(&config_version, package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: &Upgrade) {
|
||||
@@ -64,15 +143,16 @@ pub(crate) fn execute(args: &Upgrade) {
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
|
||||
let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.core.base.client.version.is_empty() {
|
||||
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, args, &package_version)
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::SocksClientPaths;
|
||||
use crate::config::template::CONFIG_TEMPLATE;
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_config::{
|
||||
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
|
||||
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use nym_client_core::config::Config as BaseClientConfig;
|
||||
pub use nym_socks5_client_core::config::Config as CoreConfig;
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
pub mod old_config_v1_1_20;
|
||||
pub mod old_config_v1_1_20_2;
|
||||
mod persistence;
|
||||
mod template;
|
||||
|
||||
const DEFAULT_SOCKS5_CLIENTS_DIR: &str = "socks5-clients";
|
||||
|
||||
/// Derive default path to clients's config directory.
|
||||
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/config`
|
||||
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_SOCKS5_CLIENTS_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_CONFIG_DIR)
|
||||
}
|
||||
|
||||
/// Derive default path to client's config file.
|
||||
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/config/config.toml`
|
||||
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
|
||||
}
|
||||
|
||||
/// Derive default path to client's data directory where files, such as keys, are stored.
|
||||
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/data`
|
||||
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_SOCKS5_CLIENTS_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_DATA_DIR)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
pub core: CoreConfig,
|
||||
|
||||
pub storage_paths: SocksClientPaths,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
}
|
||||
|
||||
impl NymConfigTemplate for Config {
|
||||
fn template() -> &'static str {
|
||||
CONFIG_TEMPLATE
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: AsRef<str>>(id: S, provider_mix_address: S) -> Self {
|
||||
Config {
|
||||
core: CoreConfig::new(
|
||||
id.as_ref(),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
provider_mix_address.as_ref(),
|
||||
),
|
||||
storage_paths: SocksClientPaths::new_default(default_data_directory(id.as_ref())),
|
||||
logging: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
pub fn default_location(&self) -> PathBuf {
|
||||
default_config_filepath(&self.core.base.client.id)
|
||||
}
|
||||
|
||||
pub fn save_to_default_location(&self) -> io::Result<()> {
|
||||
let config_save_location: PathBuf = self.default_location();
|
||||
save_formatted_config_to_file(self, config_save_location)
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.core.validate()
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.core.socks5.listening_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_anonymous_replies(mut self, anonymous_replies: bool) -> Self {
|
||||
self.core.socks5.send_anonymously = anonymous_replies;
|
||||
self
|
||||
}
|
||||
|
||||
// poor man's 'builder' method
|
||||
|
||||
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
{
|
||||
self.core = self.core.with_base(f, val);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_base<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
{
|
||||
self.core = self.core.with_optional_base(f, val);
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn with_optional_base_env<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
self.core = self.core.with_optional_base_env(f, val, env_var);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_base_custom_env<F, T, G>(
|
||||
mut self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
G: Fn(&str) -> T,
|
||||
{
|
||||
self.core = self
|
||||
.core
|
||||
.with_optional_base_custom_env(f, val, env_var, parser);
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20::{ConfigV1_1_20, Socks5V1_1_20};
|
||||
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use nym_config::must_get_home;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
pub base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
pub socks5: Socks5V1_1_20,
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for OldConfigV1_1_13 {
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = must_get_home();
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for ConfigV1_1_20 {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
ConfigV1_1_20 {
|
||||
base: value.base.into(),
|
||||
socks5: value.socks5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20_2::{
|
||||
ConfigV1_1_20_2, CoreConfigV1_1_20_2, SocksClientPathsV1_1_20_2,
|
||||
};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
|
||||
use nym_client_core::config::old_config_v1_1_20_2::ClientV1_1_20_2;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use nym_config::must_get_home;
|
||||
use nym_socks5_client_core::config::old_config_v1_1_20_2::{
|
||||
BaseClientConfigV1_1_20_2, Socks5DebugV1_1_20_2, Socks5V1_1_20_2,
|
||||
};
|
||||
use nym_socks5_client_core::config::{ProviderInterfaceVersion, Socks5ProtocolVersion};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
|
||||
const DEFAULT_PER_REQUEST_SURBS: u32 = 3;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20 {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseConfigV1_1_20<ConfigV1_1_20>,
|
||||
|
||||
pub socks5: Socks5V1_1_20,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
|
||||
fn from(value: ConfigV1_1_20) -> Self {
|
||||
ConfigV1_1_20_2 {
|
||||
core: CoreConfigV1_1_20_2 {
|
||||
base: BaseClientConfigV1_1_20_2 {
|
||||
client: ClientV1_1_20_2 {
|
||||
version: value.base.client.version,
|
||||
id: value.base.client.id,
|
||||
disabled_credentials_mode: value.base.client.disabled_credentials_mode,
|
||||
nyxd_urls: value.base.client.nyxd_urls,
|
||||
nym_api_urls: value.base.client.nym_api_urls,
|
||||
gateway_endpoint: value.base.client.gateway_endpoint.into(),
|
||||
},
|
||||
debug: value.base.debug.into(),
|
||||
},
|
||||
socks5: value.socks5.into(),
|
||||
},
|
||||
storage_paths: SocksClientPathsV1_1_20_2 {
|
||||
common_paths: CommonClientPathsV1_1_20_2 {
|
||||
keys: ClientKeysPaths {
|
||||
private_identity_key_file: value.base.client.private_identity_key_file,
|
||||
public_identity_key_file: value.base.client.public_identity_key_file,
|
||||
private_encryption_key_file: value.base.client.private_encryption_key_file,
|
||||
public_encryption_key_file: value.base.client.public_encryption_key_file,
|
||||
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
|
||||
ack_key_file: value.base.client.ack_key_file,
|
||||
},
|
||||
credentials_database: value.base.client.database_path,
|
||||
reply_surb_database: value.base.client.reply_surb_database_path,
|
||||
},
|
||||
},
|
||||
logging: LoggingSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for ConfigV1_1_20 {
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = must_get_home();
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5V1_1_20 {
|
||||
pub listening_port: u16,
|
||||
|
||||
pub provider_mix_address: String,
|
||||
|
||||
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
|
||||
pub provider_interface_version: ProviderInterfaceVersion,
|
||||
|
||||
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
|
||||
pub socks5_protocol_version: Socks5ProtocolVersion,
|
||||
|
||||
#[serde(default)]
|
||||
pub send_anonymously: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub socks5_debug: Socks5DebugV1_1_20,
|
||||
}
|
||||
|
||||
impl From<Socks5V1_1_20> for Socks5V1_1_20_2 {
|
||||
fn from(value: Socks5V1_1_20) -> Self {
|
||||
Socks5V1_1_20_2 {
|
||||
listening_port: value.listening_port,
|
||||
provider_mix_address: value.provider_mix_address,
|
||||
provider_interface_version: value.provider_interface_version,
|
||||
socks5_protocol_version: value.socks5_protocol_version,
|
||||
send_anonymously: value.send_anonymously,
|
||||
socks5_debug: value.socks5_debug.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5DebugV1_1_20 {
|
||||
connection_start_surbs: u32,
|
||||
per_request_surbs: u32,
|
||||
}
|
||||
|
||||
impl From<Socks5DebugV1_1_20> for Socks5DebugV1_1_20_2 {
|
||||
fn from(value: Socks5DebugV1_1_20) -> Self {
|
||||
Socks5DebugV1_1_20_2 {
|
||||
connection_start_surbs: value.connection_start_surbs,
|
||||
per_request_surbs: value.per_request_surbs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Socks5DebugV1_1_20 {
|
||||
fn default() -> Self {
|
||||
Socks5DebugV1_1_20 {
|
||||
connection_start_surbs: DEFAULT_CONNECTION_START_SURBS,
|
||||
per_request_surbs: DEFAULT_PER_REQUEST_SURBS,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::SocksClientPaths;
|
||||
use crate::config::{default_config_filepath, Config};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_config::read_config_from_toml_file;
|
||||
pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct SocksClientPathsV1_1_20_2 {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPathsV1_1_20_2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
pub core: CoreConfigV1_1_20_2,
|
||||
|
||||
pub storage_paths: SocksClientPathsV1_1_20_2,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
}
|
||||
|
||||
impl ConfigV1_1_20_2 {
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
// in this upgrade, gateway endpoint configuration was moved out of the config file,
|
||||
// so its returned to be stored elsewhere.
|
||||
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
|
||||
let gateway_details = self.core.base.client.gateway_endpoint.clone().into();
|
||||
let config = Config {
|
||||
core: self.core.into(),
|
||||
storage_paths: SocksClientPaths {
|
||||
common_paths: self.storage_paths.common_paths.upgrade_default(),
|
||||
},
|
||||
logging: self.logging,
|
||||
};
|
||||
|
||||
(config, gateway_details)
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct SocksClientPaths {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPaths,
|
||||
}
|
||||
|
||||
impl SocksClientPaths {
|
||||
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
SocksClientPaths {
|
||||
common_paths: CommonClientPaths::new_default(base_data_directory),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// 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.
|
||||
pub(crate) const CONFIG_TEMPLATE: &str = r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
##### main base client config options #####
|
||||
|
||||
[core.client]
|
||||
# Version of the client for which this configuration was created.
|
||||
version = '{{ core.client.version }}'
|
||||
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ core.client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
disabled_credentials_mode = {{ core.client.disabled_credentials_mode }}
|
||||
|
||||
# Addresses to nyxd validators via which the client can communicate with the chain.
|
||||
nyxd_urls = [
|
||||
{{#each core.client.nyxd_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
nym_api_urls = [
|
||||
{{#each core.client.nym_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
[storage_paths]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
|
||||
|
||||
# Path to file containing public identity key.
|
||||
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
keys.gateway_shared_key_file = '{{ storage_paths.keys.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.
|
||||
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
|
||||
|
||||
# Path to the database containing bandwidth credentials
|
||||
credentials_database = '{{ storage_paths.credentials_database }}'
|
||||
|
||||
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
|
||||
|
||||
# Path to the file containing information about gateway used by this client,
|
||||
# i.e. details such as its public key, owner address or the network information.
|
||||
gateway_details = '{{ storage_paths.gateway_details }}'
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
[core.socks5]
|
||||
|
||||
# The mix address of the provider to which all requests are going to be sent.
|
||||
provider_mix_address = '{{ core.socks5.provider_mix_address }}'
|
||||
|
||||
# The port on which the client will be listening for incoming requests
|
||||
listening_port = {{ core.socks5.listening_port }}
|
||||
|
||||
# Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
|
||||
# While this is going to hide its actual address information, it will make the actual communication
|
||||
# slower and consume nearly double the bandwidth as it will require sending reply SURBs.
|
||||
#
|
||||
# Note that some service providers might not support this.
|
||||
send_anonymously = {{ core.socks5.send_anonymously }}
|
||||
|
||||
##### 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.
|
||||
|
||||
# [core.socks5.socks5_debug]
|
||||
|
||||
|
||||
[core.debug]
|
||||
|
||||
[core.debug.traffic]
|
||||
average_packet_delay = '{{ core.debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ core.debug.traffic.message_sending_average_delay }}'
|
||||
|
||||
[core.debug.acknowledgements]
|
||||
average_ack_delay = '{{ core.debug.acknowledgements.average_ack_delay }}'
|
||||
|
||||
[core.debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ core.debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
|
||||
"#;
|
||||
@@ -8,7 +8,6 @@ use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
mod commands;
|
||||
mod config;
|
||||
pub mod error;
|
||||
|
||||
#[tokio::main]
|
||||
|
||||
Generated
+22
-104
@@ -62,7 +62,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
@@ -225,9 +225,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@@ -622,7 +622,7 @@ dependencies = [
|
||||
"cosmos-sdk-proto",
|
||||
"ecdsa",
|
||||
"eyre",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"k256",
|
||||
"prost",
|
||||
"prost-types",
|
||||
@@ -995,16 +995,7 @@ version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1018,18 +1009,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.15.0"
|
||||
@@ -1442,9 +1421,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
@@ -2249,7 +2228,6 @@ dependencies = [
|
||||
"log",
|
||||
"pretty_env_logger",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"vergen",
|
||||
]
|
||||
|
||||
@@ -2258,9 +2236,8 @@ name = "nym-client-core"
|
||||
version = "1.1.14"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.21.2",
|
||||
"dashmap",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"gloo-timers",
|
||||
"humantime-serde",
|
||||
@@ -2281,7 +2258,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.6",
|
||||
"sqlx 0.6.3",
|
||||
"tap",
|
||||
"thiserror",
|
||||
@@ -2345,7 +2321,7 @@ dependencies = [
|
||||
"bs58",
|
||||
"digest 0.9.0",
|
||||
"ff 0.11.1",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"group 0.11.0",
|
||||
"itertools",
|
||||
"nym-dkg",
|
||||
@@ -2394,12 +2370,12 @@ dependencies = [
|
||||
name = "nym-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs 5.0.1",
|
||||
"cfg-if 1.0.0",
|
||||
"handlebars",
|
||||
"log",
|
||||
"nym-network-defaults",
|
||||
"serde",
|
||||
"toml 0.7.4",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -2489,7 +2465,7 @@ name = "nym-gateway-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-coconut-interface",
|
||||
@@ -2636,7 +2612,7 @@ dependencies = [
|
||||
"chacha20",
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
@@ -2816,7 +2792,7 @@ dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2",
|
||||
"generic-array 0.14.7",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2986,12 +2962,6 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.20.0"
|
||||
@@ -3402,7 +3372,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3470,7 +3440,7 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"redox_syscall 0.2.16",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -3498,7 +3468,7 @@ version = "0.11.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@@ -3632,7 +3602,7 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3864,15 +3834,6 @@ dependencies = [
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -4356,7 +4317,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tendermint",
|
||||
"toml 0.5.11",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -4388,7 +4349,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"flex-error",
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-proxy",
|
||||
@@ -4593,40 +4554,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
@@ -4788,7 +4715,7 @@ version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -4964,7 +4891,7 @@ name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"getrandom 0.2.9",
|
||||
"indexed_db_futures",
|
||||
"js-sys",
|
||||
"nym-store-cipher",
|
||||
@@ -5215,15 +5142,6 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "nym-client-wasm"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
version = "1.1.1"
|
||||
version = "1.1.0"
|
||||
edition = "2021"
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
@@ -107,20 +107,20 @@ function printAndDisplayTestResult(result) {
|
||||
}
|
||||
|
||||
async function testWithTester() {
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
|
||||
// A) construct with hardcoded topology
|
||||
const topology = dummyTopology()
|
||||
const nodeTester = await new NymNodeTester(topology, preferredGateway);
|
||||
const nodeTester = await new NymNodeTester(topology, dummyGateway);
|
||||
|
||||
// B) first get topology directly from nym-api
|
||||
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
// const topology = await current_network_topology(validator)
|
||||
// const nodeTester = await new NymNodeTester(topology, undefined, preferredGateway);
|
||||
// const nodeTester = await new NymNodeTester(topology, dummyGateway);
|
||||
//
|
||||
// C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers)
|
||||
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
// const nodeTester = await NymNodeTester.new_with_api(validator, undefined, preferredGateway)
|
||||
// const nodeTester = await NymNodeTester.new_with_api(validator, dummyGateway)
|
||||
|
||||
// D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
|
||||
// const topology = dummyTopology()
|
||||
@@ -139,44 +139,10 @@ async function testWithTester() {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function testerReconnection() {
|
||||
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
const nodeTester = await NymNodeTester.new_with_api(validator);
|
||||
|
||||
self.onmessage = async event => {
|
||||
if (event.data && event.data.kind) {
|
||||
switch (event.data.kind) {
|
||||
case 'TestPacket': {
|
||||
const {mixnodeIdentity} = event.data.args;
|
||||
console.log("starting node test...");
|
||||
|
||||
let result1 = await nodeTester.test_node(mixnodeIdentity);
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await nodeTester.disconnect_from_gateway();
|
||||
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
await nodeTester.reconnect_to_gateway();
|
||||
let result2 = await nodeTester.test_node(mixnodeIdentity);
|
||||
|
||||
printAndDisplayTestResult(result1)
|
||||
printAndDisplayTestResult(result2)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function testWithNymClient() {
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const topology = dummyTopology()
|
||||
|
||||
let received = 0
|
||||
@@ -198,7 +164,7 @@ async function testWithNymClient() {
|
||||
|
||||
console.log('Instantiating WASM client...');
|
||||
|
||||
let clientBuilder = NymClientBuilder.new_tester(topology, onMessageHandler, preferredGateway)
|
||||
let clientBuilder = NymClientBuilder.new_tester(topology, onMessageHandler, dummyGateway)
|
||||
console.log('Web worker creating WASM client...');
|
||||
let local_client = await clientBuilder.start_client();
|
||||
console.log('WASM client running!');
|
||||
@@ -256,10 +222,10 @@ async function normalNymClientUsage() {
|
||||
|
||||
debug.topology_refresh_rate_ms = BigInt(60000)
|
||||
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
|
||||
const config = new Config('my-awesome-wasm-client', validator, debug);
|
||||
const config = new Config('my-awesome-wasm-client', validator, dummyGateway, debug);
|
||||
|
||||
const onMessageHandler = (message) => {
|
||||
console.log(message);
|
||||
@@ -364,17 +330,14 @@ async function main() {
|
||||
// sets up better stack traces in case of in-rust panics
|
||||
set_panic_hook();
|
||||
|
||||
// show reconnection capabilities
|
||||
// await testerReconnection()
|
||||
|
||||
// run test on simplified and dedicated tester:
|
||||
await testWithTester()
|
||||
// await testWithTester()
|
||||
|
||||
// hook-up the whole client for testing
|
||||
// await testWithNymClient()
|
||||
|
||||
// 'Normal' client setup (to send 'normal' messages)
|
||||
// await normalNymClientUsage()
|
||||
await normalNymClientUsage()
|
||||
}
|
||||
|
||||
// Let's get started!
|
||||
|
||||
@@ -7,49 +7,73 @@
|
||||
#![allow(clippy::drop_copy)]
|
||||
|
||||
use nym_client_core::config::{
|
||||
Acknowledgements as ConfigAcknowledgements, Config as BaseClientConfig,
|
||||
CoverTraffic as ConfigCoverTraffic, DebugConfig as ConfigDebug,
|
||||
GatewayConnection as ConfigGatewayConnection, ReplySurbs as ConfigReplySurbs,
|
||||
Topology as ConfigTopology, Traffic as ConfigTraffic,
|
||||
Acknowledgements as ConfigAcknowledgements, CoverTraffic as ConfigCoverTraffic,
|
||||
DebugConfig as ConfigDebug, GatewayConnection as ConfigGatewayConnection,
|
||||
ReplySurbs as ConfigReplySurbs, Topology as ConfigTopology, Traffic as ConfigTraffic,
|
||||
};
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
pub(crate) base: BaseClientConfig,
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
pub(crate) id: String,
|
||||
|
||||
pub(crate) nym_api_url: Option<Url>,
|
||||
|
||||
pub(crate) disabled_credentials_mode: bool,
|
||||
|
||||
/// Information regarding how the client should choose gateway.
|
||||
/// If unspecified, the client will attempt to load the config from the storage.
|
||||
pub(crate) gateway: Option<IdentityKey>,
|
||||
|
||||
pub(crate) debug: ConfigDebug,
|
||||
|
||||
pub(crate) packet_type: PacketType,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Config {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(id: String, validator_server: String, debug: Option<DebugWasm>) -> Self {
|
||||
pub fn new(
|
||||
id: String,
|
||||
validator_server: String,
|
||||
packet_type: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
debug: Option<Debug>,
|
||||
) -> Self {
|
||||
let packet_type = if let Some(packet_type) = packet_type {
|
||||
match packet_type.as_str() {
|
||||
"outfox" => PacketType::Outfox,
|
||||
_ => PacketType::Mix,
|
||||
}
|
||||
} else {
|
||||
PacketType::Mix
|
||||
};
|
||||
Config {
|
||||
base: BaseClientConfig::new(id, env!("CARGO_PKG_VERSION").to_string())
|
||||
.with_custom_nyxd(vec![validator_server
|
||||
id,
|
||||
nym_api_url: Some(
|
||||
validator_server
|
||||
.parse()
|
||||
.expect("provided url was malformed")])
|
||||
.with_debug_config(debug.map(Into::into).unwrap_or_default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_tester_config<S: Into<String>>(id: S) -> Self {
|
||||
Config {
|
||||
base: BaseClientConfig::new(id.into(), env!("CARGO_PKG_VERSION").to_string())
|
||||
.with_disabled_credentials(true)
|
||||
.with_disabled_cover_traffic(true)
|
||||
.with_disabled_topology_refresh(true),
|
||||
.expect("provided url was malformed"),
|
||||
),
|
||||
disabled_credentials_mode: true,
|
||||
gateway,
|
||||
debug: debug.map(Into::into).unwrap_or_default(),
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TrafficWasm {
|
||||
pub struct Traffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// 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
|
||||
@@ -68,23 +92,14 @@ pub struct TrafficWasm {
|
||||
|
||||
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
pub use_extended_packet_size: bool,
|
||||
|
||||
/// Controls whether the sent packets should use outfox as opposed to the default sphinx.
|
||||
pub use_outfox: bool,
|
||||
}
|
||||
|
||||
impl From<TrafficWasm> for ConfigTraffic {
|
||||
fn from(traffic: TrafficWasm) -> Self {
|
||||
impl From<Traffic> for ConfigTraffic {
|
||||
fn from(traffic: Traffic) -> Self {
|
||||
let use_extended_packet_size = traffic
|
||||
.use_extended_packet_size
|
||||
.then(|| PacketSize::ExtendedPacket32);
|
||||
|
||||
let packet_type = if traffic.use_outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
PacketType::Mix
|
||||
};
|
||||
|
||||
ConfigTraffic {
|
||||
average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms),
|
||||
message_sending_average_delay: Duration::from_millis(
|
||||
@@ -94,28 +109,27 @@ impl From<TrafficWasm> for ConfigTraffic {
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: use_extended_packet_size,
|
||||
packet_type,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigTraffic> for TrafficWasm {
|
||||
impl From<ConfigTraffic> for Traffic {
|
||||
fn from(traffic: ConfigTraffic) -> Self {
|
||||
TrafficWasm {
|
||||
Traffic {
|
||||
average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u64,
|
||||
message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis()
|
||||
as u64,
|
||||
disable_main_poisson_packet_distribution: traffic
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size: traffic.secondary_packet_size.is_some(),
|
||||
use_outfox: traffic.packet_type == PacketType::Outfox,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct CoverTrafficWasm {
|
||||
pub struct CoverTraffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
pub loop_cover_traffic_average_delay_ms: u64,
|
||||
@@ -129,8 +143,8 @@ pub struct CoverTrafficWasm {
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTrafficWasm> for ConfigCoverTraffic {
|
||||
fn from(cover_traffic: CoverTrafficWasm) -> Self {
|
||||
impl From<CoverTraffic> for ConfigCoverTraffic {
|
||||
fn from(cover_traffic: CoverTraffic) -> Self {
|
||||
ConfigCoverTraffic {
|
||||
loop_cover_traffic_average_delay: Duration::from_millis(
|
||||
cover_traffic.loop_cover_traffic_average_delay_ms,
|
||||
@@ -141,9 +155,9 @@ impl From<CoverTrafficWasm> for ConfigCoverTraffic {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigCoverTraffic> for CoverTrafficWasm {
|
||||
impl From<ConfigCoverTraffic> for CoverTraffic {
|
||||
fn from(cover_traffic: ConfigCoverTraffic) -> Self {
|
||||
CoverTrafficWasm {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay_ms: cover_traffic
|
||||
.loop_cover_traffic_average_delay
|
||||
.as_millis() as u64,
|
||||
@@ -155,14 +169,14 @@ impl From<ConfigCoverTraffic> for CoverTrafficWasm {
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct GatewayConnectionWasm {
|
||||
pub struct GatewayConnection {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
pub gateway_response_timeout_ms: u64,
|
||||
}
|
||||
|
||||
impl From<GatewayConnectionWasm> for ConfigGatewayConnection {
|
||||
fn from(gateway_connection: GatewayConnectionWasm) -> Self {
|
||||
impl From<GatewayConnection> for ConfigGatewayConnection {
|
||||
fn from(gateway_connection: GatewayConnection) -> Self {
|
||||
ConfigGatewayConnection {
|
||||
gateway_response_timeout: Duration::from_millis(
|
||||
gateway_connection.gateway_response_timeout_ms,
|
||||
@@ -171,9 +185,9 @@ impl From<GatewayConnectionWasm> for ConfigGatewayConnection {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigGatewayConnection> for GatewayConnectionWasm {
|
||||
impl From<ConfigGatewayConnection> for GatewayConnection {
|
||||
fn from(gateway_connection: ConfigGatewayConnection) -> Self {
|
||||
GatewayConnectionWasm {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis()
|
||||
as u64,
|
||||
}
|
||||
@@ -182,7 +196,7 @@ impl From<ConfigGatewayConnection> for GatewayConnectionWasm {
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct AcknowledgementsWasm {
|
||||
pub struct Acknowledgements {
|
||||
/// 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
|
||||
@@ -200,8 +214,8 @@ pub struct AcknowledgementsWasm {
|
||||
pub ack_wait_addition_ms: u64,
|
||||
}
|
||||
|
||||
impl From<AcknowledgementsWasm> for ConfigAcknowledgements {
|
||||
fn from(acknowledgements: AcknowledgementsWasm) -> Self {
|
||||
impl From<Acknowledgements> for ConfigAcknowledgements {
|
||||
fn from(acknowledgements: Acknowledgements) -> Self {
|
||||
ConfigAcknowledgements {
|
||||
average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms),
|
||||
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
|
||||
@@ -210,9 +224,9 @@ impl From<AcknowledgementsWasm> for ConfigAcknowledgements {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigAcknowledgements> for AcknowledgementsWasm {
|
||||
impl From<ConfigAcknowledgements> for Acknowledgements {
|
||||
fn from(acknowledgements: ConfigAcknowledgements) -> Self {
|
||||
AcknowledgementsWasm {
|
||||
Acknowledgements {
|
||||
average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u64,
|
||||
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
|
||||
ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u64,
|
||||
@@ -222,7 +236,7 @@ impl From<ConfigAcknowledgements> for AcknowledgementsWasm {
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TopologyWasm {
|
||||
pub struct Topology {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
pub topology_refresh_rate_ms: u64,
|
||||
@@ -238,8 +252,8 @@ pub struct TopologyWasm {
|
||||
pub disable_refreshing: bool,
|
||||
}
|
||||
|
||||
impl From<TopologyWasm> for ConfigTopology {
|
||||
fn from(topology: TopologyWasm) -> Self {
|
||||
impl From<Topology> for ConfigTopology {
|
||||
fn from(topology: Topology) -> Self {
|
||||
ConfigTopology {
|
||||
topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms),
|
||||
topology_resolution_timeout: Duration::from_millis(
|
||||
@@ -250,9 +264,9 @@ impl From<TopologyWasm> for ConfigTopology {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigTopology> for TopologyWasm {
|
||||
impl From<ConfigTopology> for Topology {
|
||||
fn from(topology: ConfigTopology) -> Self {
|
||||
TopologyWasm {
|
||||
Topology {
|
||||
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
|
||||
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
|
||||
disable_refreshing: topology.disable_refreshing,
|
||||
@@ -262,7 +276,7 @@ impl From<ConfigTopology> for TopologyWasm {
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ReplySurbsWasm {
|
||||
pub struct ReplySurbs {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
@@ -296,8 +310,8 @@ pub struct ReplySurbsWasm {
|
||||
pub maximum_reply_key_age_ms: u64,
|
||||
}
|
||||
|
||||
impl From<ReplySurbsWasm> for ConfigReplySurbs {
|
||||
fn from(reply_surbs: ReplySurbsWasm) -> Self {
|
||||
impl From<ReplySurbs> for ConfigReplySurbs {
|
||||
fn from(reply_surbs: ReplySurbs) -> Self {
|
||||
ConfigReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
|
||||
@@ -317,9 +331,9 @@ impl From<ReplySurbsWasm> for ConfigReplySurbs {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigReplySurbs> for ReplySurbsWasm {
|
||||
impl From<ConfigReplySurbs> for ReplySurbs {
|
||||
fn from(reply_surbs: ConfigReplySurbs) -> Self {
|
||||
ReplySurbsWasm {
|
||||
ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
|
||||
@@ -341,28 +355,28 @@ impl From<ConfigReplySurbs> for ReplySurbsWasm {
|
||||
// just a helper structure to more easily pass through the JS boundary
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DebugWasm {
|
||||
pub struct Debug {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: TrafficWasm,
|
||||
pub traffic: Traffic,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTrafficWasm,
|
||||
pub cover_traffic: CoverTraffic,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnectionWasm,
|
||||
pub gateway_connection: GatewayConnection,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: AcknowledgementsWasm,
|
||||
pub acknowledgements: Acknowledgements,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: TopologyWasm,
|
||||
pub topology: Topology,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbsWasm,
|
||||
pub reply_surbs: ReplySurbs,
|
||||
}
|
||||
|
||||
impl From<DebugWasm> for ConfigDebug {
|
||||
fn from(debug: DebugWasm) -> Self {
|
||||
impl From<Debug> for ConfigDebug {
|
||||
fn from(debug: Debug) -> Self {
|
||||
ConfigDebug {
|
||||
traffic: debug.traffic.into(),
|
||||
cover_traffic: debug.cover_traffic.into(),
|
||||
@@ -374,9 +388,9 @@ impl From<DebugWasm> for ConfigDebug {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigDebug> for DebugWasm {
|
||||
impl From<ConfigDebug> for Debug {
|
||||
fn from(debug: ConfigDebug) -> Self {
|
||||
DebugWasm {
|
||||
Debug {
|
||||
traffic: debug.traffic.into(),
|
||||
cover_traffic: debug.cover_traffic.into(),
|
||||
gateway_connection: debug.gateway_connection.into(),
|
||||
@@ -388,6 +402,6 @@ impl From<ConfigDebug> for DebugWasm {
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn default_debug() -> DebugWasm {
|
||||
pub fn default_debug() -> Debug {
|
||||
ConfigDebug::default().into()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::client::response_pusher::ResponsePusher;
|
||||
use crate::constants::NODE_TESTER_CLIENT_ID;
|
||||
use crate::error::WasmClientError;
|
||||
use crate::helpers::{
|
||||
parse_recipient, parse_sender_tag, setup_from_topology, setup_gateway_from_api,
|
||||
choose_gateway, gateway_from_topology, parse_recipient, parse_sender_tag,
|
||||
setup_reply_surb_storage_backend,
|
||||
};
|
||||
use crate::storage::traits::FullWasmClientStorage;
|
||||
@@ -15,11 +15,14 @@ use crate::storage::ClientStorage;
|
||||
use crate::topology::WasmNymTopology;
|
||||
use js_sys::Promise;
|
||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core::client::base_client::{
|
||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState, CredentialsToggle,
|
||||
};
|
||||
use nym_client_core::client::inbound_messages::InputMessage;
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_client_core::config::{CoverTraffic, DebugConfig, Topology, Traffic};
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
@@ -27,7 +30,7 @@ use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use rand::{thread_rng, RngCore};
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
@@ -50,18 +53,24 @@ pub struct NymClient {
|
||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
||||
// and if it's dropped, everything will start going offline
|
||||
_task_manager: TaskManager,
|
||||
|
||||
packet_type: PacketType,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct NymClientBuilder {
|
||||
config: Config,
|
||||
custom_topology: Option<NymTopology>,
|
||||
preferred_gateway: Option<IdentityKey>,
|
||||
|
||||
storage_passphrase: Option<String>,
|
||||
reply_surb_storage_backend: browser_backend::Backend,
|
||||
|
||||
on_message: js_sys::Function,
|
||||
|
||||
// unimplemented:
|
||||
bandwidth_controller:
|
||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||
disabled_credentials: bool,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -70,15 +79,17 @@ impl NymClientBuilder {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
on_message: js_sys::Function,
|
||||
preferred_gateway: Option<IdentityKey>,
|
||||
storage_passphrase: Option<String>,
|
||||
) -> Self {
|
||||
NymClientBuilder {
|
||||
reply_surb_storage_backend: setup_reply_surb_storage_backend(config.debug.reply_surbs),
|
||||
config,
|
||||
custom_topology: None,
|
||||
storage_passphrase,
|
||||
on_message,
|
||||
preferred_gateway,
|
||||
bandwidth_controller: None,
|
||||
disabled_credentials: true,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,14 +108,40 @@ impl NymClientBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
let full_config = Config::new_tester_config(NODE_TESTER_CLIENT_ID);
|
||||
let full_config = Config {
|
||||
id: NODE_TESTER_CLIENT_ID.to_string(),
|
||||
nym_api_url: None,
|
||||
disabled_credentials_mode: true,
|
||||
gateway,
|
||||
debug: DebugConfig {
|
||||
traffic: Traffic {
|
||||
disable_main_poisson_packet_distribution: true,
|
||||
..Default::default()
|
||||
},
|
||||
cover_traffic: CoverTraffic {
|
||||
disable_loop_cover_traffic_stream: true,
|
||||
..Default::default()
|
||||
},
|
||||
topology: Topology {
|
||||
disable_refreshing: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
packet_type: PacketType::Mix,
|
||||
};
|
||||
|
||||
NymClientBuilder {
|
||||
reply_surb_storage_backend: setup_reply_surb_storage_backend(
|
||||
full_config.debug.reply_surbs,
|
||||
),
|
||||
config: full_config,
|
||||
custom_topology: Some(topology.into()),
|
||||
on_message,
|
||||
bandwidth_controller: None,
|
||||
disabled_credentials: true,
|
||||
storage_passphrase: None,
|
||||
preferred_gateway: gateway,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,48 +157,59 @@ impl NymClientBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fn initialise_storage(config: &Config, base_storage: ClientStorage) -> FullWasmClientStorage {
|
||||
FullWasmClientStorage {
|
||||
keys_and_gateway_store: base_storage,
|
||||
reply_storage: setup_reply_surb_storage_backend(config.base.debug.reply_surbs),
|
||||
credential_storage: EphemeralCredentialStorage::default(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_client_async(mut self) -> Result<NymClient, WasmClientError> {
|
||||
console_log!("Starting the wasm client");
|
||||
|
||||
let nym_api_endpoints = self.config.base.client.nym_api_urls.clone();
|
||||
let disabled_credentials = if self.disabled_credentials {
|
||||
CredentialsToggle::Disabled
|
||||
} else {
|
||||
CredentialsToggle::Enabled
|
||||
};
|
||||
|
||||
let nym_api_endpoints = match &self.config.nym_api_url {
|
||||
Some(endpoint) => vec![endpoint.clone()],
|
||||
None => Vec::new(),
|
||||
};
|
||||
|
||||
// TODO: this will have to be re-used for surbs. but this is a problem for another PR.
|
||||
let client_store =
|
||||
ClientStorage::new_async(&self.config.base.client.id, self.storage_passphrase.take())
|
||||
.await?;
|
||||
|
||||
let user_chosen = self.preferred_gateway.clone();
|
||||
ClientStorage::new_async(&self.config.id, self.storage_passphrase.take()).await?;
|
||||
|
||||
// if we provided hardcoded topology, get gateway from it, otherwise get it the 'standard' way
|
||||
if let Some(topology) = &self.custom_topology {
|
||||
setup_from_topology(user_chosen, topology, &client_store).await?
|
||||
let gateway_endpoint = if let Some(topology) = &self.custom_topology {
|
||||
gateway_from_topology(
|
||||
&mut thread_rng(),
|
||||
self.config.gateway.as_deref(),
|
||||
topology,
|
||||
&client_store,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
setup_gateway_from_api(&client_store, user_chosen, &nym_api_endpoints).await?
|
||||
choose_gateway(
|
||||
&client_store,
|
||||
self.config.gateway.clone(),
|
||||
&nym_api_endpoints,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
let packet_type = self.config.base.debug.traffic.packet_type;
|
||||
let storage = Self::initialise_storage(&self.config, client_store);
|
||||
let maybe_topology_provider = self.topology_provider();
|
||||
|
||||
let mut base_builder: BaseClientBuilder<_, FullWasmClientStorage> =
|
||||
BaseClientBuilder::<FakeClient<DirectSigningNyxdClient>, _>::new(
|
||||
&self.config.base,
|
||||
storage,
|
||||
None,
|
||||
);
|
||||
let mut base_builder: BaseClientBuilder<_, FullWasmClientStorage> = BaseClientBuilder::new(
|
||||
&gateway_endpoint,
|
||||
&self.config.debug,
|
||||
client_store,
|
||||
self.bandwidth_controller,
|
||||
self.reply_surb_storage_backend,
|
||||
disabled_credentials,
|
||||
nym_api_endpoints,
|
||||
);
|
||||
if let Some(topology_provider) = maybe_topology_provider {
|
||||
base_builder = base_builder.with_topology_provider(topology_provider);
|
||||
}
|
||||
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.packet_type;
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address.to_string();
|
||||
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
@@ -175,7 +223,7 @@ impl NymClientBuilder {
|
||||
client_state: Arc::new(started_client.client_state),
|
||||
_full_topology: None,
|
||||
_task_manager: started_client.task_manager,
|
||||
packet_type,
|
||||
packet_type: self.packet_type,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -189,10 +237,9 @@ impl NymClient {
|
||||
async fn _new(
|
||||
config: Config,
|
||||
on_message: js_sys::Function,
|
||||
preferred_gateway: Option<IdentityKey>,
|
||||
storage_passphrase: Option<String>,
|
||||
) -> Result<NymClient, WasmClientError> {
|
||||
NymClientBuilder::new(config, on_message, preferred_gateway, storage_passphrase)
|
||||
NymClientBuilder::new(config, on_message, storage_passphrase)
|
||||
.start_client_async()
|
||||
.await
|
||||
}
|
||||
@@ -202,11 +249,10 @@ impl NymClient {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
on_message: js_sys::Function,
|
||||
preferred_gateway: Option<IdentityKey>,
|
||||
storage_passphrase: Option<String>,
|
||||
) -> Promise {
|
||||
future_to_promise(async move {
|
||||
Self::_new(config, on_message, preferred_gateway, storage_passphrase)
|
||||
Self::_new(config, on_message, storage_passphrase)
|
||||
.await
|
||||
.into_promise_result()
|
||||
})
|
||||
@@ -273,7 +319,7 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type));
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -300,13 +346,8 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(
|
||||
recipient,
|
||||
message,
|
||||
reply_surbs,
|
||||
lane,
|
||||
Some(self.packet_type),
|
||||
);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -324,7 +365,7 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane, Some(self.packet_type));
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,21 +7,22 @@ use crate::topology::WasmNymTopology;
|
||||
use js_sys::Promise;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_client_core::config;
|
||||
use nym_client_core::init::helpers::current_gateways;
|
||||
use nym_client_core::init::{setup_gateway_from, GatewaySetup, InitialisationDetails};
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_topology::{gateway, NymTopology};
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::client::{IdentityKey, IdentityKeyRef};
|
||||
use nym_validator_client::NymApiClient;
|
||||
use rand::thread_rng;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use url::Url;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_utils::PromisableResult;
|
||||
use wasm_utils::{console_log, PromisableResult};
|
||||
|
||||
// don't get too excited about the name, under the hood it's just a big fat placeholder
|
||||
// with no disk_persistence
|
||||
// with no persistence
|
||||
pub(crate) fn setup_reply_surb_storage_backend(
|
||||
config: config::ReplySurbs,
|
||||
) -> browser_backend::Backend {
|
||||
@@ -78,37 +79,87 @@ pub fn current_network_topology(nym_api_url: String) -> Promise {
|
||||
})
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
client_store: &ClientStorage,
|
||||
chosen_gateway: Option<IdentityKey>,
|
||||
gateways: &[gateway::Node],
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let setup = if client_store.has_full_gateway_info().await? {
|
||||
GatewaySetup::MustLoad
|
||||
} else {
|
||||
GatewaySetup::new_fresh(chosen_gateway.clone(), None)
|
||||
};
|
||||
|
||||
setup_gateway_from(&setup, client_store, client_store, false, Some(gateways))
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_gateway_from_api(
|
||||
pub(crate) async fn choose_gateway(
|
||||
client_store: &ClientStorage,
|
||||
chosen_gateway: Option<IdentityKey>,
|
||||
nym_apis: &[Url],
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let mut rng = thread_rng();
|
||||
let gateways = current_gateways(&mut rng, nym_apis).await?;
|
||||
setup_gateway(client_store, chosen_gateway, &gateways).await
|
||||
) -> Result<GatewayEndpointConfig, WasmClientError> {
|
||||
let existing_gateway_config = client_store.read_gateway_config().await?;
|
||||
|
||||
console_log!("loaded: {:?}", existing_gateway_config);
|
||||
|
||||
if let Some(existing) = existing_gateway_config {
|
||||
if let Some(provided) = &chosen_gateway {
|
||||
if provided != &existing.gateway_id {
|
||||
return Err(WasmClientError::AlreadyRegistered {
|
||||
gateway_config: existing,
|
||||
});
|
||||
}
|
||||
}
|
||||
return Ok(existing);
|
||||
};
|
||||
|
||||
// if NOTHING is specified nor available, choose gateway randomly.
|
||||
let setup = GatewaySetup::new(None, chosen_gateway, None);
|
||||
let config = setup.try_get_gateway_details(nym_apis).await?;
|
||||
|
||||
// perform registration + persist the new gateway info
|
||||
// TODO: this is actually quite bad. we shouldn't be persisting gateway info here since we did not have persisted
|
||||
// the shared key yet. this will only happen when we start the base client itself.
|
||||
// but unfortunately, we can't do much more until we do a bit more refactoring.
|
||||
client_store.store_gateway_config(&config).await?;
|
||||
|
||||
console_log!("stored: {:?}", config);
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_from_topology(
|
||||
explicit_gateway: Option<IdentityKey>,
|
||||
pub(crate) async fn gateway_from_topology<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
explicit_gateway: Option<IdentityKeyRef<'_>>,
|
||||
topology: &NymTopology,
|
||||
client_store: &ClientStorage,
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let gateways = topology.gateways();
|
||||
setup_gateway(client_store, explicit_gateway, gateways).await
|
||||
) -> Result<GatewayEndpointConfig, WasmClientError> {
|
||||
let existing_gateway_config = client_store.read_gateway_config().await?;
|
||||
console_log!("loaded: {:?}", existing_gateway_config);
|
||||
|
||||
let new_gateway: GatewayEndpointConfig = if let Some(provided) = explicit_gateway {
|
||||
if let Some(existing) = existing_gateway_config {
|
||||
// we have stored gateway info and explicitly provided identity key
|
||||
//
|
||||
// check if they match, otherwise return an error
|
||||
return if provided != existing.gateway_id {
|
||||
Err(WasmClientError::AlreadyRegistered {
|
||||
gateway_config: existing,
|
||||
})
|
||||
} else {
|
||||
Ok(existing)
|
||||
};
|
||||
} else {
|
||||
// we have explicitly provided identity key and didn't have any prior stored data
|
||||
//
|
||||
// try to grab details from the topology
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(provided)
|
||||
.map_err(|source| WasmClientError::InvalidGatewayIdentity { source })?;
|
||||
if let Some(gateway) = topology.get_gateway(&gateway_identity) {
|
||||
gateway.clone().into()
|
||||
} else {
|
||||
return Err(WasmClientError::NonExistentGateway {
|
||||
gateway_identity: gateway_identity.to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if let Some(existing) = existing_gateway_config {
|
||||
// we have stored data and didn't provide anything separately - use what's stored!
|
||||
return Ok(existing);
|
||||
} else {
|
||||
// we don't have anything stored nor we have provided anything
|
||||
//
|
||||
// just grab random gateway from our topology
|
||||
topology.random_gateway(rng)?.clone().into()
|
||||
};
|
||||
|
||||
console_log!("storing: {:?}", new_gateway);
|
||||
client_store.store_gateway_config(&new_gateway).await?;
|
||||
Ok(new_gateway)
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@ pub enum ClientStorageError {
|
||||
|
||||
#[error("{typ} cryptographic key is not available in storage")]
|
||||
CryptoKeyNotInStorage { typ: String },
|
||||
|
||||
#[error("the prior gateway details are not available in the storage")]
|
||||
GatewayDetailsNotInStorage,
|
||||
}
|
||||
|
||||
impl From<ClientStorageError> for JsValue {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::storage::errors::ClientStorageError;
|
||||
use js_sys::Promise;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::PersistedGatewayDetails;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_gateway_client::SharedKeys;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
@@ -28,8 +27,8 @@ mod v1 {
|
||||
pub const CORE_STORE: &str = "core";
|
||||
|
||||
// keys
|
||||
pub const CONFIG: &str = "config";
|
||||
pub const GATEWAY_DETAILS: &str = "gateway_details";
|
||||
// TODO: to replace with FULL config
|
||||
pub const GATEWAY_CONFIG: &str = "gateway_config";
|
||||
|
||||
pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair";
|
||||
pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_keypair";
|
||||
@@ -111,32 +110,15 @@ impl ClientStorage {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: persist client's config
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn read_config(&self) -> Result<Option<Config>, ClientStorageError> {
|
||||
pub(crate) async fn read_gateway_config(
|
||||
&self,
|
||||
) -> Result<Option<GatewayEndpointConfig>, ClientStorageError> {
|
||||
self.inner
|
||||
.read_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG))
|
||||
.read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_CONFIG))
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) async fn may_read_gateway_details(
|
||||
&self,
|
||||
) -> Result<Option<PersistedGatewayDetails>, ClientStorageError> {
|
||||
self.inner
|
||||
.read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_DETAILS))
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) async fn must_read_gateway_details(
|
||||
&self,
|
||||
) -> Result<PersistedGatewayDetails, ClientStorageError> {
|
||||
self.may_read_gateway_details()
|
||||
.await?
|
||||
.ok_or(ClientStorageError::GatewayDetailsNotInStorage)
|
||||
}
|
||||
|
||||
async fn may_read_identity_keypair(
|
||||
&self,
|
||||
) -> Result<Option<identity::KeyPair>, ClientStorageError> {
|
||||
@@ -262,33 +244,17 @@ impl ClientStorage {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) async fn store_gateway_details(
|
||||
pub(crate) async fn store_gateway_config(
|
||||
&self,
|
||||
gateway_endpoint: &PersistedGatewayDetails,
|
||||
gateway_endpoint: &GatewayEndpointConfig,
|
||||
) -> Result<(), ClientStorageError> {
|
||||
self.inner
|
||||
.store_value(
|
||||
v1::CORE_STORE,
|
||||
JsValue::from_str(v1::GATEWAY_DETAILS),
|
||||
JsValue::from_str(v1::GATEWAY_CONFIG),
|
||||
gateway_endpoint,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
// TODO: persist client's config
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn store_config(&self, config: &Config) -> Result<(), ClientStorageError> {
|
||||
self.inner
|
||||
.store_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG), config)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) async fn has_full_gateway_info(&self) -> Result<bool, ClientStorageError> {
|
||||
let has_keys = self.may_read_gateway_shared_key().await?.is_some();
|
||||
let has_details = self.may_read_gateway_details().await?.is_some();
|
||||
|
||||
Ok(has_keys && has_details)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
use crate::storage::errors::ClientStorageError;
|
||||
use crate::storage::ClientStorage;
|
||||
use async_trait::async_trait;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::base_client::storage::MixnetClientStorage;
|
||||
use nym_client_core::client::key_manager::persistence::KeyStore;
|
||||
use nym_client_core::client::key_manager::KeyManager;
|
||||
@@ -17,9 +14,9 @@ use wasm_utils::console_log;
|
||||
// temporary until other variants are properly implemented (probably it should get changed into `ClientStorage`
|
||||
// implementing all traits and everything getting combined
|
||||
pub struct FullWasmClientStorage {
|
||||
pub(crate) keys_and_gateway_store: ClientStorage,
|
||||
pub(crate) reply_storage: browser_backend::Backend,
|
||||
pub(crate) credential_storage: EphemeralCredentialStorage,
|
||||
key_store: ClientStorage,
|
||||
reply_storage: browser_backend::Backend,
|
||||
credential_storage: EphemeralCredentialStorage,
|
||||
}
|
||||
|
||||
impl MixnetClientStorage for FullWasmClientStorage {
|
||||
@@ -27,14 +24,12 @@ impl MixnetClientStorage for FullWasmClientStorage {
|
||||
type ReplyStore = browser_backend::Backend;
|
||||
type CredentialStore = EphemeralCredentialStorage;
|
||||
|
||||
type GatewayDetailsStore = ClientStorage;
|
||||
|
||||
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.reply_storage, self.credential_storage)
|
||||
fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.key_store, self.reply_storage, self.credential_storage)
|
||||
}
|
||||
|
||||
fn key_store(&self) -> &Self::KeyStore {
|
||||
&self.keys_and_gateway_store
|
||||
&self.key_store
|
||||
}
|
||||
|
||||
fn reply_store(&self) -> &Self::ReplyStore {
|
||||
@@ -44,10 +39,6 @@ impl MixnetClientStorage for FullWasmClientStorage {
|
||||
fn credential_store(&self) -> &Self::CredentialStore {
|
||||
&self.credential_storage
|
||||
}
|
||||
|
||||
fn gateway_details_store(&self) -> &Self::GatewayDetailsStore {
|
||||
&self.keys_and_gateway_store
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -83,19 +74,3 @@ impl KeyStore for ClientStorage {
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl GatewayDetailsStore for ClientStorage {
|
||||
type StorageError = ClientStorageError;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
|
||||
self.must_read_gateway_details().await
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
self.store_gateway_details(details).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
// due to expansion of #[wasm_bindgen] macro on NodeTestResult
|
||||
#![allow(clippy::drop_non_drop)]
|
||||
|
||||
use crate::error::WasmClientError;
|
||||
use crate::tester::LockedGatewayClient;
|
||||
use js_sys::Promise;
|
||||
use nym_node_tester_utils::processor::Received;
|
||||
use nym_node_tester_utils::receiver::ReceivedReceiver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -15,7 +12,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_utils::{console_log, console_warn};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -111,37 +107,3 @@ impl Drop for TestMarker {
|
||||
self.value.store(false, Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait GatewayReconnection {
|
||||
fn disconnect_from_gateway(&self) -> Promise;
|
||||
|
||||
fn reconnect_to_gateway(&self) -> Promise;
|
||||
}
|
||||
|
||||
impl GatewayReconnection for LockedGatewayClient {
|
||||
fn disconnect_from_gateway(&self) -> Promise {
|
||||
let this = self.clone();
|
||||
|
||||
future_to_promise(async move {
|
||||
let mut guard = this.lock().await;
|
||||
guard
|
||||
.disconnect()
|
||||
.await
|
||||
.map_err(|err| JsValue::from(WasmClientError::from(err)))?;
|
||||
Ok(JsValue::undefined())
|
||||
})
|
||||
}
|
||||
|
||||
fn reconnect_to_gateway(&self) -> Promise {
|
||||
let this = self.clone();
|
||||
|
||||
future_to_promise(async move {
|
||||
let mut guard = this.lock().await;
|
||||
guard
|
||||
.try_reconnect()
|
||||
.await
|
||||
.map_err(|err| JsValue::from(WasmClientError::from(err)))?;
|
||||
Ok(JsValue::undefined())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
use crate::constants::NODE_TESTER_ID;
|
||||
use crate::error::WasmClientError;
|
||||
use crate::helpers::{current_network_topology_async, setup_from_topology};
|
||||
use crate::helpers::{current_network_topology_async, gateway_from_topology};
|
||||
use crate::storage::ClientStorage;
|
||||
use crate::tester::ephemeral_receiver::EphemeralTestReceiver;
|
||||
use crate::tester::helpers::{
|
||||
GatewayReconnection, NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt,
|
||||
NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt,
|
||||
};
|
||||
use crate::topology::WasmNymTopology;
|
||||
use futures::channel::mpsc;
|
||||
@@ -15,7 +15,7 @@ use js_sys::Promise;
|
||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core::client::key_manager::ManagedKeys;
|
||||
use nym_client_core::init::InitialisationDetails;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_node_tester_utils::receiver::SimpleMessageReceiver;
|
||||
@@ -28,6 +28,7 @@ use nym_task::TaskManager;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex as SyncMutex};
|
||||
@@ -73,7 +74,6 @@ pub struct NymNodeTester {
|
||||
#[wasm_bindgen]
|
||||
pub struct NymNodeTesterBuilder {
|
||||
gateway: Option<IdentityKey>,
|
||||
id: Option<String>,
|
||||
|
||||
base_topology: NymTopology,
|
||||
|
||||
@@ -95,11 +95,9 @@ impl NymNodeTesterBuilder {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(
|
||||
base_topology: WasmNymTopology,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> NymNodeTesterBuilder {
|
||||
NymNodeTesterBuilder {
|
||||
id,
|
||||
gateway,
|
||||
base_topology: base_topology.into(),
|
||||
bandwidth_controller: None,
|
||||
@@ -108,51 +106,43 @@ impl NymNodeTesterBuilder {
|
||||
|
||||
async fn _new_with_api(
|
||||
api_url: String,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> Result<Self, WasmClientError> {
|
||||
let topology = current_network_topology_async(api_url).await?;
|
||||
Ok(NymNodeTesterBuilder::new(topology, id, gateway))
|
||||
Ok(NymNodeTesterBuilder::new(topology, gateway))
|
||||
}
|
||||
|
||||
pub fn new_with_api(
|
||||
api_url: String,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> Promise {
|
||||
pub fn new_with_api(gateway: Option<IdentityKey>, api_url: String) -> Promise {
|
||||
future_to_promise(async move {
|
||||
Self::_new_with_api(api_url, id, gateway)
|
||||
Self::_new_with_api(api_url, gateway)
|
||||
.await
|
||||
.into_promise_result()
|
||||
})
|
||||
}
|
||||
|
||||
async fn gateway_info(
|
||||
async fn gateway_info<R: Rng + CryptoRng>(
|
||||
&self,
|
||||
rng: &mut R,
|
||||
client_store: &ClientStorage,
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
if let Ok(loaded) = InitialisationDetails::try_load(client_store, client_store).await {
|
||||
Ok(loaded)
|
||||
} else {
|
||||
setup_from_topology(self.gateway.clone(), &self.base_topology, client_store).await
|
||||
}
|
||||
) -> Result<GatewayEndpointConfig, WasmClientError> {
|
||||
gateway_from_topology(
|
||||
rng,
|
||||
self.gateway.as_deref(),
|
||||
&self.base_topology,
|
||||
client_store,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn _setup_client(mut self) -> Result<NymNodeTester, WasmClientError> {
|
||||
let mut rng = OsRng;
|
||||
let task_manager = TaskManager::default();
|
||||
|
||||
let storage_id = if let Some(client_id) = &self.id {
|
||||
format!("{NODE_TESTER_ID}-{client_id}")
|
||||
} else {
|
||||
NODE_TESTER_ID.to_owned()
|
||||
};
|
||||
let client_store = ClientStorage::new_async(NODE_TESTER_ID, None).await?;
|
||||
|
||||
let client_store = ClientStorage::new_async(&storage_id, None).await?;
|
||||
|
||||
let init_details = self.gateway_info(&client_store).await?;
|
||||
let gateway_endpoint = init_details.gateway_details;
|
||||
let gateway_endpoint = self.gateway_info(&mut rng, &client_store).await?;
|
||||
let gateway_identity = gateway_endpoint.try_get_gateway_identity_key()?;
|
||||
let managed_keys = init_details.managed_keys;
|
||||
let mut managed_keys = ManagedKeys::load_or_generate(&mut rng, &client_store).await;
|
||||
|
||||
let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded();
|
||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
||||
@@ -161,7 +151,7 @@ impl NymNodeTesterBuilder {
|
||||
gateway_endpoint.gateway_listener,
|
||||
managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
managed_keys.gateway_shared_key(),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
Duration::from_secs(10),
|
||||
@@ -170,11 +160,14 @@ impl NymNodeTesterBuilder {
|
||||
);
|
||||
|
||||
gateway_client.set_disabled_credentials_mode(true);
|
||||
gateway_client.authenticate_and_start().await?;
|
||||
let shared_keys = gateway_client.authenticate_and_start().await?;
|
||||
managed_keys
|
||||
.deal_with_gateway_key(shared_keys, &client_store)
|
||||
.await?;
|
||||
|
||||
// TODO: make those values configurable later
|
||||
let tester = NodeTester::new(
|
||||
OsRng,
|
||||
rng,
|
||||
self.base_topology,
|
||||
Some(address(&managed_keys, gateway_identity)),
|
||||
PacketSize::default(),
|
||||
@@ -248,46 +241,29 @@ async fn test_mixnode(
|
||||
impl NymNodeTester {
|
||||
#[wasm_bindgen(constructor)]
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(
|
||||
topology: WasmNymTopology,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> Promise {
|
||||
pub fn new(topology: WasmNymTopology, gateway: Option<IdentityKey>) -> Promise {
|
||||
console_log!("constructing node tester!");
|
||||
NymNodeTesterBuilder::new(topology, id, gateway).setup_client()
|
||||
NymNodeTesterBuilder::new(topology, gateway).setup_client()
|
||||
}
|
||||
|
||||
async fn _new_with_api(
|
||||
api_url: String,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> Result<Self, WasmClientError> {
|
||||
NymNodeTesterBuilder::_new_with_api(api_url, id, gateway)
|
||||
NymNodeTesterBuilder::_new_with_api(api_url, gateway)
|
||||
.await?
|
||||
._setup_client()
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn new_with_api(
|
||||
api_url: String,
|
||||
id: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
) -> Promise {
|
||||
pub fn new_with_api(api_url: String, gateway: Option<IdentityKey>) -> Promise {
|
||||
future_to_promise(async move {
|
||||
Self::_new_with_api(api_url, id, gateway)
|
||||
Self::_new_with_api(api_url, gateway)
|
||||
.await
|
||||
.into_promise_result()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn disconnect_from_gateway(&self) -> Promise {
|
||||
self.gateway_client.disconnect_from_gateway()
|
||||
}
|
||||
|
||||
pub fn reconnect_to_gateway(&self) -> Promise {
|
||||
self.gateway_client.reconnect_to_gateway()
|
||||
}
|
||||
|
||||
fn prepare_test_packets(
|
||||
&self,
|
||||
mixnode_identity: String,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-bin-common"
|
||||
version = "0.6.0"
|
||||
version = "0.5.0"
|
||||
description = "Common code for nym binaries"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -15,21 +15,15 @@ clap_complete_fig = "4.0"
|
||||
log = { workspace = true }
|
||||
pretty_env_logger = "0.4.0"
|
||||
semver = "0.11"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
|
||||
## tracing
|
||||
tracing-appender = { version = "0.2.2", optional = true }
|
||||
tracing-subscriber = { version = "0.3.16", features = [
|
||||
"env-filter",
|
||||
], optional = true }
|
||||
tracing-tree = { version = "0.2.2", optional = true }
|
||||
opentelemetry-jaeger = { version = "0.18.0", optional = true, features = [
|
||||
"rt-tokio",
|
||||
"collector_client",
|
||||
"isahc_collector_client",
|
||||
] }
|
||||
tracing-opentelemetry = { version = "0.19.0", optional = true }
|
||||
opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] }
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
@@ -42,11 +36,5 @@ vergen = { version = "=7.4.3", default-features = false, features = [
|
||||
|
||||
[features]
|
||||
default = []
|
||||
output_format = ["serde_json"]
|
||||
tracing = [
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
"opentelemetry-jaeger",
|
||||
"tracing-opentelemetry",
|
||||
"opentelemetry",
|
||||
]
|
||||
output_format = ["serde", "serde_json"]
|
||||
tracing = ["tracing-appender", "tracing-subscriber", "tracing-tree"]
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
// TODO: at a later date this crate should probably also expose `ContractBuildInformation`
|
||||
// and be used by our smart contracts
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryBuildInformation {
|
||||
// VERGEN_BUILD_TIMESTAMP
|
||||
@@ -101,7 +99,8 @@ impl BinaryBuildInformation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct BinaryBuildInformationOwned {
|
||||
// VERGEN_BUILD_TIMESTAMP
|
||||
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
|
||||
|
||||
@@ -4,7 +4,5 @@
|
||||
pub mod build_information;
|
||||
pub mod completions;
|
||||
pub mod logging;
|
||||
pub mod version_checker;
|
||||
|
||||
#[cfg(feature = "output_format")]
|
||||
pub mod output_format;
|
||||
pub mod version_checker;
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use tracing_subscriber::{
|
||||
// fmt::Layer, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry,
|
||||
// };
|
||||
// use tracing_tree::HierarchicalLayer;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use opentelemetry;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use opentelemetry_jaeger;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_opentelemetry;
|
||||
pub use tracing_appender;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_subscriber;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_tree;
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LoggingSettings {
|
||||
// well, we need to implement something here at some point...
|
||||
}
|
||||
|
||||
// I'd argue we should start transitioning from `log` to `tracing`
|
||||
pub fn setup_logging() {
|
||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||
@@ -47,35 +39,27 @@ pub fn setup_logging() {
|
||||
#[cfg(feature = "tracing")]
|
||||
#[macro_export]
|
||||
macro_rules! setup_tracing {
|
||||
($service_name: expr) => {
|
||||
($file_name: expr) => {
|
||||
use nym_bin_common::logging::tracing_subscriber::layer::SubscriberExt;
|
||||
use nym_bin_common::logging::tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
let registry = nym_bin_common::logging::tracing_subscriber::Registry::default()
|
||||
let file_appender =
|
||||
nym_bin_common::logging::tracing_appender::rolling::hourly($file_name, "log");
|
||||
let (non_blocking, _guard) =
|
||||
nym_bin_common::logging::tracing_appender::non_blocking(file_appender);
|
||||
let appender_layer = nym_bin_common::logging::tracing_subscriber::fmt::Layer::new()
|
||||
.with_ansi(false)
|
||||
.with_writer(non_blocking);
|
||||
|
||||
nym_bin_common::logging::tracing_subscriber::Registry::default()
|
||||
.with(nym_bin_common::logging::tracing_subscriber::EnvFilter::from_default_env())
|
||||
.with(appender_layer)
|
||||
.with(
|
||||
nym_bin_common::logging::tracing_tree::HierarchicalLayer::new(4)
|
||||
.with_targets(true)
|
||||
.with_bracketed_fields(true),
|
||||
);
|
||||
|
||||
let tracer = nym_bin_common::logging::opentelemetry_jaeger::new_collector_pipeline()
|
||||
.with_endpoint("http://44.199.230.10:14268/api/traces")
|
||||
.with_service_name($service_name)
|
||||
.with_isahc()
|
||||
.with_trace_config(
|
||||
nym_bin_common::logging::opentelemetry::sdk::trace::config().with_sampler(
|
||||
nym_bin_common::logging::opentelemetry::sdk::trace::Sampler::TraceIdRatioBased(
|
||||
0.1,
|
||||
),
|
||||
),
|
||||
)
|
||||
.install_batch(nym_bin_common::logging::opentelemetry::runtime::Tokio)
|
||||
.expect("Could not init tracer");
|
||||
|
||||
let telemetry = nym_bin_common::logging::tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
registry.with(telemetry).init();
|
||||
.init();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client-core"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
@@ -9,7 +9,6 @@ rust-version = "1.66"
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
base64 = "0.21.2"
|
||||
dirs = "4.0"
|
||||
dashmap = "5.4.0"
|
||||
futures = "0.3"
|
||||
@@ -18,7 +17,6 @@ log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = "0.10.6"
|
||||
tap = "1.0.1"
|
||||
thiserror = "1.0.34"
|
||||
url = { version ="2.2", features = ["serde"] }
|
||||
|
||||
@@ -42,6 +42,7 @@ use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use rand::rngs::OsRng;
|
||||
use std::sync::Arc;
|
||||
use tap::TapFallible;
|
||||
use url::Url;
|
||||
@@ -49,8 +50,6 @@ use url::Url;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||
|
||||
use crate::client::base_client::storage::gateway_details::GatewayDetailsStore;
|
||||
use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
@@ -158,11 +157,17 @@ impl From<bool> for CredentialsToggle {
|
||||
}
|
||||
|
||||
pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
|
||||
config: &'a Config,
|
||||
client_store: S,
|
||||
dkg_query_client: Option<C>,
|
||||
// due to wasm limitations I had to split it like this : (
|
||||
gateway_config: &'a GatewayEndpointConfig,
|
||||
debug_config: &'a DebugConfig,
|
||||
disabled_credentials: bool,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
reply_storage_backend: S::ReplyStore,
|
||||
key_store: S::KeyStore,
|
||||
|
||||
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
||||
setup_method: GatewaySetup,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
managed_keys: ManagedKeys,
|
||||
}
|
||||
|
||||
impl<'a, C, S> BaseClientBuilder<'a, C, S>
|
||||
@@ -170,23 +175,47 @@ where
|
||||
S: MixnetClientStorage + 'static,
|
||||
C: DkgQueryClient + Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
base_config: &'a Config,
|
||||
client_store: S,
|
||||
dkg_query_client: Option<C>,
|
||||
// TODO: combine all storages
|
||||
pub fn new_from_base_config<T>(
|
||||
base_config: &'a Config<T>,
|
||||
key_store: S::KeyStore,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
reply_storage_backend: S::ReplyStore,
|
||||
) -> BaseClientBuilder<'a, C, S> {
|
||||
BaseClientBuilder {
|
||||
config: base_config,
|
||||
client_store,
|
||||
dkg_query_client,
|
||||
gateway_config: base_config.get_gateway_endpoint_config(),
|
||||
debug_config: base_config.get_debug_config(),
|
||||
disabled_credentials: base_config.get_disabled_credentials_mode(),
|
||||
nym_api_endpoints: base_config.get_nym_api_endpoints(),
|
||||
bandwidth_controller,
|
||||
reply_storage_backend,
|
||||
key_store,
|
||||
managed_keys: ManagedKeys::Invalidated,
|
||||
custom_topology_provider: None,
|
||||
setup_method: GatewaySetup::MustLoad,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
|
||||
self.setup_method = setup;
|
||||
self
|
||||
// TODO: combine all storages
|
||||
pub fn new(
|
||||
gateway_config: &'a GatewayEndpointConfig,
|
||||
debug_config: &'a DebugConfig,
|
||||
key_store: S::KeyStore,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
reply_storage_backend: S::ReplyStore,
|
||||
credentials_toggle: CredentialsToggle,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
) -> BaseClientBuilder<'a, C, S> {
|
||||
BaseClientBuilder {
|
||||
gateway_config,
|
||||
debug_config,
|
||||
disabled_credentials: credentials_toggle.is_disabled(),
|
||||
nym_api_endpoints,
|
||||
reply_storage_backend,
|
||||
custom_topology_provider: None,
|
||||
bandwidth_controller,
|
||||
key_store,
|
||||
managed_keys: ManagedKeys::Invalidated,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_topology_provider(
|
||||
@@ -199,16 +228,13 @@ where
|
||||
|
||||
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
|
||||
// because it relies on the crypto keys being already loaded
|
||||
fn mix_address(
|
||||
managed_keys: &ManagedKeys,
|
||||
gateway_config: &GatewayEndpointConfig,
|
||||
) -> Recipient {
|
||||
fn as_mix_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*managed_keys.identity_public_key(),
|
||||
*managed_keys.encryption_public_key(),
|
||||
*self.managed_keys.identity_public_key(),
|
||||
*self.managed_keys.encryption_public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(&gateway_config.gateway_id).unwrap(),
|
||||
NodeIdentity::from_base58_string(&self.gateway_config.gateway_id).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -292,10 +318,7 @@ where
|
||||
}
|
||||
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
gateway_config: GatewayEndpointConfig,
|
||||
managed_keys: &ManagedKeys,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
&mut self,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
shutdown: TaskClient,
|
||||
@@ -304,26 +327,33 @@ where
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
|
||||
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let gateway_address = gateway_config.gateway_listener.clone();
|
||||
let gateway_id = gateway_config.gateway_id;
|
||||
let gateway_id = self.gateway_config.gateway_id.clone();
|
||||
if gateway_id.is_empty() {
|
||||
return Err(ClientCoreError::GatewayIdUnknown);
|
||||
}
|
||||
let gateway_address = self.gateway_config.gateway_listener.clone();
|
||||
if gateway_address.is_empty() {
|
||||
return Err(ClientCoreError::GatewayAddressUnknown);
|
||||
}
|
||||
|
||||
// TODO: in theory, at this point, this should be infallible
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
managed_keys.identity_keypair(),
|
||||
self.managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
self.managed_keys.gateway_shared_key(),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
config.debug.gateway_connection.gateway_response_timeout,
|
||||
bandwidth_controller,
|
||||
self.debug_config
|
||||
.gateway_connection
|
||||
.gateway_response_timeout,
|
||||
self.bandwidth_controller.take(),
|
||||
shutdown,
|
||||
);
|
||||
|
||||
gateway_client.set_disabled_credentials_mode(config.client.disabled_credentials_mode);
|
||||
gateway_client.set_disabled_credentials_mode(self.disabled_credentials);
|
||||
|
||||
let shared_key = gateway_client
|
||||
.authenticate_and_start()
|
||||
@@ -332,7 +362,12 @@ where
|
||||
log::error!("Could not authenticate and start up the gateway connection - {err}")
|
||||
})?;
|
||||
|
||||
managed_keys.ensure_gateway_key(shared_key);
|
||||
self.managed_keys
|
||||
.deal_with_gateway_key(shared_key, &self.key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})?;
|
||||
|
||||
Ok(gateway_client)
|
||||
}
|
||||
@@ -438,41 +473,24 @@ where
|
||||
Ok(mem_store)
|
||||
}
|
||||
|
||||
async fn initialise_keys_and_gateway(&self) -> Result<InitialisationDetails, ClientCoreError>
|
||||
where
|
||||
<S::KeyStore as KeyStore>::StorageError: Sync + Send,
|
||||
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
|
||||
{
|
||||
setup_gateway(
|
||||
&self.setup_method,
|
||||
self.client_store.key_store(),
|
||||
self.client_store.gateway_details_store(),
|
||||
false,
|
||||
Some(&self.config.client.nym_api_urls),
|
||||
)
|
||||
.await
|
||||
async fn initial_key_setup(&mut self) {
|
||||
assert!(!self.managed_keys.is_valid());
|
||||
let mut rng = OsRng;
|
||||
self.managed_keys = ManagedKeys::load_or_generate(&mut rng, &self.key_store).await;
|
||||
}
|
||||
|
||||
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
|
||||
pub async fn start_base(
|
||||
mut self,
|
||||
packet_type: PacketType,
|
||||
) -> Result<BaseClient, ClientCoreError>
|
||||
where
|
||||
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send,
|
||||
S::ReplyStore: Send + Sync,
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync,
|
||||
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send,
|
||||
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
|
||||
{
|
||||
info!("Starting nym client");
|
||||
|
||||
// derive (or load) client keys and gateway configuration
|
||||
let details = self.initialise_keys_and_gateway().await?;
|
||||
let gateway_config = details.gateway_details;
|
||||
let managed_keys = details.managed_keys;
|
||||
|
||||
let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores();
|
||||
|
||||
let bandwidth_controller = self
|
||||
.dkg_query_client
|
||||
.map(|client| BandwidthController::new(credential_store, client));
|
||||
self.initial_key_setup().await;
|
||||
|
||||
// channels for inter-component communication
|
||||
// TODO: make the channels be internally created by the relevant components
|
||||
@@ -500,39 +518,34 @@ where
|
||||
let (reply_controller_sender, reply_controller_receiver) =
|
||||
reply_controller::requests::new_control_channels();
|
||||
|
||||
let self_address = Self::mix_address(&managed_keys, &gateway_config);
|
||||
let self_address = self.as_mix_recipient();
|
||||
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
// do not change that.
|
||||
let gateway_client = Self::start_gateway_client(
|
||||
self.config,
|
||||
gateway_config,
|
||||
&managed_keys,
|
||||
bandwidth_controller,
|
||||
mixnet_messages_sender,
|
||||
ack_sender,
|
||||
let gateway_client = self
|
||||
.start_gateway_client(mixnet_messages_sender, ack_sender, task_manager.subscribe())
|
||||
.await?;
|
||||
|
||||
let reply_storage = Self::setup_persistent_reply_storage(
|
||||
self.reply_storage_backend,
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let reply_storage =
|
||||
Self::setup_persistent_reply_storage(reply_storage_backend, task_manager.subscribe())
|
||||
.await?;
|
||||
|
||||
let topology_provider = Self::setup_topology_provider(
|
||||
self.custom_topology_provider.take(),
|
||||
self.config.get_nym_api_endpoints(),
|
||||
self.nym_api_endpoints,
|
||||
);
|
||||
Self::start_topology_refresher(
|
||||
topology_provider,
|
||||
self.config.debug.topology,
|
||||
self.debug_config.topology,
|
||||
shared_topology_accessor.clone(),
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Self::start_received_messages_buffer_controller(
|
||||
managed_keys.encryption_keypair(),
|
||||
self.managed_keys.encryption_keypair(),
|
||||
received_buffer_request_receiver,
|
||||
mixnet_messages_receiver,
|
||||
reply_storage.key_storage(),
|
||||
@@ -556,8 +569,8 @@ where
|
||||
let shared_lane_queue_lengths = LaneQueueLengths::new();
|
||||
|
||||
let controller_config = real_messages_control::Config::new(
|
||||
&self.config.debug,
|
||||
managed_keys.ack_key(),
|
||||
self.debug_config,
|
||||
self.managed_keys.ack_key(),
|
||||
self_address,
|
||||
);
|
||||
|
||||
@@ -573,18 +586,17 @@ where
|
||||
shared_lane_queue_lengths.clone(),
|
||||
client_connection_rx,
|
||||
task_manager.subscribe(),
|
||||
self.config.debug.traffic.packet_type,
|
||||
packet_type,
|
||||
);
|
||||
|
||||
if !self
|
||||
.config
|
||||
.debug
|
||||
.debug_config
|
||||
.cover_traffic
|
||||
.disable_loop_cover_traffic_stream
|
||||
{
|
||||
Self::start_cover_traffic_stream(
|
||||
&self.config.debug,
|
||||
managed_keys.ack_key(),
|
||||
self.debug_config,
|
||||
self.managed_keys.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor.clone(),
|
||||
message_sender,
|
||||
|
||||
@@ -101,8 +101,8 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_bandwidth_controller<St: CredentialStorage>(
|
||||
config: &Config,
|
||||
pub fn create_bandwidth_controller<T, St: CredentialStorage>(
|
||||
config: &Config<T>,
|
||||
storage: St,
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, St> {
|
||||
let nyxd_url = config
|
||||
@@ -122,30 +122,13 @@ pub fn create_bandwidth_controller_with_urls<St: CredentialStorage>(
|
||||
nym_api_url: Url,
|
||||
storage: St,
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, St> {
|
||||
let client = default_query_dkg_client(nyxd_url, nym_api_url);
|
||||
|
||||
BandwidthController::new(storage, client)
|
||||
}
|
||||
|
||||
pub fn default_query_dkg_client_from_config(config: &Config) -> Client<QueryNyxdClient> {
|
||||
let nyxd_url = config
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
|
||||
default_query_dkg_client(nyxd_url, api_url)
|
||||
}
|
||||
|
||||
pub fn default_query_dkg_client(nyxd_url: Url, nym_api_url: Url) -> Client<QueryNyxdClient> {
|
||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config = nym_validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, nym_api_url);
|
||||
nym_validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client")
|
||||
let client = nym_validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
|
||||
BandwidthController::new(storage, client)
|
||||
}
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::GatewayEndpointConfig;
|
||||
use async_trait::async_trait;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::error::Error;
|
||||
use std::ops::Deref;
|
||||
use tokio::sync::Mutex;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait GatewayDetailsStore {
|
||||
type StorageError: Error;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError>;
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistedGatewayDetails {
|
||||
// TODO: should we also verify correctness of the details themselves?
|
||||
// i.e. we could include a checksum or tag (via the shared keys)
|
||||
// counterargument: if we wanted to modify, say, the host information in the stored file on disk,
|
||||
// in order to actually use it, we'd have to recompute the whole checksum which would be a huge pain.
|
||||
/// The hash of the shared keys to ensure the correct ones are used with those gateway details.
|
||||
#[serde(with = "base64")]
|
||||
key_hash: Vec<u8>,
|
||||
|
||||
/// Actual gateway details being persisted.
|
||||
pub(crate) details: GatewayEndpointConfig,
|
||||
}
|
||||
|
||||
impl From<PersistedGatewayDetails> for GatewayEndpointConfig {
|
||||
fn from(value: PersistedGatewayDetails) -> Self {
|
||||
value.details
|
||||
}
|
||||
}
|
||||
|
||||
impl PersistedGatewayDetails {
|
||||
pub fn new(details: GatewayEndpointConfig, shared_key: &SharedKeys) -> Self {
|
||||
let key_bytes = Zeroizing::new(shared_key.to_bytes());
|
||||
|
||||
let mut key_hasher = Sha256::new();
|
||||
key_hasher.update(&key_bytes);
|
||||
let key_hash = key_hasher.finalize().to_vec();
|
||||
|
||||
PersistedGatewayDetails { key_hash, details }
|
||||
}
|
||||
|
||||
pub fn verify(&self, shared_key: &SharedKeys) -> bool {
|
||||
let key_bytes = Zeroizing::new(shared_key.to_bytes());
|
||||
|
||||
let mut key_hasher = Sha256::new();
|
||||
key_hasher.update(&key_bytes);
|
||||
let key_hash = key_hasher.finalize();
|
||||
|
||||
self.key_hash == key_hash.deref()
|
||||
}
|
||||
}
|
||||
|
||||
// helper to make Vec<u8> serialization use base64 representation to make it human readable
|
||||
// so that it would be easier for users to copy contents from the disk if they wanted to use it elsewhere
|
||||
mod base64 {
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_str(&STANDARD.encode(bytes))
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
|
||||
let s = <String>::deserialize(deserializer)?;
|
||||
STANDARD.decode(s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum OnDiskGatewayDetailsError {
|
||||
#[error("JSON failure: {0}")]
|
||||
SerializationFailure(#[from] serde_json::Error),
|
||||
|
||||
#[error("failed to store gateway details to {path}: {err}")]
|
||||
StoreFailure {
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
#[error("failed to load gateway details from {path}: {err}")]
|
||||
LoadFailure {
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct OnDiskGatewayDetails {
|
||||
file_location: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl OnDiskGatewayDetails {
|
||||
pub fn new<P: AsRef<std::path::Path>>(path: P) -> Self {
|
||||
OnDiskGatewayDetails {
|
||||
file_location: path.as_ref().to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_disk(&self) -> Result<PersistedGatewayDetails, OnDiskGatewayDetailsError> {
|
||||
let file = std::fs::File::open(&self.file_location).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::LoadFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(serde_json::from_reader(file)?)
|
||||
}
|
||||
|
||||
pub fn store_to_disk(
|
||||
&self,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), OnDiskGatewayDetailsError> {
|
||||
// ensure the whole directory structure exists
|
||||
if let Some(parent_dir) = &self.file_location.parent() {
|
||||
std::fs::create_dir_all(parent_dir).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::StoreFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?
|
||||
}
|
||||
|
||||
let file = std::fs::File::create(&self.file_location).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::StoreFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(serde_json::to_writer_pretty(file, details)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl GatewayDetailsStore for OnDiskGatewayDetails {
|
||||
type StorageError = OnDiskGatewayDetailsError;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
|
||||
self.load_from_disk()
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
gateway_details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
self.store_to_disk(gateway_details)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InMemGatewayDetails {
|
||||
details: Mutex<Option<PersistedGatewayDetails>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("old ephemeral gateway details can't be loaded from storage")]
|
||||
pub struct EphemeralGatewayDetailsError;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl GatewayDetailsStore for InMemGatewayDetails {
|
||||
type StorageError = EphemeralGatewayDetailsError;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
|
||||
self.details
|
||||
.lock()
|
||||
.await
|
||||
.clone()
|
||||
.ok_or(EphemeralGatewayDetailsError)
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
gateway_details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
*self.details.lock().await = Some(gateway_details.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -4,57 +4,46 @@
|
||||
// TODO: combine those more closely. Perhaps into a single underlying store.
|
||||
// Like for persistent, on-disk, storage, what's the point of having 3 different databases?
|
||||
|
||||
use crate::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, InMemGatewayDetails,
|
||||
};
|
||||
use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore};
|
||||
use crate::client::replies::reply_storage;
|
||||
use crate::client::replies::reply_storage::ReplyStorageBackend;
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
||||
use nym_credential_storage::ephemeral_storage::{
|
||||
EphemeralStorage as EphemeralCredentialStorage, EphemeralStorage,
|
||||
};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::base_client::non_wasm_helpers;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::key_manager::persistence::OnDiskKeys;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::replies::reply_storage::fs_backend;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::config::{self, disk_persistence::CommonClientPaths};
|
||||
use crate::config::{persistence::key_pathfinder::ClientKeyPathfinder, Config};
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::error::ClientCoreError;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
pub mod gateway_details;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::replies::reply_storage::fs_backend;
|
||||
|
||||
// TODO: ideally this should be changed into
|
||||
// `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewayDetailsStore`
|
||||
pub trait MixnetClientStorage {
|
||||
type KeyStore: KeyStore;
|
||||
type ReplyStore: ReplyStorageBackend;
|
||||
type CredentialStore: CredentialStorage;
|
||||
type GatewayDetailsStore: GatewayDetailsStore;
|
||||
|
||||
// this is a TERRIBLE name...
|
||||
// fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore, Self::GatewayDetailsStore);
|
||||
|
||||
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore);
|
||||
fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore);
|
||||
|
||||
fn key_store(&self) -> &Self::KeyStore;
|
||||
fn reply_store(&self) -> &Self::ReplyStore;
|
||||
fn credential_store(&self) -> &Self::CredentialStore;
|
||||
fn gateway_details_store(&self) -> &Self::GatewayDetailsStore;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Ephemeral {
|
||||
key_store: InMemEphemeralKeys,
|
||||
reply_store: reply_storage::Empty,
|
||||
credential_store: EphemeralCredentialStorage,
|
||||
gateway_details_store: InMemGatewayDetails,
|
||||
credential_store: EphemeralStorage,
|
||||
}
|
||||
|
||||
impl Ephemeral {
|
||||
@@ -67,10 +56,9 @@ impl MixnetClientStorage for Ephemeral {
|
||||
type KeyStore = InMemEphemeralKeys;
|
||||
type ReplyStore = reply_storage::Empty;
|
||||
type CredentialStore = EphemeralCredentialStorage;
|
||||
type GatewayDetailsStore = InMemGatewayDetails;
|
||||
|
||||
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.reply_store, self.credential_store)
|
||||
fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.key_store, self.reply_store, self.credential_store)
|
||||
}
|
||||
|
||||
fn key_store(&self) -> &Self::KeyStore {
|
||||
@@ -84,10 +72,6 @@ impl MixnetClientStorage for Ephemeral {
|
||||
fn credential_store(&self) -> &Self::CredentialStore {
|
||||
&self.credential_store
|
||||
}
|
||||
|
||||
fn gateway_details_store(&self) -> &Self::GatewayDetailsStore {
|
||||
&self.gateway_details_store
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
@@ -95,7 +79,6 @@ pub struct OnDiskPersistent {
|
||||
pub(crate) key_store: OnDiskKeys,
|
||||
pub(crate) reply_store: fs_backend::Backend,
|
||||
pub(crate) credential_store: PersistentCredentialStorage,
|
||||
pub(crate) gateway_details_store: OnDiskGatewayDetails,
|
||||
}
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
@@ -104,38 +87,31 @@ impl OnDiskPersistent {
|
||||
key_store: OnDiskKeys,
|
||||
reply_store: fs_backend::Backend,
|
||||
credential_store: PersistentCredentialStorage,
|
||||
gateway_details_store: OnDiskGatewayDetails,
|
||||
) -> Self {
|
||||
Self {
|
||||
key_store,
|
||||
reply_store,
|
||||
credential_store,
|
||||
gateway_details_store,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn from_paths(
|
||||
paths: CommonClientPaths,
|
||||
debug_config: &config::DebugConfig,
|
||||
) -> Result<Self, ClientCoreError> {
|
||||
let key_store = OnDiskKeys::new(paths.keys);
|
||||
pub async fn from_config<T>(config: &Config<T>) -> Result<Self, ClientCoreError> {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
let key_store = OnDiskKeys::new(pathfinder);
|
||||
|
||||
let reply_store = non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||
paths.reply_surb_database,
|
||||
&debug_config.reply_surbs,
|
||||
config.get_reply_surb_database_path(),
|
||||
&config.get_debug_config().reply_surbs,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let credential_store =
|
||||
nym_credential_storage::initialise_persistent_storage(paths.credentials_database).await;
|
||||
|
||||
let gateway_details_store = OnDiskGatewayDetails::new(paths.gateway_details);
|
||||
nym_credential_storage::initialise_persistent_storage(config.get_database_path()).await;
|
||||
|
||||
Ok(OnDiskPersistent {
|
||||
key_store,
|
||||
reply_store,
|
||||
credential_store,
|
||||
gateway_details_store,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -145,10 +121,9 @@ impl MixnetClientStorage for OnDiskPersistent {
|
||||
type KeyStore = OnDiskKeys;
|
||||
type ReplyStore = fs_backend::Backend;
|
||||
type CredentialStore = PersistentCredentialStorage;
|
||||
type GatewayDetailsStore = OnDiskGatewayDetails;
|
||||
|
||||
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.reply_store, self.credential_store)
|
||||
fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.key_store, self.reply_store, self.credential_store)
|
||||
}
|
||||
|
||||
fn key_store(&self) -> &Self::KeyStore {
|
||||
@@ -162,8 +137,4 @@ impl MixnetClientStorage for OnDiskPersistent {
|
||||
fn credential_store(&self) -> &Self::CredentialStore {
|
||||
&self.credential_store
|
||||
}
|
||||
|
||||
fn gateway_details_store(&self) -> &Self::GatewayDetailsStore {
|
||||
&self.gateway_details_store
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use log::*;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::cover::generate_loop_cover_packet;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::utils::sample_poisson_duration;
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::pin::Pin;
|
||||
@@ -63,8 +63,6 @@ where
|
||||
|
||||
/// Optional secondary predefined packet size used for the loop cover messages.
|
||||
secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl<R> Stream for LoopCoverTrafficStream<R>
|
||||
@@ -137,7 +135,6 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
topology_access,
|
||||
primary_packet_size: traffic_config.primary_packet_size,
|
||||
secondary_packet_size: traffic_config.secondary_packet_size,
|
||||
packet_type: traffic_config.packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +194,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
self.average_ack_delay,
|
||||
self.cover_traffic.loop_cover_traffic_average_delay,
|
||||
cover_traffic_packet_size,
|
||||
self.packet_type,
|
||||
nym_sphinx::params::PacketType::Mix,
|
||||
)
|
||||
.expect("Somehow failed to generate a loop cover message with a valid topology");
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
@@ -21,16 +20,6 @@ pub enum ManagedKeys {
|
||||
Invalidated,
|
||||
}
|
||||
|
||||
impl Debug for ManagedKeys {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ManagedKeys::Initial(_) => write!(f, "initial"),
|
||||
ManagedKeys::FullyDerived(_) => write!(f, "fully derived"),
|
||||
ManagedKeys::Invalidated => write!(f, "invalidated"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyManagerBuilder> for ManagedKeys {
|
||||
fn from(value: KeyManagerBuilder) -> Self {
|
||||
ManagedKeys::Initial(value)
|
||||
@@ -95,11 +84,6 @@ impl ManagedKeys {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn must_get_gateway_shared_key(&self) -> Arc<SharedKeys> {
|
||||
self.gateway_shared_key()
|
||||
.expect("failed to extract gateway shared key")
|
||||
}
|
||||
|
||||
pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
|
||||
match self {
|
||||
ManagedKeys::Initial(_) => None,
|
||||
@@ -124,17 +108,6 @@ impl ManagedKeys {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_gateway_key(&self, gateway_shared_key: Arc<SharedKeys>) {
|
||||
if let ManagedKeys::FullyDerived(key_manager) = &self {
|
||||
if !Arc::ptr_eq(&key_manager.gateway_shared_key, &gateway_shared_key)
|
||||
|| key_manager.gateway_shared_key != gateway_shared_key
|
||||
{
|
||||
// this should NEVER happen thus panic here
|
||||
panic!("derived fresh gateway shared key whilst already holding one!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn deal_with_gateway_key<S: KeyStore>(
|
||||
&mut self,
|
||||
gateway_shared_key: Arc<SharedKeys>,
|
||||
@@ -147,7 +120,12 @@ impl ManagedKeys {
|
||||
key_manager
|
||||
}
|
||||
ManagedKeys::FullyDerived(key_manager) => {
|
||||
self.ensure_gateway_key(gateway_shared_key);
|
||||
if !Arc::ptr_eq(&key_manager.gateway_shared_key, &gateway_shared_key)
|
||||
|| key_manager.gateway_shared_key != gateway_shared_key
|
||||
{
|
||||
// this should NEVER happen thus panic here
|
||||
panic!("derived fresh gateway shared key whilst already holding one!")
|
||||
}
|
||||
key_manager
|
||||
}
|
||||
ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
use crate::client::key_manager::KeyManager;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::config::Config;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -37,7 +38,6 @@ pub enum OnDiskKeysError {
|
||||
KeyPairLoadFailure {
|
||||
keys: String,
|
||||
paths: nym_pemstore::KeyPairPath,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
@@ -45,7 +45,6 @@ pub enum OnDiskKeysError {
|
||||
KeyPairStoreFailure {
|
||||
keys: String,
|
||||
paths: nym_pemstore::KeyPairPath,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
@@ -53,7 +52,6 @@ pub enum OnDiskKeysError {
|
||||
KeyLoadFailure {
|
||||
key: String,
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
@@ -61,47 +59,30 @@ pub enum OnDiskKeysError {
|
||||
KeyStoreFailure {
|
||||
key: String,
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct OnDiskKeys {
|
||||
paths: ClientKeysPaths,
|
||||
pathfinder: ClientKeyPathfinder,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl From<ClientKeysPaths> for OnDiskKeys {
|
||||
fn from(paths: ClientKeysPaths) -> Self {
|
||||
OnDiskKeys { paths }
|
||||
impl From<ClientKeyPathfinder> for OnDiskKeys {
|
||||
fn from(pathfinder: ClientKeyPathfinder) -> Self {
|
||||
OnDiskKeys { pathfinder }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl OnDiskKeys {
|
||||
pub fn new(paths: ClientKeysPaths) -> Self {
|
||||
OnDiskKeys { paths }
|
||||
pub fn new(pathfinder: ClientKeyPathfinder) -> Self {
|
||||
OnDiskKeys { pathfinder }
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn ephemeral_load_gateway_keys(
|
||||
&self,
|
||||
) -> Result<zeroize::Zeroizing<SharedKeys>, OnDiskKeysError> {
|
||||
self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")
|
||||
.map(zeroize::Zeroizing::new)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> {
|
||||
let encryption_paths = self.paths.encryption_key_pair_path();
|
||||
self.load_keypair(encryption_paths, "encryption keys")
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> {
|
||||
let identity_paths = self.paths.identity_key_pair_path();
|
||||
self.load_keypair(identity_paths, "identity keys")
|
||||
pub fn from_config<T>(config: &Config<T>) -> Self {
|
||||
OnDiskKeys::new(ClientKeyPathfinder::new_from_config(config))
|
||||
}
|
||||
|
||||
fn load_key<T: PemStorableKey>(
|
||||
@@ -157,12 +138,17 @@ impl OnDiskKeys {
|
||||
}
|
||||
|
||||
fn load_keys(&self) -> Result<KeyManager, OnDiskKeysError> {
|
||||
let identity_keypair = self.load_identity_keypair()?;
|
||||
let encryption_keypair = self.load_encryption_keypair()?;
|
||||
let identity_paths = self.pathfinder.identity_key_pair_path();
|
||||
let encryption_paths = self.pathfinder.encryption_key_pair_path();
|
||||
|
||||
let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
|
||||
let identity_keypair: identity::KeyPair =
|
||||
self.load_keypair(identity_paths, "identity keys")?;
|
||||
let encryption_keypair: encryption::KeyPair =
|
||||
self.load_keypair(encryption_paths, "encryption keys")?;
|
||||
|
||||
let ack_key: AckKey = self.load_key(self.pathfinder.ack_key(), "ack key")?;
|
||||
let gateway_shared_key: SharedKeys =
|
||||
self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")?;
|
||||
self.load_key(self.pathfinder.gateway_shared_key(), "gateway shared keys")?;
|
||||
|
||||
Ok(KeyManager::from_keys(
|
||||
identity_keypair,
|
||||
@@ -173,8 +159,8 @@ impl OnDiskKeys {
|
||||
}
|
||||
|
||||
fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> {
|
||||
let identity_paths = self.paths.identity_key_pair_path();
|
||||
let encryption_paths = self.paths.encryption_key_pair_path();
|
||||
let identity_paths = self.pathfinder.identity_key_pair_path();
|
||||
let encryption_paths = self.pathfinder.encryption_key_pair_path();
|
||||
|
||||
self.store_keypair(
|
||||
keys.identity_keypair.as_ref(),
|
||||
@@ -187,10 +173,10 @@ impl OnDiskKeys {
|
||||
"encryption keys",
|
||||
)?;
|
||||
|
||||
self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?;
|
||||
self.store_key(keys.ack_key.as_ref(), self.pathfinder.ack_key(), "ack key")?;
|
||||
self.store_key(
|
||||
keys.gateway_shared_key.as_ref(),
|
||||
self.paths.gateway_shared_key(),
|
||||
self.pathfinder.gateway_shared_key(),
|
||||
"gateway shared keys",
|
||||
)?;
|
||||
|
||||
@@ -213,12 +199,10 @@ impl KeyStore for OnDiskKeys {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InMemEphemeralKeys {
|
||||
keys: Mutex<Option<KeyManager>>,
|
||||
}
|
||||
pub struct InMemEphemeralKeys;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("old ephemeral keys can't be loaded from storage")]
|
||||
#[error("ephemeral keys can't be loaded from storage")]
|
||||
pub struct EphemeralKeysError;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -227,11 +211,10 @@ impl KeyStore for InMemEphemeralKeys {
|
||||
type StorageError = EphemeralKeysError;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError> {
|
||||
self.keys.lock().await.clone().ok_or(EphemeralKeysError)
|
||||
Err(EphemeralKeysError)
|
||||
}
|
||||
|
||||
async fn store_keys(&self, keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
*self.keys.lock().await = Some(keys.clone());
|
||||
async fn store_keys(&self, _keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use self::sending_delay_controller::SendingDelayController;
|
||||
@@ -247,7 +247,7 @@ where
|
||||
self.config.average_ack_delay,
|
||||
self.config.traffic.average_packet_delay,
|
||||
cover_traffic_packet_size,
|
||||
self.config.traffic.packet_type,
|
||||
self.config.traffic.packet_type.unwrap_or_default(),
|
||||
)
|
||||
.expect(
|
||||
"Somehow failed to generate a loop cover message with a valid topology",
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem";
|
||||
pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem";
|
||||
pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem";
|
||||
pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem";
|
||||
pub const DEFAULT_GATEWAY_SHARED_KEY_FILENAME: &str = "gateway_shared.pem";
|
||||
pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientKeysPaths {
|
||||
/// Path to file containing private identity key.
|
||||
pub private_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public identity key.
|
||||
pub public_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing private encryption key.
|
||||
pub private_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public encryption key.
|
||||
pub public_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing shared key derived with the specified gateway that is used
|
||||
/// for all communication with it.
|
||||
pub gateway_shared_key_file: PathBuf,
|
||||
|
||||
/// 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.
|
||||
pub ack_key_file: PathBuf,
|
||||
}
|
||||
|
||||
impl ClientKeysPaths {
|
||||
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
let base_dir = base_data_directory.as_ref();
|
||||
|
||||
ClientKeysPaths {
|
||||
private_identity_key_file: base_dir.join(DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME),
|
||||
public_identity_key_file: base_dir.join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME),
|
||||
private_encryption_key_file: base_dir.join(DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME),
|
||||
public_encryption_key_file: base_dir.join(DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME),
|
||||
gateway_shared_key_file: base_dir.join(DEFAULT_GATEWAY_SHARED_KEY_FILENAME),
|
||||
ack_key_file: base_dir.join(DEFAULT_ACK_KEY_FILENAME),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identity_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_identity_key().to_path_buf(),
|
||||
self.public_identity_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn encryption_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_encryption_key().to_path_buf(),
|
||||
self.public_encryption_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn any_file_exists(&self) -> bool {
|
||||
matches!(self.public_identity_key_file.try_exists(), Ok(true))
|
||||
|| matches!(self.private_identity_key_file.try_exists(), Ok(true))
|
||||
|| matches!(self.public_encryption_key_file.try_exists(), Ok(true))
|
||||
|| matches!(self.private_encryption_key_file.try_exists(), Ok(true))
|
||||
|| matches!(self.gateway_shared_key_file.try_exists(), Ok(true))
|
||||
|| matches!(self.ack_key_file.try_exists(), Ok(true))
|
||||
}
|
||||
|
||||
pub fn any_file_exists_and_return(&self) -> Option<PathBuf> {
|
||||
file_exists(&self.public_identity_key_file)
|
||||
.or_else(|| file_exists(&self.private_identity_key_file))
|
||||
.or_else(|| file_exists(&self.public_encryption_key_file))
|
||||
.or_else(|| file_exists(&self.private_encryption_key_file))
|
||||
.or_else(|| file_exists(&self.gateway_shared_key_file))
|
||||
.or_else(|| file_exists(&self.ack_key_file))
|
||||
}
|
||||
|
||||
pub fn gateway_key_file_exists(&self) -> bool {
|
||||
matches!(self.gateway_shared_key_file.try_exists(), Ok(true))
|
||||
}
|
||||
|
||||
pub fn private_identity_key(&self) -> &Path {
|
||||
&self.private_identity_key_file
|
||||
}
|
||||
|
||||
pub fn public_identity_key(&self) -> &Path {
|
||||
&self.public_identity_key_file
|
||||
}
|
||||
|
||||
pub fn private_encryption_key(&self) -> &Path {
|
||||
&self.private_encryption_key_file
|
||||
}
|
||||
|
||||
pub fn public_encryption_key(&self) -> &Path {
|
||||
&self.public_encryption_key_file
|
||||
}
|
||||
|
||||
pub fn gateway_shared_key(&self) -> &Path {
|
||||
&self.gateway_shared_key_file
|
||||
}
|
||||
|
||||
pub fn ack_key(&self) -> &Path {
|
||||
&self.ack_key_file
|
||||
}
|
||||
}
|
||||
|
||||
fn file_exists(path: &Path) -> Option<PathBuf> {
|
||||
if matches!(path.try_exists(), Ok(true)) {
|
||||
return Some(path.to_path_buf());
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod keys_paths;
|
||||
pub mod old_v1_1_20_2;
|
||||
|
||||
pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json";
|
||||
pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite";
|
||||
pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPaths {
|
||||
pub keys: ClientKeysPaths,
|
||||
|
||||
/// Path to the file containing information about gateway used by this client,
|
||||
/// i.e. details such as its public key, owner address or the network information.
|
||||
pub gateway_details: PathBuf,
|
||||
|
||||
/// Path to the database containing bandwidth credentials of this client.
|
||||
pub credentials_database: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPaths {
|
||||
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
let base_dir = base_data_directory.as_ref();
|
||||
|
||||
CommonClientPaths {
|
||||
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
|
||||
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
|
||||
gateway_details: base_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
|
||||
keys: ClientKeysPaths::new_default(base_data_directory),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAY_DETAILS_FILENAME};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPathsV1_1_20_2 {
|
||||
pub keys: ClientKeysPaths,
|
||||
pub credentials_database: PathBuf,
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPathsV1_1_20_2 {
|
||||
pub fn upgrade_default(self) -> CommonClientPaths {
|
||||
let data_dir = self
|
||||
.reply_surb_database
|
||||
.parent()
|
||||
.expect("client paths upgrade failure");
|
||||
CommonClientPaths {
|
||||
keys: self.keys,
|
||||
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
|
||||
credentials_database: self.credentials_database,
|
||||
reply_surb_database: self.reply_surb_database,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
@@ -12,10 +15,19 @@ use crate::error::ClientCoreError;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod disk_persistence;
|
||||
pub mod old_config_v1_1_13;
|
||||
pub mod old_config_v1_1_20;
|
||||
pub mod old_config_v1_1_20_2;
|
||||
pub mod persistence;
|
||||
|
||||
pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem";
|
||||
pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem";
|
||||
pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem";
|
||||
pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem";
|
||||
pub const DEFAULT_GATEWAY_KEYS_FILENAME: &str = "gateway_shared.pem";
|
||||
pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem";
|
||||
pub const DEFAULT_REPLY_STORE_FILENAME: &str = "persistent_reply_store.sqlite";
|
||||
pub const DEFAULT_CREDENTIAL_STORE_FILENAME: &str = CRED_DB_FILE_NAME;
|
||||
|
||||
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
||||
|
||||
// 'DEBUG'
|
||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
@@ -56,41 +68,172 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
pub client: Client,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfig,
|
||||
pub fn missing_string_value() -> String {
|
||||
MISSING_VALUE.to_string()
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: Into<String>>(id: S, version: S) -> Self {
|
||||
Config {
|
||||
client: Client::new_default(id, version),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
pub trait ClientCoreConfigTrait {
|
||||
fn get_gateway_endpoint(&self) -> &GatewayEndpointConfig;
|
||||
}
|
||||
|
||||
pub fn from_client_config(client: Client, debug: DebugConfig) -> Self {
|
||||
Config { client, debug }
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config<T> {
|
||||
client: Client<T>,
|
||||
|
||||
#[serde(default)]
|
||||
logging: Logging,
|
||||
#[serde(default)]
|
||||
debug: DebugConfig,
|
||||
}
|
||||
|
||||
impl<T> ClientCoreConfigTrait for Config<T> {
|
||||
fn get_gateway_endpoint(&self) -> &GatewayEndpointConfig {
|
||||
&self.client.gateway_endpoint
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OptionalSet for Config<T> where T: NymConfig {}
|
||||
|
||||
impl<T> Config<T> {
|
||||
pub fn new<S: Into<String>>(id: S) -> Self
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
Config::default().with_id(id)
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.debug.validate()
|
||||
}
|
||||
|
||||
pub fn with_debug_config(mut self, debug: DebugConfig) -> Self {
|
||||
self.debug = debug;
|
||||
#[must_use]
|
||||
pub fn with_id<S: Into<String>>(mut self, id: S) -> Self
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
self.client.id = id.into();
|
||||
self.set_empty_fields_to_defaults();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
// TODO: this totally contradicts our trait... we REALLY have to refactor it...
|
||||
pub fn reset_data_directory<P: AsRef<Path>>(mut self, dir: P) -> Self {
|
||||
self.client.private_identity_key_file =
|
||||
dir.as_ref().join(DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME);
|
||||
self.client.public_identity_key_file =
|
||||
dir.as_ref().join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME);
|
||||
self.client.private_encryption_key_file =
|
||||
dir.as_ref().join(DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME);
|
||||
self.client.public_encryption_key_file =
|
||||
dir.as_ref().join(DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME);
|
||||
self.client.gateway_shared_key_file = dir.as_ref().join(DEFAULT_GATEWAY_KEYS_FILENAME);
|
||||
self.client.ack_key_file = dir.as_ref().join(DEFAULT_ACK_KEY_FILENAME);
|
||||
self.client.reply_surb_database_path = dir.as_ref().join(DEFAULT_REPLY_STORE_FILENAME);
|
||||
self.client.database_path = dir.as_ref().join(DEFAULT_CREDENTIAL_STORE_FILENAME);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
// TODO: this totally contradicts our trait... we REALLY have to refactor it...
|
||||
pub fn reset_nym_root_directory<P: AsRef<Path>>(mut self, dir: P) -> Self
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
self.client.nym_root_directory = dir.as_ref().to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_empty_fields_to_defaults(&mut self) -> bool
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
let id = &self.client.id;
|
||||
let mut changes_made = false;
|
||||
|
||||
// identity key setting
|
||||
if self.client.private_identity_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.private_identity_key_file =
|
||||
self::Client::<T>::default_private_identity_key_file(id);
|
||||
}
|
||||
if self.client.public_identity_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.public_identity_key_file =
|
||||
self::Client::<T>::default_public_identity_key_file(id);
|
||||
}
|
||||
|
||||
// encryption key setting
|
||||
if self
|
||||
.client
|
||||
.private_encryption_key_file
|
||||
.as_os_str()
|
||||
.is_empty()
|
||||
{
|
||||
changes_made = true;
|
||||
self.client.private_encryption_key_file =
|
||||
self::Client::<T>::default_private_encryption_key_file(id);
|
||||
}
|
||||
if self
|
||||
.client
|
||||
.public_encryption_key_file
|
||||
.as_os_str()
|
||||
.is_empty()
|
||||
{
|
||||
changes_made = true;
|
||||
self.client.public_encryption_key_file =
|
||||
self::Client::<T>::default_public_encryption_key_file(id);
|
||||
}
|
||||
|
||||
// shared gateway key setting
|
||||
if self.client.gateway_shared_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.gateway_shared_key_file =
|
||||
self::Client::<T>::default_gateway_shared_key_file(id);
|
||||
}
|
||||
|
||||
// ack key setting
|
||||
if self.client.ack_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.ack_key_file = self::Client::<T>::default_ack_key_file(id);
|
||||
}
|
||||
|
||||
if self.client.reply_surb_database_path.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.reply_surb_database_path =
|
||||
self::Client::<T>::default_reply_surb_database_path(id);
|
||||
}
|
||||
|
||||
if self.client.database_path.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.database_path = self::Client::<T>::default_database_path(id);
|
||||
}
|
||||
changes_made
|
||||
}
|
||||
|
||||
pub fn with_disabled_credentials(mut self, disabled_credentials_mode: bool) -> Self {
|
||||
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpointConfig) {
|
||||
self.client.gateway_endpoint = gateway_endpoint;
|
||||
}
|
||||
|
||||
pub fn with_gateway_endpoint(mut self, gateway_endpoint: GatewayEndpointConfig) -> Self {
|
||||
self.client.gateway_endpoint = gateway_endpoint;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_endpoint.gateway_id = id.into();
|
||||
}
|
||||
|
||||
pub fn with_custom_nyxd(mut self, urls: Vec<Url>) -> Self {
|
||||
self.client.nyxd_urls = urls;
|
||||
self
|
||||
@@ -117,7 +260,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
|
||||
self.debug.traffic.packet_type = packet_type;
|
||||
self.client.packet_type = Some(packet_type);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -137,11 +280,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
|
||||
self.debug.topology.disable_refreshing = disable_topology_refresh;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
@@ -159,6 +297,34 @@ impl Config {
|
||||
self.client.disabled_credentials_mode
|
||||
}
|
||||
|
||||
pub fn get_nym_root_directory(&self) -> PathBuf {
|
||||
self.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
pub fn get_private_identity_key_file(&self) -> PathBuf {
|
||||
self.client.private_identity_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_public_identity_key_file(&self) -> PathBuf {
|
||||
self.client.public_identity_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_private_encryption_key_file(&self) -> PathBuf {
|
||||
self.client.private_encryption_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_public_encryption_key_file(&self) -> PathBuf {
|
||||
self.client.public_encryption_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_shared_key_file(&self) -> PathBuf {
|
||||
self.client.gateway_shared_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_ack_key_file(&self) -> PathBuf {
|
||||
self.client.ack_key_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_validator_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nyxd_urls.clone()
|
||||
}
|
||||
@@ -166,6 +332,139 @@ impl Config {
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nym_api_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_id.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_owner(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_owner.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_listener(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_listener.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_endpoint_config(&self) -> &GatewayEndpointConfig {
|
||||
&self.client.gateway_endpoint
|
||||
}
|
||||
|
||||
pub fn get_database_path(&self) -> PathBuf {
|
||||
self.client.database_path.clone()
|
||||
}
|
||||
|
||||
pub fn get_reply_surb_database_path(&self) -> PathBuf {
|
||||
self.client.reply_surb_database_path.clone()
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> &str {
|
||||
&self.client.version
|
||||
}
|
||||
|
||||
// Debug getters
|
||||
pub fn get_debug_config(&self) -> &DebugConfig {
|
||||
&self.debug
|
||||
}
|
||||
|
||||
pub fn get_average_packet_delay(&self) -> Duration {
|
||||
self.debug.traffic.average_packet_delay
|
||||
}
|
||||
|
||||
pub fn get_average_ack_delay(&self) -> Duration {
|
||||
self.debug.acknowledgements.average_ack_delay
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_multiplier(&self) -> f64 {
|
||||
self.debug.acknowledgements.ack_wait_multiplier
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_addition(&self) -> Duration {
|
||||
self.debug.acknowledgements.ack_wait_addition
|
||||
}
|
||||
|
||||
pub fn get_loop_cover_traffic_average_delay(&self) -> Duration {
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay
|
||||
}
|
||||
|
||||
pub fn get_message_sending_average_delay(&self) -> Duration {
|
||||
self.debug.traffic.message_sending_average_delay
|
||||
}
|
||||
|
||||
pub fn get_gateway_response_timeout(&self) -> Duration {
|
||||
self.debug.gateway_connection.gateway_response_timeout
|
||||
}
|
||||
|
||||
pub fn get_topology_refresh_rate(&self) -> Duration {
|
||||
self.debug.topology.topology_refresh_rate
|
||||
}
|
||||
|
||||
pub fn get_topology_resolution_timeout(&self) -> Duration {
|
||||
self.debug.topology.topology_resolution_timeout
|
||||
}
|
||||
|
||||
pub fn get_disabled_loop_cover_traffic_stream(&self) -> bool {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream
|
||||
}
|
||||
|
||||
pub fn get_disabled_main_poisson_packet_distribution(&self) -> bool {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution
|
||||
}
|
||||
|
||||
pub fn get_minimum_reply_surb_storage_threshold(&self) -> usize {
|
||||
self.debug.reply_surbs.minimum_reply_surb_storage_threshold
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_storage_threshold(&self) -> usize {
|
||||
self.debug.reply_surbs.maximum_reply_surb_storage_threshold
|
||||
}
|
||||
|
||||
pub fn get_minimum_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug.reply_surbs.minimum_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug.reply_surbs.maximum_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_allowed_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_allowed_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_rerequest_waiting_period(&self) -> Duration {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_rerequest_waiting_period
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_drop_waiting_period(&self) -> Duration {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_drop_waiting_period
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_age(&self) -> Duration {
|
||||
self.debug.reply_surbs.maximum_reply_surb_age
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_key_age(&self) -> Duration {
|
||||
self.debug.reply_surbs.maximum_reply_key_age
|
||||
}
|
||||
|
||||
pub fn get_packet_type(&self) -> PacketType {
|
||||
self.client.packet_type.unwrap_or(PacketType::Mix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Config<T> {
|
||||
fn default() -> Self {
|
||||
Config {
|
||||
client: Client::<T>::default(),
|
||||
logging: Default::default(),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
@@ -218,10 +517,9 @@ impl From<nym_topology::gateway::Node> for GatewayEndpointConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Client {
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
#[serde(default = "missing_string_value")]
|
||||
pub version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
@@ -229,7 +527,6 @@ pub struct Client {
|
||||
|
||||
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
// TODO: this should be moved to `debug.gateway_connection`
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
|
||||
@@ -240,10 +537,52 @@ pub struct Client {
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
pub private_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public identity key.
|
||||
pub public_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing private encryption key.
|
||||
pub private_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public encryption key.
|
||||
pub public_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing shared key derived with the specified gateway that is used
|
||||
/// for all communication with it.
|
||||
pub gateway_shared_key_file: PathBuf,
|
||||
|
||||
/// 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.
|
||||
pub ack_key_file: PathBuf,
|
||||
|
||||
/// Information regarding how the client should send data to gateway.
|
||||
pub gateway_endpoint: GatewayEndpointConfig,
|
||||
|
||||
/// Path to the database containing bandwidth credentials of this client.
|
||||
pub database_path: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
// this was set to use #[serde(default)] for the purposes of compatibility for multi-surbs introduced in 1.1.4.
|
||||
// if you're reading this message and we have already introduced some breaking changes, feel free
|
||||
// to remove that attribute since at this point the client configs should have gotten regenerated
|
||||
#[serde(default)]
|
||||
pub reply_surb_database_path: PathBuf,
|
||||
|
||||
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
||||
/// It is expected to use default value and hence .toml file should not redefine this field.
|
||||
pub nym_root_directory: PathBuf,
|
||||
|
||||
#[serde(skip)]
|
||||
pub super_struct: PhantomData<T>,
|
||||
|
||||
pub packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new_default<S: Into<String>>(id: S, version: S) -> Self {
|
||||
impl<T: NymConfig> Default for Client<T> {
|
||||
fn default() -> Self {
|
||||
let network = NymNetworkDetails::new_mainnet();
|
||||
let nyxd_urls = network
|
||||
.endpoints
|
||||
@@ -256,31 +595,71 @@ impl Client {
|
||||
.filter_map(|validator| validator.api_url())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if nym_api_urls.is_empty() {
|
||||
panic!("we do not have any default nym-api urls available!")
|
||||
}
|
||||
|
||||
// there must be explicit checks for whether id is not empty later
|
||||
Client {
|
||||
version: version.into(),
|
||||
id: id.into(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
disabled_credentials_mode: true,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<S: Into<String>>(
|
||||
id: S,
|
||||
disabled_credentials_mode: bool,
|
||||
nyxd_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Self {
|
||||
Client {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: id.into(),
|
||||
disabled_credentials_mode,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
private_encryption_key_file: Default::default(),
|
||||
public_encryption_key_file: Default::default(),
|
||||
gateway_shared_key_file: Default::default(),
|
||||
ack_key_file: Default::default(),
|
||||
gateway_endpoint: Default::default(),
|
||||
database_path: Default::default(),
|
||||
reply_surb_database_path: Default::default(),
|
||||
nym_root_directory: T::default_root_directory(),
|
||||
super_struct: Default::default(),
|
||||
packet_type: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Client<T> {
|
||||
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("private_identity.pem")
|
||||
}
|
||||
|
||||
fn default_public_identity_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("public_identity.pem")
|
||||
}
|
||||
|
||||
fn default_private_encryption_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("private_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_public_encryption_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("public_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_gateway_shared_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("gateway_shared.pem")
|
||||
}
|
||||
|
||||
fn default_ack_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("ack_key.pem")
|
||||
}
|
||||
|
||||
fn default_reply_surb_database_path(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join("persistent_reply_store.sqlite")
|
||||
}
|
||||
|
||||
fn default_database_path(id: &str) -> PathBuf {
|
||||
T::default_data_directory(id).join(CRED_DB_FILE_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Logging {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct Traffic {
|
||||
@@ -311,7 +690,7 @@ pub struct Traffic {
|
||||
/// Do not set it it unless you understand the consequences of that change.
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
pub packet_type: PacketType,
|
||||
pub packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Traffic {
|
||||
@@ -335,7 +714,7 @@ impl Default for Traffic {
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: PacketType::Mix,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20::{
|
||||
AcknowledgementsV1_1_20, ClientV1_1_20, ConfigV1_1_20, CoverTrafficV1_1_20, DebugConfigV1_1_20,
|
||||
GatewayConnectionV1_1_20, LoggingV1_1_20, ReplySurbsV1_1_20, TopologyV1_1_20, TrafficV1_1_20,
|
||||
DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
DEFAULT_GATEWAY_RESPONSE_TIMEOUT, DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_AGE, DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
use crate::config::{
|
||||
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, Logging,
|
||||
ReplySurbs, Topology, Traffic, DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
DEFAULT_AVERAGE_PACKET_DELAY, DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_KEY_AGE, DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
DEFAULT_TOPOLOGY_REFRESH_RATE, DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
};
|
||||
use nym_config::NymConfig;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
@@ -39,21 +40,21 @@ impl From<ExtendedPacketSize> for PacketSize {
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13<T> {
|
||||
pub client: ClientV1_1_20<T>,
|
||||
pub client: Client<T>,
|
||||
|
||||
#[serde(default)]
|
||||
pub logging: OldLoggingV1_1_13,
|
||||
logging: Logging,
|
||||
#[serde(default)]
|
||||
pub debug: OldDebugConfigV1_1_13,
|
||||
debug: OldDebugConfigV1_1_13,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldLoggingV1_1_13 {}
|
||||
|
||||
impl From<OldLoggingV1_1_13> for LoggingV1_1_20 {
|
||||
fn from(_value: OldLoggingV1_1_13) -> Self {
|
||||
LoggingV1_1_20 {}
|
||||
impl<T: NymConfig> Default for OldConfigV1_1_13<T> {
|
||||
fn default() -> Self {
|
||||
OldConfigV1_1_13 {
|
||||
client: Client::<T>::default(),
|
||||
logging: Default::default(),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,36 +115,37 @@ pub struct OldDebugConfigV1_1_13 {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
|
||||
impl From<OldDebugConfigV1_1_13> for DebugConfig {
|
||||
fn from(value: OldDebugConfigV1_1_13) -> Self {
|
||||
DebugConfigV1_1_20 {
|
||||
traffic: TrafficV1_1_20 {
|
||||
DebugConfig {
|
||||
traffic: Traffic {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: value.use_extended_packet_size.map(Into::into),
|
||||
packet_type: None,
|
||||
},
|
||||
cover_traffic: CoverTrafficV1_1_20 {
|
||||
cover_traffic: CoverTraffic {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
..CoverTrafficV1_1_20::default()
|
||||
..CoverTraffic::default()
|
||||
},
|
||||
gateway_connection: GatewayConnectionV1_1_20 {
|
||||
gateway_connection: GatewayConnection {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
},
|
||||
acknowledgements: AcknowledgementsV1_1_20 {
|
||||
acknowledgements: Acknowledgements {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
},
|
||||
topology: TopologyV1_1_20 {
|
||||
topology: Topology {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: false,
|
||||
},
|
||||
reply_surbs: ReplySurbsV1_1_20 {
|
||||
reply_surbs: ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
@@ -190,10 +192,10 @@ impl Default for OldDebugConfigV1_1_13 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<OldConfigV1_1_13<T>> for ConfigV1_1_20<U> {
|
||||
impl<T, U> From<OldConfigV1_1_13<T>> for Config<U> {
|
||||
fn from(value: OldConfigV1_1_13<T>) -> Self {
|
||||
ConfigV1_1_20 {
|
||||
client: ClientV1_1_20 {
|
||||
Config {
|
||||
client: Client {
|
||||
version: value.client.version,
|
||||
id: value.client.id,
|
||||
disabled_credentials_mode: value.client.disabled_credentials_mode,
|
||||
@@ -209,10 +211,10 @@ impl<T, U> From<OldConfigV1_1_13<T>> for ConfigV1_1_20<U> {
|
||||
database_path: value.client.database_path,
|
||||
reply_surb_database_path: value.client.reply_surb_database_path,
|
||||
nym_root_directory: value.client.nym_root_directory,
|
||||
|
||||
super_struct: PhantomData,
|
||||
packet_type: Some(nym_sphinx::params::PacketType::Mix),
|
||||
},
|
||||
logging: value.logging.into(),
|
||||
logging: value.logging,
|
||||
debug: value.debug.into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20_2::{
|
||||
AcknowledgementsV1_1_20_2, CoverTrafficV1_1_20_2, DebugConfigV1_1_20_2,
|
||||
GatewayConnectionV1_1_20_2, GatewayEndpointConfigV1_1_20_2, ReplySurbsV1_1_20_2,
|
||||
TopologyV1_1_20_2, TrafficV1_1_20_2,
|
||||
};
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
// 'DEBUG'
|
||||
pub(crate) const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
pub(crate) const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
|
||||
pub(crate) const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
||||
pub(crate) const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
|
||||
pub(crate) const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
||||
pub(crate) const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
||||
pub(crate) const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
||||
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
|
||||
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
|
||||
// bandwidth bridging protocol, we can come back to a smaller timeout value
|
||||
pub(crate) const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
pub(crate) const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
|
||||
|
||||
// reply-surbs related:
|
||||
|
||||
// define when to request
|
||||
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
|
||||
pub(crate) const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
|
||||
|
||||
// define how much to request at once
|
||||
// clients/client-core/src/client/replies/reply_controller.rs
|
||||
pub(crate) const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
|
||||
|
||||
pub(crate) const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
||||
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration =
|
||||
Duration::from_secs(10);
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration =
|
||||
Duration::from_secs(5 * 60);
|
||||
|
||||
// 12 hours
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
|
||||
|
||||
// 24 hours
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20<T> {
|
||||
pub client: ClientV1_1_20<T>,
|
||||
|
||||
#[serde(default)]
|
||||
pub logging: LoggingV1_1_20,
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_20,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct GatewayEndpointConfigV1_1_20 {
|
||||
pub gateway_id: String,
|
||||
pub gateway_owner: String,
|
||||
pub gateway_listener: String,
|
||||
}
|
||||
|
||||
impl From<GatewayEndpointConfigV1_1_20> for GatewayEndpointConfigV1_1_20_2 {
|
||||
fn from(value: GatewayEndpointConfigV1_1_20) -> Self {
|
||||
GatewayEndpointConfigV1_1_20_2 {
|
||||
gateway_id: value.gateway_id,
|
||||
gateway_owner: value.gateway_owner,
|
||||
gateway_listener: value.gateway_listener,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientV1_1_20<T> {
|
||||
pub version: String,
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
#[serde(alias = "validator_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
pub private_identity_key_file: PathBuf,
|
||||
pub public_identity_key_file: PathBuf,
|
||||
pub private_encryption_key_file: PathBuf,
|
||||
pub public_encryption_key_file: PathBuf,
|
||||
pub gateway_shared_key_file: PathBuf,
|
||||
pub ack_key_file: PathBuf,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV1_1_20,
|
||||
pub database_path: PathBuf,
|
||||
#[serde(default)]
|
||||
pub reply_surb_database_path: PathBuf,
|
||||
pub nym_root_directory: PathBuf,
|
||||
|
||||
#[serde(skip)]
|
||||
pub super_struct: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LoggingV1_1_20 {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct TrafficV1_1_20 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
pub primary_packet_size: PacketSize,
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
}
|
||||
|
||||
impl From<TrafficV1_1_20> for TrafficV1_1_20_2 {
|
||||
fn from(value: TrafficV1_1_20) -> Self {
|
||||
TrafficV1_1_20_2 {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: value.primary_packet_size,
|
||||
secondary_packet_size: value.secondary_packet_size,
|
||||
packet_type: PacketType::Mix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_20 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_20 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_20 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTrafficV1_1_20> for CoverTrafficV1_1_20_2 {
|
||||
fn from(value: CoverTrafficV1_1_20) -> Self {
|
||||
CoverTrafficV1_1_20_2 {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_20 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_20 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_20 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl From<GatewayConnectionV1_1_20> for GatewayConnectionV1_1_20_2 {
|
||||
fn from(value: GatewayConnectionV1_1_20) -> Self {
|
||||
GatewayConnectionV1_1_20_2 {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_20 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_20 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_20 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
pub ack_wait_multiplier: f64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl From<AcknowledgementsV1_1_20> for AcknowledgementsV1_1_20_2 {
|
||||
fn from(value: AcknowledgementsV1_1_20) -> Self {
|
||||
AcknowledgementsV1_1_20_2 {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_20 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_20 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_20 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
pub disable_refreshing: bool,
|
||||
}
|
||||
|
||||
impl From<TopologyV1_1_20> for TopologyV1_1_20_2 {
|
||||
fn from(value: TopologyV1_1_20) -> Self {
|
||||
TopologyV1_1_20_2 {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: value.disable_refreshing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_20 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_20 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_20 {
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
pub maximum_reply_surb_request_size: u32,
|
||||
pub maximum_allowed_reply_surb_request_size: u32,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_rerequest_waiting_period: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_drop_waiting_period: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_age: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl From<ReplySurbsV1_1_20> for ReplySurbsV1_1_20_2 {
|
||||
fn from(value: ReplySurbsV1_1_20) -> Self {
|
||||
ReplySurbsV1_1_20_2 {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: value.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: value.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: value
|
||||
.maximum_reply_surb_rerequest_waiting_period,
|
||||
maximum_reply_surb_drop_waiting_period: value.maximum_reply_surb_drop_waiting_period,
|
||||
maximum_reply_surb_age: value.maximum_reply_surb_age,
|
||||
maximum_reply_key_age: value.maximum_reply_key_age,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_20 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_20 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_rerequest_waiting_period:
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_20 {
|
||||
pub traffic: TrafficV1_1_20,
|
||||
pub cover_traffic: CoverTrafficV1_1_20,
|
||||
pub gateway_connection: GatewayConnectionV1_1_20,
|
||||
pub acknowledgements: AcknowledgementsV1_1_20,
|
||||
pub topology: TopologyV1_1_20,
|
||||
pub reply_surbs: ReplySurbsV1_1_20,
|
||||
}
|
||||
|
||||
impl From<DebugConfigV1_1_20> for DebugConfigV1_1_20_2 {
|
||||
fn from(value: DebugConfigV1_1_20) -> Self {
|
||||
DebugConfigV1_1_20_2 {
|
||||
traffic: value.traffic.into(),
|
||||
cover_traffic: value.cover_traffic.into(),
|
||||
gateway_connection: value.gateway_connection.into(),
|
||||
acknowledgements: value.acknowledgements.into(),
|
||||
topology: value.topology.into(),
|
||||
reply_surbs: value.reply_surbs.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,348 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::{
|
||||
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection,
|
||||
GatewayEndpointConfig, ReplySurbs, Topology, Traffic,
|
||||
};
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
// 'DEBUG'
|
||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
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);
|
||||
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
|
||||
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
|
||||
// bandwidth bridging protocol, we can come back to a smaller timeout value
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
|
||||
|
||||
// reply-surbs related:
|
||||
|
||||
// define when to request
|
||||
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
|
||||
|
||||
// define how much to request at once
|
||||
// clients/client-core/src/client/replies/reply_controller.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
|
||||
|
||||
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
||||
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
// 12 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
|
||||
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
pub client: ClientV1_1_20_2,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_20_2,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20_2> for Config {
|
||||
fn from(value: ConfigV1_1_20_2) -> Self {
|
||||
Config {
|
||||
client: value.client.into(),
|
||||
debug: value.debug.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct GatewayEndpointConfigV1_1_20_2 {
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
pub gateway_id: String,
|
||||
|
||||
/// Address of the gateway owner to which the client should send messages.
|
||||
pub gateway_owner: String,
|
||||
|
||||
/// Address of the gateway listener to which all client requests should be sent.
|
||||
pub gateway_listener: String,
|
||||
}
|
||||
|
||||
impl From<GatewayEndpointConfigV1_1_20_2> for GatewayEndpointConfig {
|
||||
fn from(value: GatewayEndpointConfigV1_1_20_2) -> Self {
|
||||
GatewayEndpointConfig {
|
||||
gateway_id: value.gateway_id,
|
||||
gateway_owner: value.gateway_owner,
|
||||
gateway_listener: value.gateway_listener,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientV1_1_20_2 {
|
||||
pub version: String,
|
||||
|
||||
pub id: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
|
||||
#[serde(alias = "validator_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV1_1_20_2,
|
||||
}
|
||||
|
||||
impl From<ClientV1_1_20_2> for Client {
|
||||
fn from(value: ClientV1_1_20_2) -> Self {
|
||||
Client {
|
||||
version: value.version,
|
||||
id: value.id,
|
||||
disabled_credentials_mode: value.disabled_credentials_mode,
|
||||
nyxd_urls: value.nyxd_urls,
|
||||
nym_api_urls: value.nym_api_urls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct TrafficV1_1_20_2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
pub primary_packet_size: PacketSize,
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl From<TrafficV1_1_20_2> for Traffic {
|
||||
fn from(value: TrafficV1_1_20_2) -> Self {
|
||||
Traffic {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: value.primary_packet_size,
|
||||
secondary_packet_size: value.secondary_packet_size,
|
||||
packet_type: PacketType::Mix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_20_2 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: PacketType::Mix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_20_2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTrafficV1_1_20_2> for CoverTraffic {
|
||||
fn from(value: CoverTrafficV1_1_20_2) -> Self {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_20_2 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_20_2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl From<GatewayConnectionV1_1_20_2> for GatewayConnection {
|
||||
fn from(value: GatewayConnectionV1_1_20_2) -> Self {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_20_2 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_20_2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
pub ack_wait_multiplier: f64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl From<AcknowledgementsV1_1_20_2> for Acknowledgements {
|
||||
fn from(value: AcknowledgementsV1_1_20_2) -> Self {
|
||||
Acknowledgements {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_20_2 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_20_2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
pub disable_refreshing: bool,
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_20_2 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TopologyV1_1_20_2> for Topology {
|
||||
fn from(value: TopologyV1_1_20_2) -> Self {
|
||||
Topology {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: value.disable_refreshing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_20_2 {
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
pub maximum_reply_surb_request_size: u32,
|
||||
pub maximum_allowed_reply_surb_request_size: u32,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_rerequest_waiting_period: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_drop_waiting_period: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_age: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_20_2 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_rerequest_waiting_period:
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReplySurbsV1_1_20_2> for ReplySurbs {
|
||||
fn from(value: ReplySurbsV1_1_20_2) -> Self {
|
||||
ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: value.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: value.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: value
|
||||
.maximum_reply_surb_rerequest_waiting_period,
|
||||
maximum_reply_surb_drop_waiting_period: value.maximum_reply_surb_drop_waiting_period,
|
||||
maximum_reply_surb_age: value.maximum_reply_surb_age,
|
||||
maximum_reply_key_age: value.maximum_reply_key_age,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_20_2 {
|
||||
pub traffic: TrafficV1_1_20_2,
|
||||
pub cover_traffic: CoverTrafficV1_1_20_2,
|
||||
pub gateway_connection: GatewayConnectionV1_1_20_2,
|
||||
pub acknowledgements: AcknowledgementsV1_1_20_2,
|
||||
pub topology: TopologyV1_1_20_2,
|
||||
pub reply_surbs: ReplySurbsV1_1_20_2,
|
||||
}
|
||||
|
||||
impl From<DebugConfigV1_1_20_2> for DebugConfig {
|
||||
fn from(value: DebugConfigV1_1_20_2) -> Self {
|
||||
DebugConfig {
|
||||
traffic: value.traffic.into(),
|
||||
cover_traffic: value.cover_traffic.into(),
|
||||
gateway_connection: value.gateway_connection.into(),
|
||||
acknowledgements: value.acknowledgements.into(),
|
||||
topology: value.topology.into(),
|
||||
reply_surbs: value.reply_surbs.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClientKeyPathfinder {
|
||||
pub identity_private_key: PathBuf,
|
||||
pub identity_public_key: PathBuf,
|
||||
pub encryption_private_key: PathBuf,
|
||||
pub encryption_public_key: PathBuf,
|
||||
pub gateway_shared_key: PathBuf,
|
||||
pub ack_key: PathBuf,
|
||||
}
|
||||
|
||||
impl ClientKeyPathfinder {
|
||||
pub fn new(id: String) -> Self {
|
||||
let os_config_dir = dirs::config_dir().expect("no config directory known for this OS"); // grabs the OS default config dir
|
||||
let config_dir = os_config_dir.join("nym").join("clients").join(id);
|
||||
ClientKeyPathfinder {
|
||||
identity_private_key: config_dir.join("private_identity.pem"),
|
||||
identity_public_key: config_dir.join("public_identity.pem"),
|
||||
encryption_private_key: config_dir.join("private_encryption.pem"),
|
||||
encryption_public_key: config_dir.join("public_encryption.pem"),
|
||||
gateway_shared_key: config_dir.join("gateway_shared.pem"),
|
||||
ack_key: config_dir.join("ack_key.pem"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_config<T>(config: &Config<T>) -> Self {
|
||||
ClientKeyPathfinder {
|
||||
identity_private_key: config.get_private_identity_key_file(),
|
||||
identity_public_key: config.get_public_identity_key_file(),
|
||||
encryption_private_key: config.get_private_encryption_key_file(),
|
||||
encryption_public_key: config.get_public_encryption_key_file(),
|
||||
gateway_shared_key: config.get_gateway_shared_key_file(),
|
||||
ack_key: config.get_ack_key_file(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identity_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_identity_key().to_path_buf(),
|
||||
self.public_identity_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn encryption_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_encryption_key().to_path_buf(),
|
||||
self.public_encryption_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn any_file_exists(&self) -> bool {
|
||||
matches!(self.identity_public_key.try_exists(), Ok(true))
|
||||
|| matches!(self.identity_private_key.try_exists(), Ok(true))
|
||||
|| matches!(self.encryption_public_key.try_exists(), Ok(true))
|
||||
|| matches!(self.encryption_private_key.try_exists(), Ok(true))
|
||||
|| matches!(self.gateway_shared_key.try_exists(), Ok(true))
|
||||
|| matches!(self.ack_key.try_exists(), Ok(true))
|
||||
}
|
||||
|
||||
pub fn any_file_exists_and_return(&self) -> Option<PathBuf> {
|
||||
file_exists(&self.identity_public_key)
|
||||
.or_else(|| file_exists(&self.identity_private_key))
|
||||
.or_else(|| file_exists(&self.encryption_public_key))
|
||||
.or_else(|| file_exists(&self.encryption_private_key))
|
||||
.or_else(|| file_exists(&self.gateway_shared_key))
|
||||
.or_else(|| file_exists(&self.ack_key))
|
||||
}
|
||||
|
||||
pub fn gateway_key_file_exists(&self) -> bool {
|
||||
matches!(self.gateway_shared_key.try_exists(), Ok(true))
|
||||
}
|
||||
|
||||
pub fn private_identity_key(&self) -> &Path {
|
||||
&self.identity_private_key
|
||||
}
|
||||
|
||||
pub fn public_identity_key(&self) -> &Path {
|
||||
&self.identity_public_key
|
||||
}
|
||||
|
||||
pub fn private_encryption_key(&self) -> &Path {
|
||||
&self.encryption_private_key
|
||||
}
|
||||
|
||||
pub fn public_encryption_key(&self) -> &Path {
|
||||
&self.encryption_public_key
|
||||
}
|
||||
|
||||
pub fn gateway_shared_key(&self) -> &Path {
|
||||
&self.gateway_shared_key
|
||||
}
|
||||
|
||||
pub fn ack_key(&self) -> &Path {
|
||||
&self.ack_key
|
||||
}
|
||||
}
|
||||
|
||||
fn file_exists(path: &Path) -> Option<PathBuf> {
|
||||
if matches!(path.try_exists(), Ok(true)) {
|
||||
return Some(path.to_path_buf());
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod key_pathfinder;
|
||||
@@ -50,11 +50,6 @@ pub enum ClientCoreError {
|
||||
source: Box<dyn Error + Send + Sync>,
|
||||
},
|
||||
|
||||
#[error("experienced a failure with our gateway details storage: {source}")]
|
||||
GatewayDetailsStoreError {
|
||||
source: Box<dyn Error + Send + Sync>,
|
||||
},
|
||||
|
||||
#[error("The gateway id is invalid - {0}")]
|
||||
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
|
||||
|
||||
@@ -102,20 +97,6 @@ pub enum ClientCoreError {
|
||||
"This operation would have resulted in clients keys being overwritten without permission"
|
||||
)]
|
||||
ForbiddenKeyOverwrite,
|
||||
|
||||
#[error("gateway details are unavailable")]
|
||||
UnavailableGatewayDetails {
|
||||
source: Box<dyn Error + Send + Sync>,
|
||||
},
|
||||
|
||||
#[error("gateway shared key is unavailable whilst we have full node information")]
|
||||
UnavailableSharedKey,
|
||||
|
||||
#[error("attempted to obtain fresh gateway details whilst already knowing about one")]
|
||||
UnexpectedGatewayDetails,
|
||||
|
||||
#[error("the provided gateway details (for gateway {gateway_id}) do not correspond to the shared keys")]
|
||||
MismatchedGatewayDetails { gateway_id: String },
|
||||
}
|
||||
|
||||
/// Set of messages that the client can send to listeners via the task manager
|
||||
|
||||
@@ -44,18 +44,18 @@ const MEASUREMENTS: usize = 3;
|
||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
||||
struct GatewayWithLatency<'a> {
|
||||
gateway: &'a gateway::Node,
|
||||
struct GatewayWithLatency {
|
||||
gateway: gateway::Node,
|
||||
latency: Duration,
|
||||
}
|
||||
|
||||
impl<'a> GatewayWithLatency<'a> {
|
||||
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
|
||||
impl GatewayWithLatency {
|
||||
fn new(gateway: gateway::Node, latency: Duration) -> Self {
|
||||
GatewayWithLatency { gateway, latency }
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn current_gateways<R: Rng>(
|
||||
pub(super) async fn current_gateways<R: Rng>(
|
||||
rng: &mut R,
|
||||
nym_apis: &[Url],
|
||||
) -> Result<Vec<gateway::Node>, ClientCoreError> {
|
||||
@@ -64,7 +64,7 @@ pub async fn current_gateways<R: Rng>(
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {nym_api}");
|
||||
log::trace!("Fetching list of gateways from: {}", nym_api);
|
||||
|
||||
let gateways = client.get_cached_gateways().await?;
|
||||
let valid_gateways = gateways
|
||||
@@ -91,7 +91,7 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
|
||||
}
|
||||
|
||||
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
async fn measure_latency(gateway: gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
let addr = gateway.clients_address();
|
||||
trace!(
|
||||
"establishing connection to {} ({addr})...",
|
||||
@@ -156,7 +156,7 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
|
||||
pub(super) async fn choose_gateway_by_latency<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
gateways: Vec<gateway::Node>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
info!("choosing gateway by latency...");
|
||||
|
||||
@@ -189,7 +189,7 @@ pub(super) async fn choose_gateway_by_latency<R: Rng>(
|
||||
|
||||
pub(super) fn uniformly_random_gateway<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
gateways: Vec<gateway::Node>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
gateways
|
||||
.choose(rng)
|
||||
|
||||
+206
-275
@@ -3,82 +3,31 @@
|
||||
|
||||
//! Collection of initialization steps used by client implementations
|
||||
|
||||
use crate::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, PersistedGatewayDetails,
|
||||
};
|
||||
use crate::client::base_client::storage::MixnetClientStorage;
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::ManagedKeys;
|
||||
use crate::client::key_manager::{KeyManager, ManagedKeys};
|
||||
use crate::init::helpers::{choose_gateway_by_latency, current_gateways, uniformly_random_gateway};
|
||||
use crate::{
|
||||
config::{Config, GatewayEndpointConfig},
|
||||
config::{
|
||||
persistence::key_pathfinder::ClientKeyPathfinder, ClientCoreConfigTrait, Config,
|
||||
GatewayEndpointConfig,
|
||||
},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||
use nym_topology::gateway;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Debug, Display};
|
||||
use tap::TapFallible;
|
||||
use url::Url;
|
||||
|
||||
pub mod helpers;
|
||||
mod helpers;
|
||||
|
||||
// TODO: rename to something better...
|
||||
#[derive(Debug)]
|
||||
pub struct InitialisationDetails {
|
||||
pub gateway_details: GatewayEndpointConfig,
|
||||
pub managed_keys: ManagedKeys,
|
||||
}
|
||||
|
||||
impl InitialisationDetails {
|
||||
pub fn new(gateway_details: GatewayEndpointConfig, managed_keys: ManagedKeys) -> Self {
|
||||
InitialisationDetails {
|
||||
gateway_details,
|
||||
managed_keys,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn try_load<K, D>(key_store: &K, details_store: &D) -> Result<Self, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
D: GatewayDetailsStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let loaded_details = _load_gateway_details(details_store).await?;
|
||||
let loaded_keys = _load_managed_keys(key_store).await?;
|
||||
|
||||
if !loaded_details.verify(&loaded_keys.must_get_gateway_shared_key()) {
|
||||
return Err(ClientCoreError::MismatchedGatewayDetails {
|
||||
gateway_id: loaded_details.details.gateway_id,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(InitialisationDetails {
|
||||
gateway_details: loaded_details.into(),
|
||||
managed_keys: loaded_keys,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn client_address(&self) -> Result<Recipient, ClientCoreError> {
|
||||
let client_recipient = Recipient::new(
|
||||
*self.managed_keys.identity_public_key(),
|
||||
*self.managed_keys.encryption_public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(&self.gateway_details.gateway_id)?,
|
||||
);
|
||||
|
||||
Ok(client_recipient)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub enum GatewaySetup {
|
||||
/// The gateway specification MUST BE loaded from the underlying storage.
|
||||
MustLoad,
|
||||
|
||||
/// Specifies usage of a new, random, gateway.
|
||||
New {
|
||||
/// Should the new gateway be selected based on latency.
|
||||
@@ -90,13 +39,13 @@ pub enum GatewaySetup {
|
||||
},
|
||||
Predefined {
|
||||
/// Full gateway configuration
|
||||
details: PersistedGatewayDetails,
|
||||
config: GatewayEndpointConfig,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<PersistedGatewayDetails> for GatewaySetup {
|
||||
fn from(details: PersistedGatewayDetails) -> Self {
|
||||
GatewaySetup::Predefined { details }
|
||||
impl From<GatewayEndpointConfig> for GatewaySetup {
|
||||
fn from(config: GatewayEndpointConfig) -> Self {
|
||||
GatewaySetup::Predefined { config }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,11 +62,14 @@ impl Default for GatewaySetup {
|
||||
}
|
||||
|
||||
impl GatewaySetup {
|
||||
pub fn new_fresh(
|
||||
gateway_identity: Option<String>,
|
||||
pub fn new(
|
||||
full_config: Option<GatewayEndpointConfig>,
|
||||
gateway_identity: Option<IdentityKey>,
|
||||
latency_based_selection: Option<bool>,
|
||||
) -> Self {
|
||||
if let Some(gateway_identity) = gateway_identity {
|
||||
if let Some(config) = full_config {
|
||||
GatewaySetup::Predefined { config }
|
||||
} else if let Some(gateway_identity) = gateway_identity {
|
||||
GatewaySetup::Specified { gateway_identity }
|
||||
} else {
|
||||
GatewaySetup::New {
|
||||
@@ -126,22 +78,15 @@ impl GatewaySetup {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_must_load(&self) -> bool {
|
||||
matches!(self, GatewaySetup::MustLoad)
|
||||
}
|
||||
|
||||
pub fn has_full_details(&self) -> bool {
|
||||
matches!(self, GatewaySetup::Predefined { .. }) || self.is_must_load()
|
||||
}
|
||||
|
||||
pub async fn choose_gateway(
|
||||
&self,
|
||||
gateways: &[gateway::Node],
|
||||
pub async fn try_get_gateway_details(
|
||||
self,
|
||||
validator_servers: &[Url],
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
||||
match self {
|
||||
GatewaySetup::New { by_latency } => {
|
||||
let mut rng = OsRng;
|
||||
if *by_latency {
|
||||
let gateways = current_gateways(&mut rng, validator_servers).await?;
|
||||
if by_latency {
|
||||
choose_gateway_by_latency(&mut rng, gateways).await
|
||||
} else {
|
||||
uniformly_random_gateway(&mut rng, gateways)
|
||||
@@ -149,28 +94,20 @@ impl GatewaySetup {
|
||||
}
|
||||
.map(Into::into),
|
||||
GatewaySetup::Specified { gateway_identity } => {
|
||||
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
|
||||
let user_gateway = identity::PublicKey::from_base58_string(&gateway_identity)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
let mut rng = OsRng;
|
||||
let gateways = current_gateways(&mut rng, validator_servers).await?;
|
||||
gateways
|
||||
.iter()
|
||||
.into_iter()
|
||||
.find(|gateway| gateway.identity_key == user_gateway)
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_identity.to_string()))
|
||||
.cloned()
|
||||
}
|
||||
.map(Into::into),
|
||||
_ => Err(ClientCoreError::UnexpectedGatewayDetails),
|
||||
GatewaySetup::Predefined { config } => Ok(config),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn try_get_new_gateway_details(
|
||||
&self,
|
||||
validator_servers: &[Url],
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
||||
let mut rng = OsRng;
|
||||
let gateways = current_gateways(&mut rng, validator_servers).await?;
|
||||
self.choose_gateway(&gateways).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct describing the results of the client initialization procedure.
|
||||
@@ -185,14 +122,17 @@ pub struct InitResults {
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
pub fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
|
||||
pub fn new<T>(config: &Config<T>, address: &Recipient) -> Self
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
Self {
|
||||
version: config.client.version.clone(),
|
||||
id: config.client.id.clone(),
|
||||
version: config.get_version().to_string(),
|
||||
id: config.get_id(),
|
||||
identity_key: address.identity().to_base58_string(),
|
||||
encryption_key: address.encryption_key().to_base58_string(),
|
||||
gateway_id: gateway.gateway_id.clone(),
|
||||
gateway_listener: gateway.gateway_listener.clone(),
|
||||
gateway_id: config.get_gateway_id(),
|
||||
gateway_listener: config.get_gateway_listener(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,164 +148,38 @@ impl Display for InitResults {
|
||||
}
|
||||
}
|
||||
|
||||
// helpers for error wrapping
|
||||
async fn _store_gateway_details<D>(
|
||||
details_store: &D,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), ClientCoreError>
|
||||
/// Recovers the already present gateway information or attempts to register with new gateway
|
||||
/// and stores the newly obtained key
|
||||
pub async fn get_registered_gateway<S>(
|
||||
validator_servers: Vec<Url>,
|
||||
key_store: &S::KeyStore,
|
||||
setup: GatewaySetup,
|
||||
overwrite_keys: bool,
|
||||
) -> Result<(GatewayEndpointConfig, ManagedKeys), ClientCoreError>
|
||||
where
|
||||
D: GatewayDetailsStore,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
details_store
|
||||
.store_gateway_details(details)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::GatewayDetailsStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
}
|
||||
|
||||
async fn _load_gateway_details<D>(
|
||||
details_store: &D,
|
||||
) -> Result<PersistedGatewayDetails, ClientCoreError>
|
||||
where
|
||||
D: GatewayDetailsStore,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
details_store
|
||||
.load_gateway_details()
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::UnavailableGatewayDetails {
|
||||
source: Box::new(source),
|
||||
})
|
||||
}
|
||||
|
||||
async fn _load_managed_keys<K>(key_store: &K) -> Result<ManagedKeys, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
ManagedKeys::try_load(key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
}
|
||||
|
||||
fn ensure_valid_details(
|
||||
details: &PersistedGatewayDetails,
|
||||
loaded_keys: &ManagedKeys,
|
||||
) -> Result<(), ClientCoreError> {
|
||||
if !details.verify(&loaded_keys.must_get_gateway_shared_key()) {
|
||||
Err(ClientCoreError::MismatchedGatewayDetails {
|
||||
gateway_id: details.details.gateway_id.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn setup_gateway_from<K, D>(
|
||||
setup: &GatewaySetup,
|
||||
key_store: &K,
|
||||
details_store: &D,
|
||||
overwrite_data: bool,
|
||||
gateways: Option<&[gateway::Node]>,
|
||||
) -> Result<InitialisationDetails, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
D: GatewayDetailsStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
S: MixnetClientStorage,
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
|
||||
// try load gateway details
|
||||
let loaded_details = _load_gateway_details(details_store).await;
|
||||
|
||||
// try load keys and decide what to do based on the GatewaySetup
|
||||
// try load keys
|
||||
let mut managed_keys = match ManagedKeys::try_load(key_store).await {
|
||||
Ok(loaded_keys) => {
|
||||
match setup {
|
||||
GatewaySetup::MustLoad => {
|
||||
// get EVERYTHING from the storage
|
||||
let details = loaded_details?;
|
||||
ensure_valid_details(&details, &loaded_keys)?;
|
||||
|
||||
// no need to persist anything as we got everything from the storage
|
||||
return Ok(InitialisationDetails::new(details.into(), loaded_keys));
|
||||
}
|
||||
GatewaySetup::Predefined { details } => {
|
||||
// we already have defined gateway details AND a shared key
|
||||
ensure_valid_details(details, &loaded_keys)?;
|
||||
|
||||
// if nothing was stored or we're allowed to overwrite what's there, just persist the passed data
|
||||
if overwrite_data || loaded_details.is_err() {
|
||||
_store_gateway_details(details_store, details).await?;
|
||||
}
|
||||
|
||||
return Ok(InitialisationDetails::new(
|
||||
details.clone().into(),
|
||||
loaded_keys,
|
||||
));
|
||||
}
|
||||
GatewaySetup::Specified { gateway_identity } => {
|
||||
// if that data was already stored...
|
||||
if let Ok(existing_gateway) = loaded_details {
|
||||
ensure_valid_details(&existing_gateway, &loaded_keys)?;
|
||||
if &existing_gateway.details.gateway_id != gateway_identity
|
||||
&& !overwrite_data
|
||||
{
|
||||
// if our loaded details don't match requested value and we CANT overwrite it...
|
||||
return Err(ClientCoreError::UnexpectedGatewayDetails);
|
||||
} else if &existing_gateway.details.gateway_id == gateway_identity {
|
||||
// if they do match up, just return it
|
||||
return Ok(InitialisationDetails::new(
|
||||
existing_gateway.into(),
|
||||
loaded_keys,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// we didn't get full details from the store and we have loaded some keys
|
||||
// so we can only continue if we're allowed to overwrite keys
|
||||
if overwrite_data {
|
||||
ManagedKeys::generate_new(&mut rng)
|
||||
} else {
|
||||
return Err(ClientCoreError::ForbiddenKeyOverwrite);
|
||||
}
|
||||
}
|
||||
GatewaySetup::New { .. } => {
|
||||
if let Ok(existing_gateway) = loaded_details {
|
||||
ensure_valid_details(&existing_gateway, &loaded_keys)?;
|
||||
return Ok(InitialisationDetails::new(
|
||||
existing_gateway.into(),
|
||||
loaded_keys,
|
||||
));
|
||||
}
|
||||
|
||||
// we didn't get full details from the store and we have loaded some keys
|
||||
// so we can only continue if we're allowed to overwrite keys
|
||||
if overwrite_data {
|
||||
ManagedKeys::generate_new(&mut rng)
|
||||
} else {
|
||||
return Err(ClientCoreError::ForbiddenKeyOverwrite);
|
||||
}
|
||||
}
|
||||
// if we loaded something and we don't have full gateway details, check if we can overwrite the data
|
||||
if let GatewaySetup::Predefined { config } = setup {
|
||||
// we already have defined gateway details AND a shared key, so nothing more for us to do
|
||||
return Ok((config, loaded_keys));
|
||||
} else if overwrite_keys {
|
||||
ManagedKeys::generate_new(&mut rng)
|
||||
} else {
|
||||
return Err(ClientCoreError::ForbiddenKeyOverwrite);
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// if we failed to load the keys, ensure we didn't provide gateway details in some form
|
||||
// (in that case we CAN'T generate new keys
|
||||
if setup.has_full_details() {
|
||||
return Err(ClientCoreError::UnavailableSharedKey);
|
||||
}
|
||||
ManagedKeys::generate_new(&mut rng)
|
||||
}
|
||||
Err(_) => ManagedKeys::generate_new(&mut rng),
|
||||
};
|
||||
|
||||
// choose gateway
|
||||
let gateway_details = setup.choose_gateway(gateways.unwrap_or_default()).await?;
|
||||
let gateway_details = setup.try_get_gateway_details(&validator_servers).await?;
|
||||
|
||||
// get our identity key
|
||||
let our_identity = managed_keys.identity_keypair();
|
||||
@@ -373,9 +187,6 @@ where
|
||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||
let shared_keys = helpers::register_with_gateway(&gateway_details, our_identity).await?;
|
||||
|
||||
let persisted_details = PersistedGatewayDetails::new(gateway_details, &shared_keys);
|
||||
|
||||
// persist gateway keys
|
||||
managed_keys
|
||||
.deal_with_gateway_key(shared_keys, key_store)
|
||||
.await
|
||||
@@ -383,39 +194,159 @@ where
|
||||
source: Box::new(source),
|
||||
})?;
|
||||
|
||||
// persist gateway config
|
||||
_store_gateway_details(details_store, &persisted_details).await?;
|
||||
// TODO: here we should be probably persisting gateway details as opposed to returning them
|
||||
|
||||
Ok(InitialisationDetails::new(
|
||||
persisted_details.into(),
|
||||
managed_keys,
|
||||
))
|
||||
Ok((gateway_details, managed_keys))
|
||||
}
|
||||
|
||||
pub async fn setup_gateway<K, D>(
|
||||
setup: &GatewaySetup,
|
||||
key_store: &K,
|
||||
details_store: &D,
|
||||
overwrite_data: bool,
|
||||
validator_servers: Option<&[Url]>,
|
||||
) -> Result<InitialisationDetails, ClientCoreError>
|
||||
/// Convenience function for setting up the gateway for a client given a `Config`. Depending on the
|
||||
/// arguments given it will do the sensible thing. Either it will
|
||||
///
|
||||
/// a. Reuse existing gateway configuration from storage.
|
||||
/// b. Create a new gateway configuration but keep existing keys. This assumes that the caller
|
||||
/// knows what they are doing and that the keys match the requested gateway.
|
||||
/// c. Create a new gateway configuration with a newly registered gateway and keys.
|
||||
pub async fn setup_gateway_from_config<C, T, KSt>(
|
||||
key_store: &KSt,
|
||||
register_gateway: bool,
|
||||
user_chosen_gateway_id: Option<identity::PublicKey>,
|
||||
config: &Config<T>,
|
||||
by_latency: bool,
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
D: GatewayDetailsStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
C: NymConfig + ClientCoreConfigTrait,
|
||||
T: NymConfig,
|
||||
KSt: KeyStore,
|
||||
<KSt as KeyStore>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let gateways = current_gateways(&mut rng, validator_servers.unwrap_or_default()).await?;
|
||||
let id = config.get_id();
|
||||
|
||||
setup_gateway_from(
|
||||
setup,
|
||||
key_store,
|
||||
details_store,
|
||||
overwrite_data,
|
||||
Some(&gateways),
|
||||
// If we are not going to register gateway, and an explicitly chosen gateway is not passed in,
|
||||
// load the existing configuration file
|
||||
if !register_gateway && user_chosen_gateway_id.is_none() {
|
||||
eprintln!("Not registering gateway, will reuse existing config and keys");
|
||||
return load_existing_gateway_config::<C>(&id);
|
||||
}
|
||||
|
||||
let gateway_setup = GatewaySetup::new(
|
||||
None,
|
||||
user_chosen_gateway_id.map(|id| id.to_base58_string()),
|
||||
Some(by_latency),
|
||||
);
|
||||
// Else, we proceed by querying the nym-api
|
||||
let gateway = gateway_setup
|
||||
.try_get_gateway_details(&config.get_nym_api_endpoints())
|
||||
.await?;
|
||||
log::debug!("Querying gateway gives: {:?}", gateway);
|
||||
|
||||
// If we are not registering, just return this and assume the caller has the keys already and
|
||||
// wants to keep the,
|
||||
if !register_gateway && user_chosen_gateway_id.is_some() {
|
||||
eprintln!("Using gateway provided by user, keeping existing keys");
|
||||
return Ok(gateway);
|
||||
}
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut managed_keys =
|
||||
crate::client::key_manager::ManagedKeys::load_or_generate(&mut rng, key_store).await;
|
||||
|
||||
// Create new keys and derive our identity
|
||||
let our_identity = managed_keys.identity_keypair();
|
||||
|
||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||
eprintln!("Registering with new gateway");
|
||||
let shared_keys = helpers::register_with_gateway(&gateway, our_identity).await?;
|
||||
managed_keys
|
||||
.deal_with_gateway_key(shared_keys, key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})?;
|
||||
|
||||
Ok(gateway)
|
||||
}
|
||||
|
||||
/// Read and reuse the existing gateway configuration from a file that was generate earlier.
|
||||
pub fn load_existing_gateway_config<T>(id: &str) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||
where
|
||||
T: NymConfig + ClientCoreConfigTrait,
|
||||
{
|
||||
T::load_from_file(id)
|
||||
.map(|existing_config| existing_config.get_gateway_endpoint().clone())
|
||||
.map_err(|err| {
|
||||
log::error!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
);
|
||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the full client address from the client keys and the gateway identity
|
||||
pub fn get_client_address(
|
||||
key_manager: &KeyManager,
|
||||
gateway_config: &GatewayEndpointConfig,
|
||||
) -> Recipient {
|
||||
Recipient::new(
|
||||
*key_manager.identity_keypair().public_key(),
|
||||
*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(&gateway_config.gateway_id).unwrap(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn load_identity_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
nym_pemstore::load_keypair(&pathfinder.identity_key_pair_path())
|
||||
.tap_err(|_| log::error!("Failed to read stored identity key files"))?;
|
||||
Ok(identity_keypair)
|
||||
}
|
||||
|
||||
/// Get the client address by loading the keys from stored files.
|
||||
// TODO: rethink that sucker
|
||||
pub fn get_client_address_from_stored_ondisk_keys<T>(
|
||||
config: &Config<T>,
|
||||
) -> Result<Recipient, ClientCoreError>
|
||||
where
|
||||
T: nym_config::NymConfig,
|
||||
{
|
||||
fn load_identity_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
nym_pemstore::load_keypair(&pathfinder.identity_key_pair_path())
|
||||
.tap_err(|_| log::error!("Failed to read stored identity key files"))?;
|
||||
Ok(identity_keypair)
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
nym_pemstore::load_keypair(&pathfinder.encryption_key_pair_path())
|
||||
.tap_err(|_| log::error!("Failed to read stored sphinx key files"))?;
|
||||
Ok(sphinx_keypair)
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
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_gateway_id())?,
|
||||
);
|
||||
|
||||
Ok(client_recipient)
|
||||
}
|
||||
|
||||
pub fn output_to_json<T: Serialize>(init_results: &T, output_file: &str) {
|
||||
|
||||
@@ -724,7 +724,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn try_reconnect(&mut self) -> Result<(), GatewayClientError> {
|
||||
async fn try_reconnect(&mut self) -> Result<(), GatewayClientError> {
|
||||
if !self.connection.is_established() {
|
||||
self.establish_connection().await?;
|
||||
}
|
||||
@@ -738,12 +738,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn disconnect(&mut self) -> Result<(), GatewayClientError> {
|
||||
self.recover_socket_connection().await?;
|
||||
self.connection = SocketState::NotConnected;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn authenticate_and_start(&mut self) -> Result<Arc<SharedKeys>, GatewayClientError>
|
||||
where
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
|
||||
@@ -48,21 +48,17 @@ impl PacketRouter {
|
||||
// data he takes the SURB-ACK and first hop address.
|
||||
// currently SURB-ACKs are attached in EVERY packet, even cover, so this is always true
|
||||
let ack_overhead = PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
let outfox_ack_overhead =
|
||||
PacketSize::OutfoxAckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
|
||||
for received_packet in unwrapped_packets {
|
||||
if received_packet.len() == PacketSize::AckPacket.plaintext_size()
|
||||
// we don't know the real size of the payload, it could be anything <= 48 bytes
|
||||
|| received_packet.len() <= PacketSize::OutfoxAckPacket.plaintext_size()
|
||||
|| received_packet.len() == PacketSize::OutfoxAckPacket.plaintext_size()
|
||||
{
|
||||
received_acks.push(received_packet);
|
||||
} else if received_packet.len()
|
||||
== PacketSize::RegularPacket.plaintext_size() - ack_overhead
|
||||
|| received_packet.len()
|
||||
== PacketSize::OutfoxRegularPacket.plaintext_size() - outfox_ack_overhead
|
||||
|| received_packet.len()
|
||||
== PacketSize::OutfoxRegularPacket.size() - outfox_ack_overhead
|
||||
== PacketSize::OutfoxRegularPacket.plaintext_size() - ack_overhead
|
||||
|| received_packet.len() == PacketSize::OutfoxRegularPacket.size() - 6
|
||||
{
|
||||
trace!("routing regular packet");
|
||||
received_messages.push(received_packet);
|
||||
|
||||
@@ -29,7 +29,6 @@ log = { workspace = true }
|
||||
url = { version = "2.2", features = ["serde"] }
|
||||
tokio = { version = "1.24.1", features = ["sync", "time"] }
|
||||
futures = "0.3"
|
||||
openssl = { version = "0.10", features = ["vendored"], optional = true }
|
||||
|
||||
nym-coconut-interface = { path = "../../coconut-interface" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
@@ -78,14 +77,13 @@ required-features = ["nyxd-client"]
|
||||
nyxd-client = [
|
||||
"async-trait",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"flate2",
|
||||
"itertools",
|
||||
"openssl",
|
||||
"prost",
|
||||
"flate2",
|
||||
"sha2",
|
||||
"itertools",
|
||||
"cosmwasm-std",
|
||||
"signing"
|
||||
]
|
||||
signing = [
|
||||
|
||||
@@ -7,14 +7,11 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dirs = { version = "5.0.1", optional = true }
|
||||
handlebars = "3.5.5"
|
||||
cfg-if = "1.0.0"
|
||||
handlebars = "3.0.1"
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
toml = "0.7.4"
|
||||
toml = "0.5.6"
|
||||
url = "2.2"
|
||||
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
[features]
|
||||
default = ["dirs"]
|
||||
@@ -1,208 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_network_defaults::mainnet::read_var_if_not_default;
|
||||
use nym_network_defaults::var_names::CONFIGURED;
|
||||
use std::any::type_name;
|
||||
use std::fmt::Debug;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
||||
|
||||
/// Helper for providing default value for templated config fields.
|
||||
pub fn missing_string_value<T: From<String>>() -> T {
|
||||
MISSING_VALUE.to_string().into()
|
||||
}
|
||||
|
||||
/// Helper for providing default INADDR_ANY IpAddr, i.e. `0.0.0.0`
|
||||
pub fn inaddr_any() -> IpAddr {
|
||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED)
|
||||
}
|
||||
|
||||
/// Helper for providing default IN6ADDR_ANY_INIT IpAddr, i.e. `::`
|
||||
pub fn in6addr_any_init() -> IpAddr {
|
||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED)
|
||||
}
|
||||
|
||||
/// Helper for providing binding warnings if node tries to bind to any of those
|
||||
pub const SPECIAL_ADDRESSES: &[IpAddr] = &[
|
||||
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||
IpAddr::V4(Ipv4Addr::BROADCAST),
|
||||
IpAddr::V6(Ipv6Addr::LOCALHOST),
|
||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
||||
];
|
||||
|
||||
// TODO: is it really part of 'Config'?
|
||||
pub trait OptionalSet {
|
||||
/// If the value is available (i.e. `Some`), the provided closure is applied.
|
||||
/// Otherwise `self` is returned with no modifications.
|
||||
fn with_optional<F, T>(self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
f(self, val)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// If the value is available (i.e. `Some`) it is validated and then the provided closure is applied.
|
||||
/// Otherwise `self` is returned with no modifications.
|
||||
fn with_validated_optional<F, T, V, E>(
|
||||
self,
|
||||
f: F,
|
||||
value: Option<T>,
|
||||
validate: V,
|
||||
) -> Result<Self, E>
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
V: Fn(&T) -> Result<(), E>,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = value {
|
||||
validate(&val)?;
|
||||
Ok(f(self, val))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// If the value is available (i.e. `Some`), the provided closure is applied.
|
||||
/// Otherwise, if the environment was configured and the corresponding variable was set,
|
||||
/// the value is parsed using the `FromStr` implementation and the closure is applied on that instead.
|
||||
/// Finally, if none of those were available, `self` is returned with no modifications.
|
||||
fn with_optional_env<F, T>(self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
return f(self, val);
|
||||
} else if std::env::var(CONFIGURED).is_ok() {
|
||||
if let Some(raw) = read_var_if_not_default(env_var) {
|
||||
return f(
|
||||
self,
|
||||
raw.parse().unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to parse value of {raw} into type {}. the error was {:?}",
|
||||
type_name::<T>(),
|
||||
err
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// If the value is available (i.e. `Some`), the provided closure is applied.
|
||||
/// Otherwise, if the environment was configured and the corresponding variable was set,
|
||||
/// the value is parsed using the provided parser and the closure is applied on that instead.
|
||||
/// Finally, if none of those were available, `self` is returned with no modifications.
|
||||
fn with_optional_custom_env<F, T, G>(
|
||||
self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
G: Fn(&str) -> T,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
return f(self, val);
|
||||
} else if std::env::var(CONFIGURED).is_ok() {
|
||||
if let Some(raw) = read_var_if_not_default(env_var) {
|
||||
return f(self, parser(&raw));
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// helper for when we want to use `OptionalSet` on an inner field
|
||||
// (used by clients wanting to set the `BaseConfig` values)
|
||||
#[macro_export]
|
||||
macro_rules! define_optional_set_inner {
|
||||
( $x: ident, $inner_field_name: ident, $inner_field_typ: ty ) => {
|
||||
impl $x {
|
||||
pub fn with_optional_inner<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn($inner_field_typ, T) -> $inner_field_typ,
|
||||
{
|
||||
self.$inner_field_name = self.$inner_field_name.with_optional(f, val);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_validated_optional_inner<F, T, V, E>(
|
||||
mut self,
|
||||
f: F,
|
||||
value: Option<T>,
|
||||
validate: V,
|
||||
) -> Result<Self, E>
|
||||
where
|
||||
F: Fn($inner_field_typ, T) -> $inner_field_typ,
|
||||
V: Fn(&T) -> Result<(), E>,
|
||||
{
|
||||
self.$inner_field_name = self
|
||||
.$inner_field_name
|
||||
.with_validated_optional(f, value, validate)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn with_optional_env_inner<F, T>(
|
||||
mut self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn($inner_field_typ, T) -> $inner_field_typ,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
self.$inner_field_name = self.$inner_field_name.with_optional_env(f, val, env_var);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_custom_env_inner<F, T, G>(
|
||||
mut self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn($inner_field_typ, T) -> $inner_field_typ,
|
||||
G: Fn(&str) -> T,
|
||||
{
|
||||
self.$inner_field_name = self
|
||||
.$inner_field_name
|
||||
.with_optional_custom_env(f, val, env_var, parser);
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// this function is only used for parsing values from the network defaults and thus the "expect" there are fine
|
||||
pub fn parse_urls(raw: &str) -> Vec<url::Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_url| {
|
||||
raw_url
|
||||
.trim()
|
||||
.parse()
|
||||
.expect("one of the provided urls was invalid")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl<T> OptionalSet for T {}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// removed in 1.1.19/1.1.20
|
||||
pub mod nym_config {
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
|
||||
pub const CONFIG_DIR: &str = "config";
|
||||
pub const DATA_DIR: &str = "data";
|
||||
|
||||
// no need for anything to do with saving.
|
||||
pub trait MigrationNymConfig: Serialize + DeserializeOwned {
|
||||
fn config_file_name() -> String {
|
||||
"config.toml".to_string()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf;
|
||||
|
||||
fn default_data_directory(id: &str) -> PathBuf {
|
||||
Self::default_data_directory_with_root(Self::default_root_directory(), id)
|
||||
}
|
||||
|
||||
fn default_data_directory_with_root<P: AsRef<Path>>(root: P, id: &str) -> PathBuf {
|
||||
root.as_ref().join(id).join(DATA_DIR)
|
||||
}
|
||||
|
||||
fn default_config_directory(id: &str) -> PathBuf {
|
||||
Self::default_config_directory_with_root(Self::default_root_directory(), id)
|
||||
}
|
||||
|
||||
fn default_config_directory_with_root<P: AsRef<Path>>(root: P, id: &str) -> PathBuf {
|
||||
root.as_ref().join(id).join(CONFIG_DIR)
|
||||
}
|
||||
|
||||
fn default_config_file_path(id: &str) -> PathBuf {
|
||||
Self::default_config_directory(id).join(Self::config_file_name())
|
||||
}
|
||||
|
||||
fn load_from_file(id: &str) -> io::Result<Self> {
|
||||
let file = Self::default_config_file_path(id);
|
||||
Self::load_from_filepath(file)
|
||||
}
|
||||
|
||||
fn load_from_filepath<P: AsRef<Path>>(filepath: P) -> io::Result<Self> {
|
||||
log::trace!("Loading from file: {:#?}", filepath.as_ref().to_owned());
|
||||
let config_contents = fs::read_to_string(filepath)?;
|
||||
|
||||
toml::from_str(&config_contents)
|
||||
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
|
||||
}
|
||||
}
|
||||
}
|
||||
+188
-168
@@ -1,199 +1,219 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use handlebars::{Handlebars, TemplateRenderError};
|
||||
use handlebars::Handlebars;
|
||||
use nym_network_defaults::mainnet::read_var_if_not_default;
|
||||
use nym_network_defaults::var_names::CONFIGURED;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::any::type_name;
|
||||
use std::fmt::Debug;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::{fs, io};
|
||||
|
||||
pub use helpers::{parse_urls, OptionalSet};
|
||||
pub use toml::de::Error as TomlDeError;
|
||||
|
||||
pub mod defaults;
|
||||
pub mod helpers;
|
||||
pub mod legacy_helpers;
|
||||
|
||||
pub const NYM_DIR: &str = ".nym";
|
||||
pub const DEFAULT_CONFIG_DIR: &str = "config";
|
||||
pub const DEFAULT_DATA_DIR: &str = "data";
|
||||
pub const DEFAULT_CONFIG_FILENAME: &str = "config.toml";
|
||||
pub const CONFIG_DIR: &str = "config";
|
||||
pub const DATA_DIR: &str = "data";
|
||||
pub const CRED_DB_FILE_NAME: &str = "credentials_database.db";
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn must_get_home() -> PathBuf {
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn may_get_home() -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
pub trait NymConfigTemplate: Serialize {
|
||||
pub trait NymConfig: Default + Serialize + DeserializeOwned {
|
||||
fn template() -> &'static str;
|
||||
|
||||
fn format_to_string(&self) -> String {
|
||||
// it is responsibility of whoever is implementing the trait to ensure the template is valid
|
||||
Handlebars::new()
|
||||
.render_template(Self::template(), &self)
|
||||
.unwrap()
|
||||
fn config_file_name() -> String {
|
||||
"config.toml".to_string()
|
||||
}
|
||||
|
||||
fn format_to_writer<W: Write>(&self, writer: W) -> io::Result<()> {
|
||||
if let Err(err) =
|
||||
Handlebars::new().render_template_to_write(Self::template(), &self, writer)
|
||||
{
|
||||
match err {
|
||||
TemplateRenderError::IOError(err, _) => return Err(err),
|
||||
other_err => {
|
||||
// it is responsibility of whoever is implementing the trait to ensure the template is valid
|
||||
panic!("invalid template: {other_err}")
|
||||
fn default_root_directory() -> PathBuf;
|
||||
|
||||
// default, most probable, implementations; can be easily overridden where required
|
||||
fn default_config_directory(id: &str) -> PathBuf {
|
||||
Self::default_config_directory_with_root(Self::default_root_directory(), id)
|
||||
}
|
||||
|
||||
fn default_config_directory_with_root<P: AsRef<Path>>(root: P, id: &str) -> PathBuf {
|
||||
root.as_ref().join(id).join(CONFIG_DIR)
|
||||
}
|
||||
|
||||
fn default_data_directory(id: &str) -> PathBuf {
|
||||
Self::default_data_directory_with_root(Self::default_root_directory(), id)
|
||||
}
|
||||
|
||||
fn default_data_directory_with_root<P: AsRef<Path>>(root: P, id: &str) -> PathBuf {
|
||||
root.as_ref().join(id).join(DATA_DIR)
|
||||
}
|
||||
|
||||
fn default_config_file_path(id: &str) -> PathBuf {
|
||||
Self::default_config_directory(id).join(Self::config_file_name())
|
||||
}
|
||||
|
||||
fn default_config_file_path_with_root<P: AsRef<Path>>(root: P, id: &str) -> PathBuf {
|
||||
Self::default_config_directory_with_root(root, id).join(Self::config_file_name())
|
||||
}
|
||||
|
||||
// We provide a second set of functions that tries to not panic.
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf>;
|
||||
|
||||
fn try_default_config_directory(id: &str) -> Option<PathBuf> {
|
||||
Self::try_default_root_directory().map(|d| d.join(id).join(CONFIG_DIR))
|
||||
}
|
||||
|
||||
fn try_default_data_directory(id: &str) -> Option<PathBuf> {
|
||||
Self::try_default_root_directory().map(|d| d.join(id).join(DATA_DIR))
|
||||
}
|
||||
|
||||
fn try_default_config_file_path(id: &str) -> Option<PathBuf> {
|
||||
Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name()))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf;
|
||||
fn config_directory(&self) -> PathBuf;
|
||||
fn data_directory(&self) -> PathBuf;
|
||||
|
||||
fn save_to_file(&self, custom_location: Option<PathBuf>) -> io::Result<()> {
|
||||
let reg = Handlebars::new();
|
||||
// it's whoever is implementing the trait responsibility to make sure you can execute your own template on your data
|
||||
let templated_config = reg.render_template(Self::template(), self).unwrap();
|
||||
|
||||
// make sure the whole directory structure actually exists
|
||||
match custom_location.clone() {
|
||||
Some(loc) => {
|
||||
if let Some(parent_dir) = loc.parent() {
|
||||
fs::create_dir_all(parent_dir)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
None => fs::create_dir_all(self.config_directory()),
|
||||
}?;
|
||||
|
||||
let location = custom_location
|
||||
.unwrap_or_else(|| self.config_directory().join(Self::config_file_name()));
|
||||
log::info!("Configuration file will be saved to {:?}", location);
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
fs::write(location.clone(), templated_config)?;
|
||||
let mut perms = fs::metadata(location.clone())?.permissions();
|
||||
perms.set_mode(0o600);
|
||||
fs::set_permissions(location, perms)?;
|
||||
} else {
|
||||
fs::write(location, templated_config)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_formatted_config_to_file<C, P>(config: &C, path: P) -> io::Result<()>
|
||||
where
|
||||
C: NymConfigTemplate,
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
log::trace!("trying to save config file to {}", path.as_ref().display());
|
||||
let file = File::create(path.as_ref())?;
|
||||
|
||||
// TODO: check for whether any of our configs stores anything sensitive
|
||||
// and change that to 0o644 instead
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let mut perms = fs::metadata(path.as_ref())?.permissions();
|
||||
perms.set_mode(0o600);
|
||||
fs::set_permissions(path, perms)?;
|
||||
fn load_from_file(id: &str) -> io::Result<Self> {
|
||||
let file = Self::default_config_file_path(id);
|
||||
Self::load_from_filepath(file)
|
||||
}
|
||||
|
||||
config.format_to_writer(file)
|
||||
fn load_from_filepath<P: AsRef<Path>>(filepath: P) -> io::Result<Self> {
|
||||
log::trace!("Loading from file: {:#?}", filepath.as_ref().to_owned());
|
||||
let config_contents = fs::read_to_string(filepath)?;
|
||||
|
||||
toml::from_str(&config_contents)
|
||||
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_config_from_toml_str<C>(raw: &str) -> Result<C, TomlDeError>
|
||||
where
|
||||
C: DeserializeOwned,
|
||||
{
|
||||
toml::from_str(raw)
|
||||
// this function is only used for parsing values from the network defaults and thus the "expect" there are fine
|
||||
pub fn parse_urls(raw: &str) -> Vec<url::Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_url| {
|
||||
raw_url
|
||||
.trim()
|
||||
.parse()
|
||||
.expect("one of the provided nym api urls is invalid")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn read_config_from_toml_file<C, P>(path: P) -> io::Result<C>
|
||||
where
|
||||
C: DeserializeOwned,
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
log::trace!(
|
||||
"trying to read config file from {}",
|
||||
path.as_ref().display()
|
||||
);
|
||||
let content = fs::read_to_string(path)?;
|
||||
pub trait OptionalSet {
|
||||
fn with_optional<F, T>(self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
f(self, val)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should we be preserving original error type instead?
|
||||
deserialize_config_from_toml_str(&content)
|
||||
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
|
||||
fn with_validated_optional<F, T, V, E>(
|
||||
self,
|
||||
f: F,
|
||||
value: Option<T>,
|
||||
validate: V,
|
||||
) -> Result<Self, E>
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
V: Fn(&T) -> Result<(), E>,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = value {
|
||||
validate(&val)?;
|
||||
Ok(f(self, val))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn with_optional_env<F, T>(self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
return f(self, val);
|
||||
} else if std::env::var(CONFIGURED).is_ok() {
|
||||
if let Some(raw) = read_var_if_not_default(env_var) {
|
||||
return f(
|
||||
self,
|
||||
raw.parse().unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to parse value of {raw} into type {}. the error was {:?}",
|
||||
type_name::<T>(),
|
||||
err
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn with_optional_custom_env<F, T, G>(
|
||||
self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(Self, T) -> Self,
|
||||
G: Fn(&str) -> T,
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(val) = val {
|
||||
return f(self, val);
|
||||
} else if std::env::var(CONFIGURED).is_ok() {
|
||||
if let Some(raw) = read_var_if_not_default(env_var) {
|
||||
return f(self, parser(&raw));
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// pub trait NymConfig: Default + Serialize + DeserializeOwned {
|
||||
// fn template() -> &'static str;
|
||||
//
|
||||
// fn config_file_name() -> String {
|
||||
// "config.toml".to_string()
|
||||
// }
|
||||
//
|
||||
// fn default_root_directory() -> PathBuf;
|
||||
//
|
||||
// // default, most probable, implementations; can be easily overridden where required
|
||||
// fn default_config_directory(id: &str) -> PathBuf {
|
||||
// Self::default_root_directory()
|
||||
// .join(id)
|
||||
// .join(DEFAULT_CONFIG_DIR)
|
||||
// }
|
||||
//
|
||||
// fn default_data_directory(id: &str) -> PathBuf {
|
||||
// Self::default_root_directory()
|
||||
// .join(id)
|
||||
// .join(DEFAULT_DATA_DIR)
|
||||
// }
|
||||
//
|
||||
// fn default_config_file_path(id: &str) -> PathBuf {
|
||||
// Self::default_config_directory(id).join(Self::config_file_name())
|
||||
// }
|
||||
//
|
||||
// // We provide a second set of functions that tries to not panic.
|
||||
//
|
||||
// fn try_default_root_directory() -> Option<PathBuf>;
|
||||
//
|
||||
// fn try_default_config_directory(id: &str) -> Option<PathBuf> {
|
||||
// Self::try_default_root_directory().map(|d| d.join(id).join(DEFAULT_CONFIG_DIR))
|
||||
// }
|
||||
//
|
||||
// fn try_default_data_directory(id: &str) -> Option<PathBuf> {
|
||||
// Self::try_default_root_directory().map(|d| d.join(id).join(DEFAULT_DATA_DIR))
|
||||
// }
|
||||
//
|
||||
// fn try_default_config_file_path(id: &str) -> Option<PathBuf> {
|
||||
// Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name()))
|
||||
// }
|
||||
//
|
||||
// fn root_directory(&self) -> PathBuf;
|
||||
// fn config_directory(&self) -> PathBuf;
|
||||
// fn data_directory(&self) -> PathBuf;
|
||||
//
|
||||
// fn save_to_file(&self, custom_location: Option<PathBuf>) -> io::Result<()> {
|
||||
// Ok(())
|
||||
// // let reg = Handlebars::new();
|
||||
// // // it's whoever is implementing the trait responsibility to make sure you can execute your own template on your data
|
||||
// // let templated_config = reg.render_template(Self::template(), self).unwrap();
|
||||
// //
|
||||
// // // make sure the whole directory structure actually exists
|
||||
// // match custom_location.clone() {
|
||||
// // Some(loc) => {
|
||||
// // if let Some(parent_dir) = loc.parent() {
|
||||
// // fs::create_dir_all(parent_dir)
|
||||
// // } else {
|
||||
// // Ok(())
|
||||
// // }
|
||||
// // }
|
||||
// // None => fs::create_dir_all(self.config_directory()),
|
||||
// // }?;
|
||||
// //
|
||||
// // let location = custom_location
|
||||
// // .unwrap_or_else(|| self.config_directory().join(Self::config_file_name()));
|
||||
// // log::info!("Configuration file will be saved to {:?}", location);
|
||||
// //
|
||||
// // cfg_if::cfg_if! {
|
||||
// // if #[cfg(unix)] {
|
||||
// // fs::write(location.clone(), templated_config)?;
|
||||
// // let mut perms = fs::metadata(location.clone())?.permissions();
|
||||
// // perms.set_mode(0o600);
|
||||
// // fs::set_permissions(location, perms)?;
|
||||
// // } else {
|
||||
// // fs::write(location, templated_config)?;
|
||||
// // }
|
||||
// // }
|
||||
// //
|
||||
// // Ok(())
|
||||
// }
|
||||
//
|
||||
// fn load_from_file(id: &str) -> io::Result<Self> {
|
||||
// let file = Self::default_config_file_path(id);
|
||||
// log::trace!("Loading from file: {:#?}", file);
|
||||
// let config_contents = fs::read_to_string(file)?;
|
||||
//
|
||||
// toml::from_str(&config_contents)
|
||||
// .map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
|
||||
// }
|
||||
// }
|
||||
impl<T> OptionalSet for T where T: NymConfig {}
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
*/
|
||||
|
||||
use crate::ephemeral_storage::EphemeralStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::persistent_storage::PersistentStorage;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::path::Path;
|
||||
|
||||
mod backends;
|
||||
pub mod ephemeral_storage;
|
||||
@@ -19,7 +16,7 @@ pub mod persistent_storage;
|
||||
pub mod storage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub async fn initialise_persistent_storage<P: AsRef<Path>>(path: P) -> PersistentStorage {
|
||||
pub async fn initialise_persistent_storage(path: std::path::PathBuf) -> PersistentStorage {
|
||||
match persistent_storage::PersistentStorage::init(path).await {
|
||||
Err(err) => panic!("failed to initialise credential storage - {err}"),
|
||||
Ok(storage) => storage,
|
||||
|
||||
@@ -23,7 +23,7 @@ impl PersistentStorage {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `database_path`: path to the database.
|
||||
pub async fn init<P: AsRef<Path>>(database_path: P) -> Result<Self, StorageError> {
|
||||
pub async fn init<P: AsRef<Path> + Send>(database_path: P) -> Result<Self, StorageError> {
|
||||
debug!(
|
||||
"Attempting to connect to database {:?}",
|
||||
database_path.as_ref().as_os_str()
|
||||
|
||||
@@ -19,20 +19,20 @@ macro_rules! measure {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
let start_cycles = $crate::cpu_cycles();
|
||||
// if the block needs to return something, we can return it
|
||||
let r = $x;
|
||||
let end_cycles = $crate::cpu_cycles();
|
||||
let name = if let Some(meta) = tracing::Span::current().metadata() {
|
||||
meta.name()
|
||||
} else {
|
||||
"measure"
|
||||
};
|
||||
match (start_cycles, end_cycles) {
|
||||
(Ok(start), Ok(end)) => log::trace!("{} cpucycles: {}", name, end - start),
|
||||
(Err(e), _) => error!("{e}"),
|
||||
(_, Err(e)) => error!("{e}"),
|
||||
}
|
||||
r
|
||||
// if the block needs to return something, we can return it
|
||||
let r = $x;
|
||||
let end_cycles = $crate::cpu_cycles();
|
||||
let name = if let Some(meta) = tracing::Span::current().metadata() {
|
||||
meta.name()
|
||||
} else {
|
||||
"measure"
|
||||
};
|
||||
match (start_cycles, end_cycles) {
|
||||
(Ok(start), Ok(end)) => info!("{} cpucycles: {}", name, end - start),
|
||||
(Err(e), _) => error!("{e}"),
|
||||
(_, Err(e)) => error!("{e}"),
|
||||
}
|
||||
r
|
||||
} else {
|
||||
$x
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddressError;
|
||||
use nym_sphinx_types::{NymPacketError, OutfoxError, SphinxError};
|
||||
use nym_sphinx_types::{NymPacketError, SphinxError};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -25,7 +25,4 @@ pub enum MixProcessingError {
|
||||
|
||||
#[error("the received packet was set to use the very old and very much deprecated 'VPN' mode")]
|
||||
ReceivedOldTypeVpnPacket,
|
||||
|
||||
#[error("failed to process received outfox packet: {0}")]
|
||||
OutfoxProcessingError(#[from] OutfoxError),
|
||||
}
|
||||
|
||||
@@ -20,14 +20,12 @@ use tracing::instrument;
|
||||
|
||||
type ForwardAck = MixPacket;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessedFinalHop {
|
||||
pub destination: DestinationAddressBytes,
|
||||
pub forward_ack: Option<ForwardAck>,
|
||||
pub message: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MixProcessingResult {
|
||||
/// Contains unwrapped data that should first get delayed before being sent to next hop.
|
||||
ForwardHop(MixPacket, Option<SphinxDelay>),
|
||||
@@ -143,7 +141,7 @@ impl SphinxPacketProcessor {
|
||||
match SurbAck::try_recover_first_hop_packet(&ack_data, packet_type) {
|
||||
Ok((first_hop, packet)) => (first_hop, packet),
|
||||
Err(err) => {
|
||||
info!("Failed to recover first hop from ack data: {err}");
|
||||
debug!("Failed to recover first hop from ack data: {err}");
|
||||
return Err(err.into());
|
||||
}
|
||||
};
|
||||
@@ -207,7 +205,7 @@ impl SphinxPacketProcessor {
|
||||
if packet.is_final_hop() {
|
||||
self.process_final_hop(
|
||||
DestinationAddressBytes::from_bytes(next_address),
|
||||
packet.recover_plaintext()?.to_vec(),
|
||||
packet.recover_plaintext().to_vec(),
|
||||
packet_size,
|
||||
packet_type,
|
||||
)
|
||||
@@ -241,14 +239,7 @@ impl SphinxPacketProcessor {
|
||||
|
||||
// for forward packets, extract next hop and set delay (but do NOT delay here)
|
||||
// for final packets, extract SURBAck
|
||||
let final_processing_result =
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_type);
|
||||
|
||||
if final_processing_result.is_err() {
|
||||
error!("{:?}", final_processing_result)
|
||||
}
|
||||
|
||||
final_processing_result
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_type)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This should be modified whenever an updated Ethereum contract is uploaded
|
||||
pub const ETH_JSON_ABI: &str = r#"
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract CosmosERC20",
|
||||
"name": "_erc20",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "contract Gravity",
|
||||
"name": "_gravityBridge",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "Bandwidth",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "VerificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bytes",
|
||||
"name": "SignedVerificationKey",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "string",
|
||||
"name": "CosmosRecipient",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"name": "BBCredentialPurchased",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bool",
|
||||
"name": "Enabled",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "CredentialGenerationSwitch",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "NewBytesPerToken",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "RatioChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "BytesPerToken",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "bandwidthFromToken",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_newBytesPerTokenAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "changeRatio",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "credentialGenerationEnabled",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_generation",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "credentialGenerationSwitch",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "erc20",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract CosmosERC20",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_verificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "_signedVerificationKey",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "_cosmosRecipient",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"name": "generateBasicBandwidthCredential",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "gravityBridge",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract Gravity",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
"#;
|
||||
|
||||
pub const ETH_ERC20_JSON_ABI: &str = r#"
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "name_",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "symbol_",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "subtractedValue",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "decreaseAllowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "addedValue",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "increaseAllowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
"#;
|
||||
@@ -58,7 +58,6 @@ impl SurbAck {
|
||||
let packet_size = match packet_type {
|
||||
PacketType::Outfox => surb_ack_payload.len().max(MIN_PACKET_SIZE),
|
||||
PacketType::Mix => PacketSize::AckPacket.payload_size(),
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => PacketSize::AckPacket.payload_size(),
|
||||
};
|
||||
|
||||
@@ -76,7 +75,6 @@ impl SurbAck {
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
packet_size,
|
||||
surb_ack_payload,
|
||||
@@ -107,7 +105,6 @@ impl SurbAck {
|
||||
PacketSize::OutfoxAckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN
|
||||
}
|
||||
PacketType::Mix => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
}
|
||||
}
|
||||
@@ -140,7 +137,6 @@ impl SurbAck {
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(&b[address_offset..])?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
};
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ where
|
||||
>(rng, full_address.encryption_key());
|
||||
|
||||
let public_key_bytes = ephemeral_keypair.public_key().to_bytes();
|
||||
|
||||
let cover_size = packet_size.plaintext_size() - public_key_bytes.len() - ack_bytes.len();
|
||||
|
||||
let mut cover_content: Vec<_> = LOOP_COVER_MESSAGE_PAYLOAD
|
||||
@@ -123,35 +122,19 @@ where
|
||||
let delays = delays::generate_from_average_duration(route.len(), average_packet_delay);
|
||||
let destination = full_address.as_sphinx_destination();
|
||||
|
||||
// once merged, that's an easy rng injection point for sphinx packets : )
|
||||
let packet = NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?;
|
||||
|
||||
let first_hop_address =
|
||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||
|
||||
// once merged, that's an easy rng injection point for sphinx packets : )
|
||||
let packet = match packet_type {
|
||||
PacketType::Mix => NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
PacketType::Outfox => NymPacket::outfox_build(
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
Some(packet_size.plaintext_size()),
|
||||
)?,
|
||||
};
|
||||
|
||||
Ok(MixPacket::new(first_hop_address, packet, packet_type))
|
||||
Ok(MixPacket::new(first_hop_address, packet, PacketType::Mix))
|
||||
}
|
||||
|
||||
/// Helper function used to determine if given message represents a loop cover message.
|
||||
|
||||
@@ -85,7 +85,6 @@ impl Decoder for NymCodec {
|
||||
match header.packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(slice)?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(slice)?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(slice)?,
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -244,7 +244,6 @@ impl PacketSize {
|
||||
) -> Result<Self, InvalidPacketSize> {
|
||||
let overhead = match packet_type {
|
||||
PacketType::Mix => SPHINX_PACKET_OVERHEAD,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => SPHINX_PACKET_OVERHEAD,
|
||||
PacketType::Outfox => OUTFOX_PACKET_OVERHEAD,
|
||||
};
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![allow(deprecated)]
|
||||
// allow the u8 repr of `Vpn` PacketType whilst deprecating all of its other uses
|
||||
|
||||
use crate::PacketSize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::PacketSize;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketType {
|
||||
@@ -17,23 +15,17 @@ pub struct InvalidPacketType {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(deprecated)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub enum PacketType {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
#[default]
|
||||
#[serde(rename = "mix")]
|
||||
#[serde(alias = "sphinx")]
|
||||
Mix = 0,
|
||||
|
||||
/// Represents a packet that should be sent through the network as fast as possible.
|
||||
#[deprecated]
|
||||
#[serde(rename = "unsupported-mix-vpn")]
|
||||
Vpn = 1,
|
||||
|
||||
/// Abusing this to add Outfox support
|
||||
#[serde(rename = "outfox")]
|
||||
Outfox = 2,
|
||||
}
|
||||
|
||||
@@ -41,7 +33,6 @@ impl fmt::Display for PacketType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PacketType::Mix => write!(f, "Mix"),
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => write!(f, "Vpn"),
|
||||
PacketType::Outfox => write!(f, "Outfox"),
|
||||
}
|
||||
|
||||
@@ -251,7 +251,6 @@ pub trait FragmentPreparer {
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
|
||||
@@ -1,41 +1,88 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use nym_client_core::config::Config as BaseClientConfig;
|
||||
use crate::config::template::config_template;
|
||||
pub use nym_client_core::config::Config as BaseConfig;
|
||||
pub use nym_client_core::config::MISSING_VALUE;
|
||||
use nym_client_core::config::{ClientCoreConfigTrait, DebugConfig};
|
||||
use nym_config::defaults::DEFAULT_SOCKS5_LISTENING_PORT;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_service_providers_common::interface::ProviderInterfaceVersion;
|
||||
use nym_socks5_requests::Socks5ProtocolVersion;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub mod old_config_v1_1_20_2;
|
||||
|
||||
pub use nym_service_providers_common::interface::ProviderInterfaceVersion;
|
||||
pub use nym_socks5_requests::Socks5ProtocolVersion;
|
||||
pub mod old_config_v1_1_13;
|
||||
mod template;
|
||||
|
||||
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
|
||||
const DEFAULT_PER_REQUEST_SURBS: u32 = 3;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseClientConfig,
|
||||
base: BaseConfig<Config>,
|
||||
|
||||
pub socks5: Socks5,
|
||||
socks5: Socks5,
|
||||
}
|
||||
|
||||
impl NymConfig for Config {
|
||||
fn template() -> &'static str {
|
||||
config_template()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = dirs::home_dir().expect("Failed to evaluate $HOME value");
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.get_nym_root_directory()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(self.base.get_id())
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory().join(self.base.get_id()).join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientCoreConfigTrait for Config {
|
||||
fn get_gateway_endpoint(&self) -> &nym_client_core::config::GatewayEndpointConfig {
|
||||
self.base.get_gateway_endpoint()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: Into<String>>(id: S, version: S, provider_mix_address: S) -> Self {
|
||||
pub fn new<S: Into<String>>(id: S, provider_mix_address: S) -> Self {
|
||||
Config {
|
||||
base: BaseClientConfig::new(id, version),
|
||||
base: BaseConfig::new(id),
|
||||
socks5: Socks5::new(provider_mix_address),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_base(base: BaseClientConfig, socks5: Socks5) -> Self {
|
||||
Config { base, socks5 }
|
||||
#[must_use]
|
||||
pub fn with_root_directory<P: AsRef<Path>>(mut self, root_dir: P) -> Self {
|
||||
self.base = self.base.reset_nym_root_directory(root_dir);
|
||||
let data_dir = self.data_directory();
|
||||
self.base = self.base.reset_data_directory(data_dir);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
@@ -43,38 +90,63 @@ impl Config {
|
||||
self.base.validate()
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socks5.listening_port = port;
|
||||
self
|
||||
// getters
|
||||
pub fn get_base(&self) -> &BaseConfig<Self> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
pub fn with_anonymous_replies(mut self, anonymous_replies: bool) -> Self {
|
||||
self.socks5.send_anonymously = anonymous_replies;
|
||||
self
|
||||
pub fn get_base_mut(&mut self) -> &mut BaseConfig<Self> {
|
||||
&mut self.base
|
||||
}
|
||||
|
||||
pub fn get_socks5(&self) -> &Socks5 {
|
||||
&self.socks5
|
||||
}
|
||||
|
||||
pub fn get_socks5_mut(&mut self) -> &mut Socks5 {
|
||||
&mut self.socks5
|
||||
}
|
||||
|
||||
pub fn get_debug_settings(&self) -> &DebugConfig {
|
||||
self.get_base().get_debug_config()
|
||||
}
|
||||
|
||||
pub fn get_config_file_save_location(&self) -> PathBuf {
|
||||
self.config_directory().join(Self::config_file_name())
|
||||
}
|
||||
|
||||
// poor man's 'builder' method
|
||||
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
{
|
||||
self.base = f(self.base, val);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socks5.with_port(port);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_anonymous_replies(mut self, anonymous_replies: bool) -> Self {
|
||||
self.socks5.with_anonymous_replies(anonymous_replies);
|
||||
self
|
||||
}
|
||||
|
||||
// helper methods to use `OptionalSet` trait. Those are defined due to very... ehm. 'specific' structure of this config
|
||||
// (plz, lets refactor it)
|
||||
pub fn with_optional_base<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
pub fn with_optional_ext<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
{
|
||||
self.base = self.base.with_optional(f, val);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_base_env<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
pub fn with_optional_env_ext<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
@@ -82,7 +154,7 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_base_custom_env<F, T, G>(
|
||||
pub fn with_optional_custom_env_ext<F, T, G>(
|
||||
mut self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
@@ -90,7 +162,7 @@ impl Config {
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
|
||||
G: Fn(&str) -> T,
|
||||
{
|
||||
self.base = self.base.with_optional_custom_env(f, val, env_var, parser);
|
||||
@@ -102,19 +174,19 @@ impl Config {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5 {
|
||||
/// The port on which the client will be listening for incoming requests
|
||||
pub listening_port: u16,
|
||||
listening_port: u16,
|
||||
|
||||
/// The mix address of the provider to which all requests are going to be sent.
|
||||
pub provider_mix_address: String,
|
||||
provider_mix_address: String,
|
||||
|
||||
/// The version of the 'service provider' this client is going to use in its communication with the
|
||||
/// specified socks5 provider.
|
||||
// if in doubt, use the legacy version as initially nobody will be using the updated binaries
|
||||
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
|
||||
pub provider_interface_version: ProviderInterfaceVersion,
|
||||
provider_interface_version: ProviderInterfaceVersion,
|
||||
|
||||
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
|
||||
pub socks5_protocol_version: Socks5ProtocolVersion,
|
||||
socks5_protocol_version: Socks5ProtocolVersion,
|
||||
|
||||
/// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
|
||||
/// While this is going to hide its actual address information, it will make the actual communication
|
||||
@@ -122,10 +194,10 @@ pub struct Socks5 {
|
||||
///
|
||||
/// Note that some service providers might not support this.
|
||||
#[serde(default)]
|
||||
pub send_anonymously: bool,
|
||||
send_anonymously: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub socks5_debug: Socks5Debug,
|
||||
socks5_debug: Socks5Debug,
|
||||
}
|
||||
|
||||
impl Socks5 {
|
||||
@@ -140,20 +212,81 @@ impl Socks5 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_port(&mut self, port: u16) {
|
||||
self.listening_port = port;
|
||||
}
|
||||
|
||||
pub fn with_provider_mix_address(&mut self, address: String) {
|
||||
self.provider_mix_address = address;
|
||||
}
|
||||
|
||||
pub fn with_provider_interface_version(&mut self, version: ProviderInterfaceVersion) {
|
||||
self.provider_interface_version = version;
|
||||
}
|
||||
|
||||
pub fn with_socks5_protocol_version(&mut self, version: Socks5ProtocolVersion) {
|
||||
self.socks5_protocol_version = version;
|
||||
}
|
||||
|
||||
pub fn with_anonymous_replies(&mut self, anonymous_replies: bool) {
|
||||
self.send_anonymously = anonymous_replies;
|
||||
}
|
||||
|
||||
pub fn get_raw_provider_mix_address(&self) -> String {
|
||||
self.provider_mix_address.clone()
|
||||
}
|
||||
|
||||
pub fn get_provider_mix_address(&self) -> Recipient {
|
||||
Recipient::try_from_base58_string(&self.provider_mix_address)
|
||||
.expect("malformed provider address")
|
||||
}
|
||||
|
||||
pub fn get_provider_interface_version(&self) -> ProviderInterfaceVersion {
|
||||
self.provider_interface_version
|
||||
}
|
||||
|
||||
pub fn get_socks5_protocol_version(&self) -> Socks5ProtocolVersion {
|
||||
self.socks5_protocol_version
|
||||
}
|
||||
|
||||
pub fn get_send_anonymously(&self) -> bool {
|
||||
self.send_anonymously
|
||||
}
|
||||
|
||||
pub fn get_listening_port(&self) -> u16 {
|
||||
self.listening_port
|
||||
}
|
||||
|
||||
pub fn get_connection_start_surbs(&self) -> u32 {
|
||||
self.socks5_debug.connection_start_surbs
|
||||
}
|
||||
|
||||
pub fn get_per_request_surbs(&self) -> u32 {
|
||||
self.socks5_debug.per_request_surbs
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
impl Default for Socks5 {
|
||||
fn default() -> Self {
|
||||
Socks5 {
|
||||
listening_port: DEFAULT_SOCKS5_LISTENING_PORT,
|
||||
provider_mix_address: "".into(),
|
||||
provider_interface_version: ProviderInterfaceVersion::Legacy,
|
||||
socks5_protocol_version: Socks5ProtocolVersion::Legacy,
|
||||
send_anonymously: false,
|
||||
socks5_debug: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5Debug {
|
||||
/// Number of reply SURBs attached to each `Request::Connect` message.
|
||||
pub connection_start_surbs: u32,
|
||||
connection_start_surbs: u32,
|
||||
|
||||
/// Number of reply SURBs attached to each `Request::Send` message.
|
||||
pub per_request_surbs: u32,
|
||||
per_request_surbs: u32,
|
||||
}
|
||||
|
||||
impl Default for Socks5Debug {
|
||||
|
||||
@@ -3,60 +3,60 @@
|
||||
|
||||
use crate::config::{Config, Socks5};
|
||||
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
// #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
// #[serde(deny_unknown_fields)]
|
||||
// pub struct OldConfigV1_1_13 {
|
||||
// #[serde(flatten)]
|
||||
// base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
//
|
||||
// socks5: Socks5,
|
||||
// }
|
||||
//
|
||||
// //
|
||||
// // impl NymConfig for OldConfigV1_1_13 {
|
||||
// // fn template() -> &'static str {
|
||||
// // // not intended to be used
|
||||
// // unimplemented!()
|
||||
// // }
|
||||
// //
|
||||
// // fn default_root_directory() -> PathBuf {
|
||||
// // #[cfg(not(target_os = "android"))]
|
||||
// // let base_dir = dirs::home_dir().expect("Failed to evaluate $HOME value");
|
||||
// // #[cfg(target_os = "android")]
|
||||
// // let base_dir = PathBuf::from("/tmp");
|
||||
// //
|
||||
// // base_dir.join(".nym").join("socks5-clients")
|
||||
// // }
|
||||
// //
|
||||
// // fn try_default_root_directory() -> Option<PathBuf> {
|
||||
// // dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
|
||||
// // }
|
||||
// //
|
||||
// // fn root_directory(&self) -> PathBuf {
|
||||
// // self.base.client.nym_root_directory.clone()
|
||||
// // }
|
||||
// //
|
||||
// // fn config_directory(&self) -> PathBuf {
|
||||
// // self.root_directory()
|
||||
// // .join(&self.base.client.id)
|
||||
// // .join("config")
|
||||
// // }
|
||||
// //
|
||||
// // fn data_directory(&self) -> PathBuf {
|
||||
// // self.root_directory()
|
||||
// // .join(&self.base.client.id)
|
||||
// // .join("data")
|
||||
// // }
|
||||
// // }
|
||||
//
|
||||
// impl From<OldConfigV1_1_13> for Config {
|
||||
// fn from(value: OldConfigV1_1_13) -> Self {
|
||||
// Config {
|
||||
// base: value.base.into(),
|
||||
// socks5: value.socks5,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
socks5: Socks5,
|
||||
}
|
||||
|
||||
impl NymConfig for OldConfigV1_1_13 {
|
||||
fn template() -> &'static str {
|
||||
// not intended to be used
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = dirs::home_dir().expect("Failed to evaluate $HOME value");
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for Config {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socks5: value.socks5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseClientConfigV1_1_20_2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::config::{Config, Socks5, Socks5Debug};
|
||||
pub use nym_service_providers_common::interface::ProviderInterfaceVersion;
|
||||
pub use nym_socks5_requests::Socks5ProtocolVersion;
|
||||
|
||||
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
|
||||
const DEFAULT_PER_REQUEST_SURBS: u32 = 3;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseClientConfigV1_1_20_2,
|
||||
|
||||
pub socks5: Socks5V1_1_20_2,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20_2> for Config {
|
||||
fn from(value: ConfigV1_1_20_2) -> Self {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socks5: value.socks5.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5V1_1_20_2 {
|
||||
pub listening_port: u16,
|
||||
pub provider_mix_address: String,
|
||||
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
|
||||
pub provider_interface_version: ProviderInterfaceVersion,
|
||||
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
|
||||
pub socks5_protocol_version: Socks5ProtocolVersion,
|
||||
#[serde(default)]
|
||||
pub send_anonymously: bool,
|
||||
#[serde(default)]
|
||||
pub socks5_debug: Socks5DebugV1_1_20_2,
|
||||
}
|
||||
|
||||
impl From<Socks5V1_1_20_2> for Socks5 {
|
||||
fn from(value: Socks5V1_1_20_2) -> Self {
|
||||
Socks5 {
|
||||
listening_port: value.listening_port,
|
||||
provider_mix_address: value.provider_mix_address,
|
||||
provider_interface_version: value.provider_interface_version,
|
||||
socks5_protocol_version: value.socks5_protocol_version,
|
||||
send_anonymously: value.send_anonymously,
|
||||
socks5_debug: value.socks5_debug.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5DebugV1_1_20_2 {
|
||||
/// Number of reply SURBs attached to each `Request::Connect` message.
|
||||
pub connection_start_surbs: u32,
|
||||
|
||||
/// Number of reply SURBs attached to each `Request::Send` message.
|
||||
pub per_request_surbs: u32,
|
||||
}
|
||||
|
||||
impl From<Socks5DebugV1_1_20_2> for Socks5Debug {
|
||||
fn from(value: Socks5DebugV1_1_20_2) -> Self {
|
||||
Socks5Debug {
|
||||
connection_start_surbs: value.connection_start_surbs,
|
||||
per_request_surbs: value.per_request_surbs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Socks5DebugV1_1_20_2 {
|
||||
fn default() -> Self {
|
||||
Socks5DebugV1_1_20_2 {
|
||||
connection_start_surbs: DEFAULT_CONNECTION_START_SURBS,
|
||||
per_request_surbs: DEFAULT_PER_REQUEST_SURBS,
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
-43
@@ -1,97 +1,102 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// 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.
|
||||
pub(crate) const CONFIG_TEMPLATE: &str = r#"
|
||||
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.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
##### main base client config options #####
|
||||
|
||||
[core.client]
|
||||
[client]
|
||||
# Version of the client for which this configuration was created.
|
||||
version = '{{ core.client.version }}'
|
||||
version = '{{ client.version }}'
|
||||
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ core.client.id }}'
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
disabled_credentials_mode = {{ core.client.disabled_credentials_mode }}
|
||||
disabled_credentials_mode = {{ client.disabled_credentials_mode }}
|
||||
|
||||
# Addresses to nyxd validators via which the client can communicate with the chain.
|
||||
nyxd_urls = [
|
||||
{{#each core.client.nyxd_urls }}
|
||||
{{#each client.nyxd_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
nym_api_urls = [
|
||||
{{#each core.client.nym_api_urls }}
|
||||
{{#each client.nym_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
[storage_paths]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
|
||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||
|
||||
# Path to file containing public identity key.
|
||||
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
|
||||
public_identity_key_file = '{{ client.public_identity_key_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
|
||||
private_encryption_key_file = '{{ client.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
|
||||
public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
||||
|
||||
# Path to the database containing bandwidth credentials
|
||||
database_path = '{{ client.database_path }}'
|
||||
|
||||
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
reply_surb_database_path = '{{ client.reply_surb_database_path }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}'
|
||||
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.
|
||||
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
|
||||
ack_key_file = '{{ client.ack_key_file }}'
|
||||
|
||||
# Path to the database containing bandwidth credentials
|
||||
credentials_database = '{{ storage_paths.credentials_database }}'
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
# DEPRECATED
|
||||
[core.client.gateway_endpoint]
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ core.client.gateway_endpoint.gateway_id }}'
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ core.client.gateway_endpoint.gateway_owner }}'
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ core.client.gateway_endpoint.gateway_listener }}'
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
[core.socks5]
|
||||
[socks5]
|
||||
|
||||
# The mix address of the provider to which all requests are going to be sent.
|
||||
provider_mix_address = '{{ core.socks5.provider_mix_address }}'
|
||||
provider_mix_address = '{{ socks5.provider_mix_address }}'
|
||||
|
||||
# The port on which the client will be listening for incoming requests
|
||||
listening_port = {{ core.socks5.listening_port }}
|
||||
listening_port = {{ socks5.listening_port }}
|
||||
|
||||
# Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
|
||||
# While this is going to hide its actual address information, it will make the actual communication
|
||||
# slower and consume nearly double the bandwidth as it will require sending reply SURBs.
|
||||
#
|
||||
# Note that some service providers might not support this.
|
||||
send_anonymously = {{ core.socks5.send_anonymously }}
|
||||
send_anonymously = {{ socks5.send_anonymously }}
|
||||
|
||||
##### logging configuration options #####
|
||||
|
||||
@@ -104,19 +109,20 @@ send_anonymously = {{ core.socks5.send_anonymously }}
|
||||
# The following options should not be modified unless you know EXACTLY what you are doing
|
||||
# as if set incorrectly, they may impact your anonymity.
|
||||
|
||||
# [core.socks5.socks5_debug]
|
||||
# [socks5.socks5_debug]
|
||||
|
||||
|
||||
[core.debug]
|
||||
[debug]
|
||||
|
||||
[core.debug.traffic]
|
||||
average_packet_delay = '{{ core.debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ core.debug.traffic.message_sending_average_delay }}'
|
||||
[debug.traffic]
|
||||
average_packet_delay = '{{ debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}'
|
||||
|
||||
[core.debug.acknowledgements]
|
||||
average_ack_delay = '{{ core.debug.acknowledgements.average_ack_delay }}'
|
||||
[debug.acknowledgements]
|
||||
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
|
||||
|
||||
[core.debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ core.debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
[debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
|
||||
"#;
|
||||
"#
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::config::{Config, Socks5};
|
||||
use crate::error::Socks5ClientCoreError;
|
||||
use crate::socks::{
|
||||
authentication::{AuthenticationMethods, Authenticator, User},
|
||||
@@ -10,16 +10,13 @@ use crate::socks::{
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::GatewayDetailsStore;
|
||||
use nym_client_core::client::base_client::storage::MixnetClientStorage;
|
||||
use nym_client_core::client::base_client::{
|
||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::KeyStore;
|
||||
use nym_client_core::client::replies::reply_storage::ReplyStorageBackend;
|
||||
use nym_client_core::config::DebugConfig;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
@@ -54,8 +51,6 @@ pub struct NymClient<S> {
|
||||
config: Config,
|
||||
|
||||
storage: S,
|
||||
|
||||
setup_method: GatewaySetup,
|
||||
}
|
||||
|
||||
impl<S> NymClient<S>
|
||||
@@ -64,26 +59,16 @@ where
|
||||
S::ReplyStore: Send + Sync,
|
||||
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send,
|
||||
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync,
|
||||
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync,
|
||||
{
|
||||
pub fn new(config: Config, storage: S) -> Self {
|
||||
NymClient {
|
||||
config,
|
||||
storage,
|
||||
setup_method: GatewaySetup::MustLoad,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
|
||||
self.setup_method = setup;
|
||||
self
|
||||
NymClient { config, storage }
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn start_socks5_listener(
|
||||
socks5_config: &config::Socks5,
|
||||
base_debug: DebugConfig,
|
||||
socks5_config: &Socks5,
|
||||
debug_config: DebugConfig,
|
||||
client_input: ClientInput,
|
||||
client_output: ClientOutput,
|
||||
client_status: ClientState,
|
||||
@@ -109,24 +94,25 @@ where
|
||||
..
|
||||
} = client_status;
|
||||
|
||||
let packet_size = base_debug
|
||||
let packet_size = debug_config
|
||||
.traffic
|
||||
.secondary_packet_size
|
||||
.unwrap_or(base_debug.traffic.primary_packet_size);
|
||||
.unwrap_or(debug_config.traffic.primary_packet_size);
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
let mut sphinx_socks = NymSocksServer::new(
|
||||
socks5_config.listening_port,
|
||||
socks5_config.get_listening_port(),
|
||||
authenticator,
|
||||
socks5_config.get_provider_mix_address(),
|
||||
self_address,
|
||||
shared_lane_queue_lengths,
|
||||
socks::client::Config::new(
|
||||
packet_size,
|
||||
socks5_config.provider_interface_version,
|
||||
socks5_config.socks5_protocol_version,
|
||||
socks5_config.send_anonymously,
|
||||
socks5_config.socks5_debug,
|
||||
socks5_config.get_provider_interface_version(),
|
||||
socks5_config.get_socks5_protocol_version(),
|
||||
socks5_config.get_send_anonymously(),
|
||||
socks5_config.get_connection_start_surbs(),
|
||||
socks5_config.get_per_request_surbs(),
|
||||
),
|
||||
shutdown.clone(),
|
||||
packet_type,
|
||||
@@ -202,35 +188,46 @@ where
|
||||
}
|
||||
|
||||
pub async fn start(self) -> Result<StartedSocks5Client, Socks5ClientCoreError> {
|
||||
// don't create dkg client for the bandwidth controller if credentials are disabled
|
||||
let dkg_query_client = if self.config.base.client.disabled_credentials_mode {
|
||||
let (key_store, reply_storage_backend, credential_store) = self.storage.into_split();
|
||||
|
||||
// don't create bandwidth controller if credentials are disabled
|
||||
let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() {
|
||||
None
|
||||
} else {
|
||||
Some(default_query_dkg_client_from_config(&self.config.base))
|
||||
Some(non_wasm_helpers::create_bandwidth_controller(
|
||||
self.config.get_base(),
|
||||
credential_store,
|
||||
))
|
||||
};
|
||||
|
||||
let base_builder =
|
||||
BaseClientBuilder::new(&self.config.base, self.storage, dkg_query_client)
|
||||
.with_gateway_setup(self.setup_method);
|
||||
let base_builder = BaseClientBuilder::<_, S>::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
key_store,
|
||||
bandwidth_controller,
|
||||
reply_storage_backend,
|
||||
);
|
||||
|
||||
let packet_type = self.config.base.debug.traffic.packet_type;
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
let client_state = started_client.client_state;
|
||||
|
||||
info!("Running with {packet_type} packets",);
|
||||
info!(
|
||||
"Running with {:?} packets",
|
||||
self.config.get_base().get_packet_type()
|
||||
);
|
||||
|
||||
Self::start_socks5_listener(
|
||||
&self.config.socks5,
|
||||
self.config.base.debug,
|
||||
self.config.get_socks5(),
|
||||
*self.config.get_debug_settings(),
|
||||
client_input,
|
||||
client_output,
|
||||
client_state,
|
||||
self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
packet_type,
|
||||
self.config.get_base().get_packet_type(),
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
|
||||
@@ -4,7 +4,6 @@ use super::authentication::{AuthenticationMethods, Authenticator, User};
|
||||
use super::request::{SocksCommand, SocksRequest};
|
||||
use super::types::{ResponseCodeV4, ResponseCodeV5, SocksProxyError};
|
||||
use super::{SocksVersion, RESERVED, SOCKS4_VERSION, SOCKS5_VERSION};
|
||||
use crate::config;
|
||||
use futures::channel::mpsc;
|
||||
use futures::task::{Context, Poll};
|
||||
use log::*;
|
||||
@@ -148,15 +147,16 @@ impl Config {
|
||||
provider_interface_version: ProviderInterfaceVersion,
|
||||
socks5_protocol_version: Socks5ProtocolVersion,
|
||||
use_surbs_for_responses: bool,
|
||||
debug_config: config::Socks5Debug,
|
||||
connection_start_surbs: u32,
|
||||
per_request_surbs: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
biggest_packet_size,
|
||||
provider_interface_version,
|
||||
socks5_protocol_version,
|
||||
use_surbs_for_responses,
|
||||
connection_start_surbs: debug_config.connection_start_surbs,
|
||||
per_request_surbs: debug_config.per_request_surbs,
|
||||
connection_start_surbs,
|
||||
per_request_surbs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,14 +428,18 @@ impl SocksClient {
|
||||
Some(self.lane_queue_lengths.clone()),
|
||||
self.shutdown_listener.clone(),
|
||||
)
|
||||
.run(move |socket_data| {
|
||||
let lane = TransmissionLane::ConnectionId(socket_data.header.connection_id);
|
||||
let provider_request =
|
||||
Socks5Request::new_send(request_version.provider_protocol, socket_data);
|
||||
.run(move |conn_id, read_data, socket_closed| {
|
||||
let provider_request = Socks5Request::new_send(
|
||||
request_version.provider_protocol,
|
||||
conn_id,
|
||||
read_data,
|
||||
socket_closed,
|
||||
);
|
||||
let provider_message = Socks5ProviderRequest::new_provider_data(
|
||||
request_version.provider_interface,
|
||||
provider_request,
|
||||
);
|
||||
let lane = TransmissionLane::ConnectionId(conn_id);
|
||||
if anonymous {
|
||||
InputMessage::new_anonymous(
|
||||
recipient,
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::Socks5ClientCoreError;
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
|
||||
use nym_client_core::client::received_buffer::ReconstructedMessagesReceiver;
|
||||
use nym_client_core::client::received_buffer::{
|
||||
ReceivedBufferMessage, ReceivedBufferRequestSender,
|
||||
};
|
||||
use nym_service_providers_common::interface::{ControlResponse, ResponseContent};
|
||||
use nym_socks5_proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
||||
use nym_socks5_proxy_helpers::connection_controller::ControllerSender;
|
||||
use nym_socks5_requests::{Socks5ProviderResponse, Socks5Response, Socks5ResponseContent};
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::TaskClient;
|
||||
|
||||
use crate::error::Socks5ClientCoreError;
|
||||
|
||||
pub(crate) struct MixnetResponseListener {
|
||||
buffer_requester: ReceivedBufferRequestSender,
|
||||
mix_response_receiver: ReconstructedMessagesReceiver,
|
||||
@@ -80,20 +79,12 @@ impl MixnetResponseListener {
|
||||
);
|
||||
Err(err_response.into())
|
||||
}
|
||||
Socks5ResponseContent::NetworkData { content } => {
|
||||
Socks5ResponseContent::NetworkData(response) => {
|
||||
self.controller_sender
|
||||
.unbounded_send(ControllerCommand::new_send(content))
|
||||
.unbounded_send(response.into())
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
Socks5ResponseContent::Query(response) => {
|
||||
error!("received a query response which we don't know how to handle yet!");
|
||||
error!("got: {:?}", response);
|
||||
|
||||
// I guess we'd need another channel here to forward those to where they need to go
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::message::OrderedMessage;
|
||||
use log::*;
|
||||
use std::collections::BTreeMap;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, PartialEq, Eq)]
|
||||
pub enum OrderedMessageError {
|
||||
#[error("received message with sequence number {received}, which is way higher than our current {current}")]
|
||||
MessageSequenceTooLarge { current: u64, received: u64 },
|
||||
|
||||
#[error("received message with sequence number {received}, while we're already at {current}!")]
|
||||
MessageAlreadyReconstructed { current: u64, received: u64 },
|
||||
|
||||
#[error("attempted to overwrite message at sequence {received}")]
|
||||
AttemptedToOverwriteSequence { received: u64 },
|
||||
}
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Stores messages and emits them in order.
|
||||
///
|
||||
@@ -24,58 +9,36 @@ pub enum OrderedMessageError {
|
||||
/// to fill up with the full sequence.
|
||||
#[derive(Debug)]
|
||||
pub struct OrderedMessageBuffer {
|
||||
next_sequence: u64,
|
||||
messages: BTreeMap<u64, Vec<u8>>,
|
||||
next_index: u64,
|
||||
messages: HashMap<u64, OrderedMessage>,
|
||||
}
|
||||
|
||||
/// Data returned from `OrderedMessageBuffer` on a successful read of gapless ordered data.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ReadContiguousData {
|
||||
pub data: Vec<u8>,
|
||||
pub last_sequence: u64,
|
||||
pub last_index: u64,
|
||||
}
|
||||
|
||||
const MAX_REASONABLE_OFFSET: u64 = 1000;
|
||||
|
||||
impl OrderedMessageBuffer {
|
||||
pub fn new() -> OrderedMessageBuffer {
|
||||
OrderedMessageBuffer {
|
||||
next_sequence: 0,
|
||||
messages: BTreeMap::new(),
|
||||
next_index: 0,
|
||||
messages: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a message to the buffer. messages are sort on insertion, so
|
||||
/// that later on multiple reads for incomplete sequences don't result in
|
||||
/// useless sort work.
|
||||
pub fn write(&mut self, sequence: u64, data: Vec<u8>) -> Result<(), OrderedMessageError> {
|
||||
// reject messages that have clearly malformed sequence
|
||||
if sequence > self.next_sequence + MAX_REASONABLE_OFFSET {
|
||||
return Err(OrderedMessageError::MessageSequenceTooLarge {
|
||||
current: self.next_sequence,
|
||||
received: sequence,
|
||||
});
|
||||
}
|
||||
|
||||
if self.messages.contains_key(&sequence) {
|
||||
return Err(OrderedMessageError::AttemptedToOverwriteSequence { received: sequence });
|
||||
}
|
||||
|
||||
if sequence < self.next_sequence {
|
||||
return Err(OrderedMessageError::MessageAlreadyReconstructed {
|
||||
current: self.next_sequence,
|
||||
received: sequence,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn write(&mut self, message: OrderedMessage) {
|
||||
trace!(
|
||||
"Writing message index: {} length {} to OrderedMessageBuffer.",
|
||||
sequence,
|
||||
data.len()
|
||||
"Writing message index: {} length {:?} to OrderedMessageBuffer.",
|
||||
message.index,
|
||||
message.data.len()
|
||||
);
|
||||
|
||||
self.messages.insert(sequence, data);
|
||||
Ok(())
|
||||
self.messages.insert(message.index, message);
|
||||
}
|
||||
|
||||
/// Returns `Option<Vec<u8>>` where it's `Some(bytes)` if there is gapless
|
||||
@@ -86,31 +49,33 @@ impl OrderedMessageBuffer {
|
||||
/// a read will return the bytes of messages 0, 1, 2. Subsequent reads will
|
||||
/// return `None` until message 3 comes in, at which point 3, 4, and any
|
||||
/// further contiguous messages which have arrived will be returned.
|
||||
#[must_use]
|
||||
pub fn read(&mut self) -> Option<ReadContiguousData> {
|
||||
if !self.messages.contains_key(&self.next_sequence) {
|
||||
if !self.messages.contains_key(&self.next_index) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut contiguous_messages = Vec::new();
|
||||
let mut seq = self.next_sequence;
|
||||
let mut index = self.next_index;
|
||||
|
||||
while let Some(mut data) = self.messages.remove(&seq) {
|
||||
contiguous_messages.append(&mut data);
|
||||
seq += 1;
|
||||
while let Some(ordered_message) = self.messages.remove(&index) {
|
||||
contiguous_messages.push(ordered_message);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
let high_water = seq;
|
||||
self.next_sequence = high_water;
|
||||
trace!("Next high water mark is: {high_water}");
|
||||
let high_water = index;
|
||||
self.next_index = high_water;
|
||||
trace!("Next high water mark is: {}", high_water);
|
||||
|
||||
trace!(
|
||||
"Returning {} bytes from ordered message buffer",
|
||||
contiguous_messages.len()
|
||||
);
|
||||
// dig out the bytes from inside the struct
|
||||
let data: Vec<u8> = contiguous_messages
|
||||
.into_iter()
|
||||
.flat_map(|message| message.data)
|
||||
.collect();
|
||||
|
||||
trace!("Returning {} bytes from ordered message buffer", data.len());
|
||||
Some(ReadContiguousData {
|
||||
data: contiguous_messages,
|
||||
last_sequence: seq,
|
||||
data,
|
||||
last_index: index,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -125,64 +90,6 @@ impl Default for OrderedMessageBuffer {
|
||||
mod test_chunking_and_reassembling {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn trying_to_write_unreasonable_high_sequence() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
let first_message = vec![1, 2, 3, 4];
|
||||
let second_message = vec![5, 6, 7, 8];
|
||||
|
||||
buffer.write(0, first_message).unwrap();
|
||||
buffer.write(1, second_message).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
Err(OrderedMessageError::MessageSequenceTooLarge {
|
||||
current: 0,
|
||||
received: 12345678
|
||||
}),
|
||||
buffer.write(12345678, b"foomp".to_vec())
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trying_to_overwrite_sequence() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
let message = vec![1, 2, 3, 4];
|
||||
|
||||
buffer.write(0, message.clone()).unwrap();
|
||||
buffer.write(1, message.clone()).unwrap();
|
||||
buffer.write(2, message.clone()).unwrap();
|
||||
buffer.write(3, message.clone()).unwrap();
|
||||
|
||||
for seq in 0..=3 {
|
||||
assert_eq!(
|
||||
Err(OrderedMessageError::AttemptedToOverwriteSequence { received: seq }),
|
||||
buffer.write(seq, message.clone())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writing_past_data() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
let message = vec![1, 2, 3, 4];
|
||||
|
||||
buffer.write(0, message.clone()).unwrap();
|
||||
buffer.write(1, message.clone()).unwrap();
|
||||
buffer.write(2, message.clone()).unwrap();
|
||||
buffer.write(3, message.clone()).unwrap();
|
||||
let _ = buffer.read().unwrap();
|
||||
|
||||
for seq in 0..=3 {
|
||||
assert_eq!(
|
||||
Err(OrderedMessageError::MessageAlreadyReconstructed {
|
||||
current: 4,
|
||||
received: seq
|
||||
}),
|
||||
buffer.write(seq, message.clone())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod reading_from_and_writing_to_the_buffer {
|
||||
use super::*;
|
||||
@@ -195,14 +102,20 @@ mod test_chunking_and_reassembling {
|
||||
fn read_returns_ordered_bytes_and_resets_buffer() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
|
||||
let first_message = vec![1, 2, 3, 4];
|
||||
let second_message = vec![5, 6, 7, 8];
|
||||
let first_message = OrderedMessage {
|
||||
data: vec![1, 2, 3, 4],
|
||||
index: 0,
|
||||
};
|
||||
let second_message = OrderedMessage {
|
||||
data: vec![5, 6, 7, 8],
|
||||
index: 1,
|
||||
};
|
||||
|
||||
buffer.write(0, first_message).unwrap();
|
||||
buffer.write(first_message);
|
||||
let first_read = buffer.read().unwrap().data;
|
||||
assert_eq!(vec![1, 2, 3, 4], first_read);
|
||||
|
||||
buffer.write(1, second_message).unwrap();
|
||||
buffer.write(second_message);
|
||||
let second_read = buffer.read().unwrap().data;
|
||||
assert_eq!(vec![5, 6, 7, 8], second_read);
|
||||
|
||||
@@ -213,11 +126,17 @@ mod test_chunking_and_reassembling {
|
||||
fn test_multiple_adds_stacks_up_bytes_in_the_buffer() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
|
||||
let first_message = vec![1, 2, 3, 4];
|
||||
let second_message = vec![5, 6, 7, 8];
|
||||
let first_message = OrderedMessage {
|
||||
data: vec![1, 2, 3, 4],
|
||||
index: 0,
|
||||
};
|
||||
let second_message = OrderedMessage {
|
||||
data: vec![5, 6, 7, 8],
|
||||
index: 1,
|
||||
};
|
||||
|
||||
buffer.write(0, first_message).unwrap();
|
||||
buffer.write(1, second_message).unwrap();
|
||||
buffer.write(first_message);
|
||||
buffer.write(second_message);
|
||||
let second_read = buffer.read();
|
||||
assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8], second_read.unwrap().data);
|
||||
assert_eq!(None, buffer.read()); // second read on fully ordered result set is empty
|
||||
@@ -227,11 +146,17 @@ mod test_chunking_and_reassembling {
|
||||
fn out_of_order_adds_results_in_ordered_byte_vector() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
|
||||
let first_message = vec![1, 2, 3, 4];
|
||||
let second_message = vec![5, 6, 7, 8];
|
||||
let first_message = OrderedMessage {
|
||||
data: vec![1, 2, 3, 4],
|
||||
index: 0,
|
||||
};
|
||||
let second_message = OrderedMessage {
|
||||
data: vec![5, 6, 7, 8],
|
||||
index: 1,
|
||||
};
|
||||
|
||||
buffer.write(1, second_message).unwrap();
|
||||
buffer.write(0, first_message).unwrap();
|
||||
buffer.write(second_message);
|
||||
buffer.write(first_message);
|
||||
let read = buffer.read().unwrap().data;
|
||||
assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8], read);
|
||||
assert_eq!(None, buffer.read()); // second read on fully ordered result set is empty
|
||||
@@ -245,13 +170,23 @@ mod test_chunking_and_reassembling {
|
||||
fn setup() -> OrderedMessageBuffer {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
|
||||
let zero_message = vec![0, 0, 0, 0];
|
||||
let one_message = vec![1, 1, 1, 1];
|
||||
let three_message = vec![3, 3, 3, 3];
|
||||
let zero_message = OrderedMessage {
|
||||
data: vec![0, 0, 0, 0],
|
||||
index: 0,
|
||||
};
|
||||
let one_message = OrderedMessage {
|
||||
data: vec![1, 1, 1, 1],
|
||||
index: 1,
|
||||
};
|
||||
|
||||
buffer.write(0, zero_message).unwrap();
|
||||
buffer.write(1, one_message).unwrap();
|
||||
buffer.write(3, three_message).unwrap();
|
||||
let three_message = OrderedMessage {
|
||||
data: vec![3, 3, 3, 3],
|
||||
index: 3,
|
||||
};
|
||||
|
||||
buffer.write(zero_message);
|
||||
buffer.write(one_message);
|
||||
buffer.write(three_message);
|
||||
buffer
|
||||
}
|
||||
#[test]
|
||||
@@ -264,31 +199,43 @@ mod test_chunking_and_reassembling {
|
||||
assert_eq!(None, buffer.read());
|
||||
|
||||
// let's add another message, leaving a gap in place at index 2
|
||||
let five_message = vec![5, 5, 5, 5];
|
||||
buffer.write(5, five_message).unwrap();
|
||||
let five_message = OrderedMessage {
|
||||
data: vec![5, 5, 5, 5],
|
||||
index: 5,
|
||||
};
|
||||
buffer.write(five_message);
|
||||
assert_eq!(None, buffer.read());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filling_the_gap_allows_us_to_get_everything() {
|
||||
let mut buffer = setup();
|
||||
let _ = buffer.read(); // that burns the first two. We still have a gap before the 3s.
|
||||
buffer.read(); // that burns the first two. We still have a gap before the 3s.
|
||||
|
||||
let two_message = vec![2, 2, 2, 2];
|
||||
buffer.write(2, two_message).unwrap();
|
||||
let two_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 2,
|
||||
};
|
||||
buffer.write(two_message);
|
||||
|
||||
let more_ordered_bytes = buffer.read().unwrap().data;
|
||||
assert_eq!([2, 2, 2, 2, 3, 3, 3, 3].to_vec(), more_ordered_bytes);
|
||||
|
||||
// let's add another message
|
||||
let five_message = vec![5, 5, 5, 5];
|
||||
buffer.write(5, five_message).unwrap();
|
||||
let five_message = OrderedMessage {
|
||||
data: vec![5, 5, 5, 5],
|
||||
index: 5,
|
||||
};
|
||||
buffer.write(five_message);
|
||||
|
||||
assert_eq!(None, buffer.read());
|
||||
|
||||
// let's fill in the gap of 4s now and read again
|
||||
let four_message = vec![4, 4, 4, 4];
|
||||
buffer.write(4, four_message).unwrap();
|
||||
let four_message = OrderedMessage {
|
||||
data: vec![4, 4, 4, 4],
|
||||
index: 4,
|
||||
};
|
||||
buffer.write(four_message);
|
||||
|
||||
assert_eq!(
|
||||
[4, 4, 4, 4, 5, 5, 5, 5].to_vec(),
|
||||
@@ -302,47 +249,70 @@ mod test_chunking_and_reassembling {
|
||||
#[test]
|
||||
fn filling_the_gap_allows_us_to_get_everything_when_last_element_is_empty() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
let zero_message = vec![0, 0, 0, 0];
|
||||
let one_message = vec![2, 2, 2, 2];
|
||||
let two_message = vec![];
|
||||
let zero_message = OrderedMessage {
|
||||
data: vec![0, 0, 0, 0],
|
||||
index: 0,
|
||||
};
|
||||
let one_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 1,
|
||||
};
|
||||
let two_message = OrderedMessage {
|
||||
data: vec![],
|
||||
index: 2,
|
||||
};
|
||||
|
||||
buffer.write(0, zero_message).unwrap();
|
||||
buffer.write(zero_message);
|
||||
assert!(buffer.read().is_some()); // burn the buffer
|
||||
|
||||
buffer.write(2, two_message).unwrap();
|
||||
buffer.write(1, one_message).unwrap();
|
||||
buffer.write(two_message);
|
||||
buffer.write(one_message);
|
||||
assert!(buffer.read().is_some());
|
||||
assert_eq!(buffer.next_sequence, 3);
|
||||
assert_eq!(buffer.next_index, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_with_gaps_bigger_than_one() {
|
||||
let mut buffer = OrderedMessageBuffer::new();
|
||||
let zero_message = vec![0, 0, 0, 0];
|
||||
let one_message = vec![2, 2, 2, 2];
|
||||
let two_message = vec![2, 2, 2, 2];
|
||||
let three_message = vec![2, 2, 2, 2];
|
||||
let four_message = vec![2, 2, 2, 2];
|
||||
|
||||
buffer.write(0, zero_message).unwrap();
|
||||
let zero_message = OrderedMessage {
|
||||
data: vec![0, 0, 0, 0],
|
||||
index: 0,
|
||||
};
|
||||
let one_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 1,
|
||||
};
|
||||
let two_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 2,
|
||||
};
|
||||
let three_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 3,
|
||||
};
|
||||
let four_message = OrderedMessage {
|
||||
data: vec![2, 2, 2, 2],
|
||||
index: 4,
|
||||
};
|
||||
buffer.write(zero_message);
|
||||
assert!(buffer.read().is_some());
|
||||
assert_eq!(buffer.next_sequence, 1);
|
||||
assert_eq!(buffer.next_index, 1);
|
||||
|
||||
buffer.write(4, four_message).unwrap();
|
||||
buffer.write(four_message);
|
||||
assert!(buffer.read().is_none());
|
||||
assert_eq!(buffer.next_sequence, 1);
|
||||
assert_eq!(buffer.next_index, 1);
|
||||
|
||||
buffer.write(3, three_message).unwrap();
|
||||
buffer.write(three_message);
|
||||
assert!(buffer.read().is_none());
|
||||
assert_eq!(buffer.next_sequence, 1);
|
||||
assert_eq!(buffer.next_index, 1);
|
||||
|
||||
buffer.write(2, two_message).unwrap();
|
||||
buffer.write(two_message);
|
||||
assert!(buffer.read().is_none());
|
||||
assert_eq!(buffer.next_sequence, 1);
|
||||
assert_eq!(buffer.next_index, 1);
|
||||
|
||||
buffer.write(1, one_message).unwrap();
|
||||
buffer.write(one_message);
|
||||
assert!(buffer.read().is_some());
|
||||
assert_eq!(buffer.next_sequence, 5)
|
||||
assert_eq!(buffer.next_index, 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
mod buffer;
|
||||
mod message;
|
||||
mod sender;
|
||||
|
||||
pub use buffer::{OrderedMessageBuffer, OrderedMessageError, ReadContiguousData};
|
||||
pub use buffer::{OrderedMessageBuffer, ReadContiguousData};
|
||||
pub use message::MessageError;
|
||||
pub use message::OrderedMessage;
|
||||
pub use sender::OrderedMessageSender;
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, PartialEq, Eq)]
|
||||
pub enum MessageError {
|
||||
#[error("the received message was empty")]
|
||||
NoData,
|
||||
|
||||
#[error("could not extract message index. Received {received} bytes, but expected {expected}")]
|
||||
IndexTooShort { received: usize, expected: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct OrderedMessage {
|
||||
pub data: Vec<u8>,
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
impl OrderedMessage {
|
||||
/// Serializes an `OrderedMessage` into bytes.
|
||||
/// The output format is:
|
||||
/// | 8 bytes index | data... |
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
self.index
|
||||
.to_be_bytes()
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(self.data.into_iter())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Attempts to deserialize an `OrderedMessage` from bytes.
|
||||
pub fn try_from_bytes(data: Vec<u8>) -> Result<OrderedMessage, MessageError> {
|
||||
if data.is_empty() {
|
||||
return Err(MessageError::NoData);
|
||||
}
|
||||
|
||||
if data.len() < 8 {
|
||||
return Err(MessageError::IndexTooShort {
|
||||
received: data.len(),
|
||||
expected: 8,
|
||||
});
|
||||
}
|
||||
let index = u64::from_be_bytes([
|
||||
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
|
||||
]);
|
||||
Ok(OrderedMessage {
|
||||
data: data[8..].to_vec(),
|
||||
index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Order messages by their index only, ignoring their data
|
||||
impl PartialOrd for OrderedMessage {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some((self.index).cmp(&(other.index)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ordered_message_to_bytes {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn works() {
|
||||
let message = OrderedMessage {
|
||||
data: vec![123],
|
||||
index: 1,
|
||||
};
|
||||
let bytes = message.into_bytes();
|
||||
|
||||
let expected = vec![0, 0, 0, 0, 0, 0, 0, 1, 123];
|
||||
assert_eq!(expected, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ordered_message_from_bytes {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fails_when_there_is_no_data() {
|
||||
let result = OrderedMessage::try_from_bytes(Vec::new());
|
||||
assert_eq!(Err(MessageError::NoData), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_data_is_too_short() {
|
||||
let result = OrderedMessage::try_from_bytes(vec![1, 2, 3]);
|
||||
assert_eq!(
|
||||
Err(MessageError::IndexTooShort {
|
||||
received: 3,
|
||||
expected: 8
|
||||
}),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_when_there_is_enough_to_make_a_sequence_number_but_no_message_data() {
|
||||
let expected = OrderedMessage {
|
||||
data: Vec::new(),
|
||||
index: 1,
|
||||
};
|
||||
let result = OrderedMessage::try_from_bytes(vec![0, 0, 0, 0, 0, 0, 0, 1]).unwrap();
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_when_there_is_seq_number_and_data() {
|
||||
let expected = OrderedMessage {
|
||||
data: vec![255, 255, 255],
|
||||
index: 1,
|
||||
};
|
||||
let result =
|
||||
OrderedMessage::try_from_bytes(vec![0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255]).unwrap();
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_message_does_not_affect_ordering() {
|
||||
let mut msg1 = OrderedMessage {
|
||||
data: vec![255, 255, 255],
|
||||
index: 1,
|
||||
};
|
||||
|
||||
let mut msg2 = OrderedMessage {
|
||||
data: vec![],
|
||||
index: 2,
|
||||
};
|
||||
|
||||
assert!(msg1 < msg2);
|
||||
|
||||
msg1.index = 2;
|
||||
msg2.index = 1;
|
||||
|
||||
assert!(msg1 > msg2);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
use crate::message::OrderedMessage;
|
||||
|
||||
/// Assigns sequence numbers to outbound byte vectors. These messages can then
|
||||
/// be reassembled into an ordered sequence by the `OrderedMessageSender`.
|
||||
#[derive(Debug)]
|
||||
pub struct OrderedMessageSender {
|
||||
next_index: u64,
|
||||
}
|
||||
|
||||
impl OrderedMessageSender {
|
||||
pub fn new() -> OrderedMessageSender {
|
||||
OrderedMessageSender { next_index: 0 }
|
||||
}
|
||||
|
||||
/// Turns raw bytes into an OrderedMessage containing the original bytes
|
||||
/// and a sequence number;
|
||||
pub fn wrap_message(&mut self, input: Vec<u8>) -> OrderedMessage {
|
||||
let message = OrderedMessage {
|
||||
data: input.to_vec(),
|
||||
index: self.next_index,
|
||||
};
|
||||
self.next_index += 1;
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OrderedMessageSender {
|
||||
fn default() -> Self {
|
||||
OrderedMessageSender::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ordered_message_sender {
|
||||
use super::*;
|
||||
|
||||
mod when_input_bytes_are_empty {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sequence_index_numbers {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn increase_as_messages_are_sent() {
|
||||
let mut sender = OrderedMessageSender::new();
|
||||
let first_bytes = vec![1, 2, 3, 4];
|
||||
let second_bytes = vec![5, 6, 7, 8];
|
||||
|
||||
let first_message = sender.wrap_message(first_bytes);
|
||||
|
||||
assert_eq!(first_message.index, 0);
|
||||
|
||||
let second_message = sender.wrap_message(second_bytes);
|
||||
assert_eq!(second_message.index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_ordered_buffer::{OrderedMessageBuffer, ReadContiguousData};
|
||||
use nym_socks5_requests::{ConnectionId, SocketData};
|
||||
use nym_ordered_buffer::{OrderedMessage, OrderedMessageBuffer, ReadContiguousData};
|
||||
use nym_socks5_requests::{ConnectionId, NetworkData, SendRequest};
|
||||
use nym_task::connections::{ConnectionCommand, ConnectionCommandSender};
|
||||
use nym_task::TaskClient;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -40,13 +40,29 @@ pub enum ControllerCommand {
|
||||
connection_id: ConnectionId,
|
||||
},
|
||||
Send {
|
||||
data: SocketData,
|
||||
connection_id: ConnectionId,
|
||||
data: Vec<u8>,
|
||||
is_closed: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl ControllerCommand {
|
||||
pub fn new_send(data: SocketData) -> Self {
|
||||
ControllerCommand::Send { data }
|
||||
impl From<NetworkData> for ControllerCommand {
|
||||
fn from(value: NetworkData) -> Self {
|
||||
ControllerCommand::Send {
|
||||
connection_id: value.connection_id,
|
||||
data: value.data,
|
||||
is_closed: value.is_closed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SendRequest> for ControllerCommand {
|
||||
fn from(value: SendRequest) -> Self {
|
||||
ControllerCommand::Send {
|
||||
connection_id: value.conn_id,
|
||||
data: value.data,
|
||||
is_closed: value.local_closed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,13 +74,18 @@ struct ActiveConnection {
|
||||
}
|
||||
|
||||
impl ActiveConnection {
|
||||
fn write_to_buf(&mut self, seq: u64, payload: Vec<u8>, is_closed: bool) {
|
||||
fn write_to_buf(&mut self, payload: Vec<u8>, is_closed: bool) {
|
||||
let ordered_message = match OrderedMessage::try_from_bytes(payload) {
|
||||
Ok(msg) => msg,
|
||||
Err(err) => {
|
||||
error!("Malformed ordered message - {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if is_closed {
|
||||
self.closed_at_index = Some(seq);
|
||||
}
|
||||
if let Err(err) = self.ordered_buffer.write(seq, payload) {
|
||||
error!("failed to write to the buffer: {err}")
|
||||
self.closed_at_index = Some(ordered_message.index);
|
||||
}
|
||||
self.ordered_buffer.write(ordered_message);
|
||||
}
|
||||
|
||||
fn read_from_buf(&mut self) -> Option<ReadContiguousData> {
|
||||
@@ -96,7 +117,7 @@ pub struct Controller {
|
||||
|
||||
// buffer for messages received before connection was established due to mixnet being able to
|
||||
// un-order messages. Note we don't ever expect to have more than 1-2 messages per connection here
|
||||
pending_messages: HashMap<ConnectionId, Vec<SocketData>>,
|
||||
pending_messages: HashMap<ConnectionId, Vec<(Vec<u8>, bool)>>,
|
||||
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
@@ -133,8 +154,8 @@ impl Controller {
|
||||
// check if there were any pending messages
|
||||
if let Some(pending) = self.pending_messages.remove(&conn_id) {
|
||||
debug!("There were some pending messages for {}", conn_id);
|
||||
for data in pending {
|
||||
self.send_to_connection(data)
|
||||
for (payload, is_closed) in pending {
|
||||
self.send_to_connection(conn_id, payload, is_closed)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,25 +184,20 @@ impl Controller {
|
||||
}
|
||||
}
|
||||
|
||||
fn send_to_connection(&mut self, message: SocketData) {
|
||||
let hdr = message.header;
|
||||
if let Some(active_connection) = self.active_connections.get_mut(&hdr.connection_id) {
|
||||
// always write to the buffer even if payload is empty (because it could have been the keep-alive message)
|
||||
active_connection.write_to_buf(hdr.seq, message.data, hdr.local_socket_closed);
|
||||
fn send_to_connection(&mut self, conn_id: ConnectionId, payload: Vec<u8>, is_closed: bool) {
|
||||
if let Some(active_connection) = self.active_connections.get_mut(&conn_id) {
|
||||
if !payload.is_empty() {
|
||||
active_connection.write_to_buf(payload, is_closed);
|
||||
} else if !is_closed {
|
||||
error!("Tried to write an empty message to a not-closing connection. Please let us know if you see this message");
|
||||
}
|
||||
|
||||
if let Some(payload) = active_connection.read_from_buf() {
|
||||
if let Some(closed_at_index) = active_connection.closed_at_index {
|
||||
if payload.last_sequence > closed_at_index {
|
||||
if payload.last_index > closed_at_index {
|
||||
active_connection.is_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// however, don't send empty payload to the actual connection if it's not a close message
|
||||
// TODO: or should we?
|
||||
if payload.data.is_empty() && !active_connection.is_closed {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(err) = active_connection
|
||||
.connection_sender
|
||||
.as_mut()
|
||||
@@ -191,26 +207,34 @@ impl Controller {
|
||||
socket_closed: active_connection.is_closed,
|
||||
})
|
||||
{
|
||||
error!("failed to send on the active connection channel: {err}");
|
||||
error!("WTF IS THIS: {err}");
|
||||
}
|
||||
|
||||
// TODO: ABOVE UNWRAP CAUSED A CRASH IN A NORMAL USE!!!!
|
||||
// TODO:
|
||||
// TODO: surprisingly it only happened on socks client, never on nSP
|
||||
// TODO:
|
||||
// TODO:
|
||||
// TODO:
|
||||
// TODO:
|
||||
}
|
||||
} else if !self.recently_closed.contains(&hdr.connection_id) {
|
||||
} else if !self.recently_closed.contains(&conn_id) {
|
||||
debug!("Received a 'Send' before 'Connect' - going to buffer the data");
|
||||
let pending = self
|
||||
.pending_messages
|
||||
.entry(hdr.connection_id)
|
||||
.entry(conn_id)
|
||||
.or_insert_with(Vec::new);
|
||||
pending.push(message);
|
||||
} else if !hdr.local_socket_closed {
|
||||
pending.push((payload, is_closed));
|
||||
} else if !is_closed {
|
||||
error!(
|
||||
"Tried to write to closed connection {} ({} bytes were 'lost)",
|
||||
hdr.connection_id,
|
||||
message.data.len()
|
||||
conn_id,
|
||||
payload.len()
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
"Tried to write to closed connection {}, but remote is already closed",
|
||||
hdr.connection_id
|
||||
conn_id
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -219,8 +243,8 @@ impl Controller {
|
||||
loop {
|
||||
tokio::select! {
|
||||
command = self.receiver.next() => match command {
|
||||
Some(ControllerCommand::Send{data}) => {
|
||||
self.send_to_connection(data)
|
||||
Some(ControllerCommand::Send{connection_id, data, is_closed}) => {
|
||||
self.send_to_connection(connection_id, data, is_closed)
|
||||
}
|
||||
Some(ControllerCommand::Insert{connection_id, connection_sender}) => {
|
||||
self.insert_connection(connection_id, connection_sender)
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
|
||||
pub mod available_reader;
|
||||
pub mod connection_controller;
|
||||
pub mod ordered_sender;
|
||||
pub mod proxy_runner;
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::proxy_runner::MixProxySender;
|
||||
use bytes::Bytes;
|
||||
use log::{debug, error};
|
||||
use nym_socks5_requests::{ConnectionId, SocketData};
|
||||
use std::io;
|
||||
|
||||
pub(crate) struct OrderedMessageSender<F, S> {
|
||||
connection_id: ConnectionId,
|
||||
// addresses are provided for better logging
|
||||
local_destination_address: String,
|
||||
remote_source_address: String,
|
||||
mixnet_sender: MixProxySender<S>,
|
||||
|
||||
next_message_seq: u64,
|
||||
mix_message_adapter: F,
|
||||
}
|
||||
|
||||
impl<F, S> OrderedMessageSender<F, S>
|
||||
where
|
||||
F: Fn(SocketData) -> S,
|
||||
{
|
||||
pub(crate) fn new(
|
||||
local_destination_address: String,
|
||||
remote_source_address: String,
|
||||
connection_id: ConnectionId,
|
||||
mixnet_sender: MixProxySender<S>,
|
||||
mix_message_adapter: F,
|
||||
) -> Self {
|
||||
OrderedMessageSender {
|
||||
local_destination_address,
|
||||
remote_source_address,
|
||||
connection_id,
|
||||
mixnet_sender,
|
||||
next_message_seq: 0,
|
||||
mix_message_adapter,
|
||||
}
|
||||
}
|
||||
|
||||
fn sequence(&mut self) -> u64 {
|
||||
let next = self.next_message_seq;
|
||||
self.next_message_seq += 1;
|
||||
next
|
||||
}
|
||||
|
||||
fn construct_message(&mut self, data: Vec<u8>, local_socket_closed: bool) -> S {
|
||||
let data = SocketData::new(
|
||||
self.sequence(),
|
||||
self.connection_id,
|
||||
local_socket_closed,
|
||||
data,
|
||||
);
|
||||
(self.mix_message_adapter)(data)
|
||||
}
|
||||
|
||||
async fn send_message(&self, message: S) {
|
||||
if self.mixnet_sender.send(message).await.is_err() {
|
||||
panic!("BatchRealMessageReceiver has stopped receiving!")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn send_empty_close(&mut self) {
|
||||
let message = self.construct_message(Vec::new(), true);
|
||||
self.send_message(message).await
|
||||
}
|
||||
|
||||
pub(crate) async fn send_empty_keepalive(&mut self) {
|
||||
log::trace!("Sending keepalive for connection: {}", self.connection_id);
|
||||
let message = self.construct_message(Vec::new(), false);
|
||||
self.send_message(message).await
|
||||
}
|
||||
|
||||
pub(crate) fn process_data(&self, read_data: Option<io::Result<Bytes>>) -> ProcessedData {
|
||||
let (read_data, is_finished) = match read_data {
|
||||
Some(data) => match data {
|
||||
Ok(data) => (data, false),
|
||||
Err(err) => {
|
||||
error!(target: &*format!("({}) socks5 inbound", self.connection_id), "failed to read request from the socket - {err}");
|
||||
(Default::default(), true)
|
||||
}
|
||||
},
|
||||
None => (Default::default(), true),
|
||||
};
|
||||
|
||||
ProcessedData {
|
||||
data: read_data,
|
||||
is_done: is_finished,
|
||||
}
|
||||
}
|
||||
|
||||
fn log_sent_message(&self, data: &ProcessedData) {
|
||||
debug!(
|
||||
target: &*format!("({}) socks5 inbound", self.connection_id),
|
||||
"[{} bytes]\t{} → local → mixnet → remote → {}. Local closed: {}",
|
||||
data.data.len(),
|
||||
self.local_destination_address,
|
||||
self.remote_source_address,
|
||||
data.is_done
|
||||
);
|
||||
}
|
||||
|
||||
/// Send data read from local socket into the mixnet
|
||||
pub(crate) async fn send_data(&mut self, data: ProcessedData) {
|
||||
self.log_sent_message(&data);
|
||||
let message = self.construct_message(data.data.into(), data.is_done);
|
||||
self.send_message(message).await;
|
||||
}
|
||||
}
|
||||
|
||||
// helper wrapper to keep track of field meanings
|
||||
pub(crate) struct ProcessedData {
|
||||
data: Bytes,
|
||||
pub(crate) is_done: bool,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user