diff --git a/.github/workflows/ci-build-upload-binaries.yml b/.github/workflows/ci-build-upload-binaries.yml index db189fe80f..03ac19b7f2 100644 --- a/.github/workflows/ci-build-upload-binaries.yml +++ b/.github/workflows/ci-build-upload-binaries.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - platform: [ubuntu-22.04] + platform: [arc-ubuntu-22.04] runs-on: ${{ matrix.platform }} env: diff --git a/.github/workflows/ci-crates-publish-dry-run.yml b/.github/workflows/ci-crates-publish-dry-run.yml index f57efbe87e..fa2714e7bb 100644 --- a/.github/workflows/ci-crates-publish-dry-run.yml +++ b/.github/workflows/ci-crates-publish-dry-run.yml @@ -15,6 +15,9 @@ env: jobs: publish-dry-run: runs-on: arc-linux-latest + timeout-minutes: 35 + env: + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - name: Checkout repo uses: actions/checkout@v6 @@ -59,20 +62,60 @@ jobs: - name: Bump versions (local only) run: | cargo workspaces version custom ${{ inputs.version }} \ - --allow-branch ${{ github.ref_name }} \ --no-git-commit \ + --yes + + - name: Preflight publish checks + run: | + python3 tools/internal/check_publish_preflight.py # Dry run may show cascading dependency errors because packages aren't # actually uploaded - these are expected and ignored. We check for real # errors like packaging failures, missing metadata, or invalid Cargo.toml. - name: Publish (dry run) run: | - output=$(cargo workspaces publish --dry-run --allow-dirty 2>&1) || true - echo "$output" + set +e + publish_status=1 + max_attempts=2 + attempt=1 + rm -f /tmp/publish-dry-run.log - # Check for real errors (not cascading dependency errors) - # Cascading errors mention "crates.io index", real errors mention "Cargo.toml" - echo "$output" | grep -i "Cargo.toml" && exit 1 || true + while [ "$attempt" -le "$max_attempts" ]; do + echo "Dry-run publish attempt ${attempt}/${max_attempts}" + cargo workspaces publish --dry-run --allow-dirty 2>&1 | tee /tmp/publish-dry-run.log + publish_status=${PIPESTATUS[0]} + + if [ "$publish_status" -eq 0 ]; then + break + fi + + # Retry once for interruption/runner issues. + if [ "$attempt" -lt "$max_attempts" ] && \ + { [ "$publish_status" -eq 130 ] || [ "$publish_status" -eq 137 ]; }; then + echo "Publish dry-run interrupted (exit ${publish_status}), retrying in 10s..." + sleep 10 + attempt=$((attempt + 1)) + continue + fi + + break + done + set -e + + if grep -Eiq \ + "failed to verify manifest|failed to parse manifest|invalid Cargo.toml|error: package .* has no (description|license|repository)" \ + /tmp/publish-dry-run.log; then + echo "Detected real packaging/manifest errors" + exit 1 + fi + + # In dry-run mode, non-zero publish status is expected due to + # dependency-cascade failures against crates.io index. + if [ "$publish_status" -ne 0 ]; then + echo "Dry-run publish returned non-zero (${publish_status}) but no real manifest blockers were detected." + fi + + echo "Only expected dry-run dependency cascade errors detected (if any)." # Show the list of packages published - name: Show package versions diff --git a/.github/workflows/ci-crates-publish-resume.yml b/.github/workflows/ci-crates-publish-resume.yml index 77f448a2b8..8fcf5ef7b4 100644 --- a/.github/workflows/ci-crates-publish-resume.yml +++ b/.github/workflows/ci-crates-publish-resume.yml @@ -17,6 +17,8 @@ on: jobs: publish: runs-on: arc-linux-latest + env: + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - name: Checkout repo uses: actions/checkout@v6 diff --git a/.github/workflows/ci-crates-publish.yml b/.github/workflows/ci-crates-publish.yml index 3c7250d241..94290c8a2d 100644 --- a/.github/workflows/ci-crates-publish.yml +++ b/.github/workflows/ci-crates-publish.yml @@ -17,6 +17,8 @@ on: jobs: publish: runs-on: arc-linux-latest + env: + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - name: Checkout repo uses: actions/checkout@v6 diff --git a/.github/workflows/ci-crates-version-bump.yml b/.github/workflows/ci-crates-version-bump.yml index 790e2a062a..eebc0d64ac 100644 --- a/.github/workflows/ci-crates-version-bump.yml +++ b/.github/workflows/ci-crates-version-bump.yml @@ -15,6 +15,8 @@ env: jobs: version-bump: runs-on: arc-linux-latest + env: + RUSTUP_PERMIT_COPY_RENAME: 1 permissions: contents: write steps: diff --git a/.github/workflows/publish-nym-binaries.yml b/.github/workflows/publish-nym-binaries.yml index e2f4c2463f..0a15eb2717 100644 --- a/.github/workflows/publish-nym-binaries.yml +++ b/.github/workflows/publish-nym-binaries.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-22.04 + - os: arc-ubuntu-22.04 target: x86_64-unknown-linux-gnu runs-on: ${{ matrix.os }} diff --git a/.github/workflows/resume-publish-crates-io.yml b/.github/workflows/resume-publish-crates-io.yml index ef322790d7..db95e8e0fd 100644 --- a/.github/workflows/resume-publish-crates-io.yml +++ b/.github/workflows/resume-publish-crates-io.yml @@ -25,6 +25,10 @@ jobs: - name: Install cargo-workspaces run: cargo install cargo-workspaces + - name: Preflight publish checks + run: | + python3 tools/internal/check_publish_preflight.py + - name: Publish remaining crates env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a998c1e782..e58f5e8b5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ## [Unreleased] +## [2026.9-venaco] (2026-05-06) + +- Fix for v9 IPR ([#6710]) +- Only init SHARED_CLIENT if requested ([#6708]) +- Fixes to crates and CI ([#6686]) +- Return ipv6 addresses as well ([#6684]) +- Fix invalid ticket spend ([#6683]) +- Block non-public IPR/NR checks ([#6670]) + +[#6710]: https://github.com/nymtech/nym/pull/6710 +[#6708]: https://github.com/nymtech/nym/pull/6708 +[#6686]: https://github.com/nymtech/nym/pull/6686 +[#6684]: https://github.com/nymtech/nym/pull/6684 +[#6683]: https://github.com/nymtech/nym/pull/6683 +[#6670]: https://github.com/nymtech/nym/pull/6670 + ## [2026.8-urda] (2026-04-20) - Include all gateways in the returned list ([#6649]) diff --git a/Cargo.lock b/Cargo.lock index 5a8030c9da..2fc4083844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1691,7 +1691,8 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-models" version = "0.0.5" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "657f625ff361906f779745d08375ae3cc9fef87a35fba5f22874cf773010daf4" dependencies = [ "hax-lib", "pastey 0.2.1", @@ -2350,6 +2351,47 @@ dependencies = [ "x25519-dalek", ] +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.12", +] + [[package]] name = "delegate-display" version = "3.0.0" @@ -3398,6 +3440,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -3523,6 +3574,16 @@ dependencies = [ "http 1.3.1", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -4611,7 +4672,8 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libcrux-aesgcm" version = "0.0.7" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f2a019dab4097585a7d4f5b9deebe46cd1e628b16a5bc4cb0ce35e1da334e6" dependencies = [ "libcrux-intrinsics", "libcrux-platform", @@ -4621,8 +4683,9 @@ dependencies = [ [[package]] name = "libcrux-chacha20poly1305" -version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc08d044676af21343b32b988411fa98dbb5cf65a03c9df478ced221bbdfdb1b" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4634,7 +4697,8 @@ dependencies = [ [[package]] name = "libcrux-curve25519" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1e5fd8476a6ed609d24ef42aee5ab6f99f7c65d054f92412da9f499e423299" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4645,7 +4709,8 @@ dependencies = [ [[package]] name = "libcrux-ecdh" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65f73ce79337c762eb38bbac91e4c9b9e60cf318e8501b812750c640814d45e" dependencies = [ "libcrux-curve25519", "libcrux-p256", @@ -4655,8 +4720,9 @@ dependencies = [ [[package]] name = "libcrux-ed25519" -version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835919315b7042fe9e03b6458efe0db94bf2aa7b873934dbee5b5463a8124b43" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4668,7 +4734,8 @@ dependencies = [ [[package]] name = "libcrux-hacl-rs" version = "0.0.4" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2637dc87d158e1f1b550fd9b226443e84153fded4de69028d897b534d16d22e6" dependencies = [ "libcrux-macros", ] @@ -4676,7 +4743,8 @@ dependencies = [ [[package]] name = "libcrux-hkdf" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1a89ca0c89be3a268a921e47105fb7873badf7267f5e3ebf4ea46baedd73ef" dependencies = [ "libcrux-hacl-rs", "libcrux-hmac", @@ -4686,7 +4754,8 @@ dependencies = [ [[package]] name = "libcrux-hmac" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7a242707d65960770bd7e14e4f18a92bdf0b967777dd404887db8d087a643b" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4696,7 +4765,8 @@ dependencies = [ [[package]] name = "libcrux-intrinsics" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b5db005ff8001e026b73a6842ee81bbef8ec5ff0e1915a67ae65fd2a9fafa5" dependencies = [ "core-models", "hax-lib", @@ -4704,8 +4774,9 @@ dependencies = [ [[package]] name = "libcrux-kem" -version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12631592f491d22fd1a176d32b2c6edfb673998fd3987e9d95f8fa79ad2a737b" dependencies = [ "libcrux-curve25519", "libcrux-ecdh", @@ -4720,7 +4791,8 @@ dependencies = [ [[package]] name = "libcrux-macros" version = "0.0.3" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd6aa2dcd5be681662001b81d493f1569c6d49a32361f470b0c955465cd0338" dependencies = [ "quote", "syn 2.0.106", @@ -4728,8 +4800,9 @@ dependencies = [ [[package]] name = "libcrux-ml-dsa" -version = "0.0.7" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a72929ed421cc3bf16a946b3e7d2a58d215b0b5c2a12be26b53629f081bf49b2" dependencies = [ "core-models", "hax-lib", @@ -4742,8 +4815,9 @@ dependencies = [ [[package]] name = "libcrux-ml-kem" -version = "0.0.7" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a14ab3e477de9df6ee1273a114018ff62c4996ca9220070c4e5cb1743f94a67d" dependencies = [ "hax-lib", "libcrux-intrinsics", @@ -4758,7 +4832,8 @@ dependencies = [ [[package]] name = "libcrux-p256" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4778ba25cb08bb8a96bd100e19ed9aecf78337198fd176036e21042b2dd99bc" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4770,15 +4845,17 @@ dependencies = [ [[package]] name = "libcrux-platform" version = "0.0.3" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9e21d7ed31a92ac539bd69a8c970b183ee883872d2d19ce27036e24cb8ecc4" dependencies = [ "libc", ] [[package]] name = "libcrux-poly1305" -version = "0.0.4" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02491808ee5b9db8cb65fad64ae0be812db64beef179d945c00c7787dc7dfcf9" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4786,8 +4863,9 @@ dependencies = [ [[package]] name = "libcrux-psq" -version = "0.0.7" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ade7aa5e1b4b400c716b313cbf69070988dd005f92e961c2da4c3c42fbea4" dependencies = [ "classic-mceliece-rust", "libcrux-aesgcm", @@ -4809,7 +4887,8 @@ dependencies = [ [[package]] name = "libcrux-secrets" version = "0.0.5" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce650f3041b44ba40d4263852347d007cd2cd9d1cc856a6f6c8b2e10c3fd40b" dependencies = [ "hax-lib", ] @@ -4817,7 +4896,8 @@ dependencies = [ [[package]] name = "libcrux-sha2" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d253473f259fc74a280c43f29c464f7e374abdf28b4942234dc707f529d4b7" dependencies = [ "libcrux-hacl-rs", "libcrux-macros", @@ -4826,8 +4906,9 @@ dependencies = [ [[package]] name = "libcrux-sha3" -version = "0.0.7" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1ae0b7d0e1cc4793a609fd0ff2ca3b3a3fabae523770c619a3d4bc86417b0d7" dependencies = [ "hax-lib", "libcrux-intrinsics", @@ -4838,7 +4919,8 @@ dependencies = [ [[package]] name = "libcrux-traits" version = "0.0.6" -source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e4fa89f3f5e34b47f928b22b1b78395a0d4ec23b1f583db635f128159d65f" dependencies = [ "libcrux-secrets", "rand 0.9.2", @@ -5047,6 +5129,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + [[package]] name = "maplit" version = "1.0.2" @@ -5547,7 +5635,7 @@ dependencies = [ [[package]] name = "nym-api" -version = "1.1.78" +version = "1.1.79" dependencies = [ "anyhow", "async-trait", @@ -5792,7 +5880,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.75" +version = "1.1.76" dependencies = [ "anyhow", "base64 0.22.1", @@ -5875,7 +5963,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.75" +version = "1.1.76" dependencies = [ "bs58", "clap", @@ -6940,6 +7028,7 @@ dependencies = [ "bytes", "futures", "nym-ip-packet-requests", + "nym-lp", "nym-sdk", "thiserror 2.0.12", "tokio", @@ -7284,7 +7373,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.76" +version = "1.1.77" dependencies = [ "addr", "anyhow", @@ -7334,7 +7423,7 @@ dependencies = [ [[package]] name = "nym-node" -version = "1.30.0" +version = "1.31.0" dependencies = [ "anyhow", "arc-swap", @@ -7492,7 +7581,7 @@ dependencies = [ [[package]] name = "nym-node-status-api" -version = "4.5.0" +version = "4.6.1" dependencies = [ "ammonia", "anyhow", @@ -7886,7 +7975,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.75" +version = "1.1.76" dependencies = [ "bs58", "clap", @@ -8684,7 +8773,7 @@ dependencies = [ [[package]] name = "nymvisor" -version = "0.1.40" +version = "0.1.41" dependencies = [ "anyhow", "bytes", @@ -11074,6 +11163,47 @@ dependencies = [ "serde_core", ] +[[package]] +name = "smolmix" +version = "0.0.1" +dependencies = [ + "futures", + "hickory-proto", + "hickory-resolver", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "nym-bin-common", + "nym-ip-packet-requests", + "nym-sdk", + "reqwest 0.13.1", + "rustls 0.23.37", + "smoltcp", + "thiserror 2.0.12", + "tokio", + "tokio-rustls 0.26.2", + "tokio-smoltcp", + "tokio-tungstenite", + "tracing", + "webpki-roots 0.26.11", +] + +[[package]] +name = "smoltcp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless", + "libc", + "log", + "managed", +] + [[package]] name = "snafu" version = "0.7.5" @@ -12040,6 +12170,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-smoltcp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f5d53da1c3095663a8900d86c2abb0ffe02d3f6aa86527b066148fcb33e65e" +dependencies = [ + "futures", + "parking_lot", + "pin-project-lite", + "smoltcp", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-stream" version = "0.1.17" diff --git a/Cargo.toml b/Cargo.toml index f559bae048..1d1db9f1da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -147,6 +147,7 @@ members = [ "sdk/ffi/go", "sdk/ffi/shared", "sdk/rust/nym-sdk", + "smolmix/core", "service-providers/common", "service-providers/ip-packet-router", "service-providers/network-requester", @@ -279,6 +280,7 @@ getrandom03 = { package = "getrandom", version = "=0.3.3" } glob = "0.3" handlebars = "3.5.5" hex = "0.4.3" +hickory-proto = "0.25.2" hickory-resolver = "0.25.2" hkdf = "0.12.3" hmac = "0.12.1" @@ -347,6 +349,8 @@ serde_yaml = "0.9.25" serde_plain = "1.0.2" sha2 = "0.10.3" si-scale = "0.2.3" +smolmix = { version = "0.0.1", path = "smolmix/core" } +smoltcp = "0.12" snow = "0.9.6" sphinx-packet = "=0.6.0" sqlx = "0.8.6" @@ -367,6 +371,8 @@ tokio-postgres = "0.7" tokio-stream = "0.1.17" tokio-test = "0.4.4" tokio-tun = "0.11.5" +tokio-rustls = "0.26" +tokio-smoltcp = "0.5" tokio-tungstenite = { version = "0.20.1" } tokio-util = "0.7.15" toml = "0.8.22" @@ -398,14 +404,14 @@ prometheus = { version = "0.14.0" } # libcrux -libcrux-kem = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-ecdh = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-curve25519 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-chacha20poly1305 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-psq = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-ml-kem = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-sha3 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } -libcrux-traits = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" } +libcrux-kem = "0.0.7" +libcrux-ecdh = "0.0.6" +libcrux-curve25519 = "0.0.6" +libcrux-chacha20poly1305 = "0.0.7" +libcrux-psq = "0.0.8" +libcrux-ml-kem = "0.0.8" +libcrux-sha3 = "0.0.8" +libcrux-traits = "0.0.8" # Workspace dep definitions required by crates.io publication - we need a workspace version since `cargo workspaces` doesn't work with path imports from crate manifests nym-api-requests = { version = "1.20.4", path = "nym-api/nym-api-requests" } @@ -559,6 +565,7 @@ wasm-bindgen = "0.2.99" wasm-bindgen-futures = "0.4.49" wasm-bindgen-test = "0.3.49" wasmtimer = "0.4.1" +webpki-roots = "0.26" web-sys = "0.3.76" # for local development: diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 14a515e844..83e9bd5d97 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "nym-client" description = "Implementation of the Nym Client" -version = "1.1.75" +version = "1.1.76" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] edition = "2021" -rust-version = "1.85" license.workspace = true +rust-version = "1.85" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clients/native/websocket-requests/Cargo.toml b/clients/native/websocket-requests/Cargo.toml index 25defd82ff..ae232bd83c 100644 --- a/clients/native/websocket-requests/Cargo.toml +++ b/clients/native/websocket-requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-client-websocket-requests" +description = "Request and response definitions for Nym client websocket connections" version.workspace = true authors = ["Jędrzej Stuczyński "] edition = "2021" license.workspace = true -description = "Request and response definitions for Nym client websocket connections" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index e184ad58ee..a22ad47a08 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "nym-socks5-client" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" -version = "1.1.75" +version = "1.1.76" authors = ["Dave Hrycyszyn "] edition = "2021" -rust-version = "1.85" license.workspace = true +rust-version = "1.85" publish = false [dependencies] diff --git a/common/async-file-watcher/Cargo.toml b/common/async-file-watcher/Cargo.toml index 4c4af2ab4c..1a8e3a4b87 100644 --- a/common/async-file-watcher/Cargo.toml +++ b/common/async-file-watcher/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-async-file-watcher" +description = "Simple file watcher that sends a notification whenever there was any change in the watched file" version.workspace = true +authors.workspace = true edition.workspace = true license.workspace = true -description = "Simple file watcher that sends a notification whenever there was any change in the watched file" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/authenticator-requests/Cargo.toml b/common/authenticator-requests/Cargo.toml index 89873c5c20..27d3fcfc6e 100644 --- a/common/authenticator-requests/Cargo.toml +++ b/common/authenticator-requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-authenticator-requests" +description = "Crate defining requests and responses for the Nym authenticator client" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Crate defining requests and responses for the Nym authenticator client" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] base64 = { workspace = true } diff --git a/common/bandwidth-controller/Cargo.toml b/common/bandwidth-controller/Cargo.toml index d93ddbab85..228442a053 100644 --- a/common/bandwidth-controller/Cargo.toml +++ b/common/bandwidth-controller/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-bandwidth-controller" +description = "Crate for controlling the use of zknym credentials to ensure constant bandwidth availability for NymVPN app" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Crate for controlling the use of zknym credentials to ensure constant bandwidth availability for NymVPN app" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/bin-common/Cargo.toml b/common/bin-common/Cargo.toml index b10a29b84c..db389c8a4c 100644 --- a/common/bin-common/Cargo.toml +++ b/common/bin-common/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-bin-common" -version.workspace = true description = "Common code for nym binaries" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] clap = { workspace = true, features = ["derive"], optional = true } @@ -38,6 +43,7 @@ default = [] openapi = ["utoipa"] output_format = ["serde_json", "dep:clap"] bin_info_schema = ["schemars"] +ip_check = [] basic_tracing = ["dep:tracing", "dep:tracing-subscriber"] otel-otlp = [ "basic_tracing", diff --git a/nym-node/src/node/mixnet/packet_forwarding/global.rs b/common/bin-common/src/ip_check/mod.rs similarity index 92% rename from nym-node/src/node/mixnet/packet_forwarding/global.rs rename to common/bin-common/src/ip_check/mod.rs index 6f27444a57..26a10e9005 100644 --- a/nym-node/src/node/mixnet/packet_forwarding/global.rs +++ b/common/bin-common/src/ip_check/mod.rs @@ -1,29 +1,12 @@ -// Copyright 2025 - Nym Technologies SA -// SPDX-License-Identifier: GPL-3.0-only - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -// use `ip` feature without nightly -// issue: https://github.com/rust-lang/rust/issues/27709 -pub(crate) const fn is_global_ip(ip: &IpAddr) -> bool { +pub const fn is_global_ip(ip: &IpAddr) -> bool { match ip { IpAddr::V4(addr) => is_global_ipv4(addr), IpAddr::V6(addr) => is_global_ipv6(addr), } } -const fn is_shared_ipv4(ip: &Ipv4Addr) -> bool { - ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000 == 0b0100_0000) -} - -const fn is_benchmarking_ipv4(ip: &Ipv4Addr) -> bool { - ip.octets()[0] == 198 && (ip.octets()[1] & 0xfe) == 18 -} - -const fn is_reserved_ipv4(ip: &Ipv4Addr) -> bool { - ip.octets()[0] & 240 == 240 && !ip.is_broadcast() -} - const fn is_global_ipv4(ip: &Ipv4Addr) -> bool { !(ip.octets()[0] == 0 // "This network" || ip.is_private() @@ -42,6 +25,18 @@ const fn is_global_ipv4(ip: &Ipv4Addr) -> bool { || ip.is_broadcast()) } +const fn is_shared_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000 == 0b0100_0000) +} + +const fn is_benchmarking_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] == 198 && (ip.octets()[1] & 0xfe) == 18 +} + +const fn is_reserved_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] & 240 == 240 && !ip.is_broadcast() +} + const fn is_documentation_ipv6(ip: &Ipv6Addr) -> bool { (ip.segments()[0] == 0x2001) && (ip.segments()[1] == 0xdb8) } diff --git a/common/bin-common/src/lib.rs b/common/bin-common/src/lib.rs index 9353302b2f..663936085d 100644 --- a/common/bin-common/src/lib.rs +++ b/common/bin-common/src/lib.rs @@ -9,3 +9,6 @@ pub mod completions; #[cfg(feature = "output_format")] pub mod output_format; + +#[cfg(feature = "ip_check")] +pub mod ip_check; diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index ce2e932b17..351ed58fc8 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "nym-client-core" +description = "Crate containing core client functionality and configs, used by all other Nym client implentations" version.workspace = true authors = ["Dave Hrycyszyn "] edition = "2024" -rust-version = "1.85" license.workspace = true -description = "Crate containing core client functionality and configs, used by all other Nym client implentations" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-core/config-types/Cargo.toml b/common/client-core/config-types/Cargo.toml index 4c586ec1c3..9236820211 100644 --- a/common/client-core/config-types/Cargo.toml +++ b/common/client-core/config-types/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-client-core-config-types" +description = "Low level configs and constants used by Nym clients and nodes" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Low level configs and constants used by Nym clients and nodes" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index 1a1e9f7c2d..e788467688 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-client-core-gateways-storage" +description = "Functionality for Nym clients to store and retrive Gateway connections" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -rust-version.workspace = true -description = "Functionality for Nym clients to store and retrive Gateway connections" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-core/surb-storage/Cargo.toml b/common/client-core/surb-storage/Cargo.toml index 04168ec19e..6bb6c2f965 100644 --- a/common/client-core/surb-storage/Cargo.toml +++ b/common/client-core/surb-storage/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-client-core-surb-storage" +description = "Functionality for Nym clients to generate and use Single Use Reply Blocks (SURBs)" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Functionality for Nym clients to generate and use Single Use Reply Blocks (SURBs)" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-libs/gateway-client/Cargo.toml b/common/client-libs/gateway-client/Cargo.toml index 914c23a45e..8a9a3157f2 100644 --- a/common/client-libs/gateway-client/Cargo.toml +++ b/common/client-libs/gateway-client/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-gateway-client" +description = "Functions and types for Nym client <> Gateway connections" version.workspace = true authors = ["Jędrzej Stuczyński "] edition = "2021" license.workspace = true -description = "Functions and types for Nym client <> Gateway connections" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-libs/mixnet-client/Cargo.toml b/common/client-libs/mixnet-client/Cargo.toml index 72f838e50b..614e4e698e 100644 --- a/common/client-libs/mixnet-client/Cargo.toml +++ b/common/client-libs/mixnet-client/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-mixnet-client" +description = "Client for Mix Node <> Mix Node & Mix Node <> Gateway communication" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true -description = "Client for Mix Node <> Mix Node & Mix Node <> Gateway communication" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-libs/validator-client/Cargo.toml b/common/client-libs/validator-client/Cargo.toml index e7215d456b..ea1de63563 100644 --- a/common/client-libs/validator-client/Cargo.toml +++ b/common/client-libs/validator-client/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "nym-validator-client" +description = "Client for interacting with Nyx Cosmos SDK blockchain" version.workspace = true authors = ["Jędrzej Stuczyński "] edition = "2021" -rust-version = "1.85" license.workspace = true -description = "Client for interacting with Nyx Cosmos SDK blockchain" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/commands/Cargo.toml b/common/commands/Cargo.toml index 1c7d1f8da8..53b29b842f 100644 --- a/common/commands/Cargo.toml +++ b/common/commands/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-cli-commands" +description = "Common commands crate used by the nym-cli tool for interacting with the Nyx Cosmos SDK blockchain and Mixnet endpoints" version.workspace = true authors.workspace = true edition = "2021" license.workspace = true -description = "Common commands crate used by the nym-cli tool for interacting with the Nyx Cosmos SDK blockchain and Mixnet endpoints" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] anyhow = { workspace = true } diff --git a/common/config/Cargo.toml b/common/config/Cargo.toml index 4c364f9292..6e34d07d41 100644 --- a/common/config/Cargo.toml +++ b/common/config/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-config" +description = "Config related helpers and functions" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true +repository.workspace = true homepage.workspace = true -description = "Config related helpers and functions" +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/cosmwasm-smart-contracts/coconut-dkg/Cargo.toml b/common/cosmwasm-smart-contracts/coconut-dkg/Cargo.toml index 158b920e24..dc4fe926af 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg/Cargo.toml +++ b/common/cosmwasm-smart-contracts/coconut-dkg/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-coconut-dkg-common" +description = "Common crate for Nym's DKG cosmwasm contract" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Common crate for Nym's DKG cosmwasm contract" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/cosmwasm-smart-contracts/contracts-common-testing/Cargo.toml b/common/cosmwasm-smart-contracts/contracts-common-testing/Cargo.toml index 69f429b24d..0cef554a87 100644 --- a/common/cosmwasm-smart-contracts/contracts-common-testing/Cargo.toml +++ b/common/cosmwasm-smart-contracts/contracts-common-testing/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-contracts-common-testing" +description = "Common crate for cosmwasm contract tests" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true +rust-version = "1.85" readme.workspace = true -description = "Common crate for cosmwasm contract tests" +publish = true [dependencies] anyhow = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml index 277351d5d0..82ac9871ae 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml +++ b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-contracts-common" -version.workspace = true description = "Common library for Nym cosmwasm contracts" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true [dependencies] bs58 = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/easy_addr/Cargo.toml b/common/cosmwasm-smart-contracts/easy_addr/Cargo.toml index b8a48b40a7..e832cd96e9 100644 --- a/common/cosmwasm-smart-contracts/easy_addr/Cargo.toml +++ b/common/cosmwasm-smart-contracts/easy_addr/Cargo.toml @@ -2,8 +2,8 @@ name = "easy-addr" version.workspace = true edition = "2021" -publish = false license.workspace = true +publish = false [lib] proc-macro = true diff --git a/common/cosmwasm-smart-contracts/ecash-contract/Cargo.toml b/common/cosmwasm-smart-contracts/ecash-contract/Cargo.toml index dce59308ce..dd9a616b2d 100644 --- a/common/cosmwasm-smart-contracts/ecash-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/ecash-contract/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-ecash-contract-common" +description = "Common crate for Nym's ecash/zknym cosmwasm contract" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Common crate for Nym's ecash/zknym cosmwasm contract" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/cosmwasm-smart-contracts/group-contract/Cargo.toml b/common/cosmwasm-smart-contracts/group-contract/Cargo.toml index 17cb3e83db..9de9779622 100644 --- a/common/cosmwasm-smart-contracts/group-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/group-contract/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-group-contract-common" +description = "Common crate for Nym's group cosmwasm contract" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Common crate for Nym's group cosmwasm contract" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true [dependencies] cosmwasm-schema = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml index fb7143723d..b53e1d3420 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-mixnet-contract-common" -version.workspace = true description = "Common library for the Nym mixnet contract" -rust-version = "1.85" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true [dependencies] bs58 = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml index 31aef542af..7fc32eacab 100644 --- a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml @@ -1,10 +1,16 @@ [package] name = "nym-multisig-contract-common" +description = "Common code for the Nym multisig CosmWasm smart contract" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Common code for the Nym multisig CosmWasm smart contract" +repository.workspace = true homepage.workspace = true +documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true [dependencies] cosmwasm-schema = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/nym-performance-contract/Cargo.toml b/common/cosmwasm-smart-contracts/nym-performance-contract/Cargo.toml index 8fd19ff838..13612c9b96 100644 --- a/common/cosmwasm-smart-contracts/nym-performance-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/nym-performance-contract/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-performance-contract-common" +description = "Common crate for Nym's group performance contract" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true +rust-version = "1.85" readme.workspace = true -description = "Common crate for Nym's group performance contract" +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/nym-pool-contract/Cargo.toml b/common/cosmwasm-smart-contracts/nym-pool-contract/Cargo.toml index a4567fb0c2..02f6fdd4a3 100644 --- a/common/cosmwasm-smart-contracts/nym-pool-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/nym-pool-contract/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-pool-contract-common" -version.workspace = true description = "Common library for the Nym Pool contract" +version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true +rust-version = "1.85" readme.workspace = true +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/vesting-contract/Cargo.toml b/common/cosmwasm-smart-contracts/vesting-contract/Cargo.toml index cc29aebe12..dd9553bc05 100644 --- a/common/cosmwasm-smart-contracts/vesting-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/vesting-contract/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-vesting-contract-common" -version.workspace = true description = "Common library for the Nym vesting contract" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version = "1.85" +readme.workspace = true +publish = true [dependencies] cosmwasm-std = { workspace = true } diff --git a/common/credential-proxy/Cargo.toml b/common/credential-proxy/Cargo.toml index 65549f2753..56a02266e3 100644 --- a/common/credential-proxy/Cargo.toml +++ b/common/credential-proxy/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-credential-proxy-lib" +description = "Build script and core functionality of the Nym Credential Proxy" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Build script and core functionality of the Nym Credential Proxy" +publish = true [dependencies] anyhow = { workspace = true } diff --git a/common/credential-storage/Cargo.toml b/common/credential-storage/Cargo.toml index 42da92cedc..c6b49edb6c 100644 --- a/common/credential-storage/Cargo.toml +++ b/common/credential-storage/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-credential-storage" +description = "Crate for handling and storing spent and unspent zknym ticketbooks" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -rust-version.workspace = true -description = "Crate for handling and storing spent and unspent zknym ticketbooks" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/credential-utils/Cargo.toml b/common/credential-utils/Cargo.toml index f3d6986d1d..3dfaacf07a 100644 --- a/common/credential-utils/Cargo.toml +++ b/common/credential-utils/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-credential-utils" +description = "Utils crate for dealing with zknym credentials" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Utils crate for dealing with zknym credentials" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/common/credential-verification/Cargo.toml b/common/credential-verification/Cargo.toml index d5af1fff19..80e0918330 100644 --- a/common/credential-verification/Cargo.toml +++ b/common/credential-verification/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-credential-verification" +description = "Store and verify zknym credentials" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Store and verify zknym credentials" +publish = true [dependencies] async-trait = { workspace = true } diff --git a/common/credentials-interface/Cargo.toml b/common/credentials-interface/Cargo.toml index fd2f6d895d..615bec2bbc 100644 --- a/common/credentials-interface/Cargo.toml +++ b/common/credentials-interface/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-credentials-interface" +description = "Interface for Nym's compact eacash / zknym credential scheme" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Interface for Nym's compact eacash / zknym credential scheme" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/credentials/Cargo.toml b/common/credentials/Cargo.toml index 1a429bc24c..ab45bf851f 100644 --- a/common/credentials/Cargo.toml +++ b/common/credentials/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-credentials" +description = "Crate for using Nym's zknym credentials" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Crate for using Nym's zknym credentials" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/crypto/Cargo.toml b/common/crypto/Cargo.toml index 7d037f1a97..1cc48788b6 100644 --- a/common/crypto/Cargo.toml +++ b/common/crypto/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-crypto" -version.workspace = true description = "Crypto library for the nym mixnet" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] aes-gcm-siv = { workspace = true, optional = true } diff --git a/common/dkg/Cargo.toml b/common/dkg/Cargo.toml index e45a2a8d7f..da5584b76a 100644 --- a/common/dkg/Cargo.toml +++ b/common/dkg/Cargo.toml @@ -1,13 +1,17 @@ [package] name = "nym-dkg" -version.workspace = true -edition = "2021" -resolver = "2" -license.workspace = true description = "Nym's Distributed Key Generation functionality" +version.workspace = true +authors.workspace = true +edition = "2021" +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true +resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/ecash-signer-check-types/Cargo.toml b/common/ecash-signer-check-types/Cargo.toml index ac3a6f084d..6536ed5b76 100644 --- a/common/ecash-signer-check-types/Cargo.toml +++ b/common/ecash-signer-check-types/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-ecash-signer-check-types" +description = "Crate containing types for the `ecash-signer-check` crate used to check if zknym signers are up and running properly" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Crate containing types for the `ecash-signer-check` crate used to check if zknym signers are up and running properly" +publish = true [dependencies] semver = { workspace = true } diff --git a/common/ecash-signer-check/Cargo.toml b/common/ecash-signer-check/Cargo.toml index 976df1bf55..425b4d3697 100644 --- a/common/ecash-signer-check/Cargo.toml +++ b/common/ecash-signer-check/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-ecash-signer-check" +description = "Functions to interact with zknym signers, checking their status and health" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Functions to interact with zknym signers, checking their status and health" +publish = true [dependencies] futures = { workspace = true } diff --git a/common/ecash-time/Cargo.toml b/common/ecash-time/Cargo.toml index 1780a96afe..bc7021167a 100644 --- a/common/ecash-time/Cargo.toml +++ b/common/ecash-time/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-ecash-time" +description = "Time-related helper functions for Nym's zknym scheme" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Time-related helper functions for Nym's zknym scheme" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/exit-policy/Cargo.toml b/common/exit-policy/Cargo.toml index 3db220a920..172f95c90f 100644 --- a/common/exit-policy/Cargo.toml +++ b/common/exit-policy/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-exit-policy" +description = "Get and set the Nym Exit Policy, used by Exit Gateways" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Get and set the Nym Exit Policy, used by Exit Gateways" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/gateway-requests/Cargo.toml b/common/gateway-requests/Cargo.toml index b9cdf43d01..7803769ada 100644 --- a/common/gateway-requests/Cargo.toml +++ b/common/gateway-requests/Cargo.toml @@ -3,14 +3,17 @@ [package] name = "nym-gateway-requests" +description = "Request and response definitions for Nym Gateway <> client communication" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true -description = "Request and response definitions for Nym Gateway <> client communication" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/gateway-stats-storage/Cargo.toml b/common/gateway-stats-storage/Cargo.toml index 7c1f996059..cb37725db1 100644 --- a/common/gateway-stats-storage/Cargo.toml +++ b/common/gateway-stats-storage/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "nym-gateway-stats-storage" +description = "Functionality Nym Gateway statistics storage" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true -description = "Functionality Nym Gateway statistics storage" +readme.workspace = true +publish = true [dependencies] sqlx = { workspace = true, features = [ diff --git a/common/gateway-storage/Cargo.toml b/common/gateway-storage/Cargo.toml index 32424e7d4a..76a8ad56d0 100644 --- a/common/gateway-storage/Cargo.toml +++ b/common/gateway-storage/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "nym-gateway-storage" +description = "Crate handling db setup and use for Nym Gateways, used for credentials, packets, connections" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true -description = "Crate handling db setup and use for Nym Gateways, used for credentials, packets, connections" +readme.workspace = true +publish = true [dependencies] async-trait = { workspace = true } diff --git a/common/http-api-client-macro/Cargo.toml b/common/http-api-client-macro/Cargo.toml index f5e12bef4c..de4e6e619a 100644 --- a/common/http-api-client-macro/Cargo.toml +++ b/common/http-api-client-macro/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-http-api-client-macro" +description = "Proc-macros for configuring HTTP clients globally via the `inventory` crate" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Proc-macros for configuring HTTP clients globally via the `inventory` crate" +publish = true [lib] proc-macro = true diff --git a/common/http-api-client/Cargo.toml b/common/http-api-client/Cargo.toml index 00d083bbf2..0952580bce 100644 --- a/common/http-api-client/Cargo.toml +++ b/common/http-api-client/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-http-api-client" +description = "Nym's HTTP API client, examples, and tests" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Nym's HTTP API client, examples, and tests" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/http-api-client/src/lib.rs b/common/http-api-client/src/lib.rs index 9d94dcf30e..856b2ad0e7 100644 --- a/common/http-api-client/src/lib.rs +++ b/common/http-api-client/src/lib.rs @@ -1152,7 +1152,10 @@ impl ApiClientCore for Client { #[cfg(target_arch = "wasm32")] let response: Result = { - let client = self.reqwest_client.as_ref().unwrap_or(&*SHARED_CLIENT); + let client = self + .reqwest_client + .as_ref() + .unwrap_or_else(|| &*SHARED_CLIENT); Ok( wasmtimer::tokio::timeout(self.request_timeout, client.execute(req)) .await @@ -1162,7 +1165,10 @@ impl ApiClientCore for Client { #[cfg(not(target_arch = "wasm32"))] let response = { - let client = self.reqwest_client.as_ref().unwrap_or(&*SHARED_CLIENT); + let client = self + .reqwest_client + .as_ref() + .unwrap_or_else(|| &*SHARED_CLIENT); client.execute(req).await }; diff --git a/common/http-api-common/Cargo.toml b/common/http-api-common/Cargo.toml index 17d7521788..94601f3b61 100644 --- a/common/http-api-common/Cargo.toml +++ b/common/http-api-common/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-http-api-common" +description = "Common crate for Nym-related HTTP API interaction" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Common crate for Nym-related HTTP API interaction" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/inclusion-probability/Cargo.toml b/common/inclusion-probability/Cargo.toml index d27d0a23fa..f73167cd3d 100644 --- a/common/inclusion-probability/Cargo.toml +++ b/common/inclusion-probability/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-inclusion-probability" -version.workspace = true description = "Nym active set probability simulator" -edition.workspace = true +version.workspace = true authors.workspace = true +edition.workspace = true license.workspace = true repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] log = { workspace = true } diff --git a/common/ip-packet-requests/Cargo.toml b/common/ip-packet-requests/Cargo.toml index 0d062b2d45..bd95393c99 100644 --- a/common/ip-packet-requests/Cargo.toml +++ b/common/ip-packet-requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-ip-packet-requests" +description = "Codec, signing functionality, and different version definitions for IP packet request and responses" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Codec, signing functionality, and different version definitions for IP packet request and responses" +rust-version.workspace = true +readme.workspace = true +publish = true [features] diff --git a/common/ip-packet-requests/src/lib.rs b/common/ip-packet-requests/src/lib.rs index f3014a69ec..eb1ef05086 100644 --- a/common/ip-packet-requests/src/lib.rs +++ b/common/ip-packet-requests/src/lib.rs @@ -12,6 +12,26 @@ pub mod v7; pub mod v8; pub mod v9; +/// Highest IPR protocol version that is allowed to be sent as a **non-stream** mixnet payload +/// (i.e. not wrapped in `LpFrameKind::SphinxStream`). +pub const MAX_NON_STREAM_VERSION: u8 = v8::VERSION; + +/// First IPR protocol version that **requires** the SphinxStream (LP) transport for non-stream +/// mixnet sends, matching the node-side enforcement in `ip-packet-router`. +pub const SPHINX_STREAM_VERSION_THRESHOLD: u8 = v9::VERSION; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stream_transport_threshold_is_consistent() { + assert_eq!(MAX_NON_STREAM_VERSION, 8); + assert_eq!(SPHINX_STREAM_VERSION_THRESHOLD, 9); + assert!(SPHINX_STREAM_VERSION_THRESHOLD > MAX_NON_STREAM_VERSION); + } +} + // version 3: initial version // version 4: IPv6 support // version 5: Add severity level to info response diff --git a/common/mixnode-common/Cargo.toml b/common/mixnode-common/Cargo.toml index 50d1c94cde..9a4a587867 100644 --- a/common/mixnode-common/Cargo.toml +++ b/common/mixnode-common/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-mixnode-common" +description = "Common crate for Nym Mix Nodes" version.workspace = true authors = ["Jędrzej Stuczyński "] edition = "2021" license.workspace = true -description = "Common crate for Nym Mix Nodes" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/network-defaults/Cargo.toml b/common/network-defaults/Cargo.toml index 305f31916f..238503673d 100644 --- a/common/network-defaults/Cargo.toml +++ b/common/network-defaults/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-network-defaults" -version.workspace = true description = "Nym network defaults" -edition.workspace = true +version.workspace = true authors.workspace = true +edition.workspace = true license.workspace = true repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # Exclude build.rs from published crate - it's only used for dev-time sync # of env files and requires workspace context exclude = ["build.rs"] diff --git a/common/node-tester-utils/Cargo.toml b/common/node-tester-utils/Cargo.toml index d3845fb094..ff1bd497a4 100644 --- a/common/node-tester-utils/Cargo.toml +++ b/common/node-tester-utils/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-node-tester-utils" +description = "Utils for the Nym Node Tester" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Utils for the Nym Node Tester" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nonexhaustive-delayqueue/Cargo.toml b/common/nonexhaustive-delayqueue/Cargo.toml index f8d4671688..8705ebaa55 100644 --- a/common/nonexhaustive-delayqueue/Cargo.toml +++ b/common/nonexhaustive-delayqueue/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-nonexhaustive-delayqueue" +description = "A copy of tokio-util delay_queue with `Sleep` and `Instant` being replaced with`wasm_timer` equivalents" version.workspace = true authors = ["Jędrzej Stuczyński "] edition = "2021" license.workspace = true -description = "A copy of tokio-util delay_queue with `Sleep` and `Instant` being replaced with`wasm_timer` equivalents" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nym-cache/Cargo.toml b/common/nym-cache/Cargo.toml index 3d935c3e89..ea344bc050 100644 --- a/common/nym-cache/Cargo.toml +++ b/common/nym-cache/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-cache" +description = "Helper functions around a RwLock for writing to local cache of items" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Helper functions around a RwLock for writing to local cache of items" +publish = true [dependencies] tokio = { workspace = true, features = ["sync"] } diff --git a/common/nym-common/Cargo.toml b/common/nym-common/Cargo.toml index 6bdbef1bce..ba59dbf46e 100644 --- a/common/nym-common/Cargo.toml +++ b/common/nym-common/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-common" +description = "Runtime diagnostics for high frequency logging, debugging and error handling utilities" version.workspace = true authors.workspace = true -repository.workspace = true -license.workspace = true edition.workspace = true -description = "Runtime diagnostics for high frequency logging, debugging and error handling utilities" +license.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [lints] workspace = true diff --git a/common/nym-connection-monitor/Cargo.toml b/common/nym-connection-monitor/Cargo.toml index 03de5da740..c7ce2c445e 100644 --- a/common/nym-connection-monitor/Cargo.toml +++ b/common/nym-connection-monitor/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-connection-monitor" version = "1.18.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false [lints] diff --git a/common/nym-id/Cargo.toml b/common/nym-id/Cargo.toml index 17b4ac31ef..5ef2a3d119 100644 --- a/common/nym-id/Cargo.toml +++ b/common/nym-id/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-id" +description = "Functionality for importing and storing credentials and cryptographic keys" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Functionality for importing and storing credentials and cryptographic keys" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nym-kcp/Cargo.toml b/common/nym-kcp/Cargo.toml index 3f435e94e5..b866fd7954 100644 --- a/common/nym-kcp/Cargo.toml +++ b/common/nym-kcp/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "nym-kcp" -version = "0.1.0" description = "KCP protocol implementation for Nym" -edition = { workspace = true } +version = "0.1.0" authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } publish = false diff --git a/common/nym-kkt-ciphersuite/Cargo.toml b/common/nym-kkt-ciphersuite/Cargo.toml index ef1b8e7738..d1d69e9fea 100644 --- a/common/nym-kkt-ciphersuite/Cargo.toml +++ b/common/nym-kkt-ciphersuite/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-kkt-ciphersuite" +description = "Nym KKT ciphersuite" +version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -version.workspace = true -publish = false +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/nym-kkt-context/Cargo.toml b/common/nym-kkt-context/Cargo.toml index 9ab1c8e123..53f5bbf530 100644 --- a/common/nym-kkt-context/Cargo.toml +++ b/common/nym-kkt-context/Cargo.toml @@ -1,21 +1,22 @@ [package] name = "nym-kkt-context" +description = "Context types and definitions for the Nym KKT protocol" +version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -version.workspace = true -publish = false +publish = true [dependencies] num_enum = { workspace = true } thiserror = { workspace = true } -nym-kkt-ciphersuite = { path = "../nym-kkt-ciphersuite" } +nym-kkt-ciphersuite = { workspace = true } [lints] workspace = true diff --git a/common/nym-kkt/Cargo.toml b/common/nym-kkt/Cargo.toml index 02c9f50d49..e278e33887 100644 --- a/common/nym-kkt/Cargo.toml +++ b/common/nym-kkt/Cargo.toml @@ -1,10 +1,16 @@ [package] name = "nym-kkt" +description = "Key transport protocol for the Nym network" version = "0.1.0" authors = ["Georgio Nicolas "] edition = { workspace = true } license.workspace = true -publish = false +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/nym-lp/Cargo.toml b/common/nym-lp/Cargo.toml index 56ba2c2c11..24f78711a0 100644 --- a/common/nym-lp/Cargo.toml +++ b/common/nym-lp/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-lp" +description = "Lewes Protocol session and transport layer for the Nym network" +version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -version.workspace = true -publish = false +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/nym-metrics/Cargo.toml b/common/nym-metrics/Cargo.toml index 491b72f07d..ab459c35f3 100644 --- a/common/nym-metrics/Cargo.toml +++ b/common/nym-metrics/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-metrics" +description = "Metrics macros" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Metrics macros" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nym_offline_compact_ecash/Cargo.toml b/common/nym_offline_compact_ecash/Cargo.toml index e70063bd17..1eac6b4af8 100644 --- a/common/nym_offline_compact_ecash/Cargo.toml +++ b/common/nym_offline_compact_ecash/Cargo.toml @@ -3,14 +3,17 @@ [package] name = "nym-compact-ecash" +description = "Nym's ecash implementation" version.workspace = true authors = ["Ania Piotrowska "] edition = "2021" license = { workspace = true } -description = "Nym's ecash implementation" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nymnoise/Cargo.toml b/common/nymnoise/Cargo.toml index 64dd0470f5..aa7d184518 100644 --- a/common/nymnoise/Cargo.toml +++ b/common/nymnoise/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-noise" +description = "Nym's Noise protocol implementation" version.workspace = true authors = ["Simon Wicky "] edition = "2021" license.workspace = true -description = "Nym's Noise protocol implementation" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] arc-swap = { workspace = true } diff --git a/common/nymnoise/keys/Cargo.toml b/common/nymnoise/keys/Cargo.toml index 3dfc1c64d2..779dae7a02 100644 --- a/common/nymnoise/keys/Cargo.toml +++ b/common/nymnoise/keys/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-noise-keys" +description = "Helpers and type definition of Nym's Noise protocol keys" version.workspace = true authors = ["Simon Wicky "] edition = "2021" license.workspace = true -description = "Helpers and type definition of Nym's Noise protocol keys" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] schemars = { workspace = true, features = ["preserve_order"] } diff --git a/common/nymsphinx/Cargo.toml b/common/nymsphinx/Cargo.toml index 1fba34a0c2..2ff13840ec 100644 --- a/common/nymsphinx/Cargo.toml +++ b/common/nymsphinx/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx" -version.workspace = true description = "Top-level crate for sphinx packets as used by the Nym mixnet" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] tracing = { workspace = true } diff --git a/common/nymsphinx/acknowledgements/Cargo.toml b/common/nymsphinx/acknowledgements/Cargo.toml index 6d0fe4fcff..bf94fd649a 100644 --- a/common/nymsphinx/acknowledgements/Cargo.toml +++ b/common/nymsphinx/acknowledgements/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-acknowledgements" -version.workspace = true description = "Sphinx packet ack messages" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] rand = { workspace = true } diff --git a/common/nymsphinx/addressing/Cargo.toml b/common/nymsphinx/addressing/Cargo.toml index 5aec9af3ed..a5b2ed291e 100644 --- a/common/nymsphinx/addressing/Cargo.toml +++ b/common/nymsphinx/addressing/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-addressing" -version.workspace = true description = "Nym mixnet addressing" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] nym-crypto = { workspace = true, features = ["asymmetric", "sphinx"] } # all addresses are expressed in terms on their crypto keys diff --git a/common/nymsphinx/anonymous-replies/Cargo.toml b/common/nymsphinx/anonymous-replies/Cargo.toml index fe9f272146..75d651fe60 100644 --- a/common/nymsphinx/anonymous-replies/Cargo.toml +++ b/common/nymsphinx/anonymous-replies/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-anonymous-replies" -version.workspace = true description = "Anonymous sphinx packet replies using singly-use-reply-blocks (SURB)" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] rand = { workspace = true } diff --git a/common/nymsphinx/chunking/Cargo.toml b/common/nymsphinx/chunking/Cargo.toml index 708ecb5c10..625a330a1d 100644 --- a/common/nymsphinx/chunking/Cargo.toml +++ b/common/nymsphinx/chunking/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-chunking" -version.workspace = true description = "Sphinx packet chunking of underlying data packets" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/nymsphinx/cover/Cargo.toml b/common/nymsphinx/cover/Cargo.toml index 69dcf6fe65..cf65805c02 100644 --- a/common/nymsphinx/cover/Cargo.toml +++ b/common/nymsphinx/cover/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-cover" -version.workspace = true description = "Sphinx packets used as cover traffic" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] rand = { workspace = true } diff --git a/common/nymsphinx/forwarding/Cargo.toml b/common/nymsphinx/forwarding/Cargo.toml index e9a299c626..6ba8d1403f 100644 --- a/common/nymsphinx/forwarding/Cargo.toml +++ b/common/nymsphinx/forwarding/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-forwarding" -version.workspace = true description = "Sphinx packet forwarding as Nym mix packets" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] nym-sphinx-addressing = { workspace = true } diff --git a/common/nymsphinx/framing/Cargo.toml b/common/nymsphinx/framing/Cargo.toml index a2f42c7e16..78a4e5954e 100644 --- a/common/nymsphinx/framing/Cargo.toml +++ b/common/nymsphinx/framing/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-framing" -version.workspace = true description = "Sphinx packet framing for the Nym mixnet" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] bytes = { workspace = true } diff --git a/common/nymsphinx/params/Cargo.toml b/common/nymsphinx/params/Cargo.toml index c5fd617d63..88ffe4a225 100644 --- a/common/nymsphinx/params/Cargo.toml +++ b/common/nymsphinx/params/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-params" -version.workspace = true description = "Sphinx packet parameters for the Nym mixnet" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/nymsphinx/routing/Cargo.toml b/common/nymsphinx/routing/Cargo.toml index 209c9baefb..53d424b803 100644 --- a/common/nymsphinx/routing/Cargo.toml +++ b/common/nymsphinx/routing/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-routing" -version.workspace = true description = "Sphinx packet routing as Nym mix packets" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] thiserror = { workspace = true } diff --git a/common/nymsphinx/types/Cargo.toml b/common/nymsphinx/types/Cargo.toml index 776f88a41a..234382035c 100644 --- a/common/nymsphinx/types/Cargo.toml +++ b/common/nymsphinx/types/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-sphinx-types" -version.workspace = true description = "Re-export sphinx packet types" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] sphinx-packet = { workspace = true, optional = true } diff --git a/common/nyxd-scraper-psql/Cargo.toml b/common/nyxd-scraper-psql/Cargo.toml index c99249f0cd..51e62a2092 100644 --- a/common/nyxd-scraper-psql/Cargo.toml +++ b/common/nyxd-scraper-psql/Cargo.toml @@ -2,11 +2,11 @@ name = "nyxd-scraper-psql" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/common/nyxd-scraper-shared/Cargo.toml b/common/nyxd-scraper-shared/Cargo.toml index 299d2a6186..986b39319c 100644 --- a/common/nyxd-scraper-shared/Cargo.toml +++ b/common/nyxd-scraper-shared/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nyxd-scraper-shared" +description = "Common crate for the sqlite and psql Nyxd blockchain scrapers" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Common crate for the sqlite and psql Nyxd blockchain scrapers" +publish = true [dependencies] async-trait.workspace = true diff --git a/common/nyxd-scraper-sqlite/Cargo.toml b/common/nyxd-scraper-sqlite/Cargo.toml index bcf59ce2cf..20bf4bd39b 100644 --- a/common/nyxd-scraper-sqlite/Cargo.toml +++ b/common/nyxd-scraper-sqlite/Cargo.toml @@ -2,11 +2,11 @@ name = "nyxd-scraper-sqlite" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/pemstore/Cargo.toml b/common/pemstore/Cargo.toml index 5534b81dd0..ff2d78250e 100644 --- a/common/pemstore/Cargo.toml +++ b/common/pemstore/Cargo.toml @@ -2,10 +2,15 @@ name = "nym-pemstore" description = "Store private-public keypairs in PEM format" version.workspace = true -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] pem = { workspace = true } diff --git a/common/registration/Cargo.toml b/common/registration/Cargo.toml index c361b21461..75f882a4f5 100644 --- a/common/registration/Cargo.toml +++ b/common/registration/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-registration-common" +description = "Struct definitions for NymNode, GatewayData, and AssignedAddresses" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Struct definitions for NymNode, GatewayData, and AssignedAddresses" +rust-version.workspace = true +readme.workspace = true +publish = true [lints] workspace = true diff --git a/common/serde-helpers/Cargo.toml b/common/serde-helpers/Cargo.toml index 9b219e23cb..609474808d 100644 --- a/common/serde-helpers/Cargo.toml +++ b/common/serde-helpers/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-serde-helpers" +description = "Serde helpers for hex/base64/base58/datetime" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Serde helpers for hex/base64/base58/datetime" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/service-provider-requests-common/Cargo.toml b/common/service-provider-requests-common/Cargo.toml index b289a776b7..c25adafdde 100644 --- a/common/service-provider-requests-common/Cargo.toml +++ b/common/service-provider-requests-common/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-service-provider-requests-common" +description = "Common crate for requests and responses for Nym Service Providers" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Common crate for requests and responses for Nym Service Providers" +publish = true [dependencies] serde = { workspace = true, features = ["derive"] } diff --git a/common/socks5-client-core/Cargo.toml b/common/socks5-client-core/Cargo.toml index f86c6cf686..911e9e23fa 100644 --- a/common/socks5-client-core/Cargo.toml +++ b/common/socks5-client-core/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-socks5-client-core" +description = "Core functionality of the Nym SOCKS client" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Core functionality of the Nym SOCKS client" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/socks5/ordered-buffer/Cargo.toml b/common/socks5/ordered-buffer/Cargo.toml index 572f2c0d59..fc66833eb4 100644 --- a/common/socks5/ordered-buffer/Cargo.toml +++ b/common/socks5/ordered-buffer/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-ordered-buffer" +description = "This crate takes care of reliably and speedily turning bytes into a series of ordered message fragments on one side, and of reliably reassembling the fragments into the original message on the other" version.workspace = true authors = ["Dave Hrycyszyn "] edition = "2021" license.workspace = true -description = "This crate takes care of reliably and speedily turning bytes into a series of ordered message fragments on one side, and of reliably reassembling the fragments into the original message on the other" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/socks5/proxy-helpers/Cargo.toml b/common/socks5/proxy-helpers/Cargo.toml index 9b74fd005d..6d58b118a1 100644 --- a/common/socks5/proxy-helpers/Cargo.toml +++ b/common/socks5/proxy-helpers/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-socks5-proxy-helpers" +description = "Helpers for the Nym SOCKS client" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true -description = "Helpers for the Nym SOCKS client" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/socks5/requests/Cargo.toml b/common/socks5/requests/Cargo.toml index 1197c4beb3..b1aae2ed1a 100644 --- a/common/socks5/requests/Cargo.toml +++ b/common/socks5/requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-socks5-requests" +description = "Request and response definitions for the Nym SOCKS client" version.workspace = true authors = ["Dave Hrycyszyn "] edition = "2021" license.workspace = true -description = "Request and response definitions for the Nym SOCKS client" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/statistics/Cargo.toml b/common/statistics/Cargo.toml index c086bd8374..b92798f180 100644 --- a/common/statistics/Cargo.toml +++ b/common/statistics/Cargo.toml @@ -3,13 +3,17 @@ [package] name = "nym-statistics-common" +description = "This crate contains basic statistics utilities and abstractions to be re-used and applied throughout both the client and gateway implementations" version.workspace = true +authors.workspace = true edition.workspace = true license.workspace = true -description = "This crate contains basic statistics utilities and abstractions to be re-used and applied throughout both the client and gateway implementations" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/store-cipher/Cargo.toml b/common/store-cipher/Cargo.toml index a2066a5247..29792d9ce6 100644 --- a/common/store-cipher/Cargo.toml +++ b/common/store-cipher/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-store-cipher" +description = "Helpers for various ciphers used throughout the Nym network" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Helpers for various ciphers used throughout the Nym network" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/task/Cargo.toml b/common/task/Cargo.toml index 0daef2c763..a6d9e396c7 100644 --- a/common/task/Cargo.toml +++ b/common/task/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-task" -version.workspace = true description = "Task handling" -edition.workspace = true +version.workspace = true authors.workspace = true +edition.workspace = true license.workspace = true repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] cfg-if = { workspace = true } diff --git a/common/test-utils/Cargo.toml b/common/test-utils/Cargo.toml index ead0cff923..8d8cb55116 100644 --- a/common/test-utils/Cargo.toml +++ b/common/test-utils/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-test-utils" +description = "Helpers, traits, and mock definitions for tests" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Helpers, traits, and mock definitions for tests" +publish = true [dependencies] anyhow = { workspace = true } diff --git a/common/ticketbooks-merkle/Cargo.toml b/common/ticketbooks-merkle/Cargo.toml index 037852a91d..feb2354c47 100644 --- a/common/ticketbooks-merkle/Cargo.toml +++ b/common/ticketbooks-merkle/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-ticketbooks-merkle" +description = "Generate and verify merkleproofs of zknym ticketbooks" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Generate and verify merkleproofs of zknym ticketbooks" +publish = true [dependencies] sha2 = { workspace = true } diff --git a/common/topology/Cargo.toml b/common/topology/Cargo.toml index da51f63bbd..32530840bc 100644 --- a/common/topology/Cargo.toml +++ b/common/topology/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-topology" +description = "Nym's topology crate" version.workspace = true -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } homepage = { workspace = true } documentation = { workspace = true } -description = "Nym's topology crate" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/tun/Cargo.toml b/common/tun/Cargo.toml index e5451f0f81..318c53fa6b 100644 --- a/common/tun/Cargo.toml +++ b/common/tun/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-tun" +description = "Nym's tun implementation" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Nym's tun implementation" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/types/Cargo.toml b/common/types/Cargo.toml index 2f6ae032b4..31fdcfc200 100644 --- a/common/types/Cargo.toml +++ b/common/types/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "nym-types" -version.workspace = true description = "Nym common types" +version.workspace = true authors.workspace = true edition = "2021" -rust-version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] base64 = { workspace = true } diff --git a/common/upgrade-mode-check/Cargo.toml b/common/upgrade-mode-check/Cargo.toml index d47d4ba5f9..e3fe21f506 100644 --- a/common/upgrade-mode-check/Cargo.toml +++ b/common/upgrade-mode-check/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-upgrade-mode-check" +description = "Functions and tests for checking Nym's Credential Proxy is being properly upgraded" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Functions and tests for checking Nym's Credential Proxy is being properly upgraded" +publish = true [dependencies] jwt-simple = { workspace = true } diff --git a/common/verloc/Cargo.toml b/common/verloc/Cargo.toml index fa218f9aee..0617192dff 100644 --- a/common/verloc/Cargo.toml +++ b/common/verloc/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "nym-verloc" +description = "Nym's verloc (Verifiable Location) implementation" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true -description = "Nym's verloc (Verifiable Location) implementation" +publish = true [dependencies] bytes = { workspace = true } diff --git a/common/wasm/client-core/Cargo.toml b/common/wasm/client-core/Cargo.toml index f7811e6f84..749272e9a2 100644 --- a/common/wasm/client-core/Cargo.toml +++ b/common/wasm/client-core/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-wasm-client-core" -authors = ["Jedrzej Stuczynski "] +description = "Crate containing core WASM client functionality and configs" version.workspace = true +authors = ["Jedrzej Stuczynski "] edition = "2021" license = "Apache-2.0" repository = "https://github.com/nymtech/nym" -description = "Crate containing core WASM client functionality and configs" +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/wasm/storage/Cargo.toml b/common/wasm/storage/Cargo.toml index 7c07592da2..2e4f4430c4 100644 --- a/common/wasm/storage/Cargo.toml +++ b/common/wasm/storage/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wasm-storage" +description = "indexeddb-backed in-browser storage with optional encryption implentation and helpers" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true -description = "indexeddb-backed in-browser storage with optional encryption implentation and helpers" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/wasm/utils/Cargo.toml b/common/wasm/utils/Cargo.toml index 49af79aa41..73984f73e6 100644 --- a/common/wasm/utils/Cargo.toml +++ b/common/wasm/utils/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wasm-utils" +description = "Helpers and macros for the Nym WASM client" version.workspace = true authors = ["Jedrzej Stuczynski "] edition = "2021" license.workspace = true -description = "Helpers and macros for the Nym WASM client" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/wireguard-private-metadata/client/Cargo.toml b/common/wireguard-private-metadata/client/Cargo.toml index d039810387..dc5ee67df4 100644 --- a/common/wireguard-private-metadata/client/Cargo.toml +++ b/common/wireguard-private-metadata/client/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard-private-metadata-client" +description = "nym-wireguard client implementation" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "nym-wireguard client implementation" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] async-trait = { workspace = true } diff --git a/common/wireguard-private-metadata/server/Cargo.toml b/common/wireguard-private-metadata/server/Cargo.toml index b16725b149..5e551a986c 100644 --- a/common/wireguard-private-metadata/server/Cargo.toml +++ b/common/wireguard-private-metadata/server/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard-private-metadata-server" +description = "nym-wireguard server implementation" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "nym-wireguard server implementation" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] anyhow = { workspace = true } diff --git a/common/wireguard-private-metadata/shared/Cargo.toml b/common/wireguard-private-metadata/shared/Cargo.toml index 4c4ffacca8..cc43487b3a 100644 --- a/common/wireguard-private-metadata/shared/Cargo.toml +++ b/common/wireguard-private-metadata/shared/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard-private-metadata-shared" +description = "Common crate for nym-wireguard server, client, and tests" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Common crate for nym-wireguard server, client, and tests" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] axum = { workspace = true } diff --git a/common/wireguard-private-metadata/tests/Cargo.toml b/common/wireguard-private-metadata/tests/Cargo.toml index de8a2ab501..552afc0468 100644 --- a/common/wireguard-private-metadata/tests/Cargo.toml +++ b/common/wireguard-private-metadata/tests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard-private-metadata-tests" +description = "Tests for nym-wireguard implementation" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Tests for nym-wireguard implementation" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] async-trait = { workspace = true } diff --git a/common/wireguard-types/Cargo.toml b/common/wireguard-types/Cargo.toml index 8d271feb0e..30df325d31 100644 --- a/common/wireguard-types/Cargo.toml +++ b/common/wireguard-types/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard-types" +description = "Wireguard public key and config definitions" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Wireguard public key and config definitions" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/wireguard/Cargo.toml b/common/wireguard/Cargo.toml index f6b3c0e6fb..70b95559ff 100644 --- a/common/wireguard/Cargo.toml +++ b/common/wireguard/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-wireguard" +description = "Interface and peer handling functionality for Wireguard protocol" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Interface and peer handling functionality for Wireguard protocol" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/zulip-client/Cargo.toml b/common/zulip-client/Cargo.toml index 8661cbe247..bef2cc57fc 100644 --- a/common/zulip-client/Cargo.toml +++ b/common/zulip-client/Cargo.toml @@ -2,11 +2,11 @@ name = "zulip-client" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/contracts/coconut-dkg/Cargo.toml b/contracts/coconut-dkg/Cargo.toml index 66cb2acbe0..bc410dc4ef 100644 --- a/contracts/coconut-dkg/Cargo.toml +++ b/contracts/coconut-dkg/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "nym-coconut-dkg" version = "0.1.0" -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/contracts/ecash/Cargo.toml b/contracts/ecash/Cargo.toml index 6391ebd269..81d323f29c 100644 --- a/contracts/ecash/Cargo.toml +++ b/contracts/ecash/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "nym-ecash" version = "0.1.0" -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +publish = false [[bin]] name = "schema" diff --git a/contracts/mixnet-vesting-integration-tests/Cargo.toml b/contracts/mixnet-vesting-integration-tests/Cargo.toml index a1f6aa3104..361885e353 100644 --- a/contracts/mixnet-vesting-integration-tests/Cargo.toml +++ b/contracts/mixnet-vesting-integration-tests/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "mixnet-vesting-integration-tests" version = "0.1.0" -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } publish = false diff --git a/contracts/mixnet/Cargo.toml b/contracts/mixnet/Cargo.toml index e5c7b47719..20222063f6 100644 --- a/contracts/mixnet/Cargo.toml +++ b/contracts/mixnet/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nym-mixnet-contract" -version = "1.5.1" description = "Nym mixnet contract" -edition = { workspace = true } +version = "1.5.1" authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } readme = "README.md" - +publish = false exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. "contract.wasm", diff --git a/contracts/multisig/cw3-flex-multisig/Cargo.toml b/contracts/multisig/cw3-flex-multisig/Cargo.toml index e016a5f4c8..649b946357 100644 --- a/contracts/multisig/cw3-flex-multisig/Cargo.toml +++ b/contracts/multisig/cw3-flex-multisig/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "cw3-flex-multisig" +description = "Implementing cw3 with multiple voting patterns and dynamic groups" version = "2.0.0" authors = ["Ethan Frey "] edition = "2021" -description = "Implementing cw3 with multiple voting patterns and dynamic groups" license = "Apache-2.0" repository = "https://github.com/CosmWasm/cw-plus" homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" +publish = false [[bin]] name = "schema" diff --git a/contracts/multisig/cw4-group/Cargo.toml b/contracts/multisig/cw4-group/Cargo.toml index b8334b756e..e6c2940d73 100644 --- a/contracts/multisig/cw4-group/Cargo.toml +++ b/contracts/multisig/cw4-group/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "cw4-group" +description = "Simple cw4 implementation of group membership controlled by admin " version = "2.0.0" authors = ["Ethan Frey "] edition = "2021" -description = "Simple cw4 implementation of group membership controlled by admin " license = "Apache-2.0" repository = "https://github.com/CosmWasm/cw-plus" homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" - +publish = false exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. "artifacts/*", diff --git a/contracts/nym-pool/Cargo.toml b/contracts/nym-pool/Cargo.toml index f3fc80740e..d4d68fde37 100644 --- a/contracts/nym-pool/Cargo.toml +++ b/contracts/nym-pool/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "nym-pool-contract" version = "0.1.0" -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +publish = false [[bin]] name = "schema" diff --git a/contracts/performance/Cargo.toml b/contracts/performance/Cargo.toml index 72086ad419..78069a02de 100644 --- a/contracts/performance/Cargo.toml +++ b/contracts/performance/Cargo.toml @@ -2,11 +2,12 @@ name = "nym-performance-contract" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true +publish = false [[bin]] name = "schema" diff --git a/contracts/vesting/Cargo.toml b/contracts/vesting/Cargo.toml index bc227c5806..467e35c7d7 100644 --- a/contracts/vesting/Cargo.toml +++ b/contracts/vesting/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nym-vesting-contract" -version = "1.4.1" description = "Nym vesting contract" -edition = { workspace = true } +version = "1.4.1" authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } readme = "README.md" - +publish = false exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. "contract.wasm", diff --git a/cpu-cycles/Cargo.toml b/cpu-cycles/Cargo.toml index 4c234b8d30..fe139b5d47 100644 --- a/cpu-cycles/Cargo.toml +++ b/cpu-cycles/Cargo.toml @@ -2,9 +2,10 @@ name = "cpu-cycles" version = "0.1.0" edition = "2021" +license = "LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT" +publish = false build = "build.rs" links = "cpucycles" -license = "LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT" [dependencies] libc = "0.2.140" diff --git a/documentation/autodoc/Cargo.toml b/documentation/autodoc/Cargo.toml index 1905285f99..6586cdd256 100644 --- a/documentation/autodoc/Cargo.toml +++ b/documentation/autodoc/Cargo.toml @@ -2,11 +2,11 @@ name = "autodoc" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false [dependencies] diff --git a/documentation/docs/pages/operators/changelog.mdx b/documentation/docs/pages/operators/changelog.mdx index 24a04cb6d1..a5124633e1 100644 --- a/documentation/docs/pages/operators/changelog.mdx +++ b/documentation/docs/pages/operators/changelog.mdx @@ -57,6 +57,34 @@ This page displays a full list of all the changes during our release cycle from +## `v2026.8-urda` + +- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.8-urda) +- [`nym-node`](nodes/nym-node.mdx) version `1.30.0` + +```sh +nym-node +Binary Name: nym-node +Build Timestamp: 2026-04-21T10:11:28.164080002Z +Build Version: 1.30.0 +Commit SHA: 0c83ae2408ea9efcc1abae613711c6e4e16148ad +Commit Date: 2026-04-21T12:06:23.000000000+02:00 +Commit Branch: HEAD +rustc Version: 1.91.1 +rustc Channel: stable +cargo Profile: release +``` + +### Features + +- [Include all gateways in the returned list](https://github.com/nymtech/nym/pull/6649): Ensures gateway APIs return the full gateway set instead of filtered results, improving consistency across services. +- [Max/sdk stream wrapper](https://github.com/nymtech/nym/pull/6320): Introduces a Rust SDK stream abstraction enabling IPR-based mixnet communication and client-side streaming support. +- [Max/sdk docrs](https://github.com/nymtech/nym/pull/6566): Updates SDK documentation to reflect the new stream-based architecture and IPR communication model. + +### Refactors & Maintenance + +- [Optimize GW probe in NS agent](https://github.com/nymtech/nym/pull/6636): Refactors gateway probe integration from subprocess execution to library usage, removing CLI dependency and improving typed communication between agent and probe. + ## `v2026.7-tola` - [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.7-tola) diff --git a/documentation/docs/pages/operators/nodes/nym-node/setup.mdx b/documentation/docs/pages/operators/nodes/nym-node/setup.mdx index 6873349219..9b33e1c891 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/setup.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/setup.mdx @@ -20,10 +20,10 @@ This documentation page provides a guide on how to set up and run a [NYM NODE](. ```sh Binary Name: nym-node -Build Timestamp: 2026-04-08T10:31:49.141185557Z -Build Version: 1.29.0 -Commit SHA: 97068b2aace6626e3dff6864a26e7b1ff35f5725 -Commit Date: 2026-04-07T15:51:44.000000000+02:00 +Build Timestamp: 2026-04-21T10:11:28.164080002Z +Build Version: 1.30.0 +Commit SHA: 0c83ae2408ea9efcc1abae613711c6e4e16148ad +Commit Date: 2026-04-21T12:06:23.000000000+02:00 Commit Branch: HEAD rustc Version: 1.91.1 rustc Channel: stable diff --git a/examples/cli/commands/verify-signature/Cargo.toml b/examples/cli/commands/verify-signature/Cargo.toml index 5ad0673115..bd4c0553a0 100644 --- a/examples/cli/commands/verify-signature/Cargo.toml +++ b/examples/cli/commands/verify-signature/Cargo.toml @@ -2,6 +2,7 @@ name = "example-verify-signature" version = "0.1.0" edition = "2021" +publish = false [workspace] diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 51e3c98c6c..d5c76b9b54 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -3,14 +3,14 @@ [package] name = "nym-gateway" -license = "GPL-3.0" +description = "Implementation of the Nym Mixnet Gateway" version = "1.1.36" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", ] -description = "Implementation of the Nym Mixnet Gateway" edition = "2021" +license = "GPL-3.0" rust-version = "1.85" publish = false diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index aaeced8b6d..9f7fe77d06 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -2,11 +2,11 @@ name = "integration-tests" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/lefthook.yml b/lefthook.yml index 0687e78972..27c29ce3a2 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -51,3 +51,6 @@ pre-commit: glob: "*.rs" run: cargo fmt stage_fixed: true + cargo-toml-order: + glob: "**/Cargo.toml" + run: python3 tools/internal/check_cargo_toml_field_order.py {staged_files} diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index a493e14604..93f2e44db4 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -3,9 +3,10 @@ [package] name = "nym-api" -version = "1.1.78" +version = "1.1.79" authors.workspace = true edition = "2021" +license = "GPL-3.0" rust-version.workspace = true publish = false diff --git a/nym-api/nym-api-requests/Cargo.toml b/nym-api/nym-api-requests/Cargo.toml index 176eb0920f..28d18fc632 100644 --- a/nym-api/nym-api-requests/Cargo.toml +++ b/nym-api/nym-api-requests/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-api-requests" +description = "Nym API request types and functions" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Nym API request types and functions" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-authenticator-client/Cargo.toml b/nym-authenticator-client/Cargo.toml index b1793b6cbf..b502237316 100644 --- a/nym-authenticator-client/Cargo.toml +++ b/nym-authenticator-client/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-authenticator-client" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false [lints] diff --git a/nym-browser-extension/storage/Cargo.toml b/nym-browser-extension/storage/Cargo.toml index e25c1b107f..5ee0d1b961 100644 --- a/nym-browser-extension/storage/Cargo.toml +++ b/nym-browser-extension/storage/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "extension-storage" +description = "WebAssembly-based secure storage for browser extension mnemonics" version = "1.4.1" +authors = ["Nym Technologies SA "] edition = "2024" license = "Apache-2.0" repository = "https://github.com/nymtech/nym" -description = "WebAssembly-based secure storage for browser extension mnemonics" -authors = ["Nym Technologies SA "] publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-credential-proxy/nym-credential-proxy-requests/Cargo.toml b/nym-credential-proxy/nym-credential-proxy-requests/Cargo.toml index d81b35e70b..2adbd39d9a 100644 --- a/nym-credential-proxy/nym-credential-proxy-requests/Cargo.toml +++ b/nym-credential-proxy/nym-credential-proxy-requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-credential-proxy-requests" +description = "Request and response definitions for interacting with the Nym Credential Proxy" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Request and response definitions for interacting with the Nym Credential Proxy" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-credential-proxy/nym-credential-proxy/Cargo.toml b/nym-credential-proxy/nym-credential-proxy/Cargo.toml index 9a680358a7..4354534ee3 100644 --- a/nym-credential-proxy/nym-credential-proxy/Cargo.toml +++ b/nym-credential-proxy/nym-credential-proxy/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-credential-proxy" version = "0.3.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true publish = false diff --git a/nym-data-observatory/Cargo.toml b/nym-data-observatory/Cargo.toml index 4a6a09685b..906f8dd651 100644 --- a/nym-data-observatory/Cargo.toml +++ b/nym-data-observatory/Cargo.toml @@ -5,11 +5,11 @@ name = "nym-data-observatory" version = "1.0.1" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true publish = false diff --git a/nym-gateway-probe/Cargo.toml b/nym-gateway-probe/Cargo.toml index 684f54a288..7cb0bf8575 100644 --- a/nym-gateway-probe/Cargo.toml +++ b/nym-gateway-probe/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-gateway-probe" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false [lints] diff --git a/nym-gateway-probe/src/common/bandwidth_helpers.rs b/nym-gateway-probe/src/common/bandwidth_helpers.rs index 10962a1eb6..5f968b8d92 100644 --- a/nym-gateway-probe/src/common/bandwidth_helpers.rs +++ b/nym-gateway-probe/src/common/bandwidth_helpers.rs @@ -86,10 +86,21 @@ pub(crate) async fn import_bandwidth( // 2. import actual tickets for ticket in attached_ticket_materials.attached_tickets { let ticketbook = ticket.ticketbook.try_unpack()?; + let total = ticketbook.params_total_tickets(); + if ticket.usable_index as u64 >= total { + error!( + "⚠️ received usable_index {} >= params_total_tickets {} for {}. \ + This ticket is unusable: spending will fail with SpendExceedsAllowance.", + ticket.usable_index, + total, + ticketbook.ticketbook_type() + ); + } info!( - "importing partial ticketbook {}. index to use: {}", + "importing partial ticketbook {}. index to use: {}, params_total_tickets: {}", ticketbook.ticketbook_type(), - ticket.usable_index + ticket.usable_index, + total, ); bandwidth_importer .import_partial_ticketbook(&ticketbook, ticket.usable_index, ticket.usable_index) diff --git a/nym-gateway-probe/src/common/helpers.rs b/nym-gateway-probe/src/common/helpers.rs index 5dc330e9cc..54822c3987 100644 --- a/nym-gateway-probe/src/common/helpers.rs +++ b/nym-gateway-probe/src/common/helpers.rs @@ -1,9 +1,10 @@ // Copyright 2026 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use nym_ip_packet_requests::v8::response::{ +use nym_ip_packet_client::current::response::{ ControlResponse, DataResponse, InfoLevel, IpPacketResponse, IpPacketResponseData, }; +use nym_ip_packet_client::lp_stream; use nym_sdk::{ DebugConfig, NymApiTopologyProvider, NymApiTopologyProviderConfig, NymNetworkDetails, TopologyProvider, mixnet::ReconstructedMessage, @@ -32,7 +33,10 @@ pub fn mixnet_debug_config( } pub fn unpack_data_response(reconstructed_message: &ReconstructedMessage) -> Option { - match IpPacketResponse::from_reconstructed_message(reconstructed_message) { + let payload = + lp_stream::maybe_unwrap_lp_stream_payload_from_reconstructed(reconstructed_message); + + match IpPacketResponse::from_bytes(payload) { Ok(response) => match response.data { IpPacketResponseData::Data(data_response) => Some(data_response), IpPacketResponseData::Control(control) => match *control { diff --git a/nym-gateway-probe/src/common/icmp.rs b/nym-gateway-probe/src/common/icmp.rs index ec757623f1..2d96a27da5 100644 --- a/nym-gateway-probe/src/common/icmp.rs +++ b/nym-gateway-probe/src/common/icmp.rs @@ -9,7 +9,7 @@ use nym_connection_monitor::{ wrap_icmp_in_ipv6, }, }; -use nym_ip_packet_requests::{IpPair, codec::MultiIpPacketCodec, v8::request::IpPacketRequest}; +use nym_ip_packet_requests::{IpPair, codec::MultiIpPacketCodec}; use nym_sdk::mixnet::{ InputMessage, MixnetClient, MixnetMessageSender, Recipient, TransmissionLane, }; @@ -25,6 +25,7 @@ pub async fn send_ping_v4( sequence_number: u16, destination: Ipv4Addr, exit_router_address: Recipient, + stream_id: u64, ) -> anyhow::Result<()> { let icmp_identifier = icmp_identifier(); let icmp_echo_request = create_icmpv4_echo_request(sequence_number, icmp_identifier)?; @@ -35,7 +36,12 @@ pub async fn send_ping_v4( MultiIpPacketCodec::bundle_one_packet(ipv4_packet.packet().to_vec().into()); // Wrap into a mixnet input message addressed to the IPR - let mixnet_message = create_input_message(exit_router_address, bundled_packet)?; + let mixnet_message = create_input_message( + exit_router_address, + bundled_packet, + stream_id, + sequence_number, + )?; mixnet_client.send(mixnet_message).await?; Ok(()) @@ -47,6 +53,7 @@ pub async fn send_ping_v6( sequence_number: u16, destination: Ipv6Addr, exit_router_address: Recipient, + stream_id: u64, ) -> anyhow::Result<()> { let icmp_identifier = icmp_identifier(); let icmp_echo_request = create_icmpv6_echo_request( @@ -62,7 +69,12 @@ pub async fn send_ping_v6( MultiIpPacketCodec::bundle_one_packet(ipv6_packet.packet().to_vec().into()); // Wrap into a mixnet input message addressed to the IPR - let mixnet_message = create_input_message(exit_router_address, bundled_packet)?; + let mixnet_message = create_input_message( + exit_router_address, + bundled_packet, + stream_id, + sequence_number, + )?; // Send across the mixnet mixnet_client.send(mixnet_message).await?; @@ -72,15 +84,22 @@ pub async fn send_ping_v6( fn create_input_message( recipient: impl Into, bundled_packets: Bytes, + stream_id: u64, + sequence_number: u16, ) -> anyhow::Result { - let packet = IpPacketRequest::new_data_request(bundled_packets).to_bytes()?; + let packet = nym_ip_packet_client::current::new_data_request(bundled_packets).to_bytes()?; + let framed_packet = nym_ip_packet_client::lp_stream::encode_stream_frame( + stream_id, + sequence_number as u32, + packet, + ); let lane = TransmissionLane::General; let packet_type = None; let surbs = 0; Ok(InputMessage::new_anonymous( recipient.into(), - packet, + framed_packet, surbs, lane, packet_type, diff --git a/nym-gateway-probe/src/common/probe_tests.rs b/nym-gateway-probe/src/common/probe_tests.rs index d37a1042d2..7f6bee2d01 100644 --- a/nym-gateway-probe/src/common/probe_tests.rs +++ b/nym-gateway-probe/src/common/probe_tests.rs @@ -256,8 +256,8 @@ pub async fn do_ping( let (maybe_ip_pair, mut mixnet_client) = connect_exit(mixnet_client, exit_router_address).await; match maybe_ip_pair { - Some(ip_pair) => ( - do_ping_exit(&mut mixnet_client, ip_pair, exit_router_address).await, + Some((ip_pair, stream_id)) => ( + do_ping_exit(&mut mixnet_client, ip_pair, stream_id, exit_router_address).await, mixnet_client, ), None => (Ok(Some(Exit::fail_to_connect())), mixnet_client), @@ -304,7 +304,7 @@ async fn do_ping_entry( async fn connect_exit( mixnet_client: MixnetClient, exit_router_address: Recipient, -) -> (Option, MixnetClient) { +) -> (Option<(IpPair, u64)>, MixnetClient) { // Step 2: connect to the exit gateway info!( "Connecting to exit gateway: {}", @@ -315,12 +315,19 @@ async fn connect_exit( let mut ipr_client = IprClientConnect::new(mixnet_client, cancel_token); let maybe_ip_pair = ipr_client.connect(exit_router_address).await; + let stream_id = ipr_client.stream_id(); let mixnet_client = ipr_client.into_mixnet_client(); if let Ok(our_ips) = maybe_ip_pair { info!("Successfully connected to exit gateway"); info!("Using mixnet VPN IP addresses: {our_ips}"); - (Some(our_ips), mixnet_client) + let Some(stream_id) = stream_id else { + tracing::warn!( + "No active IPR stream id set after connect; cannot run IPR data-plane tests" + ); + return (None, mixnet_client); + }; + (Some((our_ips, stream_id)), mixnet_client) } else { (None, mixnet_client) } @@ -329,10 +336,11 @@ async fn connect_exit( pub async fn do_ping_exit( mixnet_client: &mut MixnetClient, our_ips: IpPair, + stream_id: u64, exit_router_address: Recipient, ) -> anyhow::Result> { // Step 3: perform ICMP connectivity checks for the exit gateway - send_icmp_pings(mixnet_client, our_ips, exit_router_address).await?; + send_icmp_pings(mixnet_client, our_ips, exit_router_address, stream_id).await?; listen_for_icmp_ping_replies(mixnet_client, our_ips).await } @@ -340,6 +348,7 @@ async fn send_icmp_pings( mixnet_client: &MixnetClient, our_ips: IpPair, exit_router_address: Recipient, + stream_id: u64, ) -> anyhow::Result<()> { // ipv4 addresses for testing let ipr_tun_ip_v4 = NYM_TUN_DEVICE_ADDRESS_V4; @@ -361,6 +370,7 @@ async fn send_icmp_pings( ii, ipr_tun_ip_v4, exit_router_address, + stream_id, ) .await?; icmp::send_ping_v4( @@ -369,6 +379,7 @@ async fn send_icmp_pings( ii, external_ip_v4, exit_router_address, + stream_id, ) .await?; } @@ -381,6 +392,7 @@ async fn send_icmp_pings( ii, ipr_tun_ip_v6, exit_router_address, + stream_id, ) .await?; icmp::send_ping_v6( @@ -389,6 +401,7 @@ async fn send_icmp_pings( ii, external_ip_v6, exit_router_address, + stream_id, ) .await?; } diff --git a/nym-ip-packet-client/Cargo.toml b/nym-ip-packet-client/Cargo.toml index e631a759ca..4117d80350 100644 --- a/nym-ip-packet-client/Cargo.toml +++ b/nym-ip-packet-client/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-ip-packet-client" +description = "Nym's implementation of a client that sends and receives IP packets" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Nym's implementation of a client that sends and receives IP packets" +rust-version.workspace = true +readme.workspace = true +publish = true [lints] workspace = true @@ -23,3 +26,4 @@ tracing.workspace = true nym-sdk = { workspace = true } nym-ip-packet-requests = { workspace = true } +nym-lp = { workspace = true } diff --git a/nym-ip-packet-client/src/connect.rs b/nym-ip-packet-client/src/connect.rs index 0448c0cf40..b49d87daa5 100644 --- a/nym-ip-packet-client/src/connect.rs +++ b/nym-ip-packet-client/src/connect.rs @@ -14,7 +14,7 @@ use tracing::{debug, error}; use nym_ip_packet_requests::response_helpers::{self, IprResponseError}; use crate::{ - current::{request::IpPacketRequest, response::IpPacketResponse}, + current::{self, response::IpPacketResponse}, error::{Error, Result}, helpers::check_ipr_message_version, }; @@ -24,8 +24,12 @@ const IPR_CONNECT_TIMEOUT: Duration = Duration::from_secs(10); #[derive(Clone, Debug, PartialEq, Eq)] enum ConnectionState { Disconnected, - Connecting, - Connected, + Connecting { + stream_id: u64, + }, + Connected { + stream_id: u64, + }, #[allow(unused)] Disconnecting, } @@ -51,17 +55,27 @@ impl IprClientConnect { self.mixnet_client } + pub fn stream_id(&self) -> Option { + match self.connected { + ConnectionState::Connecting { stream_id } + | ConnectionState::Connected { stream_id } => Some(stream_id), + ConnectionState::Disconnected | ConnectionState::Disconnecting => None, + } + } + pub async fn connect(&mut self, ip_packet_router_address: Recipient) -> Result { if self.connected != ConnectionState::Disconnected { return Err(Error::AlreadyConnected); } tracing::info!("Connecting to exit gateway"); - self.connected = ConnectionState::Connecting; match self.connect_inner(ip_packet_router_address).await { Ok(ips) => { debug!("Successfully connected to the ip-packet-router"); - self.connected = ConnectionState::Connected; + let Some(stream_id) = self.stream_id() else { + return Err(Error::UnexpectedConnectResponse); + }; + self.connected = ConnectionState::Connected { stream_id }; Ok(ips) } Err(err) => { @@ -74,21 +88,37 @@ impl IprClientConnect { async fn connect_inner(&mut self, ip_packet_router_address: Recipient) -> Result { let request_id = self.send_connect_request(ip_packet_router_address).await?; + self.connected = ConnectionState::Connecting { + stream_id: request_id, + }; debug!("Waiting for reply..."); self.listen_for_connect_response(request_id).await } - async fn send_connect_request(&self, ip_packet_router_address: Recipient) -> Result { - let (request, request_id) = IpPacketRequest::new_connect_request(None); + async fn send_connect_request(&mut self, ip_packet_router_address: Recipient) -> Result { + let (request, request_id) = current::new_connect_request(None); + tracing::info!( + request_id = request_id, + protocol_version = request.protocol.version, + current_version = crate::current::VERSION, + "Sending IPR connect request" + ); + if let Ok(bytes) = request.to_bytes() { + let prefix = bytes.get(0..2).unwrap_or(&bytes); + let prefix_hex = format!("{:02x?}", prefix); + tracing::info!(request_id = request_id, prefix = %prefix_hex, "IPR connect bytes prefix"); + } // We use 20 surbs for the connect request because typically the IPR is configured to have // a min threshold of 10 surbs that it reserves for itself to request additional surbs. let surbs = 20; + let request_bytes = request.to_bytes()?; + let framed_bytes = maybe_wrap_stream_frame(request_id, 0, request_bytes); self.mixnet_client .send(create_input_message( ip_packet_router_address, - request, + framed_bytes, surbs, )?) .await @@ -129,13 +159,19 @@ impl IprClientConnect { for msg in msgs { // Confirm that the version is correct if let Err(err) = check_ipr_message_version(&msg) { - tracing::info!("Mixnet message version mismatch: {err}"); + let raw: &[u8] = msg.message.as_ref(); + tracing::warn!( + first_byte = raw.first().copied(), + expected = crate::current::VERSION, + len = raw.len(), + "Mixnet message version mismatch: {err}" + ); continue; } // Then we deserialize the message tracing::debug!("IprClient: got message while waiting for connect response"); - let Ok(response) = IpPacketResponse::from_reconstructed_message(&msg) else { + let Ok(response) = ipr_response_from_reconstructed_message(&msg) else { // This is ok, it's likely just one of our self-pings tracing::debug!("Failed to deserialize mixnet message"); continue; @@ -160,14 +196,27 @@ impl IprClientConnect { } } -fn create_input_message( - recipient: Recipient, - request: IpPacketRequest, - surbs: u32, -) -> Result { +fn maybe_wrap_stream_frame(stream_id: u64, sequence_num: u32, payload: Vec) -> Vec { + if !crate::lp_stream::current_requires_sphinx_stream_transport() { + return payload; + } + + crate::lp_stream::encode_stream_frame(stream_id, sequence_num, payload) +} + +fn ipr_response_from_reconstructed_message( + msg: &nym_sdk::mixnet::ReconstructedMessage, +) -> std::result::Result { + let warn_on_unexpected = crate::lp_stream::current_requires_sphinx_stream_transport(); + let payload = + crate::lp_stream::maybe_unwrap_lp_stream_payload(&msg.message, warn_on_unexpected); + IpPacketResponse::from_bytes(payload) +} + +fn create_input_message(recipient: Recipient, bytes: Vec, surbs: u32) -> Result { Ok(InputMessage::new_anonymous( recipient, - request.to_bytes()?, + bytes, surbs, TransmissionLane::General, None, diff --git a/nym-ip-packet-client/src/helpers.rs b/nym-ip-packet-client/src/helpers.rs index 1b31870ff8..cfa0957aec 100644 --- a/nym-ip-packet-client/src/helpers.rs +++ b/nym-ip-packet-client/src/helpers.rs @@ -7,18 +7,16 @@ use nym_sdk::mixnet::ReconstructedMessage; use crate::{current::VERSION as CURRENT_VERSION, error::Result}; pub(crate) fn check_ipr_message_version(message: &ReconstructedMessage) -> Result<()> { - nym_ip_packet_requests::response_helpers::check_ipr_message_version( - &message.message, - CURRENT_VERSION, - ) - .map_err(|e| match e { - IprResponseError::NoVersionByte => crate::Error::NoVersionInMessage, - IprResponseError::VersionMismatch { expected, received } if received < expected => { - crate::Error::ReceivedResponseWithOldVersion { expected, received } - } - IprResponseError::VersionMismatch { expected, received } => { - crate::Error::ReceivedResponseWithNewVersion { expected, received } - } - _ => crate::Error::NoVersionInMessage, - }) + let payload = crate::lp_stream::maybe_unwrap_lp_stream_payload_from_reconstructed(message); + nym_ip_packet_requests::response_helpers::check_ipr_message_version(payload, CURRENT_VERSION) + .map_err(|e| match e { + IprResponseError::NoVersionByte => crate::Error::NoVersionInMessage, + IprResponseError::VersionMismatch { expected, received } if received < expected => { + crate::Error::ReceivedResponseWithOldVersion { expected, received } + } + IprResponseError::VersionMismatch { expected, received } => { + crate::Error::ReceivedResponseWithNewVersion { expected, received } + } + _ => crate::Error::NoVersionInMessage, + }) } diff --git a/nym-ip-packet-client/src/lib.rs b/nym-ip-packet-client/src/lib.rs index 0ab5c2eb24..40478fc650 100644 --- a/nym-ip-packet-client/src/lib.rs +++ b/nym-ip-packet-client/src/lib.rs @@ -5,6 +5,7 @@ mod connect; mod error; mod helpers; mod listener; +pub mod lp_stream; pub use connect::IprClientConnect; pub use error::Error; diff --git a/nym-ip-packet-client/src/lp_stream.rs b/nym-ip-packet-client/src/lp_stream.rs new file mode 100644 index 0000000000..736d55f378 --- /dev/null +++ b/nym-ip-packet-client/src/lp_stream.rs @@ -0,0 +1,100 @@ +use bytes::BytesMut; +use nym_ip_packet_requests::SPHINX_STREAM_VERSION_THRESHOLD; +use nym_lp::packet::frame::{ + LpFrame, LpFrameHeader, LpFrameKind, SphinxStreamFrameAttributes, SphinxStreamMsgType, +}; +use nym_sdk::mixnet::ReconstructedMessage; +use tracing::warn; + +/// Whether the "current" IPR client is operating at a version where the node expects +/// non-stream mixnet IPR messages to be LP Stream framed (see `SPHINX_STREAM_VERSION_THRESHOLD`). +pub(crate) fn current_requires_sphinx_stream_transport() -> bool { + crate::current::VERSION >= SPHINX_STREAM_VERSION_THRESHOLD +} + +pub fn maybe_unwrap_lp_stream_payload(data: &[u8], warn_on_unexpected: bool) -> &[u8] { + if data.len() < LpFrameHeader::SIZE { + if warn_on_unexpected { + warn!( + len = data.len(), + header_size = LpFrameHeader::SIZE, + "expected LP SphinxStream frame for IPR payload, but message is shorter than LP header; treating as raw payload" + ); + } + return data; + } + + let Ok(header) = LpFrameHeader::parse(data) else { + if warn_on_unexpected { + warn!( + "expected LP SphinxStream frame for IPR payload, but failed to parse LP header; treating as raw payload" + ); + } + return data; + }; + + if header.kind == LpFrameKind::SphinxStream { + &data[LpFrameHeader::SIZE..] + } else { + if warn_on_unexpected { + warn!( + kind = ?header.kind, + "expected LP SphinxStream frame for IPR payload, but got different LP frame kind; treating as raw payload" + ); + } + data + } +} + +pub fn maybe_unwrap_lp_stream_payload_from_reconstructed(message: &ReconstructedMessage) -> &[u8] { + maybe_unwrap_lp_stream_payload(&message.message, false) +} + +pub fn encode_stream_frame(stream_id: u64, sequence_num: u32, payload: Vec) -> Vec { + let attrs = SphinxStreamFrameAttributes { + stream_id, + msg_type: SphinxStreamMsgType::Data, + sequence_num, + }; + let frame = LpFrame::new_stream(attrs, payload); + let mut buf = BytesMut::with_capacity(LpFrameHeader::SIZE + frame.content.len()); + frame.encode(&mut buf); + buf.to_vec() +} + +#[cfg(test)] +mod tests { + use super::*; + use nym_lp::packet::frame::SphinxStreamFrameAttributes; + + #[test] + fn stream_frame_roundtrip_unwraps_payload() { + let stream_id = 0x0123_4567_89ab_cdef; + let seq = 42u32; + let payload = b"hello-ipr".to_vec(); + + let framed = encode_stream_frame(stream_id, seq, payload.clone()); + + let header = LpFrameHeader::parse(&framed).expect("valid lp header"); + assert_eq!(header.kind, LpFrameKind::SphinxStream); + + let attrs = + SphinxStreamFrameAttributes::parse(&header.frame_attributes).expect("valid attrs"); + assert_eq!(attrs.stream_id, stream_id); + assert_eq!(attrs.sequence_num, seq); + assert_eq!(attrs.msg_type, SphinxStreamMsgType::Data); + + let unwrapped = maybe_unwrap_lp_stream_payload(&framed, false); + assert_eq!(unwrapped, payload.as_slice()); + } + + #[test] + fn unwrap_noops_on_non_stream_or_malformed_data() { + let raw = b"\x09\x00\x01\x02\x03"; + assert_eq!(maybe_unwrap_lp_stream_payload(raw, false), raw); + + // malformed header: not enough bytes for LP header + let short = b"\x00\x01"; + assert_eq!(maybe_unwrap_lp_stream_payload(short, false), short); + } +} diff --git a/nym-network-monitor/Cargo.toml b/nym-network-monitor/Cargo.toml index 5f68dec06e..eba4bd06d9 100644 --- a/nym-network-monitor/Cargo.toml +++ b/nym-network-monitor/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-network-monitor" version = "1.0.2" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-node-status-api/nym-node-status-agent/Cargo.toml b/nym-node-status-api/nym-node-status-agent/Cargo.toml index 653bda4b95..6171d7c927 100644 --- a/nym-node-status-api/nym-node-status-agent/Cargo.toml +++ b/nym-node-status-api/nym-node-status-agent/Cargo.toml @@ -5,11 +5,11 @@ name = "nym-node-status-agent" version = "2.0.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/nym-node-status-api/nym-node-status-api/Cargo.toml b/nym-node-status-api/nym-node-status-api/Cargo.toml index 2f534a1f7c..729404d8b6 100644 --- a/nym-node-status-api/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/nym-node-status-api/Cargo.toml @@ -3,13 +3,13 @@ [package] name = "nym-node-status-api" -version = "4.5.0" +version = "4.6.1" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true publish = false diff --git a/nym-node-status-api/nym-node-status-api/src/http/state.rs b/nym-node-status-api/nym-node-status-api/src/http/state.rs index 3f5d5c2887..b630c17d40 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/state.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/state.rs @@ -9,7 +9,7 @@ use nym_node_status_client::auth::VerifiableRequest; use nym_validator_client::nym_api::SkimmedNodeV1; use semver::Version; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, net::IpAddr, sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use time::UtcDateTime; use tokio::sync::RwLock; use tracing::{error, instrument, trace, warn}; @@ -456,7 +456,6 @@ impl HttpCache { .await .into_iter() .flat_map(|gw| gw.ip_addresses) - .filter(IpAddr::is_ipv4) .map(|ip| ip.to_string()) .sorted() .dedup() diff --git a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/state.rs b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/state.rs index bf4ad1e161..e1e507b272 100644 --- a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/state.rs +++ b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/state.rs @@ -68,8 +68,8 @@ impl TicketbookManagerState { for typ in &self.buffered_ticket_types { debug!("attempting to get materials for ticket of type {typ}"); if let Some(ticket) = self.storage.next_ticket(*typ, testrun_id).await? { - let epoch_id = ticket.ticketbook.epoch_id(); - let expiration_date = ticket.ticketbook.expiration_date(); + let epoch_id = ticket.epoch_id(); + let expiration_date = ticket.expiration_date(); debug!( "retrieved ticket corresponds to epoch {epoch_id} and expiration date {expiration_date}" diff --git a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/auxiliary_models.rs b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/auxiliary_models.rs index 904bb7eb57..a40611ea08 100644 --- a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/auxiliary_models.rs +++ b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/auxiliary_models.rs @@ -1,25 +1,50 @@ // Copyright 2025 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use anyhow::bail; use nym_credentials::IssuedTicketBook; use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise; use nym_gateway_probe::types::AttachedTicket; +use nym_validator_client::nym_api::EpochId; use sqlx::FromRow; use time::Date; use zeroize::{Zeroize, ZeroizeOnDrop}; -pub struct RetrievedTicketbook { - pub ticketbook_id: i32, - pub total_tickets: u32, - pub spent_tickets: u32, - pub ticketbook: IssuedTicketBook, +pub(crate) struct RetrievedTicketbook { + usable_index: u32, + ticketbook: IssuedTicketBook, +} + +impl RetrievedTicketbook { + pub fn new(ticketbook: IssuedTicketBook) -> anyhow::Result { + let usable_index = ticketbook.spent_tickets() as u32 - 1; + // spent_tickets is the post-increment number from the DB: the ticket we're + // handing out has already been counted as "used" in the DB, but has NOT YET + // been spent yet by the recipient. To get its 0-based index in the ticketbook, + // subtract 1 (e.g. spent_tickets=1, the ticket at index 0). + if usable_index < 1 { + bail!("Malformed ticket: cannot convert from ticket with spent_tickets=0"); + } + Ok(Self { + usable_index, + ticketbook, + }) + } + + pub fn epoch_id(&self) -> EpochId { + self.ticketbook.epoch_id() + } + + pub fn expiration_date(&self) -> time::Date { + self.ticketbook.expiration_date() + } } impl From for AttachedTicket { fn from(retrieved: RetrievedTicketbook) -> Self { AttachedTicket { ticketbook: retrieved.ticketbook.pack(), - usable_index: retrieved.spent_tickets, + usable_index: retrieved.usable_index, } } } diff --git a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/mod.rs b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/mod.rs index e8f2091448..f2aebcfafd 100644 --- a/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/ticketbook_manager/storage/mod.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::db::Storage; -use crate::ticketbook_manager::storage::auxiliary_models::RetrievedTicketbook; -use anyhow::{Context, anyhow}; +use anyhow::{Context, anyhow, bail}; +use auxiliary_models::RetrievedTicketbook; use nym_credential_proxy_lib::error::CredentialProxyError; use nym_credential_proxy_lib::shared_state::ecash_state::{ IssuanceTicketBook, IssuedTicketBook, TicketType, @@ -16,6 +16,7 @@ use nym_crypto::aes::cipher::zeroize::Zeroizing; use nym_ecash_time::{EcashTime, ecash_today}; use nym_validator_client::nym_api::EpochId; use time::Date; +use tracing::warn; pub(crate) mod auxiliary_models; @@ -85,7 +86,7 @@ impl TicketbookManagerStorage { /// Tries to retrieve one of the stored ticketbook that has not yet expired /// it immediately updated the on-disk number of used tickets so that another task /// could obtain their own tickets at the same time - pub(crate) async fn next_ticket( + pub(super) async fn next_ticket( &self, ticket_type: TicketType, testrun_id: i32, @@ -113,16 +114,33 @@ impl TicketbookManagerStorage { .set_distributed_ticketbook(testrun_id, raw.id, raw.used_tickets) .await?; - deserialised.update_spent_tickets(raw.used_tickets as u64); - Ok(Some(RetrievedTicketbook { - ticketbook_id: raw.id, - total_tickets: raw - .total_tickets - .try_into() - .context("failed to convert i32 total tickets into u32")?, - spent_tickets: deserialised.spent_tickets() as u32, - ticketbook: deserialised, - })) + deserialised.update_spent_tickets((raw.used_tickets) as u64); + + let total = deserialised.params_total_tickets(); + let spent = raw.used_tickets as u64; + + if spent > total { + // should never happen: implies a bug in DB fetching + bail!( + "testrun_id={testrun_id}, ticketbook_id={}, ticket_type={ticket_type}, \ + marked as used_tickets = {spent} > params_total_tickets = {total}. \ + Cannot have spent more than is in the ticketbook", + raw.id, + ); + } else { + tracing::debug!( + "testrun_id={testrun_id}, ticketbook_id={}, ticket_type={ticket_type}, \ + db_used_tickets={} / total_tickets={total}", + raw.id, + raw.used_tickets, + ); + } + + let retrieved_ticketbook = RetrievedTicketbook::new(deserialised) + .inspect_err(|e| warn!("Failed to convert retrieved ticketbook: {e}")) + .ok(); + + Ok(retrieved_ticketbook) } } diff --git a/nym-node-status-api/nym-node-status-client/Cargo.toml b/nym-node-status-api/nym-node-status-client/Cargo.toml index 8bd8541f55..63272148a1 100644 --- a/nym-node-status-api/nym-node-status-client/Cargo.toml +++ b/nym-node-status-api/nym-node-status-client/Cargo.toml @@ -5,11 +5,11 @@ name = "nym-node-status-client" version = "0.3.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index a5d38b3a1e..574d41d60a 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -3,13 +3,13 @@ [package] name = "nym-node" -version = "1.30.0" +version = "1.31.0" authors.workspace = true +edition.workspace = true +license = "GPL-3.0" repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license = "GPL-3.0" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -58,6 +58,7 @@ sysinfo = { workspace = true } nym-bin-common = { workspace = true, features = [ "basic_tracing", "output_format", + "ip_check" ] } nym-client-core-config-types = { workspace = true, features = [ "disk-persistence", diff --git a/nym-node/nym-node-metrics/Cargo.toml b/nym-node/nym-node-metrics/Cargo.toml index 28b32ac5e8..9e6b4c416c 100644 --- a/nym-node/nym-node-metrics/Cargo.toml +++ b/nym-node/nym-node-metrics/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-node-metrics" +description = "Crate defining various metrics for Nym Nodes (Mix Nodes and Gateways) such as ongoing connections, packets mixed, and packets dropped" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Crate defining various metrics for Nym Nodes (Mix Nodes and Gateways) such as ongoing connections, packets mixed, and packets dropped" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] dashmap = { workspace = true } diff --git a/nym-node/nym-node-requests/Cargo.toml b/nym-node/nym-node-requests/Cargo.toml index b051086220..bd78701287 100644 --- a/nym-node/nym-node-requests/Cargo.toml +++ b/nym-node/nym-node-requests/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "nym-node-requests" +description = "Nym Node API endpoint definitions and functions" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Nym Node API endpoint definitions and functions" +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-node/src/cli/commands/run/mod.rs b/nym-node/src/cli/commands/run/mod.rs index 450a88a761..d436bc441e 100644 --- a/nym-node/src/cli/commands/run/mod.rs +++ b/nym-node/src/cli/commands/run/mod.rs @@ -5,7 +5,7 @@ use crate::config::upgrade_helpers::try_load_current_config; use crate::error::NymNodeError; use crate::node::NymNode; use crate::node::bonding_information::BondingInformation; -use crate::node::mixnet::packet_forwarding::global::is_global_ip; +use nym_bin_common::ip_check::is_global_ip; use std::fs; use std::net::IpAddr; use tracing::{debug, info, trace, warn}; diff --git a/nym-node/src/cli/helpers.rs b/nym-node/src/cli/helpers.rs index 147a5a0129..85e0df1b7e 100644 --- a/nym-node/src/cli/helpers.rs +++ b/nym-node/src/cli/helpers.rs @@ -512,6 +512,26 @@ pub(crate) struct ExitGatewayArgs { env = NYMNODE_OPEN_PROXY_ARG, )] pub(crate) open_proxy: Option, + + /// Allow the network requester to forward traffic to non-globally-routable + /// addresses. Intended for local development, private-network deployments, + /// and testnet scenarios. + /// Not recommended on production exit gateway unless you know what you're doing. + #[clap( + long, + env = NYMNODE_NR_ALLOW_LOCAL_IPS_ARG, + )] + pub(crate) nr_allow_local_ips: Option, + + /// Allow the IP packet router to forward traffic to non-globally-routable + /// addresses. Intended for local development, private-network deployments, + /// and testnet scenarios. + /// Not recommended on production exit gateway unless you know what you're doing. + #[clap( + long, + env = NYMNODE_IPR_ALLOW_LOCAL_IPS_ARG, + )] + pub(crate) ipr_allow_local_ips: Option, } impl ExitGatewayArgs { @@ -533,6 +553,12 @@ impl ExitGatewayArgs { if let Some(open_proxy) = self.open_proxy { section.open_proxy = open_proxy } + if let Some(allow_local_ips) = self.nr_allow_local_ips { + section.network_requester.allow_local_ips = allow_local_ips + } + if let Some(allow_local_ips) = self.ipr_allow_local_ips { + section.ip_packet_router.allow_local_ips = allow_local_ips + } section } diff --git a/nym-node/src/config/helpers.rs b/nym-node/src/config/helpers.rs index 88f225fc93..8d43a10f3d 100644 --- a/nym-node/src/config/helpers.rs +++ b/nym-node/src/config/helpers.rs @@ -107,6 +107,7 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig { }, network_requester: nym_network_requester::config::NetworkRequester { open_proxy: config.service_providers.open_proxy, + allow_local_ips: config.service_providers.network_requester.allow_local_ips, disable_poisson_rate: config .service_providers .network_requester @@ -150,6 +151,7 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig { }, ip_packet_router: nym_ip_packet_router::config::IpPacketRouter { open_proxy: config.service_providers.open_proxy, + allow_local_ips: config.service_providers.ip_packet_router.allow_local_ips, disable_poisson_rate: config .service_providers .ip_packet_router diff --git a/nym-node/src/config/old_configs/old_config_v12.rs b/nym-node/src/config/old_configs/old_config_v12.rs index 9e71ab6be4..ce0b381e3f 100644 --- a/nym-node/src/config/old_configs/old_config_v12.rs +++ b/nym-node/src/config/old_configs/old_config_v12.rs @@ -938,6 +938,7 @@ pub async fn try_upgrade_config_v12>( open_proxy: old_cfg.service_providers.open_proxy, upstream_exit_policy_url: old_cfg.service_providers.upstream_exit_policy_url, network_requester: NetworkRequester { + allow_local_ips: false, debug: NetworkRequesterDebug { enabled: old_cfg.service_providers.network_requester.debug.enabled, disable_poisson_rate: old_cfg @@ -953,6 +954,7 @@ pub async fn try_upgrade_config_v12>( }, }, ip_packet_router: IpPacketRouter { + allow_local_ips: false, debug: IpPacketRouterDebug { enabled: old_cfg.service_providers.ip_packet_router.debug.enabled, disable_poisson_rate: old_cfg diff --git a/nym-node/src/config/service_providers.rs b/nym-node/src/config/service_providers.rs index b7d2f2cb77..863218b1f8 100644 --- a/nym-node/src/config/service_providers.rs +++ b/nym-node/src/config/service_providers.rs @@ -75,6 +75,11 @@ impl ServiceProvidersConfig { #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] pub struct NetworkRequester { + /// Allow the network requester to forward traffic to non-globally-routable addresses. + /// Intended for development & testing. + #[serde(default)] + pub allow_local_ips: bool, + #[serde(default)] pub debug: NetworkRequesterDebug, } @@ -83,6 +88,7 @@ pub struct NetworkRequester { impl Default for NetworkRequester { fn default() -> Self { NetworkRequester { + allow_local_ips: false, debug: Default::default(), } } @@ -117,6 +123,11 @@ impl Default for NetworkRequesterDebug { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] pub struct IpPacketRouter { + /// Allow the IP packet router to forward traffic to non-globally-routable addresses. + /// Intended for development & testing. + #[serde(default)] + pub allow_local_ips: bool, + #[serde(default)] pub debug: IpPacketRouterDebug, } @@ -125,6 +136,7 @@ pub struct IpPacketRouter { impl Default for IpPacketRouter { fn default() -> Self { IpPacketRouter { + allow_local_ips: false, debug: Default::default(), } } diff --git a/nym-node/src/env.rs b/nym-node/src/env.rs index 01f8a7113d..196c5dcc2f 100644 --- a/nym-node/src/env.rs +++ b/nym-node/src/env.rs @@ -70,6 +70,8 @@ pub mod vars { // exit gateway: pub const NYMNODE_UPSTREAM_EXIT_POLICY_ARG: &str = "NYMNODE_UPSTREAM_EXIT_POLICY"; pub const NYMNODE_OPEN_PROXY_ARG: &str = "NYMNODE_OPEN_PROXY"; + pub const NYMNODE_NR_ALLOW_LOCAL_IPS_ARG: &str = "NYMNODE_NR_ALLOW_LOCAL_IPS"; + pub const NYMNODE_IPR_ALLOW_LOCAL_IPS_ARG: &str = "NYMNODE_IPR_ALLOW_LOCAL_IPS"; // LP: pub const NYMNODE_LP_CONTROL_BIND_ADDRESS_ARG: &str = "NYMNODE_LP_CONTROL_BIND_ADDRESS"; diff --git a/nym-node/src/node/mixnet/packet_forwarding/mod.rs b/nym-node/src/node/mixnet/packet_forwarding/mod.rs index 6fa21d31c5..dc8d4af7d4 100644 --- a/nym-node/src/node/mixnet/packet_forwarding/mod.rs +++ b/nym-node/src/node/mixnet/packet_forwarding/mod.rs @@ -15,8 +15,6 @@ use std::io; use tokio::time::Instant; use tracing::{debug, error, trace, warn}; -pub(crate) mod global; - pub struct PacketForwarder { delay_queue: NonExhaustiveDelayQueue, mixnet_client: C, diff --git a/nym-node/src/node/routing_filter/network_filter.rs b/nym-node/src/node/routing_filter/network_filter.rs index eae67a66f7..274015f784 100644 --- a/nym-node/src/node/routing_filter/network_filter.rs +++ b/nym-node/src/node/routing_filter/network_filter.rs @@ -1,9 +1,9 @@ // Copyright 2025 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::node::mixnet::packet_forwarding::global::is_global_ip; use crate::node::routing_filter::RoutingFilter; use arc_swap::ArcSwap; +use nym_bin_common::ip_check::is_global_ip; use std::collections::HashSet; use std::net::IpAddr; use std::sync::Arc; diff --git a/nym-outfox/Cargo.toml b/nym-outfox/Cargo.toml index d3ea59291d..075c380d28 100644 --- a/nym-outfox/Cargo.toml +++ b/nym-outfox/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "nym-outfox" -version.workspace = true description = "Outfox package format" -edition = { workspace = true } +version.workspace = true authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-registration-client/Cargo.toml b/nym-registration-client/Cargo.toml index a1c3aa335a..0a7e845864 100644 --- a/nym-registration-client/Cargo.toml +++ b/nym-registration-client/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nym-registration-client" +description = "Crate for dealing with Mixnet and Wireguard registration between Nym clients and Gateways" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true -description = "Crate for dealing with Mixnet and Wireguard registration between Nym clients and Gateways" publish = false [lints] diff --git a/nym-signers-monitor/Cargo.toml b/nym-signers-monitor/Cargo.toml index 56adfc4ac5..265ee22192 100644 --- a/nym-signers-monitor/Cargo.toml +++ b/nym-signers-monitor/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-signers-monitor" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/nym-sqlx-pool-guard/Cargo.toml b/nym-sqlx-pool-guard/Cargo.toml index 3eecfffb99..85622863ad 100644 --- a/nym-sqlx-pool-guard/Cargo.toml +++ b/nym-sqlx-pool-guard/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-sqlx-pool-guard" +description = "Platform-specific functions for SQLX dbs" version.workspace = true +authors.workspace = true edition = "2024" license.workspace = true -description = "Platform-specific functions for SQLX dbs" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true [lints] workspace = true diff --git a/nym-statistics-api/Cargo.toml b/nym-statistics-api/Cargo.toml index d603503585..e826ca90ac 100644 --- a/nym-statistics-api/Cargo.toml +++ b/nym-statistics-api/Cargo.toml @@ -5,11 +5,11 @@ name = "nym-statistics-api" version = "0.3.1" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true publish = false diff --git a/nym-validator-rewarder/Cargo.toml b/nym-validator-rewarder/Cargo.toml index bf2fc671f8..66de013893 100644 --- a/nym-validator-rewarder/Cargo.toml +++ b/nym-validator-rewarder/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-validator-rewarder" version = "0.3.0" authors.workspace = true +edition.workspace = true +license = "GPL-3.0" repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license = "GPL-3.0" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-wallet/nym-wallet-recovery-cli/Cargo.toml b/nym-wallet/nym-wallet-recovery-cli/Cargo.toml index 5d78d02d41..4a60d01ba5 100644 --- a/nym-wallet/nym-wallet-recovery-cli/Cargo.toml +++ b/nym-wallet/nym-wallet-recovery-cli/Cargo.toml @@ -2,6 +2,7 @@ name = "nym-wallet-recovery-cli" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nym-wallet/nym-wallet-types/Cargo.toml b/nym-wallet/nym-wallet-types/Cargo.toml index b07382912a..a91188a94a 100644 --- a/nym-wallet/nym-wallet-types/Cargo.toml +++ b/nym-wallet/nym-wallet-types/Cargo.toml @@ -2,8 +2,9 @@ name = "nym-wallet-types" version = "1.0.0" edition = "2021" -rust-version = "1.85" license = "Apache-2.0" +rust-version = "1.85" +publish = false [dependencies] hex-literal = "0.3.3" diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index ace8911a78..0ade98b950 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -1,14 +1,15 @@ [package] name = "NymWallet" -version = "1.2.19" description = "Nym Native Wallet" +version = "1.2.19" authors = ["Nym Technologies SA"] +edition = "2021" license = "" repository = "" -default-run = "NymWallet" -edition = "2021" -build = "src/build.rs" rust-version = "1.85" +publish = false +build = "src/build.rs" +default-run = "NymWallet" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/nyx-chain-watcher/Cargo.toml b/nyx-chain-watcher/Cargo.toml index e8f2b4b2e0..04c7b41793 100644 --- a/nyx-chain-watcher/Cargo.toml +++ b/nyx-chain-watcher/Cargo.toml @@ -5,11 +5,11 @@ name = "nyx-chain-watcher" version = "0.1.15" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/sdk/ffi/cpp/Cargo.toml b/sdk/ffi/cpp/Cargo.toml index 307f669a15..786009064e 100644 --- a/sdk/ffi/cpp/Cargo.toml +++ b/sdk/ffi/cpp/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-cpp-ffi" +description = "C++ FFI bindings for Nym Rust SDK" version.workspace = true +authors.workspace = true edition = "2021" +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -license.workspace = true -description = "C++ FFI bindings for Nym Rust SDK" +rust-version.workspace = true +readme.workspace = true +publish = true [lib] name = "nym_cpp_ffi" diff --git a/sdk/ffi/go/Cargo.toml b/sdk/ffi/go/Cargo.toml index 76b1e91a57..a47eb63308 100644 --- a/sdk/ffi/go/Cargo.toml +++ b/sdk/ffi/go/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-go-ffi" +description = "Go FFI bindings for Nym Rust SDK" version.workspace = true +authors.workspace = true edition = "2021" +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -license.workspace = true -description = "Go FFI bindings for Nym Rust SDK" +rust-version.workspace = true +readme.workspace = true +publish = true [lib] crate-type = ["cdylib"] diff --git a/sdk/ffi/shared/Cargo.toml b/sdk/ffi/shared/Cargo.toml index d5e3434892..c4531df638 100644 --- a/sdk/ffi/shared/Cargo.toml +++ b/sdk/ffi/shared/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-ffi-shared" +description = "Common crate for use by Rust SDK FFI crates" version.workspace = true +authors.workspace = true edition = "2021" +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -license.workspace = true -description = "Common crate for use by Rust SDK FFI crates" +rust-version.workspace = true +readme.workspace = true +publish = true [dependencies] # Async runtime diff --git a/sdk/rust/nym-sdk/Cargo.toml b/sdk/rust/nym-sdk/Cargo.toml index 9fddca8295..931c640edb 100644 --- a/sdk/rust/nym-sdk/Cargo.toml +++ b/sdk/rust/nym-sdk/Cargo.toml @@ -1,10 +1,16 @@ [package] name = "nym-sdk" +description = "Nym's Rust SDK" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Nym's Rust SDK" repository = "https://github.com/nymtech/nym/sdk/rust/nym-sdk/" +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # documentation = "https://docs.rs/nym-sdk" Max: once we upload to crates.io and this is generated, this can be uncommented. # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/sdk/rust/nym-sdk/README.md b/sdk/rust/nym-sdk/README.md index be8bdab8ed..16f1989414 100644 --- a/sdk/rust/nym-sdk/README.md +++ b/sdk/rust/nym-sdk/README.md @@ -1,7 +1,5 @@ # Nym Rust SDK - - This repo contains several components: - `mixnet`: exposes Nym Client builders and methods. This is useful if you want to interact directly with the Client, or build transport abstractions. - `tcp_proxy`: exposes functionality to set up client/server instances that expose a localhost TcpSocket to read/write to like a 'normal' socket connection. `tcp_proxy/bin/` contains standalone `nym-proxy-client` and `nym-proxy-server` binaries. diff --git a/sdk/rust/nym-sdk/src/ipr_wrapper/ip_mix_stream.rs b/sdk/rust/nym-sdk/src/ipr_wrapper/ip_mix_stream.rs index 13cfb56e23..b4e75746e0 100644 --- a/sdk/rust/nym-sdk/src/ipr_wrapper/ip_mix_stream.rs +++ b/sdk/rust/nym-sdk/src/ipr_wrapper/ip_mix_stream.rs @@ -9,11 +9,9 @@ use crate::ip_packet_client::{ use crate::mixnet::{MixnetClient, MixnetStream, Recipient}; use crate::Error; use bytes::Bytes; +use current_ipr::response::IpPacketResponse; use nym_ip_packet_requests::response_helpers; -use nym_ip_packet_requests::{ - v9::{self, response::IpPacketResponse}, - IpPair, -}; +use nym_ip_packet_requests::{v9 as current_ipr, IpPair}; use nym_network_defaults::NymNetworkDetails; use std::time::Duration; use tokio::io::AsyncWriteExt; @@ -107,7 +105,7 @@ impl IpMixStream { } async fn connect_tunnel(stream: &mut MixnetStream) -> Result { - let (request, request_id) = v9::new_connect_request(None); + let (request, request_id) = current_ipr::new_connect_request(None); debug!("Sending connect request with ID: {}", request_id); let request_bytes = request.to_bytes()?; @@ -146,7 +144,7 @@ impl IpMixStream { /// Send an IP packet through the tunnel. pub async fn send_ip_packet(&mut self, packet: &[u8]) -> Result<(), Error> { self.check_connected()?; - let request = v9::new_data_request(packet.to_vec().into()); + let request = current_ipr::new_data_request(packet.to_vec().into()); let request_bytes = request.to_bytes()?; self.stream .write_all(&request_bytes) diff --git a/service-providers/common/Cargo.toml b/service-providers/common/Cargo.toml index 93661af48f..0966f51cf5 100644 --- a/service-providers/common/Cargo.toml +++ b/service-providers/common/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "nym-service-providers-common" +description = "Common crate for Nym Service Providers" version.workspace = true +authors.workspace = true edition = "2021" license.workspace = true -description = "Common crate for Nym Service Providers" repository.workspace = true homepage.workspace = true documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/service-providers/ip-packet-router/Cargo.toml b/service-providers/ip-packet-router/Cargo.toml index fdb12ae514..8c05b495e7 100644 --- a/service-providers/ip-packet-router/Cargo.toml +++ b/service-providers/ip-packet-router/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-ip-packet-router" version.workspace = true authors.workspace = true +edition.workspace = true +license = "GPL-3.0" repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license = "GPL-3.0" publish = false [dependencies] @@ -19,7 +19,7 @@ etherparse = { workspace = true } futures = { workspace = true } log = { workspace = true } -nym-bin-common = { workspace = true, features = ["clap", "basic_tracing"] } +nym-bin-common = { workspace = true, features = ["clap", "basic_tracing", "ip_check"] } nym-client-core = { workspace = true } nym-config = { workspace = true } nym-crypto = { workspace = true } diff --git a/service-providers/ip-packet-router/src/clients/connected_client_handler.rs b/service-providers/ip-packet-router/src/clients/connected_client_handler.rs index e44b543276..ff0e8e4924 100644 --- a/service-providers/ip-packet-router/src/clients/connected_client_handler.rs +++ b/service-providers/ip-packet-router/src/clients/connected_client_handler.rs @@ -218,7 +218,10 @@ fn create_ip_packet_response( ClientVersion::V6 => IpPacketResponseV6::new_ip_packet(packets).to_bytes(), ClientVersion::V7 => IpPacketResponseV7::new_ip_packet(packets).to_bytes(), ClientVersion::V8 => IpPacketResponseV8::new_ip_packet(packets).to_bytes(), - ClientVersion::V9 => v9::new_ip_packet_response(packets).to_bytes(), + ClientVersion::V9 => { + let resp = v9::new_ip_packet_response(packets); + resp.to_bytes() + } } } diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 3b39fa9706..2df5152045 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -192,6 +192,11 @@ pub struct IpPacketRouter { /// and thus would attempt to resolve **ANY** request it receives. pub open_proxy: bool, + /// Allow the IP packet router to forward traffic to non-globally-routable addresses. + /// Intended for development & testing. + #[serde(default)] + pub allow_local_ips: bool, + /// Disable Poisson sending rate. pub disable_poisson_rate: bool, @@ -204,6 +209,7 @@ impl Default for IpPacketRouter { fn default() -> Self { IpPacketRouter { open_proxy: false, + allow_local_ips: false, disable_poisson_rate: true, #[allow(clippy::expect_used)] upstream_exit_policy_url: Some( diff --git a/service-providers/ip-packet-router/src/config/old_config_v1.rs b/service-providers/ip-packet-router/src/config/old_config_v1.rs index 1352812a24..a2c5c9c2ff 100644 --- a/service-providers/ip-packet-router/src/config/old_config_v1.rs +++ b/service-providers/ip-packet-router/src/config/old_config_v1.rs @@ -95,6 +95,7 @@ impl From for IpPacketRouter { fn from(value: IpPacketRouterV1) -> Self { IpPacketRouter { open_proxy: false, + allow_local_ips: false, disable_poisson_rate: value.disable_poisson_rate, upstream_exit_policy_url: value.upstream_exit_policy_url, } diff --git a/service-providers/ip-packet-router/src/messages/request.rs b/service-providers/ip-packet-router/src/messages/request.rs index 0f8419e5e1..0c613a2fd4 100644 --- a/service-providers/ip-packet-router/src/messages/request.rs +++ b/service-providers/ip-packet-router/src/messages/request.rs @@ -10,6 +10,7 @@ use nym_ip_packet_requests::{ IpPair, v6::request::IpPacketRequest as IpPacketRequestV6, v7::request::IpPacketRequest as IpPacketRequestV7, v8::request::IpPacketRequest as IpPacketRequestV8, + v9::request::IpPacketRequest as IpPacketRequestV9, }; use nym_sdk::mixnet::ReconstructedMessage; use nym_service_provider_requests_common::{Protocol, ServiceProviderType}; @@ -131,14 +132,14 @@ impl TryFrom<&ReconstructedMessage> for IpPacketRequest { Ok(IpPacketRequest::from((request_v8, sender_tag))) } 9 => { - let request_v8 = IpPacketRequestV8::from_reconstructed_message(reconstructed) + let request_v9 = IpPacketRequestV9::from_reconstructed_message(reconstructed) .map_err( |source| IpPacketRouterError::FailedToDeserializeTaggedPacket { source }, )?; let sender_tag = reconstructed .sender_tag .ok_or(IpPacketRouterError::MissingSenderTag)?; - Ok(v9::convert(request_v8, sender_tag)) + Ok(v9::convert(request_v9, sender_tag)) } _ => { log::info!("Received packet with invalid version: v{request_version}"); diff --git a/service-providers/ip-packet-router/src/messages/response.rs b/service-providers/ip-packet-router/src/messages/response.rs index 4801983f48..e928487a26 100644 --- a/service-providers/ip-packet-router/src/messages/response.rs +++ b/service-providers/ip-packet-router/src/messages/response.rs @@ -130,7 +130,12 @@ impl VersionedResponse { ClientVersion::V6 => IpPacketResponseV6::try_from(self)?.to_bytes(), ClientVersion::V7 => IpPacketResponseV7::try_from(self)?.to_bytes(), ClientVersion::V8 => IpPacketResponseV8::try_from(self)?.to_bytes(), - ClientVersion::V9 => IpPacketResponseV8::try_from(self)?.to_bytes(), + ClientVersion::V9 => { + let mut resp = IpPacketResponseV8::try_from(self)?; + resp.version = nym_ip_packet_requests::v9::VERSION; + let bytes = resp.to_bytes(); + bytes + } } .map_err(|err| IpPacketRouterError::FailedToSerializeResponsePacket { source: err }) } diff --git a/service-providers/ip-packet-router/src/mixnet_listener.rs b/service-providers/ip-packet-router/src/mixnet_listener.rs index fa25adbf71..3295dfeeb1 100644 --- a/service-providers/ip-packet-router/src/mixnet_listener.rs +++ b/service-providers/ip-packet-router/src/mixnet_listener.rs @@ -23,6 +23,7 @@ use crate::{ }; use futures::StreamExt; use nym_ip_packet_requests::codec::MultiIpPacketCodec; +use nym_ip_packet_requests::{MAX_NON_STREAM_VERSION, SPHINX_STREAM_VERSION_THRESHOLD}; use nym_lp::packet::frame::{LpFrameHeader, LpFrameKind, SphinxStreamFrameAttributes}; use nym_sdk::mixnet::MixnetMessageSender; use nym_sphinx::receiver::ReconstructedMessage; @@ -559,8 +560,9 @@ impl MixnetListener { /// /// # Version / transport enforcement /// - /// - LP Stream frames (`stream_id` is `Some`) **must** carry v9+ payloads. - /// - Non-stream messages (`stream_id` is `None`) **must** be v8 or lower. + /// - LP Stream frames (`stream_id` is `Some`) **must** carry payloads with version + /// `>= SPHINX_STREAM_VERSION_THRESHOLD` (see `nym_ip_packet_requests`). + /// - Non-stream messages (`stream_id` is `None`) **must** be `<= MAX_NON_STREAM_VERSION`. /// /// Messages that violate these rules are dropped. async fn on_ipr_message( @@ -578,16 +580,22 @@ impl MixnetListener { }?; // Enforce version/transport consistency: - // - LP Stream frames must carry v9+ payloads - // - Non-stream messages must be v8 or lower + // - LP Stream frames must carry payloads at/above the SphinxStream threshold + // - Non-stream messages must be at/below the max non-stream version let version_num = request.version().into_u8(); - if stream_id.is_some() && version_num < 9 { - log::warn!("LP Stream frame contains v{version_num} payload, expected v9+; dropping",); + if stream_id.is_some() && version_num < SPHINX_STREAM_VERSION_THRESHOLD { + log::warn!( + "LP Stream frame contains v{version_num} payload, expected v{expected}+; dropping", + expected = SPHINX_STREAM_VERSION_THRESHOLD + ); return Ok(vec![]); } - if stream_id.is_none() && version_num >= 9 { - log::warn!("Non-stream message claims v{version_num}, expected v8 or lower; dropping",); + if stream_id.is_none() && version_num > MAX_NON_STREAM_VERSION { + log::warn!( + "Non-stream message claims v{version_num}, expected v{expected} or lower; dropping", + expected = MAX_NON_STREAM_VERSION + ); return Ok(vec![]); } diff --git a/service-providers/ip-packet-router/src/request_filter/exit_policy/mod.rs b/service-providers/ip-packet-router/src/request_filter/exit_policy/mod.rs index 133df560c7..544768cdd8 100644 --- a/service-providers/ip-packet-router/src/request_filter/exit_policy/mod.rs +++ b/service-providers/ip-packet-router/src/request_filter/exit_policy/mod.rs @@ -4,6 +4,8 @@ use std::net::SocketAddr; use crate::error::IpPacketRouterError; +use log::warn; +use nym_bin_common::ip_check::is_global_ip; use nym_exit_policy::ExitPolicy; use nym_exit_policy::client::get_exit_policy; use reqwest::IntoUrl; @@ -13,10 +15,14 @@ pub struct ExitPolicyRequestFilter { #[allow(unused)] upstream: Option, policy: ExitPolicy, + allow_local_ips: bool, } impl ExitPolicyRequestFilter { - pub(crate) async fn new_upstream(url: impl IntoUrl) -> Result { + pub(crate) async fn new_upstream( + url: impl IntoUrl, + allow_local_ips: bool, + ) -> Result { let url = url .into_url() .map_err(|source| IpPacketRouterError::MalformedExitPolicyUpstreamUrl { source })?; @@ -24,21 +30,24 @@ impl ExitPolicyRequestFilter { Ok(ExitPolicyRequestFilter { upstream: Some(url.clone()), policy: get_exit_policy(url).await?, + allow_local_ips, }) } #[allow(unused)] - pub(crate) fn new(policy: ExitPolicy) -> Self { + pub(crate) fn new(policy: ExitPolicy, allow_local_ips: bool) -> Self { ExitPolicyRequestFilter { upstream: None, policy, + allow_local_ips, } } - pub fn new_from_policy(policy: ExitPolicy) -> Self { + pub fn new_from_policy(policy: ExitPolicy, allow_local_ips: bool) -> Self { ExitPolicyRequestFilter { upstream: None, policy, + allow_local_ips, } } @@ -53,6 +62,13 @@ impl ExitPolicyRequestFilter { } pub(crate) async fn check(&self, addr: &SocketAddr) -> Result { + // private ranges are disallowed regardless of policy: end user has + // no business with internal/private IP ranges of IPR + if !self.allow_local_ips && !is_global_ip(&addr.ip()) { + warn!("Rejecting non-global address {addr}"); + return Ok(false); + } + self.policy .allows_sockaddr(addr) .ok_or(IpPacketRouterError::AddressNotCoveredByExitPolicy { addr: *addr }) diff --git a/service-providers/ip-packet-router/src/request_filter/mod.rs b/service-providers/ip-packet-router/src/request_filter/mod.rs index 2c724af9eb..4d928e366a 100644 --- a/service-providers/ip-packet-router/src/request_filter/mod.rs +++ b/service-providers/ip-packet-router/src/request_filter/mod.rs @@ -43,15 +43,23 @@ impl RequestFilter { } async fn new_exit_policy_filter(config: &Config) -> Result { + let allow_local_ips = config.ip_packet_router.allow_local_ips; + if allow_local_ips { + warn!( + "Requests to non-global destinations are allowed by the policy guard. \ + This is intended for local development and NOT recommended in production \ + unless you know what you're doing." + ); + } let policy_filter = if config.ip_packet_router.open_proxy { - ExitPolicyRequestFilter::new_from_policy(ExitPolicy::new_open()) + ExitPolicyRequestFilter::new_from_policy(ExitPolicy::new_open(), allow_local_ips) } else { let upstream_url = config .ip_packet_router .upstream_exit_policy_url .as_ref() .ok_or(IpPacketRouterError::NoUpstreamExitPolicy)?; - ExitPolicyRequestFilter::new_upstream(upstream_url.clone()).await? + ExitPolicyRequestFilter::new_upstream(upstream_url.clone(), allow_local_ips).await? }; Ok(RequestFilter { diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 4e1de94ee9..c55c845e97 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -3,9 +3,10 @@ [package] name = "nym-network-requester" -version = "1.1.76" +version = "1.1.77" authors.workspace = true edition.workspace = true +license = "GPL-3.0" rust-version = "1.85" publish = false @@ -43,7 +44,7 @@ zeroize = { workspace = true } # internal nym-async-file-watcher = { workspace = true } -nym-bin-common = { workspace = true, features = ["output_format", "clap", "basic_tracing"] } +nym-bin-common = { workspace = true, features = ["output_format", "clap", "basic_tracing", "ip_check"] } nym-client-core = { workspace = true, features = ["cli", "fs-gateways-storage", "fs-surb-storage"] } nym-client-websocket-requests = { workspace = true } nym-config = { workspace = true } diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index 635e7f16b0..3d0e7f2fd1 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -210,6 +210,11 @@ pub struct NetworkRequester { /// and thus would attempt to resolve **ANY** request it receives. pub open_proxy: bool, + /// Allow the network requester to forward traffic to non-globally-routable addresses. + /// Intended for development & testing. + #[serde(default)] + pub allow_local_ips: bool, + /// Disable Poisson sending rate. /// This is equivalent to setting debug.traffic.disable_main_poisson_packet_distribution = true, pub disable_poisson_rate: bool, @@ -223,6 +228,7 @@ impl Default for NetworkRequester { fn default() -> Self { NetworkRequester { open_proxy: false, + allow_local_ips: false, disable_poisson_rate: true, upstream_exit_policy_url: Some( mainnet::EXIT_POLICY_URL diff --git a/service-providers/network-requester/src/config/old/v5.rs b/service-providers/network-requester/src/config/old/v5.rs index 6e6d5de055..6fe5042007 100644 --- a/service-providers/network-requester/src/config/old/v5.rs +++ b/service-providers/network-requester/src/config/old/v5.rs @@ -113,6 +113,7 @@ impl From for NetworkRequester { fn from(value: NetworkRequesterV5) -> Self { NetworkRequester { open_proxy: value.open_proxy, + allow_local_ips: false, disable_poisson_rate: value.disable_poisson_rate, upstream_exit_policy_url: value.upstream_exit_policy_url, } diff --git a/service-providers/network-requester/src/config/template.rs b/service-providers/network-requester/src/config/template.rs index ac1f52f37b..a9886c16d3 100644 --- a/service-providers/network-requester/src/config/template.rs +++ b/service-providers/network-requester/src/config/template.rs @@ -81,6 +81,11 @@ nr_description = '{{ storage_paths.nr_description }}' # and thus would attempt to resolve **ANY** request it receives. open_proxy = {{ network_requester.open_proxy }} +# Allow forwarding traffic to non-globally-routable addresses. +# Intended for local development for security reasons. +# Only enable if you know what you're doing. +allow_local_ips = {{ network_requester.allow_local_ips }} + # Disable Poisson sending rate # This is equivalent to setting debug.traffic.disable_main_poisson_packet_distribution = true, disable_poisson_rate = {{ network_requester.disable_poisson_rate }} diff --git a/service-providers/network-requester/src/request_filter/exit_policy/mod.rs b/service-providers/network-requester/src/request_filter/exit_policy/mod.rs index 140091625e..61e15ca438 100644 --- a/service-providers/network-requester/src/request_filter/exit_policy/mod.rs +++ b/service-providers/network-requester/src/request_filter/exit_policy/mod.rs @@ -3,7 +3,8 @@ use crate::config::Config; use crate::error::NetworkRequesterError; -use log::trace; +use log::{trace, warn}; +use nym_bin_common::ip_check::is_global_ip; use nym_exit_policy::ExitPolicy; use nym_exit_policy::client::get_exit_policy; use nym_socks5_requests::RemoteAddress; @@ -14,16 +15,20 @@ use url::Url; pub struct ExitPolicyRequestFilter { upstream: Option, policy: ExitPolicy, + allow_local_ips: bool, } impl From for ExitPolicyRequestFilter { fn from(value: ExitPolicy) -> Self { - ExitPolicyRequestFilter::new_from_policy(value) + ExitPolicyRequestFilter::new_from_policy(value, false) } } impl ExitPolicyRequestFilter { - pub(crate) async fn new_upstream(url: impl IntoUrl) -> Result { + pub(crate) async fn new_upstream( + url: impl IntoUrl, + allow_local_ips: bool, + ) -> Result { let url = url .into_url() .map_err(|source| NetworkRequesterError::MalformedExitPolicyUpstreamUrl { source })?; @@ -31,27 +36,37 @@ impl ExitPolicyRequestFilter { Ok(ExitPolicyRequestFilter { upstream: Some(url.clone()), policy: get_exit_policy(url).await?, + allow_local_ips, }) } pub(crate) async fn new(config: &Config) -> Result { + let allow_local_ips = config.network_requester.allow_local_ips; + if allow_local_ips { + warn!( + "Requests to non-global destinations are allowed by the policy guard. \ + This is intended for local development and NOT recommended in production \ + unless you know what you're doing." + ); + } let policy_filter = if config.network_requester.open_proxy { - ExitPolicyRequestFilter::new_from_policy(ExitPolicy::new_open()) + ExitPolicyRequestFilter::new_from_policy(ExitPolicy::new_open(), allow_local_ips) } else { let upstream_url = config .network_requester .upstream_exit_policy_url .as_ref() .ok_or(NetworkRequesterError::NoUpstreamExitPolicy)?; - ExitPolicyRequestFilter::new_upstream(upstream_url.clone()).await? + ExitPolicyRequestFilter::new_upstream(upstream_url.clone(), allow_local_ips).await? }; Ok(policy_filter) } - pub fn new_from_policy(policy: ExitPolicy) -> Self { + pub fn new_from_policy(policy: ExitPolicy, allow_local_ips: bool) -> Self { ExitPolicyRequestFilter { upstream: None, policy, + allow_local_ips, } } @@ -89,6 +104,13 @@ impl ExitPolicyRequestFilter { // if the remote decided to give us an address that can resolve to multiple socket addresses, // they'd better make sure all of them are allowed by the exit policy. for addr in addrs { + // private ranges are disallowed regardless of policy: end user has + // no business with internal/private IP ranges of network requester + if !self.allow_local_ips && !is_global_ip(&addr.ip()) { + warn!("Rejecting non-global address {addr} for '{remote}'"); + return Ok(false); + } + // exit policy determines which PUBLIC facing addresses are allowed if !self .policy .allows_sockaddr(&addr) diff --git a/smolmix/README.md b/smolmix/README.md new file mode 100644 index 0000000000..3bd4e861b7 --- /dev/null +++ b/smolmix/README.md @@ -0,0 +1,67 @@ +# smolmix + +TCP/UDP tunnel over the Nym mixnet. Uses a userspace network stack (smoltcp) +to provide real `TcpStream` and `UdpSocket` types that work transparently +with the async Rust ecosystem — tokio-rustls, hyper, tokio-tungstenite, +libp2p, and anything else built on `AsyncRead + AsyncWrite`. + +## Why IP, not messages + +The Nym SDK works at the **message layer**: you send and receive `Vec` +payloads through the mixnet. Every protocol must be hand-adapted — you need +custom framing, ordering, connection state, and flow control. + +`smolmix` operates at the **IP layer**. A userspace smoltcp stack manages +real TCP state machines (retransmits, windowing, port allocation) and UDP +datagram delivery, and the mixnet becomes a transparent transport underneath. +Any protocol that works over TCP or UDP works over smolmix — with zero +adaptation. + +```text +┌──────────────────────────────────────────────────────────────────┐ +│ Application protocols that "just work" over smolmix │ +│ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌────────────────┐ │ +│ │ TLS │ │ HTTP/1.1 │ │ WebSocket │ │ libp2p │ │ +│ │ (rustls) │ │ (hyper) │ │ (tungstenite)│ │ (noise+yamux) │ │ +│ └────┬─────┘ └────┬─────┘ └──────┬───────┘ └───────┬────────┘ │ +│ │ │ │ │ │ +│ └─────────────┴──────────────┴─────────────────┘ │ +│ │ │ +│ tokio_smoltcp::TcpStream │ +│ (AsyncRead + AsyncWrite, Send, Unpin) │ +├──────────────────────────────────────────────────────────────────┤ +│ smolmix Tunnel │ +│ (smoltcp → mixnet → IPR) │ +└──────────────────────────────────────────────────────────────────┘ +``` + +## Quick start + +```rust +use smolmix::Tunnel; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +let tunnel = Tunnel::new().await?; + +// Raw TCP — works with any protocol +let mut tcp = tunnel.tcp_connect("1.1.1.1:80".parse()?).await?; +tcp.write_all(b"GET / HTTP/1.1\r\nHost: 1.1.1.1\r\nConnection: close\r\n\r\n").await?; + +// Raw UDP — datagrams over the mixnet +let udp = tunnel.udp_socket().await?; +udp.send_to(&packet, "1.1.1.1:53".parse()?).await?; +``` + +## Examples + +```sh +cargo run -p smolmix --example tcp # HTTPS via hyper +cargo run -p smolmix --example udp # DNS via hickory-proto +cargo run -p smolmix --example websocket # WebSocket via tungstenite +``` + +## Architecture + +See [`core/src/ARCHITECTURE.md`](core/src/ARCHITECTURE.md) for the internal +stack (smoltcp, device adapter, bridge, mixnet client). diff --git a/smolmix/core/Cargo.toml b/smolmix/core/Cargo.toml new file mode 100644 index 0000000000..9ef598b42d --- /dev/null +++ b/smolmix/core/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "smolmix" +description = "Tunnel for TCP and UDP traffic to be sent over Nym mixnet to clearnet remote hosts" +version = "0.0.1" +authors.workspace = true +edition = "2021" +license.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true +readme.workspace = true +publish = true + +[dependencies] +smoltcp = { workspace = true, features = [ + "std", + "medium-ip", + "proto-ipv4", + "socket-tcp", + "socket-udp", +] } +tokio = { workspace = true } +tokio-smoltcp = { workspace = true } +futures = { workspace = true } +tracing = { workspace = true } +nym-sdk = { workspace = true } +nym-ip-packet-requests = { workspace = true } +thiserror.workspace = true + +[dev-dependencies] +futures = { workspace = true } +tokio = { workspace = true, features = ["io-util", "macros", "rt-multi-thread", "time", "net"] } +tokio-tungstenite.workspace = true +webpki-roots.workspace = true +rustls = { workspace = true, features = ["std", "ring"] } +tokio-rustls = { workspace = true } +nym-bin-common = { workspace = true, features = ["basic_tracing"] } +hickory-proto = { workspace = true } +hickory-resolver = { workspace = true, features = ["tokio", "system-config"] } +hyper = { workspace = true, features = ["client", "http1"] } +hyper-util = { workspace = true, features = ["tokio"] } +http-body-util = { workspace = true } +reqwest = { workspace = true, features = ["rustls"] } diff --git a/smolmix/core/README.md b/smolmix/core/README.md new file mode 100644 index 0000000000..500941938a --- /dev/null +++ b/smolmix/core/README.md @@ -0,0 +1,19 @@ +# smolmix + +A TCP/UDP tunnel over the Nym mixnet. Uses smoltcp as a userspace network stack and connects to an Exit Gateway's IP Packet Router, so the exit IP is the gateway's — not yours. + +`Tunnel` gives you standard `TcpStream` and `UdpSocket` types (from tokio-smoltcp) that work transparently with the async Rust ecosystem: tokio-rustls for TLS, hyper for HTTP, tokio-tungstenite for WebSockets, etc. + +## Examples + +All examples include a clearnet-vs-mixnet comparison with timing and accept `--ipr
` for targeting a specific exit node. + +```sh +cargo run -p smolmix --example tcp # raw TCP connection +cargo run -p smolmix --example udp # raw UDP datagram +cargo run -p smolmix --example websocket # WebSocket over TLS (raw TcpStream composability) +``` + +## Architecture + +See [`src/ARCHITECTURE.md`](src/ARCHITECTURE.md). diff --git a/smolmix/core/examples/tcp.rs b/smolmix/core/examples/tcp.rs new file mode 100644 index 0000000000..884346a85c --- /dev/null +++ b/smolmix/core/examples/tcp.rs @@ -0,0 +1,131 @@ +//! HTTPS request through the Nym mixnet. +//! +//! Fetches Cloudflare's `/cdn-cgi/trace` diagnostic endpoint over clearnet +//! (reqwest) and through the mixnet (hyper over tokio-rustls over smolmix), +//! then compares the responses. The exit IP should differ — the mixnet path +//! exits through an IPR gateway. +//! +//! Run with: +//! cargo run -p smolmix --example tcp +//! cargo run -p smolmix --example tcp -- --ipr + +use std::sync::Arc; + +use http_body_util::BodyExt; +use hyper::body::Bytes; +use hyper::Request; +use hyper_util::rt::TokioIo; +use rustls::pki_types::ServerName; +use smolmix::Tunnel; +use tokio_rustls::TlsConnector; +use tracing::info; + +type BoxError = Box; + +const HOST: &str = "cloudflare.com"; +const PATH: &str = "/cdn-cgi/trace"; + +fn tls_connector() -> TlsConnector { + let mut root_store = rustls::RootCertStore::empty(); + root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); + let config = rustls::ClientConfig::builder() + .with_root_certificates(root_store) + .with_no_client_auth(); + TlsConnector::from(Arc::new(config)) +} + +#[tokio::main] +async fn main() -> Result<(), BoxError> { + nym_bin_common::logging::setup_tracing_logger(); + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rustls crypto provider"); + + // Clearnet baseline via reqwest + info!("Fetching via clearnet..."); + let clearnet_start = tokio::time::Instant::now(); + let clearnet_resp = reqwest::get(format!("https://{HOST}{PATH}")).await?; + let clearnet_status = clearnet_resp.status(); + let clearnet_body = clearnet_resp.text().await?; + let clearnet_duration = clearnet_start.elapsed(); + info!("Clearnet: {} in {:?}", clearnet_status, clearnet_duration); + + // Mixnet: smolmix TCP -> tokio-rustls -> hyper + let args: Vec = std::env::args().collect(); + let ipr_addr = args + .iter() + .position(|a| a == "--ipr") + .and_then(|i| args.get(i + 1)); + + let mut builder = Tunnel::builder(); + if let Some(addr) = ipr_addr { + builder = builder.ipr_address(addr.parse().expect("invalid IPR address")); + } + let tunnel = builder.build().await?; + + // Phase 1: Setup (TCP + TLS + HTTP handshakes) + let setup_start = tokio::time::Instant::now(); + + info!("TCP connecting to 1.1.1.1:443 via mixnet..."); + let tcp = tunnel.tcp_connect("1.1.1.1:443".parse()?).await?; + info!("TCP connected ({:?})", setup_start.elapsed()); + + info!("TLS handshake..."); + let connector = tls_connector(); + let domain = ServerName::try_from(HOST)?.to_owned(); + let tls = connector.connect(domain, tcp).await?; + info!("TLS established ({:?})", setup_start.elapsed()); + + info!("HTTP/1.1 handshake..."); + let (mut sender, conn) = hyper::client::conn::http1::handshake(TokioIo::new(tls)).await?; + tokio::spawn(conn); + + let setup_duration = setup_start.elapsed(); + info!("Setup complete ({:?})", setup_duration); + + // Phase 2: Request/response + let request_start = tokio::time::Instant::now(); + + info!("Sending GET {PATH}..."); + let req = Request::get(PATH) + .header("Host", HOST) + .body(http_body_util::Empty::::new())?; + let resp = sender.send_request(req).await?; + let mixnet_status = resp.status(); + let body_bytes = resp.into_body().collect().await?.to_bytes(); + let mixnet_body = String::from_utf8_lossy(&body_bytes); + + let request_duration = request_start.elapsed(); + info!( + "Response: {} ({} bytes, {:?})", + mixnet_status, + body_bytes.len(), + request_duration + ); + + // Results + let clearnet_ip = clearnet_body.lines().find(|l| l.starts_with("ip=")); + let mixnet_ip = mixnet_body.lines().find(|l| l.starts_with("ip=")); + + info!("Clearnet: {} in {:?}", clearnet_status, clearnet_duration); + info!( + "Mixnet: {} (setup {:?} + request {:?} = {:?})", + mixnet_status, + setup_duration, + request_duration, + setup_duration + request_duration + ); + info!("Clearnet IP: {}", clearnet_ip.unwrap_or("?")); + info!("Mixnet IP: {}", mixnet_ip.unwrap_or("?")); + + let total = setup_duration + request_duration; + let slowdown = total.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64; + info!( + "Slowdown: {slowdown:.1}x (setup: {:.1}x, request: {:.1}x)", + setup_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64, + request_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64 + ); + + tunnel.shutdown().await; + Ok(()) +} diff --git a/smolmix/core/examples/udp.rs b/smolmix/core/examples/udp.rs new file mode 100644 index 0000000000..6600fe6e8b --- /dev/null +++ b/smolmix/core/examples/udp.rs @@ -0,0 +1,96 @@ +//! DNS lookup through the Nym mixnet. +//! +//! Resolves `example.com` via clearnet (hickory-resolver) and via the mixnet +//! (hickory-proto UDP query to Cloudflare 1.1.1.1), then compares resolved +//! IPs and timing. +//! +//! +//! Run with: +//! cargo run -p smolmix --example udp +//! cargo run -p smolmix --example udp -- --ipr + +use std::net::Ipv4Addr; + +use hickory_proto::op::{Message, Query}; +use hickory_proto::rr::{Name, RData, RecordType}; +use hickory_resolver::TokioResolver; +use smolmix::Tunnel; +use tracing::info; + +type BoxError = Box; + +#[tokio::main] +async fn main() -> Result<(), BoxError> { + nym_bin_common::logging::setup_tracing_logger(); + + let domain = "example.com"; + + // Clearnet baseline via hickory-resolver + info!("Clearnet DNS lookup for '{domain}'..."); + let resolver = TokioResolver::builder_tokio()?.build(); + let clearnet_start = tokio::time::Instant::now(); + let lookup = resolver.lookup_ip(domain).await?; + let clearnet_ips: Vec = lookup + .iter() + .filter_map(|ip| match ip { + std::net::IpAddr::V4(v4) => Some(v4), + _ => None, + }) + .collect(); + let clearnet_duration = clearnet_start.elapsed(); + info!("Clearnet: {:?} in {:?}", clearnet_ips, clearnet_duration); + + // Mixnet: hickory-proto query over smolmix UDP + let args: Vec = std::env::args().collect(); + let ipr_addr = args + .iter() + .position(|a| a == "--ipr") + .and_then(|i| args.get(i + 1)); + + let mut builder = Tunnel::builder(); + if let Some(addr) = ipr_addr { + builder = builder.ipr_address(addr.parse().expect("invalid IPR address")); + } + let tunnel = builder.build().await?; + + let udp = tunnel.udp_socket().await?; + + let mut query = Message::new(); + query.set_recursion_desired(true); + query.add_query(Query::query(Name::from_ascii(domain)?, RecordType::A)); + let query_bytes = query.to_vec()?; + + // UDP is connectionless — no setup phase, just send/recv + info!("Sending DNS query via mixnet..."); + let mixnet_start = tokio::time::Instant::now(); + udp.send_to(&query_bytes, "1.1.1.1:53".parse()?).await?; + info!("Query sent ({:?})", mixnet_start.elapsed()); + + let mut buf = vec![0u8; 1500]; + let (n, _from) = udp.recv_from(&mut buf).await?; + let mixnet_duration = mixnet_start.elapsed(); + info!("Response received ({} bytes, {:?})", n, mixnet_duration); + + let response = Message::from_vec(&buf[..n])?; + let mixnet_ips: Vec = response + .answers() + .iter() + .filter_map(|r| match r.data() { + RData::A(a) => Some(a.0), + _ => None, + }) + .collect(); + + // Results + info!("Clearnet: {:?} ({:?})", clearnet_ips, clearnet_duration); + info!("Mixnet: {:?} ({:?})", mixnet_ips, mixnet_duration); + + let ips_match = !mixnet_ips.is_empty() && mixnet_ips.iter().all(|ip| clearnet_ips.contains(ip)); + info!("IPs match: {ips_match}"); + + let slowdown = mixnet_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64; + info!("Slowdown: {slowdown:.1}x"); + + tunnel.shutdown().await; + Ok(()) +} diff --git a/smolmix/core/examples/websocket.rs b/smolmix/core/examples/websocket.rs new file mode 100644 index 0000000000..e5f3070e72 --- /dev/null +++ b/smolmix/core/examples/websocket.rs @@ -0,0 +1,143 @@ +//! WebSocket echo over the Nym mixnet. +//! +//! Demonstrates stacking tokio-tungstenite on top of tokio-rustls on top of +//! smolmix TcpStream. Sends a message to a public echo server via clearnet +//! and via the mixnet, then compares responses and timing. +//! +//! The clearnet and mixnet paths use the *exact same* TLS + WebSocket stack — +//! only the underlying TCP transport differs: +//! +//! ```text +//! tokio-tungstenite (WebSocket framing) +//! └─ tokio-rustls (TLS encryption) +//! └─ tokio::net::TcpStream (clearnet) +//! └─ smolmix::TcpStream (mixnet) +//! ``` +//! +//! Run with: +//! cargo run -p smolmix --example websocket +//! cargo run -p smolmix --example websocket -- --ipr + +use std::sync::Arc; + +use futures::{SinkExt, StreamExt}; +use rustls::pki_types::ServerName; +use smolmix::Tunnel; +use tokio_tungstenite::tungstenite::Message; +use tracing::info; + +type BoxError = Box; + +const WS_HOST: &str = "ws.postman-echo.com"; +const WS_PATH: &str = "/raw"; +const ECHO_MSG: &str = "Hello from the Nym mixnet!"; + +fn tls_connector() -> tokio_rustls::TlsConnector { + let mut root_store = rustls::RootCertStore::empty(); + root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); + let config = rustls::ClientConfig::builder() + .with_root_certificates(root_store) + .with_no_client_auth(); + tokio_rustls::TlsConnector::from(Arc::new(config)) +} + +#[tokio::main] +async fn main() -> Result<(), BoxError> { + nym_bin_common::logging::setup_tracing_logger(); + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rustls crypto provider"); + + // Resolve hostname via clearnet DNS - you can resolve via the Mixnet (see UDP example) but for this test its not necessary + let addr = tokio::net::lookup_host(format!("{WS_HOST}:443")) + .await? + .next() + .ok_or("DNS resolution failed")?; + info!("Resolved {WS_HOST} -> {addr}"); + + let connector = tls_connector(); + let domain = ServerName::try_from(WS_HOST)?.to_owned(); + + // Clearnet baseline: tokio TCP -> rustls -> tungstenite + info!("Connecting via clearnet..."); + let clearnet_start = tokio::time::Instant::now(); + + let clearnet_tcp = tokio::net::TcpStream::connect(addr).await?; + let clearnet_tls = connector.connect(domain.clone(), clearnet_tcp).await?; + let (mut clearnet_ws, _) = + tokio_tungstenite::client_async(format!("wss://{WS_HOST}{WS_PATH}"), clearnet_tls).await?; + + clearnet_ws.send(Message::Text(ECHO_MSG.into())).await?; + let clearnet_reply = clearnet_ws.next().await.ok_or("no clearnet reply")??; + let clearnet_duration = clearnet_start.elapsed(); + let clearnet_text = clearnet_reply.into_text()?; + clearnet_ws.close(None).await?; + + info!("Clearnet: \"{clearnet_text}\" in {clearnet_duration:?}"); + + // Mixnet: smolmix TCP -> rustls -> tungstenite (same stack) + let args: Vec = std::env::args().collect(); + let ipr_addr = args + .iter() + .position(|a| a == "--ipr") + .and_then(|i| args.get(i + 1)); + + let mut builder = Tunnel::builder(); + if let Some(addr) = ipr_addr { + builder = builder.ipr_address(addr.parse().expect("invalid IPR address")); + } + let tunnel = builder.build().await?; + info!("Allocated IP: {}", tunnel.allocated_ips().ipv4); + + // Phase 1: Setup (TCP + TLS + WebSocket handshakes) + let setup_start = tokio::time::Instant::now(); + + info!("TCP connecting via mixnet..."); + let mixnet_tcp = tunnel.tcp_connect(addr).await?; + info!("TCP connected ({:?})", setup_start.elapsed()); + + info!("TLS handshake..."); + let mixnet_tls = connector.connect(domain, mixnet_tcp).await?; + info!("TLS established ({:?})", setup_start.elapsed()); + + info!("WebSocket upgrade..."); + let (mut mixnet_ws, _) = + tokio_tungstenite::client_async(format!("wss://{WS_HOST}{WS_PATH}"), mixnet_tls).await?; + + let setup_duration = setup_start.elapsed(); + info!("Setup complete ({:?})", setup_duration); + + // Phase 2: Echo request/response + let request_start = tokio::time::Instant::now(); + + mixnet_ws.send(Message::Text(ECHO_MSG.into())).await?; + let mixnet_reply = mixnet_ws.next().await.ok_or("no mixnet reply")??; + + let request_duration = request_start.elapsed(); + let mixnet_text = mixnet_reply.into_text()?; + mixnet_ws.close(None).await?; + + info!("Echo: \"{mixnet_text}\" ({:?})", request_duration); + + // Results + info!("Clearnet: \"{clearnet_text}\" in {clearnet_duration:?}"); + info!( + "Mixnet: \"{mixnet_text}\" (setup {:?} + echo {:?} = {:?})", + setup_duration, + request_duration, + setup_duration + request_duration + ); + info!("Clearnet echo match: {}", clearnet_text == ECHO_MSG); + info!("Mixnet echo match: {}", mixnet_text == ECHO_MSG); + + let total = setup_duration + request_duration; + let slowdown = total.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64; + info!( + "Slowdown: {slowdown:.1}x (setup: {:.1}x, echo: {:.1}x)", + setup_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64, + request_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64 + ); + + tunnel.shutdown().await; + Ok(()) +} diff --git a/smolmix/core/src/ARCHITECTURE.md b/smolmix/core/src/ARCHITECTURE.md new file mode 100644 index 0000000000..5425ad8b47 --- /dev/null +++ b/smolmix/core/src/ARCHITECTURE.md @@ -0,0 +1,70 @@ +# Architecture + +smolmix is a TCP/UDP tunnel over the Nym mixnet. It gives you standard +`TcpStream` and `UdpSocket` types that work transparently with the async Rust +ecosystem (tokio-rustls, hyper, tokio-tungstenite, etc.) while routing all +traffic through the mixnet for metadata privacy. + +## Stack + +```text +┌─────────────────────────────────────────────────────────────────┐ +│ User code │ +│ tunnel.tcp_connect() → TcpStream (AsyncRead + AsyncWrite) │ +│ tunnel.udp_socket() → UdpSocket (send_to / recv_from) │ +├─────────────────────────────────────────────────────────────────┤ +│ tokio-smoltcp::Net │ +│ Owns the smoltcp Interface + SocketSet + async poll loop. │ +│ Manages TCP state machines, retransmits, port allocation. │ +├─────────────────────────────────────────────────────────────────┤ +│ NymAsyncDevice (device.rs) │ +│ Stream + Sink adapter for raw IP packets over mpsc channels. │ +├─────────────────────────────────────────────────────────────────┤ +│ NymIprBridge (bridge.rs) │ +│ Background task shuttling packets between channels and the │ +│ mixnet. Bundles outgoing packets with MultiIpPacketCodec │ +│ (required by the IPR protocol). │ +├─────────────────────────────────────────────────────────────────┤ +│ IpMixStream → MixnetClient → Nym mixnet → IPR exit node │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Data flow + +```text +outgoing: smoltcp → NymAsyncDevice (Sink) → channel → NymIprBridge → IpMixStream → mixnet +incoming: mixnet → IpMixStream → NymIprBridge → channel → NymAsyncDevice (Stream) → smoltcp +``` + +tokio-smoltcp handles all the hard parts (smoltcp polling, TCP state machines, +port allocation, waker management). We just give it a device that produces and +consumes raw IP packets — `NymAsyncDevice` wraps the mpsc channel ends in the +`Stream`/`Sink` traits that tokio-smoltcp requires. + +## Key design decisions + +- **Single async device adapter.** All traffic flows through one + `NymAsyncDevice`. If you need a new transport type (e.g. ICMP), add a method + to `Tunnel` rather than introducing a separate device — the device and bridge + don't need to change. smoltcp already supports ICMP sockets; you'd enable + the `socket-icmp` feature in `Cargo.toml`, add a method like + `Tunnel::icmp_socket()` that calls the appropriate `Net` method, and expose + the socket type via a re-export in `lib.rs`. + +- **Tokio-only.** The bridge, SDK (`IpMixStream`, `MixnetClient`), and shutdown + signaling are tokio-based. The data-plane channels use `futures::channel::mpsc` + because `UnboundedSender` implements `Sink` — required by tokio-smoltcp's + `AsyncDevice` trait. An earlier version had a sync smoltcp `Device` adapter + for use without tokio-smoltcp, but it still required a tokio runtime + underneath (for the bridge and SDK), so it provided no real runtime + independence — just duplicated the bridging logic. If alternative-runtime + support is ever needed, it would require swapping out the bridge, SDK, and + channel layers — a separate crate, not a feature flag on this one. + +- **Unbounded channels.** The channels between the device and bridge are + unbounded. Backpressure is handled at the mixnet layer (IPR protocol), not + at the channel level. If that assumption changes, consider bounded channels + with a drop policy. + +- **`Medium::Ip` (no Ethernet framing).** Raw IP packets go in and out, + matching what the IPR protocol expects. diff --git a/smolmix/core/src/bridge.rs b/smolmix/core/src/bridge.rs new file mode 100644 index 0000000000..39577aba71 --- /dev/null +++ b/smolmix/core/src/bridge.rs @@ -0,0 +1,164 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-2.0-only + +use crate::error::SmolmixError; +use futures::channel::mpsc; +use futures::StreamExt; +use nym_ip_packet_requests::codec::MultiIpPacketCodec; +use nym_sdk::ipr_wrapper::IpMixStream; +use tokio::sync::oneshot; +use tracing::{debug, error, info, trace, warn}; + +/// Asynchronous bridge between the smoltcp device and the Nym mixnet. +/// +/// Runs as a background task, shuttling raw IP packets in both directions: +/// +/// **Outgoing** (smoltcp → mixnet): receives packets from the device via channel, +/// bundles them with [`MultiIpPacketCodec`] (required by the IPR protocol), and +/// sends them through the mixnet. +/// +/// **Incoming** (mixnet → smoltcp): polls the mixnet for packets and forwards +/// them to the device via channel for smoltcp consumption. +pub(crate) struct NymIprBridge { + stream: IpMixStream, + /// Receives outgoing packets from the device (smoltcp → bridge → mixnet). + outgoing_rx: mpsc::UnboundedReceiver>, + /// Sends incoming packets to the device (mixnet → bridge → smoltcp). + /// + /// Unbounded: backpressure is handled at the mixnet layer (IPR protocol), + /// not here. If that changes, consider bounded channels with a drop policy. + incoming_tx: mpsc::UnboundedSender>, + shutdown_rx: oneshot::Receiver<()>, +} + +/// Handle for signaling the bridge to shut down gracefully. +pub(crate) struct BridgeShutdownHandle { + tx: Option>, +} + +impl BridgeShutdownHandle { + /// Signal the bridge to shut down gracefully. + /// + /// Sends a one-shot signal that breaks the bridge event loop. The bridge + /// then calls `IpMixStream::disconnect()` before returning. Consumes + /// `self` — can only be called once. + /// + /// If this handle is dropped without calling `shutdown()`, the `Drop` + /// impl sends the signal automatically. + pub(crate) fn shutdown(mut self) { + if let Some(tx) = self.tx.take() { + let _ = tx.send(()); + } + } +} + +impl Drop for BridgeShutdownHandle { + fn drop(&mut self) { + if let Some(tx) = self.tx.take() { + let _ = tx.send(()); + } + } +} + +impl NymIprBridge { + /// Create a new bridge and its associated shutdown handle. + /// + /// Returns `(bridge, shutdown_handle)`. + /// + /// # Parameters + /// - `stream` — the connected `IpMixStream` (owns the mixnet client) + /// - `outgoing_rx` — receives raw IP packets from the smoltcp device + /// - `incoming_tx` — sends raw IP packets to the smoltcp device + pub(crate) fn new( + stream: IpMixStream, + outgoing_rx: mpsc::UnboundedReceiver>, + incoming_tx: mpsc::UnboundedSender>, + ) -> (Self, BridgeShutdownHandle) { + let (shutdown_tx, shutdown_rx) = oneshot::channel(); + ( + Self { + stream, + outgoing_rx, + incoming_tx, + shutdown_rx, + }, + BridgeShutdownHandle { + tx: Some(shutdown_tx), + }, + ) + } + + /// Runs the bridge event loop. + /// + /// Should be spawned via `tokio::spawn`. The loop exits when a shutdown + /// signal is received, channels close, or an unrecoverable error occurs. + /// + /// # Cancel safety + /// + /// `IpMixStream::handle_incoming()` is **not** cancel-safe — its internal + /// `FramedRead` buffers partial frames, and it mutates connection state after + /// awaiting. In `tokio::select!`, the shutdown branch can cancel a pending + /// `handle_incoming()` call, potentially losing buffered data. This is + /// acceptable during shutdown but worth noting for future changes. + pub(crate) async fn run(mut self) -> Result<(), SmolmixError> { + info!("Starting bridge"); + let mut packets_sent: u64 = 0; + let mut packets_received: u64 = 0; + + loop { + tokio::select! { + _ = &mut self.shutdown_rx => { + info!(packets_sent, packets_received, "Bridge received shutdown signal"); + break; + } + + Some(packet) = self.outgoing_rx.next() => { + trace!(len = packet.len(), "Sending packet to mixnet"); + + // IPR expects packets wrapped in MultiIpPacketCodec framing. + let bundled = MultiIpPacketCodec::bundle_one_packet(packet.into()); + if let Err(e) = self.stream.send_ip_packet(&bundled).await { + error!("Failed to send packet through mixnet: {e}"); + } else { + packets_sent += 1; + debug!(packets_sent, "Packet sent"); + } + } + + result = self.stream.handle_incoming() => { + match result { + Ok(packets) if !packets.is_empty() => { + trace!(count = packets.len(), "Received packets from mixnet"); + for packet in packets { + if self.incoming_tx.unbounded_send(packet.to_vec()).is_err() { + error!("Device channel closed"); + return Err(SmolmixError::ChannelClosed); + } + packets_received += 1; + } + debug!(packets_received, "Packets received"); + } + Ok(_) => {} // empty batch, keep polling + Err(e) => { + // handle_incoming() internally uses a 10-second timeout, + // so this won't busy-loop on persistent errors. + warn!("Mixnet receive error: {e}"); + } + } + } + + else => { + info!(packets_sent, packets_received, "All channels closed, shutting down"); + break; + } + } + } + + // disconnect() internally waits for all SDK tasks via TaskTracker. + info!("Disconnecting from mixnet..."); + self.stream.disconnect().await; + info!("Disconnected"); + + Ok(()) + } +} diff --git a/smolmix/core/src/device.rs b/smolmix/core/src/device.rs new file mode 100644 index 0000000000..012c3fa768 --- /dev/null +++ b/smolmix/core/src/device.rs @@ -0,0 +1,94 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-2.0-only + +//! Async device adapter for tokio-smoltcp. +//! +//! Wraps mpsc channel ends (connected to [`NymIprBridge`](crate::bridge::NymIprBridge)) +//! in the [`Stream`]/[`Sink`] traits that tokio-smoltcp requires. See the +//! [crate-level docs](crate) for how this fits into the full stack. + +use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use futures::channel::mpsc; +use futures::{Sink, Stream}; +use smoltcp::phy::{DeviceCapabilities, Medium}; +use tokio_smoltcp::device::AsyncDevice; + +/// Async adapter bridging mpsc channels to tokio-smoltcp's [`AsyncDevice`] trait. +/// +/// Incoming packets (mixnet → smoltcp) arrive via the `rx` channel as a [`Stream`]. +/// Outgoing packets (smoltcp → mixnet) are sent via the `tx` channel as a [`Sink`]. +pub(crate) struct NymAsyncDevice { + rx: mpsc::UnboundedReceiver>, + tx: mpsc::UnboundedSender>, + capabilities: DeviceCapabilities, +} + +impl NymAsyncDevice { + pub(crate) fn new( + rx: mpsc::UnboundedReceiver>, + tx: mpsc::UnboundedSender>, + ) -> Self { + let mut capabilities = DeviceCapabilities::default(); + capabilities.medium = Medium::Ip; + capabilities.max_transmission_unit = 1500; + capabilities.max_burst_size = Some(1); + + Self { + rx, + tx, + capabilities, + } + } +} + +// tokio-smoltcp calls poll_next() in its reactor loop to feed packets into the +// smoltcp Interface for processing. +impl Stream for NymAsyncDevice { + type Item = io::Result>; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.rx).poll_next(cx).map(|opt| opt.map(Ok)) + } +} + +// When smoltcp produces a packet (e.g. TCP SYN, data segment, UDP datagram), +// tokio-smoltcp sends it here and we forward it to the bridge for mixnet delivery. +// +// Delegates to the built-in Sink impl on futures::channel::mpsc::UnboundedSender, +// which handles channel liveness checks (poll_ready) and disconnect (poll_close). +impl Sink> for NymAsyncDevice { + type Error = io::Error; + + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.tx) + .poll_ready(cx) + .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "bridge channel closed")) + } + + fn start_send(mut self: Pin<&mut Self>, item: Vec) -> Result<(), Self::Error> { + Pin::new(&mut self.tx) + .start_send(item) + .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "bridge channel closed")) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.tx) + .poll_flush(cx) + .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "bridge channel closed")) + } + + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.tx) + .poll_close(cx) + .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "bridge channel closed")) + } +} + +impl AsyncDevice for NymAsyncDevice { + fn capabilities(&self) -> &DeviceCapabilities { + &self.capabilities + } +} diff --git a/smolmix/core/src/error.rs b/smolmix/core/src/error.rs new file mode 100644 index 0000000000..226fcb9efd --- /dev/null +++ b/smolmix/core/src/error.rs @@ -0,0 +1,19 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-2.0-only + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum SmolmixError { + #[error("Channel closed")] + ChannelClosed, + + #[error("Not connected to IPR")] + NotConnected, + + #[error("Nym SDK error: {0}")] + NymSdk(#[from] nym_sdk::Error), + + #[error("IO error: {0}")] + Io(#[from] std::io::Error), +} diff --git a/smolmix/core/src/lib.rs b/smolmix/core/src/lib.rs new file mode 100644 index 0000000000..45a0392ab4 --- /dev/null +++ b/smolmix/core/src/lib.rs @@ -0,0 +1,62 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-2.0-only + +#![doc = include_str!("ARCHITECTURE.md")] + +mod bridge; +mod device; +mod error; +mod tunnel; + +/// Error type for all fallible smolmix operations. +pub use error::SmolmixError; + +/// The IPv4/IPv6 address pair allocated to this tunnel by the IPR. +pub use tunnel::IpPair; + +/// A Nym mixnet address, used to target a specific IPR exit node. +pub use tunnel::Recipient; + +/// A TCP stream routed through the mixnet. Implements `AsyncRead + AsyncWrite`. +/// +/// Obtained via [`Tunnel::tcp_connect`]. Works as a drop-in replacement for +/// `tokio::net::TcpStream` with tokio-rustls, hyper, tokio-tungstenite, etc. +/// +/// ```no_run +/// # async fn example() -> Result<(), Box> { +/// # let tunnel = smolmix::Tunnel::new().await?; +/// use tokio::io::{AsyncReadExt, AsyncWriteExt}; +/// +/// let mut stream = tunnel.tcp_connect("1.1.1.1:80".parse()?).await?; +/// stream.write_all(b"GET / HTTP/1.1\r\nHost: 1.1.1.1\r\nConnection: close\r\n\r\n").await?; +/// let mut buf = Vec::new(); +/// stream.read_to_end(&mut buf).await?; +/// # Ok(()) +/// # } +/// ``` +pub use tunnel::TcpStream; + +/// A mixnet tunnel providing TCP and UDP socket access. +pub use tunnel::Tunnel; + +/// Builder for configuring and creating a [`Tunnel`]. +/// +/// See [`Tunnel::builder()`] for usage. +pub use tunnel::TunnelBuilder; + +/// A UDP socket routed through the mixnet. Supports `send_to` / `recv_from`. +/// +/// Obtained via [`Tunnel::udp_socket`] or [`Tunnel::udp_socket_on`]. +/// +/// ```no_run +/// # async fn example() -> Result<(), Box> { +/// # let tunnel = smolmix::Tunnel::new().await?; +/// let udp = tunnel.udp_socket().await?; +/// udp.send_to(b"hello", "1.1.1.1:9999".parse()?).await?; +/// +/// let mut buf = [0u8; 1024]; +/// let (len, _src) = udp.recv_from(&mut buf).await?; +/// # Ok(()) +/// # } +/// ``` +pub use tunnel::UdpSocket; diff --git a/smolmix/core/src/tunnel.rs b/smolmix/core/src/tunnel.rs new file mode 100644 index 0000000000..b59b86953b --- /dev/null +++ b/smolmix/core/src/tunnel.rs @@ -0,0 +1,361 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-2.0-only + +//! High-level tunnel providing TCP and UDP sockets over the Nym mixnet. +//! +//! See the [crate-level docs](crate) for the full architecture diagram. +//! +//! The returned [`TcpStream`] implements `tokio::io::AsyncRead + AsyncWrite`, so it +//! works transparently with the entire async Rust ecosystem: tokio-rustls for TLS, +//! tokio-tungstenite for WebSockets, hyper for HTTP, etc. + +use std::net::SocketAddr; +use std::sync::Arc; + +use futures::channel::mpsc; +pub use nym_ip_packet_requests::IpPair; +use nym_sdk::ipr_wrapper::IpMixStream; +use smoltcp::iface::Config; +use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr, Ipv4Address}; +use tokio::sync::Mutex; +use tokio::task::JoinHandle; +use tracing::info; + +use crate::bridge::{BridgeShutdownHandle, NymIprBridge}; +use crate::device::NymAsyncDevice; +use crate::SmolmixError; +use tokio_smoltcp::{Net, NetConfig}; + +pub use nym_sdk::mixnet::Recipient; +pub use tokio_smoltcp::{TcpStream, UdpSocket}; + +struct ShutdownState { + bridge_shutdown: BridgeShutdownHandle, + bridge_handle: JoinHandle>, +} + +struct TunnelInner { + /// tokio-smoltcp network stack. Its methods take &self, so multiple tasks can + /// open sockets concurrently without locking. + net: Net, + allocated_ips: IpPair, + /// Mutex only protects shutdown — called once, not on the hot path. + shutdown: Mutex>, +} + +/// A mixnet tunnel providing TCP and UDP socket access. +/// +/// `Tunnel` manages a smoltcp network stack connected to the Nym mixnet via an IPR +/// (Internet Packet Router). It spawns a background bridge task and a network reactor, +/// then provides familiar socket APIs on top. +/// +/// +/// # Shutdown +/// +/// Call [`shutdown()`](Self::shutdown) for a clean disconnect. Rust has no async `Drop`, +/// so dropping without calling `shutdown()` triggers a fire-and-forget cleanup via the +/// oneshot channel — the bridge will still shut down, but the caller can't await it. +/// +/// # Examples +/// +/// ```no_run +/// # async fn example() -> Result<(), Box> { +/// use smolmix::Tunnel; +/// use tokio::io::{AsyncReadExt, AsyncWriteExt}; +/// +/// let tunnel = Tunnel::new().await?; +/// +/// // TCP — connect and use like any async stream +/// let mut tcp = tunnel.tcp_connect("1.1.1.1:80".parse()?).await?; +/// tcp.write_all(b"GET / HTTP/1.1\r\nHost: 1.1.1.1\r\nConnection: close\r\n\r\n").await?; +/// let mut buf = Vec::new(); +/// tcp.read_to_end(&mut buf).await?; +/// +/// // UDP — datagrams over the mixnet +/// let udp = tunnel.udp_socket().await?; +/// udp.send_to(b"hello", "1.1.1.1:9999".parse()?).await?; +/// +/// // Share across tasks (cheap Arc-based clone) +/// let t2 = tunnel.clone(); +/// tokio::spawn(async move { +/// let _tcp2 = t2.tcp_connect("93.184.216.34:80".parse().unwrap()).await.unwrap(); +/// }); +/// +/// tunnel.shutdown().await; +/// # Ok(()) +/// # } +/// ``` +/// +/// See also the repository examples: `tcp`, `udp`, `websocket`. +#[derive(Clone)] +pub struct Tunnel { + inner: Arc, +} + +/// Builder for configuring and creating a [`Tunnel`]. +/// +/// Use [`Tunnel::builder()`] to create a new builder. +/// +/// # Examples +/// +/// ```no_run +/// # async fn example() -> Result<(), Box> { +/// use smolmix::Tunnel; +/// +/// // Auto-discover the best IPR: +/// let tunnel = Tunnel::builder().build().await?; +/// +/// // Or specify an IPR exit node: +/// use smolmix::Recipient; +/// let ipr: Recipient = "gateway-address...".parse()?; +/// let tunnel = Tunnel::builder().ipr_address(ipr).build().await?; +/// # Ok(()) +/// # } +/// ``` +/// +/// For full control over the mixnet client (credentials, gateway selection, +/// storage, etc.), configure an [`IpMixStream`] directly and pass it to +/// [`Tunnel::from_stream()`]. Deeper builder integration with `MixnetClientBuilder` +/// will require upstream SDK changes to expose `IpMixStream` internals (TODO). +pub struct TunnelBuilder { + ipr_address: Option, +} + +impl TunnelBuilder { + /// Target a specific IPR exit node instead of auto-discovering one. + pub fn ipr_address(mut self, addr: Recipient) -> Self { + self.ipr_address = Some(addr); + self + } + + /// Build and connect the tunnel. + pub async fn build(self) -> Result { + let stream = match self.ipr_address { + Some(addr) => IpMixStream::new_with_ipr(addr).await?, + None => IpMixStream::new().await?, + }; + Tunnel::from_stream(stream).await + } +} + +impl Tunnel { + /// Create a [`TunnelBuilder`] for configuring the tunnel before connecting. + /// + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// use smolmix::Tunnel; + /// let tunnel = Tunnel::builder().build().await?; + /// # Ok(()) + /// # } + /// ``` + pub fn builder() -> TunnelBuilder { + TunnelBuilder { ipr_address: None } + } + + /// Create a new tunnel, automatically discovering the best IPR exit node. + /// + /// Shorthand for `Tunnel::builder().build().await`. + /// + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// use smolmix::Tunnel; + /// let tunnel = Tunnel::new().await?; + /// let tcp = tunnel.tcp_connect("1.1.1.1:443".parse()?).await?; + /// # Ok(()) + /// # } + /// ``` + pub async fn new() -> Result { + Self::builder().build().await + } + + /// Create a new tunnel connected to a specific IPR exit node. + /// + /// Shorthand for `Tunnel::builder().ipr_address(addr).build().await`. + /// + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// use smolmix::{Recipient, Tunnel}; + /// let ipr: Recipient = "gateway-address...".parse()?; + /// let tunnel = Tunnel::new_with_ipr(ipr).await?; + /// # Ok(()) + /// # } + /// ``` + pub async fn new_with_ipr(ipr_address: Recipient) -> Result { + Self::builder().ipr_address(ipr_address).build().await + } + + /// Create a tunnel from a pre-configured [`IpMixStream`]. + /// + /// Use this for full control over the mixnet client (credentials, gateway + /// selection, storage, etc.) — configure the `IpMixStream` upstream and + /// pass it in directly. + pub async fn from_stream(ipr_stream: IpMixStream) -> Result { + ipr_stream + .check_connected() + .map_err(|_| SmolmixError::NotConnected)?; + + let allocated_ips = *ipr_stream.allocated_ips(); + + // Wire up two channel pairs connecting the bridge (async mixnet I/O) to the + // async device adapter (which tokio-smoltcp polls for raw IP packets): + // + // outgoing: smoltcp → NymAsyncDevice.Sink → outgoing_tx → outgoing_rx → Bridge → mixnet + // incoming: mixnet → Bridge → incoming_tx → incoming_rx → NymAsyncDevice.Stream → smoltcp + let (outgoing_tx, outgoing_rx) = mpsc::unbounded(); + let (incoming_tx, incoming_rx) = mpsc::unbounded(); + + // Bridge runs as a background task, shuttling packets between channels and IpMixStream. + let (bridge, bridge_shutdown) = NymIprBridge::new(ipr_stream, outgoing_rx, incoming_tx); + let bridge_handle = tokio::spawn(bridge.run()); + + // NymAsyncDevice wraps the channel ends as Stream + Sink, which is all + // tokio-smoltcp needs to drive the smoltcp Interface internally. + let device = NymAsyncDevice::new(incoming_rx, outgoing_tx); + + // Configure smoltcp: raw IP mode (no Ethernet), /32 for our allocated IP, + // default route via unspecified (the IPR handles actual routing). + let iface_config = Config::new(HardwareAddress::Ip); + let net_config = NetConfig::new( + iface_config, + IpCidr::new(IpAddress::from(allocated_ips.ipv4), 32), + vec![IpAddress::from(Ipv4Address::UNSPECIFIED)], + ); + + // Net::new spawns the smoltcp reactor as a background task. From here on, + // tcp_connect/udp_bind create sockets managed by that reactor. + let net = Net::new(device, net_config); + + info!("Tunnel ready, allocated IP: {}", allocated_ips.ipv4); + + Ok(Self { + inner: Arc::new(TunnelInner { + net, + allocated_ips, + shutdown: Mutex::new(Some(ShutdownState { + bridge_shutdown, + bridge_handle, + })), + }), + }) + } + + /// Open a TCP connection to `addr` through the mixnet. + /// + /// The returned [`TcpStream`] implements `tokio::io::AsyncRead + AsyncWrite`, + /// so it works transparently with tokio-rustls, hyper, tokio-tungstenite, and + /// any other async I/O consumer. + /// + /// # Errors + /// + /// Returns [`SmolmixError::Io`] if the TCP handshake fails (connection + /// refused, timeout, etc.) or if the tunnel has been shut down. + /// + /// # Examples + /// + /// Raw HTTP request: + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// # let tunnel = smolmix::Tunnel::new().await?; + /// use tokio::io::{AsyncReadExt, AsyncWriteExt}; + /// + /// let mut tcp = tunnel.tcp_connect("1.1.1.1:80".parse()?).await?; + /// tcp.write_all(b"GET / HTTP/1.1\r\nHost: 1.1.1.1\r\nConnection: close\r\n\r\n").await?; + /// + /// let mut response = Vec::new(); + /// tcp.read_to_end(&mut response).await?; + /// # Ok(()) + /// # } + /// ``` + /// + /// TLS via tokio-rustls (the stream is a drop-in for `tokio::net::TcpStream`): + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// # let tunnel = smolmix::Tunnel::new().await?; + /// use rustls::pki_types::ServerName; + /// use tokio_rustls::TlsConnector; + /// + /// let tcp = tunnel.tcp_connect("93.184.216.34:443".parse()?).await?; + /// # let connector: TlsConnector = todo!(); + /// let tls = connector.connect(ServerName::try_from("example.com")?.to_owned(), tcp).await?; + /// // `tls` implements AsyncRead + AsyncWrite — use with hyper, tungstenite, etc. + /// # Ok(()) + /// # } + /// ``` + pub async fn tcp_connect(&self, addr: SocketAddr) -> Result { + Ok(self.inner.net.tcp_connect(addr).await?) + } + + /// Create a UDP socket bound to an ephemeral port. + /// + /// The port is chosen by smoltcp's allocator. Use [`udp_socket_on`](Self::udp_socket_on) + /// if you need a specific port (e.g. for a protocol that expects replies on + /// a known port). + /// + /// The returned [`UdpSocket`] supports `send_to` / `recv_from` for datagram I/O. + /// + /// # Examples + /// + /// Send a DNS query and read the response: + /// ```no_run + /// # async fn example() -> Result<(), Box> { + /// # let tunnel = smolmix::Tunnel::new().await?; + /// let udp = tunnel.udp_socket().await?; + /// + /// // Send a raw DNS query to Cloudflare + /// let query = b"\x12\x34\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\ + /// \x07example\x03com\x00\x00\x01\x00\x01"; + /// udp.send_to(query, "1.1.1.1:53".parse()?).await?; + /// + /// let mut buf = [0u8; 512]; + /// let (len, _src) = udp.recv_from(&mut buf).await?; + /// println!("Got {} bytes back", len); + /// # Ok(()) + /// # } + /// ``` + pub async fn udp_socket(&self) -> Result { + let addr: SocketAddr = ([0, 0, 0, 0], 0).into(); + Ok(self.inner.net.udp_bind(addr).await?) + } + + /// Create a UDP socket bound to a specific local port. + /// + /// Binds to `0.0.0.0:` on the tunnel's virtual interface. Use this when + /// the remote side expects replies on a well-known port, or when you need + /// multiple sockets on distinct ports. + pub async fn udp_socket_on(&self, port: u16) -> Result { + let addr: SocketAddr = ([0, 0, 0, 0], port).into(); + Ok(self.inner.net.udp_bind(addr).await?) + } + + /// The IPv4/IPv6 address pair allocated to this tunnel by the IPR. + /// + /// Available immediately after construction. The IPv4 address is assigned as + /// a /32 on the tunnel's virtual interface — all traffic to/from external + /// hosts appears to originate from this IP at the exit gateway. + pub fn allocated_ips(&self) -> IpPair { + self.inner.allocated_ips + } + + /// Gracefully shut down the tunnel. + /// + /// Signals the bridge to disconnect from the mixnet and waits for it to finish. + /// The smoltcp reactor stops when all `Tunnel` clones are dropped. + /// + /// If the `Tunnel` is dropped without calling `shutdown()`, cleanup still happens: + /// dropping the `Arc` drops the oneshot sender inside `ShutdownState`, + /// which resolves the bridge's `shutdown_rx` and triggers its shutdown path. However, + /// the drop path is fire-and-forget — call `shutdown()` explicitly if you need to + /// wait for the mixnet disconnect to complete. + /// + /// After shutdown, new socket operations (`tcp_connect`, `udp_socket`) will fail + /// with IO errors — the bridge channels are closed. + pub async fn shutdown(&self) { + let mut state = self.inner.shutdown.lock().await; + if let Some(s) = state.take() { + info!("Shutting down tunnel"); + s.bridge_shutdown.shutdown(); + let _ = s.bridge_handle.await; + info!("Tunnel shut down"); + } + } +} diff --git a/tools/echo-server/Cargo.toml b/tools/echo-server/Cargo.toml index 4f9ec4de02..73f57d986d 100644 --- a/tools/echo-server/Cargo.toml +++ b/tools/echo-server/Cargo.toml @@ -2,11 +2,11 @@ name = "echo-server" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true publish = false diff --git a/tools/internal/check_cargo_toml_field_order.py b/tools/internal/check_cargo_toml_field_order.py new file mode 100644 index 0000000000..dbe3ddfa64 --- /dev/null +++ b/tools/internal/check_cargo_toml_field_order.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Check [package] field ordering and required fields in Cargo.toml files.""" +import re, sys + +ORDER = [ + "name", "description", "version", "authors", "edition", "license", + "repository", "homepage", "documentation", "rust-version", "readme", + "publish", "keywords", "exclude", "build", "links", "default-run", + "resolver", +] + +# Required when publish = true or publish.workspace = true +REQUIRED = { + "name", "description", "version", "authors", "edition", "license", + "repository", "homepage", "documentation", "rust-version", "readme", + "publish", +} + +bad = [] +for path in sys.argv[1:]: + fields, values, in_pkg = [], {}, False + for line in open(path): + s = line.strip() + if s == "[package]": + in_pkg = True + continue + if in_pkg and s.startswith("["): + break + if in_pkg: + m = re.match(r"^(\w[\w-]*)", s) + if m and "=" in line: + fields.append(m.group(1)) + values[m.group(1)] = s + + if not fields: + continue + + unknown = [f for f in fields if f not in ORDER] + if unknown: + bad.append((path, f"unknown field(s): {', '.join(unknown)}")) + continue + + expected = sorted(fields, key=ORDER.index) + if fields != expected: + first = next(a for a, b in zip(fields, expected) if a != b) + bad.append((path, f"field ordering: first mismatch is '{first}'")) + + # publish must always be present (explicit intent) + field_set = set(fields) + if "publish" not in field_set: + bad.append((path, "missing 'publish' field (must be explicit)")) + # Check remaining required fields when publishable + elif "true" in values["publish"] or "workspace" in values["publish"]: + missing = sorted(REQUIRED - field_set, key=ORDER.index) + if missing: + bad.append((path, f"missing required: {', '.join(missing)}")) + +if bad: + print("[package] field issues:") + for path, reason in bad: + print(f" {path} ({reason})") + print("\nCanonical order:") + for f in ORDER: + req = " (required)" if f in REQUIRED else "" + print(f" - {f}{req}") + sys.exit(1) diff --git a/tools/internal/check_publish_preflight.py b/tools/internal/check_publish_preflight.py new file mode 100644 index 0000000000..5e6f857051 --- /dev/null +++ b/tools/internal/check_publish_preflight.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 + +import json +import pathlib +import subprocess +import sys +from collections import defaultdict + + +def dependency_section(dep): + kind = dep.get("kind") or "normal" + section = { + "normal": "dependencies", + "dev": "dev-dependencies", + "build": "build-dependencies", + }.get(kind, f"{kind}-dependencies") + target = dep.get("target") + if target: + return f"target.{target}.{section}" + return section + + +def manifest_member(root, manifest_path): + manifest_parent = pathlib.Path(manifest_path).resolve().parent + try: + return str(manifest_parent.relative_to(root)) + except ValueError: + return str(manifest_parent) + + +def publish_status(pkg): + publish = pkg.get("publish") + if publish is None: + return True, "publishable to crates.io" + + if isinstance(publish, list): + if not publish: + return False, "publish disabled (`publish = false`)" + if "crates-io" in publish: + return True, "publishable to crates.io" + registries = ", ".join(publish) + return False, f"publish restricted to non-crates.io registries ({registries})" + + return False, f"unrecognized `publish` setting: {publish!r}" + + +def main(): + root = pathlib.Path(".").resolve() + metadata = json.loads( + subprocess.check_output( + ["cargo", "metadata", "--no-deps", "--format-version", "1"], + text=True, + ) + ) + packages_by_id = {pkg["id"]: pkg for pkg in metadata["packages"]} + workspace_ids = set(metadata["workspace_members"]) + workspace_packages = [ + packages_by_id[pkg_id] for pkg_id in workspace_ids if pkg_id in packages_by_id + ] + workspace_by_name = {pkg["name"]: pkg for pkg in workspace_packages} + workspace_dir_to_name = { + str(pathlib.Path(pkg["manifest_path"]).resolve().parent): pkg["name"] + for pkg in workspace_packages + } + + package_info = {} + for pkg in workspace_packages: + name = pkg["name"] + member = manifest_member(root, pkg["manifest_path"]) + explicitly_publishable, publish_reason = publish_status(pkg) + package_info[name] = { + "pkg": pkg, + "member": member, + "explicitly_publishable": explicitly_publishable, + "publish_reason": publish_reason, + } + + direct_issues = defaultdict(set) + workspace_deps = defaultdict(list) + + for name, info in package_info.items(): + pkg = info["pkg"] + member = info["member"] + explicitly_publishable = info["explicitly_publishable"] + + if not explicitly_publishable: + direct_issues[name].add(info["publish_reason"]) + continue + + for field in ("description", "license", "repository"): + value = pkg.get(field) + if not isinstance(value, str) or not value.strip(): + direct_issues[name].add(f"missing required field '{field}'") + + for dep in pkg.get("dependencies", []): + section = dependency_section(dep) + dep_name = dep["name"] + dep_source = dep.get("source") + + dep_workspace_name = workspace_by_name.get(dep_name, {}).get("name") + dep_path = dep.get("path") + if dep_workspace_name is None and dep_path: + dep_workspace_name = workspace_dir_to_name.get( + str(pathlib.Path(dep_path).resolve()) + ) + + if dep_path and dep.get("req") in ("*", ""): + direct_issues[name].add( + f"{section}: path dependency '{dep_name}' has no explicit version ({dep_path})" + ) + + if dep_workspace_name: + dep_info = package_info[dep_workspace_name] + if not dep_info["explicitly_publishable"]: + direct_issues[name].add( + f"{section}: depends on non-publishable workspace crate '{dep_workspace_name}' ({dep_info['publish_reason']})" + ) + continue + workspace_deps[name].append((dep_workspace_name, section)) + continue + + if dep_source and not dep_source.startswith("registry+"): + direct_issues[name].add( + f"{section}: non-registry dependency '{dep_name}' from '{dep_source}'" + ) + + effective_issues = {} + + def collect_effective_issues(crate_name, stack): + cached = effective_issues.get(crate_name) + if cached is not None: + return cached + + issues = set(direct_issues.get(crate_name, set())) + stack = stack | {crate_name} + + for dep_name, dep_section in workspace_deps.get(crate_name, []): + dep_info = package_info[dep_name] + if not dep_info["explicitly_publishable"]: + issues.add( + f"{dep_section}: depends on non-publishable workspace crate '{dep_name}' ({dep_info['publish_reason']})" + ) + continue + + if dep_name in stack: + continue + + dep_issues = collect_effective_issues(dep_name, stack) + if dep_issues: + issues.add( + f"{dep_section}: depends on blocked workspace crate '{dep_name}'" + ) + + effective_issues[crate_name] = issues + return issues + + for crate_name in package_info: + collect_effective_issues(crate_name, set()) + + publish_targets = sorted( + name for name, info in package_info.items() if info["explicitly_publishable"] + ) + root_blockers = sorted( + name + for name in publish_targets + if direct_issues.get(name) + ) + transitive_blocked = sorted( + name + for name in publish_targets + if not direct_issues.get(name) and effective_issues.get(name) + ) + + disabled_by_config = sorted( + name for name, info in package_info.items() if not info["explicitly_publishable"] + ) + + print("Publishability preflight report:") + print(f"- workspace crates inspected: {len(package_info)}") + print(f"- crates configured for crates.io publish: {len(publish_targets)}") + print(f"- root blockers (direct issues): {len(root_blockers)}") + print(f"- downstream blocked crates (transitive): {len(transitive_blocked)}") + print(f"- crates excluded by config (publish = false / restricted): {len(disabled_by_config)}") + + if root_blockers: + print("\nAction required: root blockers") + for crate_name in root_blockers: + info = package_info[crate_name] + print(f"- {crate_name} ({info['member']})") + for issue in sorted(direct_issues[crate_name]): + print(f" - {issue}") + + if transitive_blocked: + print("\nDownstream blocked crates") + print("- These crates have no direct issue; they are blocked by dependencies listed below.") + for crate_name in transitive_blocked: + info = package_info[crate_name] + blockers = set() + for dep_name, dep_section in workspace_deps.get(crate_name, []): + dep_info = package_info[dep_name] + if not dep_info["explicitly_publishable"] or effective_issues.get(dep_name): + blockers.add(f"{dep_name} via {dep_section}") + + print(f"- {crate_name} ({info['member']})") + for blocker in sorted(blockers): + print(f" - blocked by {blocker}") + + if root_blockers or transitive_blocked: + print("\nPreflight checks failed:") + print(f"- {len(root_blockers) + len(transitive_blocked)} crate(s) configured for crates.io publish are blocked.") + sys.exit(1) + + print("\nPreflight checks passed.") + + +if __name__ == "__main__": + main() diff --git a/tools/internal/contract-state-importer/importer-cli/Cargo.toml b/tools/internal/contract-state-importer/importer-cli/Cargo.toml index 143b18ffbb..63e0aa5b3d 100644 --- a/tools/internal/contract-state-importer/importer-cli/Cargo.toml +++ b/tools/internal/contract-state-importer/importer-cli/Cargo.toml @@ -2,11 +2,11 @@ name = "importer-cli" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/tools/internal/contract-state-importer/importer-contract/Cargo.toml b/tools/internal/contract-state-importer/importer-contract/Cargo.toml index 72f0476206..99290faff4 100644 --- a/tools/internal/contract-state-importer/importer-contract/Cargo.toml +++ b/tools/internal/contract-state-importer/importer-contract/Cargo.toml @@ -2,11 +2,11 @@ name = "importer-contract" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true readme.workspace = true publish = false diff --git a/tools/internal/localnet-orchestrator/Cargo.toml b/tools/internal/localnet-orchestrator/Cargo.toml index 7aef726f07..8d6421cb3f 100644 --- a/tools/internal/localnet-orchestrator/Cargo.toml +++ b/tools/internal/localnet-orchestrator/Cargo.toml @@ -2,11 +2,11 @@ name = "localnet-orchestrator" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/tools/internal/localnet-orchestrator/dkg-bypass-contract/Cargo.toml b/tools/internal/localnet-orchestrator/dkg-bypass-contract/Cargo.toml index 5074d8d91f..895f133786 100644 --- a/tools/internal/localnet-orchestrator/dkg-bypass-contract/Cargo.toml +++ b/tools/internal/localnet-orchestrator/dkg-bypass-contract/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "dkg-bypass-contract" version = "0.1.0" -edition = { workspace = true } authors = { workspace = true } +edition = { workspace = true } license = { workspace = true } repository = { workspace = true } publish = false diff --git a/tools/internal/mixnet-connectivity-check/Cargo.toml b/tools/internal/mixnet-connectivity-check/Cargo.toml index 9d2d36c9d8..34210518c4 100644 --- a/tools/internal/mixnet-connectivity-check/Cargo.toml +++ b/tools/internal/mixnet-connectivity-check/Cargo.toml @@ -2,11 +2,11 @@ name = "mixnet-connectivity-check" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/tools/internal/sdk-version-bump/Cargo.toml b/tools/internal/sdk-version-bump/Cargo.toml index ba51b1caf6..281aa976ef 100644 --- a/tools/internal/sdk-version-bump/Cargo.toml +++ b/tools/internal/sdk-version-bump/Cargo.toml @@ -2,11 +2,12 @@ name = "sdk-version-bump" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/internal/validator-status-check/Cargo.toml b/tools/internal/validator-status-check/Cargo.toml index 7b335095b7..774b5c4cbb 100644 --- a/tools/internal/validator-status-check/Cargo.toml +++ b/tools/internal/validator-status-check/Cargo.toml @@ -2,11 +2,11 @@ name = "validator-status-check" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true rust-version.workspace = true readme.workspace = true publish = false diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index e40d9c7fae..f1f8836a30 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.75" +version = "1.1.76" authors.workspace = true edition = "2021" license.workspace = true diff --git a/tools/nym-id-cli/Cargo.toml b/tools/nym-id-cli/Cargo.toml index 7d264bb2e8..f718450ac0 100644 --- a/tools/nym-id-cli/Cargo.toml +++ b/tools/nym-id-cli/Cargo.toml @@ -2,11 +2,11 @@ name = "nym-id-cli" version = "0.1.0" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/nym-lp-client/Cargo.toml b/tools/nym-lp-client/Cargo.toml index e91e052662..c33b04f366 100644 --- a/tools/nym-lp-client/Cargo.toml +++ b/tools/nym-lp-client/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "nym-lp-client" +description = "LP+KCP mixnet client" version = "0.1.0" edition = "2021" -description = "LP+KCP mixnet client" license.workspace = true publish = false diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index 279a5b404a..f8dc2249cd 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "nymvisor" -version = "0.1.40" +version = "0.1.41" authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/wasm/client/Cargo.toml b/wasm/client/Cargo.toml index 2377ddcb6d..eed416767b 100644 --- a/wasm/client/Cargo.toml +++ b/wasm/client/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "nym-client-wasm" +description = "A webassembly client which can be used to interact with the the Nym privacy platform. Wasm is used for Sphinx packet generation." +version = "1.4.1" authors = [ "Dave Hrycyszyn ", "Jedrzej Stuczynski ", ] -version = "1.4.1" edition = "2021" -keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"] license = "Apache-2.0" repository = "https://github.com/nymtech/nym" -description = "A webassembly client which can be used to interact with the the Nym privacy platform. Wasm is used for Sphinx packet generation." rust-version = "1.85" publish = false +keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"] [lib] crate-type = ["cdylib", "rlib"] diff --git a/wasm/full-nym-wasm/Cargo.toml b/wasm/full-nym-wasm/Cargo.toml index f3a7357e6c..ee6aadf5fe 100644 --- a/wasm/full-nym-wasm/Cargo.toml +++ b/wasm/full-nym-wasm/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nym-wasm-sdk" -authors = ["Jedrzej Stuczynski "] version = "1.2.2" +authors = ["Jedrzej Stuczynski "] edition = "2021" -keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"] license = "Apache-2.0" repository = "https://github.com/nymtech/nym" rust-version = "1.85" publish = false +keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/wasm/mix-fetch/Cargo.toml b/wasm/mix-fetch/Cargo.toml index 9573365b4d..8fca01cdc8 100644 --- a/wasm/mix-fetch/Cargo.toml +++ b/wasm/mix-fetch/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "mix-fetch-wasm" -authors = ["Jedrzej Stuczynski "] version = "1.4.3" +authors = ["Jedrzej Stuczynski "] edition = "2021" -keywords = ["nym", "fetch", "wasm", "webassembly", "privacy"] license = "Apache-2.0" repository = "https://github.com/nymtech/nym" rust-version = "1.85" publish = false +keywords = ["nym", "fetch", "wasm", "webassembly", "privacy"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/wasm/node-tester/Cargo.toml b/wasm/node-tester/Cargo.toml index 8a61eb06ab..88e7e5b9a5 100644 --- a/wasm/node-tester/Cargo.toml +++ b/wasm/node-tester/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nym-node-tester-wasm" -authors = ["Jedrzej Stuczynski "] version = "1.3.1" +authors = ["Jedrzej Stuczynski "] edition = "2021" -keywords = ["nym", "sphinx", "webassembly", "privacy", "tester"] license = "Apache-2.0" repository = "https://github.com/nymtech/nym" rust-version = "1.85" publish = false +keywords = ["nym", "sphinx", "webassembly", "privacy", "tester"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/wasm/zknym-lib/Cargo.toml b/wasm/zknym-lib/Cargo.toml index 385ed467f1..23cc1f50ea 100644 --- a/wasm/zknym-lib/Cargo.toml +++ b/wasm/zknym-lib/Cargo.toml @@ -2,11 +2,11 @@ name = "zknym-lib" version.workspace = true authors.workspace = true +edition.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true -edition.workspace = true -license.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html