Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 080f28d626 | |||
| ae7f29313e | |||
| ab7b88d091 | |||
| 57cd4896d9 | |||
| 193baf13b4 | |||
| 5742a67014 | |||
| e594630314 | |||
| 9c2595d9ef | |||
| 5ad1f0b61a | |||
| 04f75e7e48 | |||
| 866dcd1e39 | |||
| a8526d698e | |||
| 3f5e0cdb1f | |||
| 96239a7812 | |||
| 762cfb8709 | |||
| 9835ad3396 | |||
| f73a3ac932 | |||
| 5af4d8d862 | |||
| 2c81195e79 | |||
| 4a9066fb6b | |||
| 86cc600ea3 | |||
| 459b109b5c | |||
| 08b6be93c4 | |||
| f0d3d41a1f | |||
| 9a42cab16d | |||
| 970db22702 | |||
| 2c7df5766c | |||
| 7ca2559f99 | |||
| b9dcafa04f | |||
| 260a7de083 | |||
| 51ca727ff2 | |||
| 84db9f6bcd | |||
| 660463908d | |||
| 0be844e015 | |||
| efa6e7d7c7 | |||
| 33c783bb7c | |||
| 16059211b9 | |||
| bb6c920767 | |||
| 8c4df963c9 | |||
| af737596ca | |||
| af2c4f50b6 | |||
| 02ed64557d | |||
| 38dabd8d0d | |||
| d9de5cfa33 | |||
| bdfbfde463 | |||
| 5179f38ad2 | |||
| f4e9abcd22 | |||
| 46ebd84b02 | |||
| d8d2f99a18 | |||
| cd3ec5f3bd | |||
| 32a16ef025 | |||
| 6af4e44f55 | |||
| 3cddc594b4 | |||
| d11aaed392 | |||
| 1bead28150 | |||
| 735bed5cd7 | |||
| 12e0d34885 | |||
| 43af3b8a3b | |||
| 8ff96b11c9 | |||
| df453158d6 | |||
| abeeadb661 | |||
| 752fe7fa0f | |||
| c5ec682088 | |||
| 58a569cd26 | |||
| 2e767a2586 | |||
| dc772d8759 | |||
| 9e70c7a32d | |||
| ba5e86e842 | |||
| b7313656e9 | |||
| 2eb695088f | |||
| eb612d47c0 | |||
| 2ba7b26e5d | |||
| 4cd0f7b56f | |||
| 600bf42a95 | |||
| 748e3e4248 | |||
| 8cf1b6427a | |||
| 7a888c6fdf | |||
| 9a9bb89d89 | |||
| 4cc14ddcc4 | |||
| 2dbf9d97cb | |||
| 91b6f3cc3e | |||
| 84cccffcbd | |||
| 7de346cf89 | |||
| d6c40aee01 | |||
| af16b3f059 | |||
| b1cde0716e | |||
| 45bcdb03d8 | |||
| 0841b8701d | |||
| 7ae228d8f4 | |||
| 916d33c8c0 | |||
| 9b4b2d1a46 | |||
| aef0a52c4b | |||
| 44682b5ef0 | |||
| f282ffd8a6 | |||
| dfbeb8b1f8 | |||
| fc06fe39a2 | |||
| caa94c142f | |||
| 1a5c54084e | |||
| 49d203e18d | |||
| 51c9b012e2 | |||
| 50b1175622 | |||
| 29ee5984fb | |||
| e542b25ffc | |||
| 516d3f04cf | |||
| 9225e0a630 | |||
| 08c09781c7 | |||
| 36a4d96f34 | |||
| 139c911350 | |||
| c92de832e4 | |||
| d9d62195cb | |||
| da9115d51b | |||
| bfddc1e4c1 | |||
| 080d75204e | |||
| 1367cad99d | |||
| 4f6d65ab95 | |||
| 4292d8ac03 | |||
| dcb6de2421 | |||
| 1f5ed41bb3 | |||
| 091e98aa74 | |||
| 0e38126fc5 | |||
| ecbe192a88 | |||
| f0ee49788c | |||
| d2ff3cb88d | |||
| 873d15a5e1 | |||
| 53792cc839 | |||
| 415ef1bf13 | |||
| edfe29b738 | |||
| a4f6426bf9 | |||
| 0870911b3c | |||
| 9f23887cc0 | |||
| 8ab269fa05 | |||
| 7b75f22a8e | |||
| ca0449e03d | |||
| 224e63d275 | |||
| 3d77283056 | |||
| 7cc473005b | |||
| f874284850 | |||
| 7b6077ba64 | |||
| 0d4188785b | |||
| 86c05267c2 | |||
| b4865520a4 | |||
| f52ebfb9c3 | |||
| 6ca2a3c539 | |||
| 717c9066d6 | |||
| 2760a17323 | |||
| 4e9f1bc0ed | |||
| d35023d14b | |||
| 400aa6ba6d | |||
| 2ba74ae120 | |||
| 9a4293a5b9 | |||
| cdddb44099 |
@@ -21,7 +21,7 @@ jobs:
|
||||
run: sudo apt-get install -y rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4.0.0
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
|
||||
@@ -102,6 +102,8 @@ jobs:
|
||||
- name: Run all tests
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
NYM_API: https://sandbox-nym-api1.nymtech.net/api
|
||||
with:
|
||||
command: test
|
||||
args: --workspace
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: sudo apt-get install -y rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4.0.0
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
|
||||
@@ -16,8 +16,12 @@ jobs:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_PERMIT_COPY_RENAME: 1
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y libdbus-1-dev libmnl-dev libnftnl-dev \
|
||||
libwebkit2gtk-4.1-dev build-essential curl wget libssl-dev jq \
|
||||
libgtk-3-dev squashfs-tools libayatana-appindicator3-dev make libfuse2 unzip librsvg2-dev file \
|
||||
libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check out repository code
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
name: Integration Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "nym-api/**"
|
||||
- "tests/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
integration-tests:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
API_BASE_URL: http://localhost:8000
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev
|
||||
|
||||
- name: Build nym-api
|
||||
run: cargo build --package nym-api
|
||||
|
||||
- name: Run nym-api in the background
|
||||
run: |
|
||||
./target/debug/nym-api &
|
||||
|
||||
- name: Wait for nym-api to come alive
|
||||
run: |
|
||||
for i in {1..20}; do
|
||||
curl -sSf http://localhost:8000/v1/status/config-score-details && break
|
||||
echo "Waiting for nym-api to start..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
- name: Run integration tests
|
||||
env:
|
||||
NYM_API: https://sandbox-nym-api1.nymtech.net/api
|
||||
run: cargo test --test public-api-tests -- --nocapture
|
||||
@@ -19,9 +19,7 @@ jobs:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-ubuntu-22.04]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
runs-on: arc-ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
|
||||
@@ -18,11 +18,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
release_tag: ${{ github.ref_name }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -33,10 +29,16 @@ jobs:
|
||||
node-version: 21
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Add Rust target for x86_64-apple-darwin
|
||||
run: rustup target add x86_64-apple-darwin
|
||||
|
||||
- name: Set Cargo build target to x86_64
|
||||
run: echo "CARGO_BUILD_TARGET=x86_64-apple-darwin" >> $GITHUB_ENV
|
||||
|
||||
- name: Install the Apple developer certificate for code signing
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
@@ -66,12 +68,6 @@ jobs:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Add Rust target for x86_64-apple-darwin
|
||||
run: rustup target add x86_64-apple-darwin
|
||||
|
||||
- name: Set Cargo build target to x86_64
|
||||
run: echo "CARGO_BUILD_TARGET=x86_64-apple-darwin" >> $GITHUB_ENV
|
||||
|
||||
- name: Yarn cache clean
|
||||
shell: bash
|
||||
run: cd .. && yarn cache clean
|
||||
@@ -94,10 +90,22 @@ jobs:
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
# Tauri v2 specific environment variables
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
TAURI_NOTARIZATION_USERNAME: ${{ secrets.APPLE_ID }}
|
||||
TAURI_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
TAURI_NOTARIZATION_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
run: |
|
||||
yarn build-macx86
|
||||
yarn build-macx86
|
||||
|
||||
- name: Create app tarball
|
||||
run: |
|
||||
# Navigate to where the app bundle is and create the tarball
|
||||
cd target/x86_64-apple-darwin/release/bundle/macos
|
||||
echo "Creating tarball from app bundle"
|
||||
tar -czf nym-wallet.app.tar.gz NymWallet.app
|
||||
cd -
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -120,22 +128,10 @@ jobs:
|
||||
nym-wallet/target/x86_64-apple-darwin/release/bundle/dmg/*.dmg
|
||||
nym-wallet/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/x86_64-apple-darwin/release/bundle/macos/nym-wallet.app.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
secrets: inherit
|
||||
release_tag: ${{ needs.publish-tauri.outputs.release_tag || github.ref_name }}
|
||||
secrets: inherit
|
||||
@@ -3,71 +3,108 @@ on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-wallet
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-ubuntu-22.04]
|
||||
platform: [ubuntu-22.04]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
release_tag: ${{ github.ref_name }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Tauri dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y webkit2gtk-4.0
|
||||
continue-on-error: true
|
||||
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y libdbus-1-dev libmnl-dev libnftnl-dev \
|
||||
libwebkit2gtk-4.1-dev build-essential curl wget libssl-dev jq \
|
||||
libgtk-3-dev squashfs-tools libayatana-appindicator3-dev make libfuse2 unzip librsvg2-dev file \
|
||||
libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
|
||||
|
||||
- name: Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 21
|
||||
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
|
||||
- name: Build app
|
||||
run: yarn build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Check bundle directory
|
||||
run: |
|
||||
echo "Checking bundle directory structure"
|
||||
ls -la target/release/bundle || echo "Bundle directory not found"
|
||||
if [ -d "target/release/bundle/appimage" ]; then
|
||||
echo "AppImage bundle directory exists, checking contents:"
|
||||
ls -la target/release/bundle/appimage
|
||||
else
|
||||
echo "AppImage bundle directory not found, checking alternatives:"
|
||||
find target/release/bundle -type d -name "*appimage*" -o -name "*AppImage*" || echo "No AppImage directories found"
|
||||
find target/release/bundle -name "*.AppImage" -o -name "*.appimage" || echo "No AppImage files found"
|
||||
fi
|
||||
|
||||
- name: Create AppImage tarball if needed
|
||||
run: |
|
||||
# Find the AppImage file
|
||||
APPIMAGE_FILE=$(find target/release/bundle -name "*.AppImage" | head -n 1)
|
||||
if [ -n "$APPIMAGE_FILE" ]; then
|
||||
echo "Found AppImage file: $APPIMAGE_FILE"
|
||||
APPIMAGE_DIR=$(dirname "$APPIMAGE_FILE")
|
||||
APPIMAGE_NAME=$(basename "$APPIMAGE_FILE")
|
||||
|
||||
# Create tarball if it doesn't exist
|
||||
if [ ! -f "${APPIMAGE_FILE}.tar.gz" ]; then
|
||||
echo "Creating tarball for $APPIMAGE_NAME"
|
||||
cd "$APPIMAGE_DIR"
|
||||
tar -czf "${APPIMAGE_NAME}.tar.gz" "$APPIMAGE_NAME"
|
||||
cd -
|
||||
echo "Created tarball: ${APPIMAGE_FILE}.tar.gz"
|
||||
else
|
||||
echo "Tarball already exists: ${APPIMAGE_FILE}.tar.gz"
|
||||
fi
|
||||
else
|
||||
echo "WARNING: No AppImage file found!"
|
||||
fi
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
|
||||
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
|
||||
name: nym-wallet-appimage.tar.gz
|
||||
path: |
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz
|
||||
nym-wallet/target/release/bundle/*/nym-wallet*.AppImage.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -75,24 +112,26 @@ jobs:
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz
|
||||
nym-wallet/target/release/bundle/*/nym-wallet*.AppImage
|
||||
nym-wallet/target/release/bundle/*/nym-wallet*.AppImage.tar.gz
|
||||
|
||||
- name: Find AppImage tarball path for deployment
|
||||
id: find-appimage
|
||||
run: |
|
||||
APPIMAGE_TARBALL=$(find target/release/bundle -name "*.AppImage.tar.gz" | head -n 1)
|
||||
if [ -n "$APPIMAGE_TARBALL" ]; then
|
||||
echo "Found AppImage tarball: $APPIMAGE_TARBALL"
|
||||
echo "appimage_path=$APPIMAGE_TARBALL" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "WARNING: No AppImage tarball found for deployment!"
|
||||
echo "appimage_path=target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
secrets: inherit
|
||||
release_tag: ${{ needs.publish-tauri.outputs.release_tag || github.ref_name }}
|
||||
secrets: inherit
|
||||
@@ -1,6 +1,12 @@
|
||||
name: publish-nym-wallet-win11
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
sign:
|
||||
description: "Sign this build using SSL.com. Signing is billed per signature so be careful"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
@@ -18,53 +24,61 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
release_tag: ${{ github.ref_name }}
|
||||
|
||||
steps:
|
||||
- name: Clean up first
|
||||
continue-on-error: true
|
||||
working-directory: .
|
||||
run: |
|
||||
cd ..
|
||||
del /s /q /A:H nym
|
||||
rmdir /s /q nym
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Import signing certificate
|
||||
env:
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
New-Item -ItemType directory -Path certificate
|
||||
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
|
||||
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 21
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Download EV CodeSignTool from ssl.com
|
||||
working-directory: nym-wallet/src-tauri
|
||||
if: ${{ inputs.sign }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L0 https://www.ssl.com/download/codesigntool-for-linux-and-macos/ -o codesigntool.zip
|
||||
unzip codesigntool.zip
|
||||
- name: Get EV certificate credential id
|
||||
working-directory: nym-wallet/src-tauri
|
||||
if: ${{ inputs.sign }}
|
||||
id: get_credential_ids
|
||||
shell: bash
|
||||
run: |
|
||||
echo "SSL_COM_CREDENTIAL_ID=$(./CodeSignTool.sh get_credential_ids -username=${{ secrets.SSL_COM_USERNAME }} -password=${{ secrets.SSL_COM_PASSWORD }} | sed -n '1!p' | sed 's/- //')" >> "$GITHUB_OUTPUT"
|
||||
- name: Add custom sign command to tauri.conf.json
|
||||
working-directory: nym-wallet/src-tauri
|
||||
if: ${{ inputs.sign }}
|
||||
shell: bash
|
||||
run: |
|
||||
yq eval --inplace '.bundle.windows +=
|
||||
{
|
||||
"signCommand": {
|
||||
"cmd": "C:\Program Files\Git\bin\bash.EXE",
|
||||
"args": [
|
||||
"/c/actions-runner/_work/nym/nym/nym-wallet/src-tauri/CodeSignTool.sh",
|
||||
"sign",
|
||||
"-username ${{ secrets.SSL_COM_USERNAME }}",
|
||||
"-password ${{ secrets.SSL_COM_PASSWORD }}",
|
||||
"-credential_id ${{ steps.get_credential_ids.outputs.SSL_COM_CREDENTIAL_ID }}",
|
||||
"-totp_secret ${{ secrets.SSL_COM_TOTP_SECRET }}",
|
||||
"-program_name NymWallet",
|
||||
"-input_file_path",
|
||||
"%1",
|
||||
"-override"
|
||||
]
|
||||
}
|
||||
}' tauri.conf.json
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
@@ -77,18 +91,50 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: yarn build
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
SSL_COM_USERNAME: ${{ inputs.sign && secrets.SSL_COM_USERNAME }}
|
||||
SSL_COM_PASSWORD: ${{ inputs.sign && secrets.SSL_COM_PASSWORD }}
|
||||
SSL_COM_CREDENTIAL_ID: ${{ inputs.sign && steps.get_credential_ids.outputs.SSL_COM_CREDENTIAL_ID }}
|
||||
SSL_COM_TOTP_SECRET: ${{ inputs.sign && secrets.SSL_COM_TOTP_SECRET }}
|
||||
run: |
|
||||
echo "Starting build process..."
|
||||
yarn build
|
||||
|
||||
- name: Check bundle directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Checking bundle directory structure"
|
||||
|
||||
# Check standard location
|
||||
if [ -d "target/release/bundle" ]; then
|
||||
echo "Found bundle directory at standard location"
|
||||
ls -la target/release/bundle || echo "Failed to list bundle directory"
|
||||
fi
|
||||
|
||||
# Check src-tauri location
|
||||
if [ -d "src-tauri/target/release/bundle" ]; then
|
||||
echo "Found bundle directory in src-tauri"
|
||||
ls -la src-tauri/target/release/bundle || echo "Failed to list src-tauri bundle directory"
|
||||
|
||||
# Use this path for future steps
|
||||
echo "BUNDLE_PATH=src-tauri/target/release/bundle" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Using standard bundle path"
|
||||
echo "BUNDLE_PATH=target/release/bundle" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
# Check for MSI files in any location
|
||||
find . -name "*.msi" -type f
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nym-wallet_1.0.0_x64_en-US.msi
|
||||
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
|
||||
name: nym-wallet.msi
|
||||
path: |
|
||||
nym-wallet/${{ env.BUNDLE_PATH }}/msi/*.msi
|
||||
nym-wallet/${{ env.BUNDLE_PATH }}/*/nym-wallet*.msi
|
||||
nym-wallet/src-tauri/target/release/bundle/msi/*.msi
|
||||
retention-days: 30
|
||||
|
||||
- id: create-release
|
||||
@@ -97,25 +143,28 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/msi/*.msi
|
||||
nym-wallet/target/release/bundle/msi/*.msi.zip*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
nym-wallet/${{ env.BUNDLE_PATH }}/msi/*.msi
|
||||
nym-wallet/${{ env.BUNDLE_PATH }}/msi/*.msi.zip*
|
||||
nym-wallet/${{ env.BUNDLE_PATH }}/*/nym-wallet*.msi
|
||||
nym-wallet/src-tauri/target/release/bundle/msi/*.msi
|
||||
|
||||
- name: Find MSI path for deployment
|
||||
id: find-msi
|
||||
shell: bash
|
||||
run: |
|
||||
MSI_FILE=$(find . -name "*.msi" -type f | head -n 1)
|
||||
if [ -n "$MSI_FILE" ]; then
|
||||
echo "Found MSI file: $MSI_FILE"
|
||||
echo "msi_path=$MSI_FILE" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "WARNING: No MSI file found for deployment!"
|
||||
echo "msi_path=${{ env.BUNDLE_PATH }}/msi/nym-wallet*.msi" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
secrets: inherit
|
||||
release_tag: ${{ needs.publish-tauri.outputs.release_tag || github.ref_name }}
|
||||
secrets: inherit
|
||||
@@ -4,6 +4,66 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.8-tourist] (2025-04-29)
|
||||
|
||||
- add reserved byte to reply surb serialisation ([#5731])
|
||||
- Remove inactive peers ([#5721])
|
||||
- Update Hickory DNS "0.24.4" to "0.25" ([#5709])
|
||||
- build(deps): bump the patch-updates group across 1 directory with 7 updates ([#5708])
|
||||
- Peer handle should die more gracefully ([#5704])
|
||||
- build(deps): bump crossbeam-channel from 0.5.14 to 0.5.15 ([#5702])
|
||||
- build(deps): bump actions/checkout from 3 to 4 ([#5700])
|
||||
- Feature/updated sphinx payload keys ([#5698])
|
||||
- Bump the nym-vpn deb metapackage to 1.0 ([#5697])
|
||||
- Make mix hops optional for Mixnet Client ([#5696])
|
||||
- build(deps): bump tokio from 1.44.1 to 1.44.2 ([#5693])
|
||||
- Feature/replay protection ([#5682])
|
||||
- Adding fresh nym-api tests and workflow ([#5659])
|
||||
- build(deps): bump next from 14.2.21 to 14.2.25 ([#5655])
|
||||
- build(deps): bump pnpm/action-setup from 4.0.0 to 4.1.0 ([#5436])
|
||||
|
||||
[#5731]: https://github.com/nymtech/nym/pull/5731
|
||||
[#5721]: https://github.com/nymtech/nym/pull/5721
|
||||
[#5709]: https://github.com/nymtech/nym/pull/5709
|
||||
[#5708]: https://github.com/nymtech/nym/pull/5708
|
||||
[#5704]: https://github.com/nymtech/nym/pull/5704
|
||||
[#5702]: https://github.com/nymtech/nym/pull/5702
|
||||
[#5700]: https://github.com/nymtech/nym/pull/5700
|
||||
[#5698]: https://github.com/nymtech/nym/pull/5698
|
||||
[#5697]: https://github.com/nymtech/nym/pull/5697
|
||||
[#5696]: https://github.com/nymtech/nym/pull/5696
|
||||
[#5693]: https://github.com/nymtech/nym/pull/5693
|
||||
[#5682]: https://github.com/nymtech/nym/pull/5682
|
||||
[#5659]: https://github.com/nymtech/nym/pull/5659
|
||||
[#5655]: https://github.com/nymtech/nym/pull/5655
|
||||
[#5436]: https://github.com/nymtech/nym/pull/5436
|
||||
|
||||
## [2025.7-tex] (2025-04-14)
|
||||
|
||||
- Expand /v3/nym-nodes with geodata ([#5686])
|
||||
- chore: clippy for 1.86 ([#5685])
|
||||
- Featrure: Bash scripts to init and configure VMs conveniently and update docs ([#5681])
|
||||
- Update node versions in CI ([#5677])
|
||||
- build(deps): bump the patch-updates group across 1 directory with 8 updates ([#5668])
|
||||
- Update log crate ([#5667])
|
||||
- Minor fixes involving key cloning and hashing ([#5664])
|
||||
- mix throughput tester ([#5661])
|
||||
- build(deps): bump blake3 from 1.6.1 to 1.7.0 ([#5658])
|
||||
- build(deps): bump elliptic from 6.5.5 to 6.6.1 ([#5483])
|
||||
- Move all workflows on ubuntu-20 to ubuntu-22 ([#5455])
|
||||
|
||||
[#5686]: https://github.com/nymtech/nym/pull/5686
|
||||
[#5685]: https://github.com/nymtech/nym/pull/5685
|
||||
[#5681]: https://github.com/nymtech/nym/pull/5681
|
||||
[#5677]: https://github.com/nymtech/nym/pull/5677
|
||||
[#5668]: https://github.com/nymtech/nym/pull/5668
|
||||
[#5667]: https://github.com/nymtech/nym/pull/5667
|
||||
[#5664]: https://github.com/nymtech/nym/pull/5664
|
||||
[#5661]: https://github.com/nymtech/nym/pull/5661
|
||||
[#5658]: https://github.com/nymtech/nym/pull/5658
|
||||
[#5483]: https://github.com/nymtech/nym/pull/5483
|
||||
[#5455]: https://github.com/nymtech/nym/pull/5455
|
||||
|
||||
## [2025.6-chuckles] (2025-03-31)
|
||||
|
||||
- Remove Google public DNS ([#5660])
|
||||
|
||||
Generated
+146
-121
@@ -218,9 +218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@@ -430,6 +430,17 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
@@ -489,6 +500,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@@ -516,7 +533,7 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
name = "autodoc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.11.7",
|
||||
"env_logger 0.11.8",
|
||||
"log",
|
||||
]
|
||||
|
||||
@@ -908,6 +925,16 @@ dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bloomfilter"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f6d7f06817e48ea4e17532fa61bc4e8b9a101437f0623f69d2ea54284f3a817"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"siphasher 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bls12_381"
|
||||
version = "0.8.0"
|
||||
@@ -1184,9 +1211,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.34"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
|
||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1194,9 +1221,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.34"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
|
||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1564,6 +1591,7 @@ dependencies = [
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"futures",
|
||||
"is-terminal",
|
||||
"itertools 0.10.5",
|
||||
"num-traits",
|
||||
@@ -1576,6 +1604,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"tokio",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -1590,10 +1619,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -2173,6 +2208,12 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
@@ -2364,9 +2405,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.7"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697"
|
||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -2542,9 +2583,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -2946,6 +2987,25 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.3.1",
|
||||
"indexmap 2.7.1",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
@@ -3112,57 +3172,59 @@ checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
|
||||
|
||||
[[package]]
|
||||
name = "hickory-proto"
|
||||
version = "0.24.4"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248"
|
||||
checksum = "6d844af74f7b799e41c78221be863bade11c430d46042c3b49ca8ae0c6d27287"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
"data-encoding",
|
||||
"enum-as-inner",
|
||||
"futures-channel",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"h2 0.4.9",
|
||||
"http 1.3.1",
|
||||
"idna",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.21.12",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"thiserror 1.0.69",
|
||||
"rand 0.9.0",
|
||||
"ring",
|
||||
"rustls 0.23.25",
|
||||
"thiserror 2.0.12",
|
||||
"tinyvec",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tracing",
|
||||
"url",
|
||||
"webpki-roots 0.25.4",
|
||||
"webpki-roots 0.26.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hickory-resolver"
|
||||
version = "0.24.4"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e"
|
||||
checksum = "a128410b38d6f931fcc6ca5c107a3b02cabd6c05967841269a4ad65d23c44331"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"hickory-proto",
|
||||
"ipconfig",
|
||||
"lru-cache",
|
||||
"moka",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand 0.8.5",
|
||||
"rand 0.9.0",
|
||||
"resolv-conf",
|
||||
"rustls 0.21.12",
|
||||
"rustls 0.23.25",
|
||||
"smallvec",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tracing",
|
||||
"webpki-roots 0.25.4",
|
||||
"webpki-roots 0.26.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3354,7 +3416,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
@@ -3434,9 +3496,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -3444,6 +3506,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.6.0",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -4035,9 +4098,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@@ -4079,12 +4142,6 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
@@ -4150,15 +4207,6 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-cache"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@@ -4313,9 +4361,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@@ -4685,7 +4733,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.55"
|
||||
version = "1.1.56"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4696,6 +4744,7 @@ dependencies = [
|
||||
"bip39",
|
||||
"bs58",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"clap",
|
||||
"console-subscriber",
|
||||
"cosmwasm-std",
|
||||
@@ -4705,6 +4754,7 @@ dependencies = [
|
||||
"cw4",
|
||||
"dashmap",
|
||||
"dirs",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"getset",
|
||||
"humantime-serde",
|
||||
@@ -4937,7 +4987,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.52"
|
||||
version = "1.1.54"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -5020,7 +5070,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.52"
|
||||
version = "1.1.54"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -5062,7 +5112,6 @@ dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"bs58",
|
||||
"cfg-if",
|
||||
"clap",
|
||||
"comfy-table",
|
||||
"futures",
|
||||
@@ -5077,12 +5126,10 @@ dependencies = [
|
||||
"nym-client-core-gateways-storage",
|
||||
"nym-client-core-surb-storage",
|
||||
"nym-config",
|
||||
"nym-country-group",
|
||||
"nym-credential-storage",
|
||||
"nym-credentials-interface",
|
||||
"nym-crypto",
|
||||
"nym-ecash-time",
|
||||
"nym-explorer-client",
|
||||
"nym-gateway-client",
|
||||
"nym-gateway-requests",
|
||||
"nym-http-api-client",
|
||||
@@ -5103,13 +5150,13 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"si-scale",
|
||||
"tap",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tungstenite 0.20.1",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -5125,7 +5172,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"humantime-serde",
|
||||
"nym-config",
|
||||
"nym-country-group",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-params",
|
||||
@@ -5267,14 +5313,6 @@ dependencies = [
|
||||
"vergen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-country-group"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-cpp-ffi"
|
||||
version = "0.1.2"
|
||||
@@ -5551,31 +5589,6 @@ dependencies = [
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-explorer-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nym-api-requests",
|
||||
"nym-contracts-common",
|
||||
"nym-mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-explorer-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nym-explorer-api-requests",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-ffi-shared"
|
||||
version = "0.2.1"
|
||||
@@ -5772,12 +5785,14 @@ name = "nym-http-api-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"hickory-resolver",
|
||||
"http 1.3.1",
|
||||
"mime",
|
||||
"nym-bin-common",
|
||||
"nym-http-api-common",
|
||||
"once_cell",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
@@ -5795,14 +5810,15 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"axum-client-ip",
|
||||
"bincode",
|
||||
"bytes",
|
||||
"colored",
|
||||
"futures",
|
||||
"mime",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"subtle 2.6.1",
|
||||
"time",
|
||||
"tower 0.5.2",
|
||||
"tracing",
|
||||
"utoipa",
|
||||
@@ -6055,7 +6071,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.53"
|
||||
version = "1.1.55"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -6106,7 +6122,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.8.0"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -6115,15 +6131,18 @@ dependencies = [
|
||||
"axum 0.7.9",
|
||||
"bip39",
|
||||
"blake2 0.8.1",
|
||||
"bloomfilter",
|
||||
"bs58",
|
||||
"cargo_metadata 0.18.1",
|
||||
"celes",
|
||||
"chacha",
|
||||
"clap",
|
||||
"colored",
|
||||
"criterion",
|
||||
"csv",
|
||||
"cupid",
|
||||
"futures",
|
||||
"hkdf",
|
||||
"human-repr",
|
||||
"humantime-serde",
|
||||
"indicatif",
|
||||
@@ -6163,6 +6182,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"sysinfo",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
@@ -6235,7 +6255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-status-api"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
@@ -6251,7 +6271,6 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-contracts-common",
|
||||
"nym-crypto",
|
||||
"nym-explorer-client",
|
||||
"nym-http-api-client",
|
||||
"nym-network-defaults",
|
||||
"nym-node-metrics",
|
||||
@@ -6497,7 +6516,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.52"
|
||||
version = "1.1.54"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -6594,7 +6613,6 @@ dependencies = [
|
||||
name = "nym-sphinx"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nym-crypto",
|
||||
"nym-metrics",
|
||||
"nym-mixnet-contract-common",
|
||||
@@ -6614,6 +6632,7 @@ dependencies = [
|
||||
"rand_distr",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6660,6 +6679,7 @@ dependencies = [
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -6713,8 +6733,6 @@ name = "nym-sphinx-framing"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"log",
|
||||
"nym-metrics",
|
||||
"nym-sphinx-acknowledgements",
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-forwarding",
|
||||
@@ -6723,6 +6741,7 @@ dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7101,7 +7120,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.17"
|
||||
version = "0.1.19"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7198,6 +7217,10 @@ name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
@@ -8178,7 +8201,7 @@ dependencies = [
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.32",
|
||||
@@ -8536,6 +8559,7 @@ version = "0.23.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -9236,9 +9260,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
|
||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -9246,9 +9270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sphinx-packet"
|
||||
version = "0.3.2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c23047e0cf36ff6904603f499fd13153425cdf5ba47bfbaedbc999da0bd92f4e"
|
||||
checksum = "c26f0c20d909fdda1c5d0ece3973127ca421984d55b000215df365e93722fc6e"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arrayref",
|
||||
@@ -9267,6 +9291,7 @@ dependencies = [
|
||||
"sha2 0.10.8",
|
||||
"subtle 2.6.1",
|
||||
"x25519-dalek",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9759,9 +9784,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tendermint"
|
||||
version = "0.40.1"
|
||||
version = "0.40.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9703e34d940c2a293804752555107f8dbe2b84ec4c6dd5203831235868105d2"
|
||||
checksum = "ab2972a56891bc9173eaebdd51290bc848e448aa281881f3a4712bd8fe1899b3"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"digest 0.10.7",
|
||||
@@ -9789,9 +9814,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tendermint-config"
|
||||
version = "0.40.1"
|
||||
version = "0.40.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89cc3ea9a39b7ee34eefcff771cc067ecaa0c988c1c5ac08defd878471a06f76"
|
||||
checksum = "651cb680d41e586bb688cc17ab0b6dfe2e62a959c5742d1351fe0b084cd75d59"
|
||||
dependencies = [
|
||||
"flex-error",
|
||||
"serde",
|
||||
@@ -9803,9 +9828,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tendermint-proto"
|
||||
version = "0.40.1"
|
||||
version = "0.40.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ae9e1705aa0fa5ecb2c6aa7fb78c2313c4a31158ea5f02048bf318f849352eb"
|
||||
checksum = "ca44b9eaaa98e8440fbafe5593b8a32a1c395c094ac566b3eb50497f8bd2bee0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flex-error",
|
||||
@@ -9818,9 +9843,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tendermint-rpc"
|
||||
version = "0.40.1"
|
||||
version = "0.40.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "835a52aa504c63ec05519e31348d3f4ba2fe79493c588e2cad5323d5e81b161a"
|
||||
checksum = "9367678af1a9fc6c064fab8b5d05f03c0fc243fe411581c00c7eed83f8ced380"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"async-tungstenite",
|
||||
@@ -10061,9 +10086,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -10291,7 +10316,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.32",
|
||||
|
||||
+14
-17
@@ -39,7 +39,6 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/country-group",
|
||||
"common/credential-storage",
|
||||
"common/credential-utils",
|
||||
"common/credential-verification",
|
||||
@@ -97,9 +96,6 @@ members = [
|
||||
"common/wireguard",
|
||||
"common/wireguard-types",
|
||||
"documentation/autodoc",
|
||||
# "explorer-api",
|
||||
# "explorer-api/explorer-api-requests",
|
||||
# "explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"integrations/bity",
|
||||
"nym-api",
|
||||
@@ -189,7 +185,7 @@ aes = "0.8.1"
|
||||
aes-gcm = "0.10.1"
|
||||
aes-gcm-siv = "0.11.1"
|
||||
ammonia = "4"
|
||||
anyhow = "1.0.97"
|
||||
anyhow = "1.0.98"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.88"
|
||||
@@ -204,7 +200,7 @@ bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
bit-vec = "0.7.0" # can we unify those?
|
||||
bitvec = "1.0.0"
|
||||
blake3 = "1.7.0"
|
||||
bloomfilter = "1.0.14"
|
||||
bloomfilter = "3.0.1"
|
||||
bs58 = "0.5.1"
|
||||
bytecodec = "0.4.15"
|
||||
bytes = "1.10.1"
|
||||
@@ -215,7 +211,7 @@ chacha20 = "0.9.0"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
chrono = "0.4.40"
|
||||
cipher = "0.4.3"
|
||||
clap = "4.5.34"
|
||||
clap = "4.5.36"
|
||||
clap_complete = "4.5"
|
||||
clap_complete_fig = "4.5"
|
||||
colored = "2.2"
|
||||
@@ -240,12 +236,12 @@ dotenvy = "0.15.6"
|
||||
ecdsa = "0.16"
|
||||
ed25519-dalek = "2.1"
|
||||
encoding_rs = "0.8.35"
|
||||
env_logger = "0.11.7"
|
||||
env_logger = "0.11.8"
|
||||
envy = "0.4"
|
||||
etherparse = "0.13.0"
|
||||
eyre = "0.6.9"
|
||||
fastrand = "2.1.1"
|
||||
flate2 = "1.1.0"
|
||||
flate2 = "1.1.1"
|
||||
futures = "0.3.31"
|
||||
futures-util = "0.3"
|
||||
generic-array = "0.14.7"
|
||||
@@ -255,7 +251,7 @@ handlebars = "3.5.5"
|
||||
headers = "0.4.0"
|
||||
hex = "0.4.3"
|
||||
hex-literal = "0.3.3"
|
||||
hickory-resolver = "0.24.4"
|
||||
hickory-resolver = "0.25"
|
||||
hkdf = "0.12.3"
|
||||
hmac = "0.12.1"
|
||||
http = "1"
|
||||
@@ -270,7 +266,6 @@ indicatif = "0.17.11"
|
||||
inquire = "0.6.2"
|
||||
ip_network = "0.4.1"
|
||||
ipnetwork = "0.20"
|
||||
isocountry = "0.3.2"
|
||||
itertools = "0.14.0"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.5.0"
|
||||
@@ -303,9 +298,6 @@ rand_seeder = "0.2.3"
|
||||
rayon = "1.5.1"
|
||||
regex = "1.10.6"
|
||||
reqwest = { version = "0.12.15", default-features = false }
|
||||
rocket = "0.5.0"
|
||||
rocket_cors = "0.6.0"
|
||||
rocket_okapi = "0.8.0"
|
||||
rs_merkle = "1.5.0"
|
||||
safer-ffi = "0.1.13"
|
||||
schemars = "0.8.22"
|
||||
@@ -320,7 +312,7 @@ serde_with = "3.9.0"
|
||||
serde_yaml = "0.9.25"
|
||||
sha2 = "0.10.8"
|
||||
si-scale = "0.2.3"
|
||||
sphinx-packet = "=0.3.2"
|
||||
sphinx-packet = "=0.6.0"
|
||||
sqlx = "0.7.4"
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
@@ -393,8 +385,8 @@ bip32 = { version = "0.5.3", default-features = false }
|
||||
|
||||
|
||||
cosmrs = { version = "0.21.1" }
|
||||
tendermint = "0.40.0"
|
||||
tendermint-rpc = "0.40.0"
|
||||
tendermint = "0.40.3"
|
||||
tendermint-rpc = "0.40.3"
|
||||
prost = { version = "0.13", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
@@ -410,6 +402,11 @@ wasm-bindgen-futures = "0.4.49"
|
||||
wasmtimer = "0.4.1"
|
||||
web-sys = "0.3.76"
|
||||
|
||||
|
||||
# for local development:
|
||||
#[patch.crates-io]
|
||||
#sphinx-packet = { path = "../sphinx" }
|
||||
|
||||
# Profile settings for individual crates
|
||||
|
||||
# Compile-time verified queries do quite a bit of work at compile time. Incremental
|
||||
|
||||
@@ -168,8 +168,9 @@ generate-typescript:
|
||||
cd tools/ts-rs-cli && cargo run && cd ../..
|
||||
yarn types:lint:fix
|
||||
|
||||
# Run the integration tests for public nym-api endpoints
|
||||
run-api-tests:
|
||||
cd nym-api/tests/functional_test && yarn test:qa
|
||||
dotenv -f envs/sandbox.env -- cargo test --test public-api-tests
|
||||
|
||||
# Build debian package, and update PPA
|
||||
deb-cli: build-nym-cli
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.52"
|
||||
version = "1.1.54"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.52"
|
||||
version = "1.1.54"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -87,7 +87,6 @@ impl From<Init> for OverrideConfig {
|
||||
use_anonymous_replies: init_config.use_reply_surbs,
|
||||
fastmode: init_config.common_args.fastmode,
|
||||
no_cover: init_config.common_args.no_cover,
|
||||
geo_routing: None,
|
||||
medium_toggle: false,
|
||||
nyxd_urls: init_config.common_args.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
|
||||
|
||||
@@ -16,8 +16,7 @@ use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::cli_helpers::CliClient;
|
||||
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_client_core::config::{ForgetMe, GroupBy, TopologyStructure};
|
||||
use nym_client_core::config::ForgetMe;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
@@ -107,7 +106,6 @@ pub(crate) struct OverrideConfig {
|
||||
use_anonymous_replies: Option<bool>,
|
||||
fastmode: bool,
|
||||
no_cover: bool,
|
||||
geo_routing: Option<CountryGroup>,
|
||||
medium_toggle: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
@@ -138,21 +136,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
|
||||
let no_per_hop_delays = args.medium_toggle;
|
||||
|
||||
let topology_structure = if args.medium_toggle {
|
||||
// Use the location of the network-requester
|
||||
let address = config
|
||||
.core
|
||||
.socks5
|
||||
.provider_mix_address
|
||||
.parse()
|
||||
.expect("failed to parse provider mix address");
|
||||
TopologyStructure::GeoAware(GroupBy::NymAddress(address))
|
||||
} else if let Some(code) = args.geo_routing {
|
||||
TopologyStructure::GeoAware(GroupBy::CountryGroup(code))
|
||||
} else {
|
||||
TopologyStructure::default()
|
||||
};
|
||||
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
@@ -176,10 +159,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
// NOTE: see comment above about the order of the other disble cover traffic config
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_base(
|
||||
BaseClientConfig::with_topology_structure,
|
||||
topology_structure,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_forget_me, args.forget_me)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::commands::{override_config, OverrideConfig};
|
||||
use clap::Args;
|
||||
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_socks5_client_core::NymClient;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use std::net::IpAddr;
|
||||
@@ -37,10 +36,6 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
host: Option<IpAddr>,
|
||||
|
||||
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
|
||||
#[clap(long, hide = true, value_parser = validate_country_group, group="routing")]
|
||||
geo_routing: Option<CountryGroup>,
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[clap(long, hide = true)]
|
||||
@@ -59,7 +54,6 @@ impl From<Run> for OverrideConfig {
|
||||
use_anonymous_replies: run_config.use_anonymous_replies,
|
||||
fastmode: run_config.common_args.fastmode,
|
||||
no_cover: run_config.common_args.no_cover,
|
||||
geo_routing: run_config.geo_routing,
|
||||
medium_toggle: run_config.medium_toggle,
|
||||
nyxd_urls: run_config.common_args.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
|
||||
@@ -70,13 +64,6 @@ impl From<Run> for OverrideConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
|
||||
match s.parse() {
|
||||
Ok(cg) => Ok(cg),
|
||||
Err(_) => Err(format!("failed to parse country group: {}", s)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
eprintln!("Starting client {}...", args.common_args.id);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -190,15 +190,15 @@ impl<'de> Deserialize<'de> for ClientMac {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "verify")]
|
||||
fn client_request_roundtrip() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
let client_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let nonce = 1234567890;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -199,15 +199,15 @@ impl<'de> Deserialize<'de> for ClientMac {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "verify")]
|
||||
fn client_request_roundtrip() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
let client_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let nonce = 1234567890;
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ mod tests {
|
||||
use std::{net::IpAddr, str::FromStr};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::x25519::PrivateKey;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -199,15 +199,15 @@ impl<'de> Deserialize<'de> for ClientMac {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "verify")]
|
||||
fn client_request_roundtrip() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
let client_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let nonce = 1234567890;
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ mod tests {
|
||||
};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::x25519::PrivateKey;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -251,7 +251,7 @@ impl<'de> Deserialize<'de> for ClientMac {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
|
||||
#[test]
|
||||
fn create_ip_pair() {
|
||||
@@ -266,8 +266,8 @@ mod tests {
|
||||
fn client_request_roundtrip() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
let client_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let nonce = 1234567890;
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ mod tests {
|
||||
};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::x25519::PrivateKey;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -251,7 +251,7 @@ impl<'de> Deserialize<'de> for ClientMac {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
|
||||
#[test]
|
||||
fn create_ip_pair() {
|
||||
@@ -266,8 +266,8 @@ mod tests {
|
||||
fn client_request_roundtrip() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
let client_key_pair = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let nonce = 1234567890;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
|
||||
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
|
||||
use nym_credentials::IssuedTicketBook;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_ecash_time::{ecash_default_expiration_date, Date};
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -31,7 +31,7 @@ where
|
||||
C: EcashSigningClient + EcashQueryClient + Sync,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_key = identity::PrivateKey::new(&mut rng);
|
||||
let signing_key = ed25519::PrivateKey::new(&mut rng);
|
||||
let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
|
||||
|
||||
let deposit_amount = client.get_required_deposit_amount().await?;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use nym_credentials::error::Error as CredentialsError;
|
||||
use nym_credentials_interface::CompactEcashError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
|
||||
use nym_crypto::asymmetric::x25519::KeyRecoveryError;
|
||||
use nym_validator_client::coconut::EcashApiError;
|
||||
use nym_validator_client::error::ValidatorClientError;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -12,7 +12,6 @@ license.workspace = true
|
||||
async-trait = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bs58 = { workspace = true }
|
||||
cfg-if = { workspace = true }
|
||||
clap = { workspace = true, optional = true }
|
||||
comfy-table = { workspace = true, optional = true }
|
||||
futures = { workspace = true }
|
||||
@@ -24,20 +23,18 @@ serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
si-scale = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
tokio = { workspace = true, features = ["macros"] }
|
||||
time = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-id = { path = "../nym-id" }
|
||||
nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
||||
nym-config = { path = "../config" }
|
||||
nym-country-group = { path = "../country-group" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
|
||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-http-api-client = { path = "../http-api-client" }
|
||||
|
||||
@@ -14,7 +14,6 @@ url = { workspace = true, features = ["serde"] }
|
||||
|
||||
nym-config = { path = "../../config" }
|
||||
|
||||
nym-country-group = { path = "../../country-group" }
|
||||
nym-pemstore = { path = "../../pemstore", optional = true }
|
||||
|
||||
# those are pulling so many deps T.T
|
||||
|
||||
@@ -65,11 +65,10 @@ const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60
|
||||
|
||||
// stats reporting related
|
||||
|
||||
/// Time interval between reporting statistics to the given provider if it exist
|
||||
/// Time interval between reporting statistics to the given provider if it exists
|
||||
const STATS_REPORT_INTERVAL_SECS: Duration = Duration::from_secs(300);
|
||||
|
||||
use crate::error::InvalidTrafficModeFailure;
|
||||
pub use nym_country_group::CountryGroup;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -258,15 +257,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
|
||||
self.set_topology_structure(topology_structure);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
|
||||
self.debug.topology.topology_structure = topology_structure;
|
||||
}
|
||||
|
||||
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
|
||||
if no_per_hop_delays {
|
||||
self.set_no_per_hop_delays()
|
||||
@@ -415,7 +405,21 @@ pub struct Traffic {
|
||||
/// Do not set it unless you understand the consequences of that change.
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
/// Specify whether any constructed sphinx packets should use the legacy format,
|
||||
/// where the payload keys are explicitly attached rather than using the seeds
|
||||
/// this affects any forward packets, acks and reply surbs
|
||||
/// this flag should remain disabled until sufficient number of nodes on the network has upgraded
|
||||
/// and support updated format.
|
||||
/// in the case of reply surbs, the recipient must also understand the new encoding
|
||||
pub use_legacy_sphinx_format: bool,
|
||||
|
||||
pub packet_type: PacketType,
|
||||
|
||||
/// Indicates whether to mix hops or not. If mix hops are enabled, traffic
|
||||
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
|
||||
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
|
||||
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
|
||||
pub disable_mix_hops: bool,
|
||||
}
|
||||
|
||||
impl Traffic {
|
||||
@@ -442,6 +446,11 @@ impl Default for Traffic {
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: PacketType::Mix,
|
||||
|
||||
// we should use the legacy format until sufficient number of nodes understand the
|
||||
// improved encoding
|
||||
use_legacy_sphinx_format: true,
|
||||
disable_mix_hops: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,9 +555,6 @@ pub struct Topology {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub max_startup_gateway_waiting_period: Duration,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructure,
|
||||
|
||||
/// Specifies a minimum performance of a mixnode that is used on route construction.
|
||||
/// This setting is only applicable when `NymApi` topology is used.
|
||||
pub minimum_mixnode_performance: u8,
|
||||
@@ -570,30 +576,6 @@ pub struct Topology {
|
||||
pub ignore_ingress_epoch_role: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructure {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(GroupBy),
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupBy {
|
||||
CountryGroup(CountryGroup),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupBy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupBy::CountryGroup(group) => write!(f, "group: {group}"),
|
||||
GroupBy::NymAddress(address) => write!(f, "address: {address}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
fn default() -> Self {
|
||||
Topology {
|
||||
@@ -601,7 +583,6 @@ impl Default for Topology {
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
|
||||
topology_structure: TopologyStructure::default(),
|
||||
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
|
||||
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
|
||||
use_extended_topology: false,
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::old::v5::{
|
||||
AcknowledgementsV5, ClientV5, ConfigV5, CoverTrafficV5, DebugConfigV5, GatewayConnectionV5,
|
||||
GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
|
||||
AcknowledgementsV5, ClientV5, ConfigV5, CountryGroupV5, CoverTrafficV5, DebugConfigV5,
|
||||
GatewayConnectionV5, GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
|
||||
};
|
||||
use crate::CountryGroup;
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -369,31 +368,47 @@ impl From<TopologyStructureV4> for TopologyStructureV5 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroupV4 {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<CountryGroupV4> for CountryGroupV5 {
|
||||
fn from(value: CountryGroupV4) -> Self {
|
||||
match value {
|
||||
CountryGroupV4::Europe => CountryGroupV5::Europe,
|
||||
CountryGroupV4::NorthAmerica => CountryGroupV5::NorthAmerica,
|
||||
CountryGroupV4::SouthAmerica => CountryGroupV5::SouthAmerica,
|
||||
CountryGroupV4::Oceania => CountryGroupV5::Oceania,
|
||||
CountryGroupV4::Asia => CountryGroupV5::Asia,
|
||||
CountryGroupV4::Africa => CountryGroupV5::Africa,
|
||||
CountryGroupV4::Unknown => CountryGroupV5::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupByV4 {
|
||||
CountryGroup(CountryGroup),
|
||||
CountryGroup(CountryGroupV4),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl From<GroupByV4> for GroupByV5 {
|
||||
fn from(value: GroupByV4) -> Self {
|
||||
match value {
|
||||
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country),
|
||||
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country.into()),
|
||||
GroupByV4::NymAddress(addr) => GroupByV5::NymAddress(addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupByV4 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupByV4::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV4::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV4 {
|
||||
fn default() -> Self {
|
||||
TopologyV4 {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
Acknowledgements, Client, Config, CountryGroup, CoverTraffic, DebugConfig, GatewayConnection,
|
||||
GroupBy, ReplySurbs, Topology, TopologyStructure, Traffic,
|
||||
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, ReplySurbs,
|
||||
Topology, Traffic,
|
||||
};
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
@@ -146,7 +146,6 @@ impl From<ConfigV5> for Config {
|
||||
.debug
|
||||
.topology
|
||||
.max_startup_gateway_waiting_period,
|
||||
topology_structure: value.debug.topology.topology_structure.into(),
|
||||
..Default::default()
|
||||
},
|
||||
reply_surbs: ReplySurbs {
|
||||
@@ -372,40 +371,24 @@ pub enum TopologyStructureV5 {
|
||||
GeoAware(GroupByV5),
|
||||
}
|
||||
|
||||
impl From<TopologyStructureV5> for TopologyStructure {
|
||||
fn from(value: TopologyStructureV5) -> Self {
|
||||
match value {
|
||||
TopologyStructureV5::NymApi => TopologyStructure::NymApi,
|
||||
TopologyStructureV5::GeoAware(group_by) => TopologyStructure::GeoAware(group_by.into()),
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroupV5 {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupByV5 {
|
||||
CountryGroup(CountryGroup),
|
||||
CountryGroup(CountryGroupV5),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl From<GroupByV5> for GroupBy {
|
||||
fn from(value: GroupByV5) -> Self {
|
||||
match value {
|
||||
GroupByV5::CountryGroup(country) => GroupBy::CountryGroup(country),
|
||||
GroupByV5::NymAddress(addr) => GroupBy::NymAddress(addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupByV5 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupByV5::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV5::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV5 {
|
||||
fn default() -> Self {
|
||||
TopologyV5 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
|
||||
use nym_gateway_requests::shared_key::SharedKeyConversionError;
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_requests::SharedSymmetricKey;
|
||||
use std::error::Error;
|
||||
|
||||
@@ -36,9 +36,7 @@ pub trait GatewaysDetailsStore {
|
||||
async fn all_gateways(&self) -> Result<Vec<GatewayRegistration>, Self::StorageError>;
|
||||
|
||||
/// Return identity keys of all registered gateways.
|
||||
async fn all_gateways_identities(
|
||||
&self,
|
||||
) -> Result<Vec<identity::PublicKey>, Self::StorageError> {
|
||||
async fn all_gateways_identities(&self) -> Result<Vec<ed25519::PublicKey>, Self::StorageError> {
|
||||
Ok(self
|
||||
.all_gateways()
|
||||
.await?
|
||||
@@ -64,7 +62,7 @@ pub trait GatewaysDetailsStore {
|
||||
|
||||
async fn upgrade_stored_remote_gateway_key(
|
||||
&self,
|
||||
gateway_id: identity::PublicKey,
|
||||
gateway_id: ed25519::PublicKey,
|
||||
updated_key: &SharedSymmetricKey,
|
||||
) -> Result<(), Self::StorageError>;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::BadGateway;
|
||||
use cosmrs::AccountId;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@@ -29,7 +29,7 @@ pub struct GatewayRegistration {
|
||||
}
|
||||
|
||||
impl GatewayRegistration {
|
||||
pub fn gateway_id(&self) -> identity::PublicKey {
|
||||
pub fn gateway_id(&self) -> ed25519::PublicKey {
|
||||
self.details.gateway_id()
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ impl From<GatewayDetails> for GatewayRegistration {
|
||||
|
||||
impl GatewayDetails {
|
||||
pub fn new_remote(
|
||||
gateway_id: identity::PublicKey,
|
||||
gateway_id: ed25519::PublicKey,
|
||||
shared_key: Arc<SharedGatewayKey>,
|
||||
gateway_owner_address: Option<AccountId>,
|
||||
gateway_listener: Url,
|
||||
@@ -77,11 +77,11 @@ impl GatewayDetails {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_custom(gateway_id: identity::PublicKey, data: Option<Vec<u8>>) -> Self {
|
||||
pub fn new_custom(gateway_id: ed25519::PublicKey, data: Option<Vec<u8>>) -> Self {
|
||||
GatewayDetails::Custom(CustomGatewayDetails { gateway_id, data })
|
||||
}
|
||||
|
||||
pub fn gateway_id(&self) -> identity::PublicKey {
|
||||
pub fn gateway_id(&self) -> ed25519::PublicKey {
|
||||
match self {
|
||||
GatewayDetails::Remote(details) => details.gateway_id,
|
||||
GatewayDetails::Custom(details) => details.gateway_id,
|
||||
@@ -157,7 +157,7 @@ pub struct RawRegisteredGateway {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RegisteredGateway {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub gateway_id: ed25519::PublicKey,
|
||||
|
||||
pub registration_timestamp: OffsetDateTime,
|
||||
|
||||
@@ -179,7 +179,7 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
|
||||
|
||||
fn try_from(value: RawRemoteGatewayDetails) -> Result<Self, Self::Error> {
|
||||
let gateway_id =
|
||||
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
|
||||
ed25519::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
|
||||
BadGateway::MalformedGatewayIdentity {
|
||||
gateway_id: value.gateway_id_bs58.clone(),
|
||||
source,
|
||||
@@ -267,7 +267,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteGatewayDetails {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub gateway_id: ed25519::PublicKey,
|
||||
|
||||
pub shared_key: Arc<SharedGatewayKey>,
|
||||
|
||||
@@ -288,7 +288,7 @@ impl TryFrom<RawCustomGatewayDetails> for CustomGatewayDetails {
|
||||
|
||||
fn try_from(value: RawCustomGatewayDetails) -> Result<Self, Self::Error> {
|
||||
let gateway_id =
|
||||
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
|
||||
ed25519::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
|
||||
BadGateway::MalformedGatewayIdentity {
|
||||
gateway_id: value.gateway_id_bs58.clone(),
|
||||
source,
|
||||
@@ -314,12 +314,12 @@ impl<'a> From<&'a CustomGatewayDetails> for RawCustomGatewayDetails {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomGatewayDetails {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub gateway_id: ed25519::PublicKey,
|
||||
pub data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl CustomGatewayDetails {
|
||||
pub fn new(gateway_id: identity::PublicKey) -> CustomGatewayDetails {
|
||||
pub fn new(gateway_id: ed25519::PublicKey) -> CustomGatewayDetails {
|
||||
Self {
|
||||
gateway_id,
|
||||
data: None,
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{
|
||||
};
|
||||
use log::info;
|
||||
use nym_client_core_gateways_storage::GatewayDetails;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::UserAgent;
|
||||
use std::path::PathBuf;
|
||||
@@ -29,7 +29,7 @@ pub struct CommonClientAddGatewayArgs {
|
||||
/// Explicitly specify id of the gateway to register with.
|
||||
/// If unspecified, a random gateway will be chosen instead.
|
||||
#[cfg_attr(feature = "cli", clap(long, alias = "gateway"))]
|
||||
pub gateway_id: Option<identity::PublicKey>,
|
||||
pub gateway_id: Option<ed25519::PublicKey>,
|
||||
|
||||
/// Specifies whether the client will attempt to enforce tls connection to the desired gateway.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{
|
||||
};
|
||||
use log::info;
|
||||
use nym_client_core_gateways_storage::GatewayDetails;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::UserAgent;
|
||||
@@ -42,7 +42,7 @@ pub struct CommonClientInitArgs {
|
||||
|
||||
/// Id of the gateway we are going to connect to.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub gateway: Option<identity::PublicKey>,
|
||||
pub gateway: Option<ed25519::PublicKey>,
|
||||
|
||||
/// Specifies whether the client will attempt to enforce tls connection to the desired gateway.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct CommonClientRunArgs {
|
||||
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
|
||||
/// ensure prior registration happened
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub gateway: Option<identity::PublicKey>,
|
||||
pub gateway: Option<ed25519::PublicKey>,
|
||||
|
||||
/// Comma separated list of rest endpoints of the nyxd validators
|
||||
#[cfg_attr(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage;
|
||||
use crate::client::base_client::storage::helpers::set_active_gateway;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
|
||||
#[cfg_attr(feature = "cli", derive(clap::Args))]
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -15,7 +15,7 @@ pub struct CommonClientSwitchGatewaysArgs {
|
||||
|
||||
/// Id of the gateway we want to switch to.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub gateway_id: ed25519::PublicKey,
|
||||
}
|
||||
|
||||
pub async fn switch_gateway<C, A>(args: A) -> Result<(), C::Error>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use time::OffsetDateTime;
|
||||
@@ -10,7 +10,7 @@ use url::Url;
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct GatewayInfo {
|
||||
pub registration: OffsetDateTime,
|
||||
pub identity: identity::PublicKey,
|
||||
pub identity: ed25519::PublicKey,
|
||||
pub active: bool,
|
||||
|
||||
pub typ: String,
|
||||
|
||||
@@ -39,7 +39,7 @@ use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core_config_types::ForgetMe;
|
||||
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_crypto::hkdf::DerivationMaterial;
|
||||
use nym_gateway_client::client::config::GatewayClientConfig;
|
||||
use nym_gateway_client::{
|
||||
@@ -367,7 +367,7 @@ where
|
||||
// buffer controlling all messages fetched from provider
|
||||
// required so that other components would be able to use them (say the websocket)
|
||||
fn start_received_messages_buffer_controller(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
query_receiver: ReceivedBufferRequestReceiver,
|
||||
mixnet_receiver: MixnetMessageReceiver,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
@@ -552,18 +552,12 @@ where
|
||||
user_agent: Option<UserAgent>,
|
||||
) -> Box<dyn TopologyProvider + Send + Sync> {
|
||||
// if no custom provider was ... provided ..., create one using nym-api
|
||||
custom_provider.unwrap_or_else(|| match config_topology.topology_structure {
|
||||
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
|
||||
custom_provider.unwrap_or_else(|| {
|
||||
Box::new(NymApiTopologyProvider::new(
|
||||
config_topology,
|
||||
nym_api_urls,
|
||||
user_agent,
|
||||
)),
|
||||
config::TopologyStructure::GeoAware(group_by) => {
|
||||
warn!("using deprecated 'GeoAware' topology provider - this option will be removed very soon");
|
||||
|
||||
#[allow(deprecated)]
|
||||
Box::new(crate::client::topology_control::GeoAwareTopologyProvider::new(nym_api_urls, group_by))
|
||||
}
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -942,7 +936,7 @@ where
|
||||
|
||||
pub struct BaseClient {
|
||||
pub address: Recipient,
|
||||
pub identity_keys: Arc<identity::KeyPair>,
|
||||
pub identity_keys: Arc<ed25519::KeyPair>,
|
||||
pub client_input: ClientInputStatus,
|
||||
pub client_output: ClientOutputStatus,
|
||||
pub client_state: ClientState,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use crate::error::ClientCoreError;
|
||||
use nym_client_core_gateways_storage::{ActiveGateway, GatewayRegistration, GatewaysDetailsStore};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
|
||||
// helpers for error wrapping
|
||||
pub async fn set_active_gateway<D>(
|
||||
@@ -26,7 +26,7 @@ where
|
||||
|
||||
pub async fn get_active_gateway_identity<D>(
|
||||
details_store: &D,
|
||||
) -> Result<Option<identity::PublicKey>, ClientCoreError>
|
||||
) -> Result<Option<ed25519::PublicKey>, ClientCoreError>
|
||||
where
|
||||
D: GatewaysDetailsStore,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
@@ -42,7 +42,7 @@ where
|
||||
|
||||
pub async fn get_all_registered_identities<D>(
|
||||
details_store: &D,
|
||||
) -> Result<Vec<identity::PublicKey>, ClientCoreError>
|
||||
) -> Result<Vec<ed25519::PublicKey>, ClientCoreError>
|
||||
where
|
||||
D: GatewaysDetailsStore + Sync,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
|
||||
@@ -62,6 +62,10 @@ where
|
||||
/// Optional secondary predefined packet size used for the loop cover messages.
|
||||
secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
/// Specify whether any constructed packets should use the legacy format,
|
||||
/// where the payload keys are explicitly attached rather than using the seeds
|
||||
use_legacy_sphinx_format: bool,
|
||||
|
||||
packet_type: PacketType,
|
||||
|
||||
stats_tx: ClientStatsSender,
|
||||
@@ -130,6 +134,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
topology_access,
|
||||
primary_packet_size: traffic_config.primary_packet_size,
|
||||
secondary_packet_size: traffic_config.secondary_packet_size,
|
||||
use_legacy_sphinx_format: traffic_config.use_legacy_sphinx_format,
|
||||
packet_type: traffic_config.packet_type,
|
||||
stats_tx,
|
||||
task_client,
|
||||
@@ -182,6 +187,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
|
||||
let cover_message = match generate_loop_cover_packet(
|
||||
&mut self.rng,
|
||||
self.use_legacy_sphinx_format,
|
||||
topology_ref,
|
||||
&self.ack_key,
|
||||
&self.our_full_destination,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use nym_crypto::{
|
||||
asymmetric::{encryption, identity},
|
||||
asymmetric::{ed25519, x25519},
|
||||
hkdf::{DerivationMaterial, InvalidLength},
|
||||
};
|
||||
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
|
||||
@@ -25,10 +25,10 @@ mod test;
|
||||
#[derive(Clone)]
|
||||
pub struct ClientKeys {
|
||||
/// identity key associated with the client instance.
|
||||
identity_keypair: Arc<identity::KeyPair>,
|
||||
identity_keypair: Arc<ed25519::KeyPair>,
|
||||
|
||||
/// encryption key associated with the client instance.
|
||||
encryption_keypair: Arc<encryption::KeyPair>,
|
||||
encryption_keypair: Arc<x25519::KeyPair>,
|
||||
|
||||
/// key used for producing and processing acknowledgement packets.
|
||||
ack_key: Arc<AckKey>,
|
||||
@@ -41,8 +41,8 @@ impl ClientKeys {
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
ClientKeys {
|
||||
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
identity_keypair: Arc::new(ed25519::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
}
|
||||
}
|
||||
@@ -56,18 +56,18 @@ impl ClientKeys {
|
||||
{
|
||||
let secret = derivation_material.derive_secret()?;
|
||||
Ok(ClientKeys {
|
||||
identity_keypair: Arc::new(identity::KeyPair::from_secret(
|
||||
identity_keypair: Arc::new(ed25519::KeyPair::from_secret(
|
||||
secret,
|
||||
derivation_material.index(),
|
||||
)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_keys(
|
||||
id_keypair: identity::KeyPair,
|
||||
enc_keypair: encryption::KeyPair,
|
||||
id_keypair: ed25519::KeyPair,
|
||||
enc_keypair: x25519::KeyPair,
|
||||
ack_key: AckKey,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -85,13 +85,13 @@ impl ClientKeys {
|
||||
store.store_keys(self).await
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`identity::KeyPair`].
|
||||
pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
|
||||
/// Gets an atomically reference counted pointer to [`ed25519::KeyPair`].
|
||||
pub fn identity_keypair(&self) -> Arc<ed25519::KeyPair> {
|
||||
Arc::clone(&self.identity_keypair)
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`encryption::KeyPair`].
|
||||
pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
|
||||
/// Gets an atomically reference counted pointer to [`x25519::KeyPair`].
|
||||
pub fn encryption_keypair(&self) -> Arc<x25519::KeyPair> {
|
||||
Arc::clone(&self.encryption_keypair)
|
||||
}
|
||||
/// Gets an atomically reference counted pointer to [`AckKey`].
|
||||
@@ -103,8 +103,8 @@ impl ClientKeys {
|
||||
fn _assert_keys_zeroize_on_drop() {
|
||||
fn _assert_zeroize_on_drop<T: ZeroizeOnDrop>() {}
|
||||
|
||||
_assert_zeroize_on_drop::<identity::KeyPair>();
|
||||
_assert_zeroize_on_drop::<encryption::KeyPair>();
|
||||
_assert_zeroize_on_drop::<ed25519::KeyPair>();
|
||||
_assert_zeroize_on_drop::<x25519::KeyPair>();
|
||||
_assert_zeroize_on_drop::<AckKey>();
|
||||
_assert_zeroize_on_drop::<LegacySharedKeys>();
|
||||
_assert_zeroize_on_drop::<SharedSymmetricKey>();
|
||||
|
||||
@@ -11,7 +11,7 @@ use tokio::sync::Mutex;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::config::disk_persistence::ClientKeysPaths;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -86,13 +86,13 @@ impl OnDiskKeys {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> {
|
||||
pub fn load_encryption_keypair(&self) -> Result<x25519::KeyPair, OnDiskKeysError> {
|
||||
let encryption_paths = self.paths.encryption_key_pair_path();
|
||||
self.load_keypair(encryption_paths, "encryption")
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> {
|
||||
pub fn load_identity_keypair(&self) -> Result<ed25519::KeyPair, OnDiskKeysError> {
|
||||
let identity_paths = self.paths.identity_key_pair_path();
|
||||
self.load_keypair(identity_paths, "identity")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_client::error::GatewayClientError;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
|
||||
@@ -30,7 +30,7 @@ fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGate
|
||||
/// This combines combines the functionalities of being able to send and receive mix packets.
|
||||
#[async_trait]
|
||||
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
|
||||
fn gateway_identity(&self) -> identity::PublicKey;
|
||||
fn gateway_identity(&self) -> ed25519::PublicKey;
|
||||
fn ws_fd(&self) -> Option<RawFd>;
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
@@ -75,7 +75,7 @@ pub trait GatewayReceiver {
|
||||
#[async_trait]
|
||||
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
|
||||
#[inline]
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
fn gateway_identity(&self) -> ed25519::PublicKey {
|
||||
(**self).gateway_identity()
|
||||
}
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
@@ -134,7 +134,7 @@ where
|
||||
St: CredentialStorage,
|
||||
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
fn gateway_identity(&self) -> ed25519::PublicKey {
|
||||
self.gateway_client.gateway_identity()
|
||||
}
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
@@ -190,7 +190,7 @@ pub enum LocalGatewayError {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct LocalGateway {
|
||||
/// Identity of the locally managed gateway
|
||||
local_identity: identity::PublicKey,
|
||||
local_identity: ed25519::PublicKey,
|
||||
|
||||
// 'sender' part
|
||||
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
|
||||
@@ -203,7 +203,7 @@ pub struct LocalGateway {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl LocalGateway {
|
||||
pub fn new(
|
||||
local_identity: identity::PublicKey,
|
||||
local_identity: ed25519::PublicKey,
|
||||
packet_forwarder: nym_mixnet_client::forwarder::MixForwardingSender,
|
||||
packet_router_tx: oneshot::Sender<PacketRouter>,
|
||||
) -> Self {
|
||||
@@ -221,7 +221,7 @@ mod nonwasm_sealed {
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for LocalGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
fn gateway_identity(&self) -> ed25519::PublicKey {
|
||||
self.local_identity
|
||||
}
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
@@ -263,7 +263,7 @@ mod nonwasm_sealed {
|
||||
|
||||
// if we ever decided to start writing unit tests... : )
|
||||
pub struct MockGateway {
|
||||
dummy_identity: identity::PublicKey,
|
||||
dummy_identity: ed25519::PublicKey,
|
||||
packet_router: Option<PacketRouter>,
|
||||
sent: Vec<MixPacket>,
|
||||
}
|
||||
@@ -303,7 +303,7 @@ impl GatewaySender for MockGateway {
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for MockGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
fn gateway_identity(&self) -> ed25519::PublicKey {
|
||||
self.dummy_identity
|
||||
}
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
|
||||
@@ -9,7 +9,6 @@ use crate::client::real_messages_control::{AckActionSender, Action};
|
||||
use crate::client::replies::reply_controller::MaxRetransmissions;
|
||||
use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags};
|
||||
use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
|
||||
@@ -27,6 +26,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
|
||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||
#[derive(Debug, Error)]
|
||||
@@ -98,6 +98,12 @@ pub(crate) struct Config {
|
||||
/// Specify whether route selection should be determined by the packet header.
|
||||
deterministic_route_selection: bool,
|
||||
|
||||
/// Indicates whether to mix hops or not. If mix hops are enabled, traffic
|
||||
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
|
||||
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
|
||||
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
|
||||
disable_mix_hops: bool,
|
||||
|
||||
/// Average delay a data packet is going to get delay at a single mixnode.
|
||||
average_packet_delay: Duration,
|
||||
|
||||
@@ -109,6 +115,10 @@ pub(crate) struct Config {
|
||||
|
||||
/// Optional secondary predefined packet size used for the encapsulated messages.
|
||||
secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
/// Specify whether any constructed reply surbs should use the legacy format,
|
||||
/// where the payload keys are explicitly attached rather than using the seeds
|
||||
use_legacy_sphinx_format: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -118,6 +128,7 @@ impl Config {
|
||||
average_packet_delay: Duration,
|
||||
average_ack_delay: Duration,
|
||||
deterministic_route_selection: bool,
|
||||
use_legacy_reply_surb_format: bool,
|
||||
) -> Self {
|
||||
Config {
|
||||
ack_key,
|
||||
@@ -127,6 +138,8 @@ impl Config {
|
||||
average_ack_delay,
|
||||
primary_packet_size: PacketSize::default(),
|
||||
secondary_packet_size: None,
|
||||
use_legacy_sphinx_format: use_legacy_reply_surb_format,
|
||||
disable_mix_hops: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +154,12 @@ impl Config {
|
||||
self.secondary_packet_size = packet_size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configure whether messages senders using this config should use mix hops or not when sending messages.
|
||||
pub fn disable_mix_hops(mut self, disable_mix_hops: bool) -> Self {
|
||||
self.disable_mix_hops = disable_mix_hops;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -186,6 +205,8 @@ where
|
||||
config.sender_address,
|
||||
config.average_packet_delay,
|
||||
config.average_ack_delay,
|
||||
config.use_legacy_sphinx_format,
|
||||
config.disable_mix_hops,
|
||||
);
|
||||
MessageHandler {
|
||||
config,
|
||||
@@ -254,9 +275,11 @@ where
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = self.get_topology(&topology_permit)?;
|
||||
|
||||
let reply_surbs = self
|
||||
.message_preparer
|
||||
.generate_reply_surbs(amount, topology)?;
|
||||
let reply_surbs = self.message_preparer.generate_reply_surbs(
|
||||
self.config.use_legacy_sphinx_format,
|
||||
amount,
|
||||
topology,
|
||||
)?;
|
||||
|
||||
let reply_keys = reply_surbs
|
||||
.iter()
|
||||
@@ -275,7 +298,7 @@ where
|
||||
) -> Result<(), SurbWrappedPreparationError> {
|
||||
let msg = NymMessage::new_reply(message);
|
||||
let packet_size = self.optimal_packet_size(&msg);
|
||||
debug!("Using {packet_size} packets for {msg}");
|
||||
trace!("Using {packet_size} packets for {msg}");
|
||||
|
||||
let mut fragment = self
|
||||
.message_preparer
|
||||
@@ -339,7 +362,7 @@ where
|
||||
pub(crate) fn split_reply_message(&mut self, message: Vec<u8>) -> Vec<Fragment> {
|
||||
let msg = NymMessage::new_reply(ReplyMessage::new_data_message(message));
|
||||
let packet_size = self.optimal_packet_size(&msg);
|
||||
debug!("Using {packet_size} packets for {msg}");
|
||||
trace!("Using {packet_size} packets for {msg}");
|
||||
|
||||
self.message_preparer
|
||||
.pad_and_split_message(msg, packet_size)
|
||||
@@ -472,7 +495,7 @@ where
|
||||
} else {
|
||||
self.optimal_packet_size(&message)
|
||||
};
|
||||
debug!("Using {packet_size} packets for {message}");
|
||||
trace!("Using {packet_size} packets for {message}");
|
||||
let fragments = self
|
||||
.message_preparer
|
||||
.pad_and_split_message(message, packet_size);
|
||||
@@ -522,6 +545,7 @@ where
|
||||
self.generate_reply_surbs_with_keys(amount as usize).await?;
|
||||
|
||||
let message = NymMessage::new_repliable(RepliableMessage::new_additional_surbs(
|
||||
self.config.use_legacy_sphinx_format,
|
||||
sender_tag,
|
||||
reply_surbs,
|
||||
));
|
||||
@@ -559,8 +583,12 @@ where
|
||||
.generate_reply_surbs_with_keys(num_reply_surbs as usize)
|
||||
.await?;
|
||||
|
||||
let message =
|
||||
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
|
||||
let message = NymMessage::new_repliable(RepliableMessage::new_data(
|
||||
self.config.use_legacy_sphinx_format,
|
||||
message,
|
||||
sender_tag,
|
||||
reply_surbs,
|
||||
));
|
||||
|
||||
self.try_split_and_send_non_reply_message(
|
||||
message,
|
||||
|
||||
@@ -99,9 +99,11 @@ impl<'a> From<&'a Config> for message_handler::Config {
|
||||
cfg.traffic.average_packet_delay,
|
||||
cfg.acks.average_ack_delay,
|
||||
cfg.traffic.deterministic_route_selection,
|
||||
cfg.traffic.use_legacy_sphinx_format,
|
||||
)
|
||||
.with_custom_primary_packet_size(cfg.traffic.primary_packet_size)
|
||||
.with_custom_secondary_packet_size(cfg.traffic.secondary_packet_size)
|
||||
.disable_mix_hops(cfg.traffic.disable_mix_hops)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,6 +252,7 @@ where
|
||||
(
|
||||
generate_loop_cover_packet(
|
||||
&mut self.rng,
|
||||
self.config.traffic.use_legacy_sphinx_format,
|
||||
topology_ref,
|
||||
&self.config.ack_key,
|
||||
&self.config.our_full_destination,
|
||||
|
||||
@@ -9,7 +9,7 @@ use futures::channel::mpsc;
|
||||
use futures::lock::Mutex;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_crypto::Digest;
|
||||
use nym_gateway_client::MixnetMessageReceiver;
|
||||
use nym_sphinx::anonymous_replies::requests::{
|
||||
@@ -39,7 +39,7 @@ pub type ReconstructedMessagesReceiver = mpsc::UnboundedReceiver<Vec<Reconstruct
|
||||
|
||||
struct ReceivedMessagesBufferInner<R: MessageReceiver> {
|
||||
messages: Vec<ReconstructedMessage>,
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
|
||||
// TODO: looking how it 'looks' here, perhaps `MessageReceiver` should be renamed to something
|
||||
// else instead.
|
||||
@@ -176,7 +176,7 @@ struct ReceivedMessagesBuffer<R: MessageReceiver> {
|
||||
|
||||
impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
fn new(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
@@ -250,10 +250,10 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
let mut reconstructed = Vec::new();
|
||||
for msg in msgs {
|
||||
let (reply_surbs, from_surb_request) = match msg.content {
|
||||
RepliableMessageContent::Data {
|
||||
message,
|
||||
reply_surbs,
|
||||
} => {
|
||||
RepliableMessageContent::Data(content) => {
|
||||
let reply_surbs = content.reply_surbs;
|
||||
let message = content.message;
|
||||
|
||||
trace!(
|
||||
"received message that also contained additional {} reply surbs from {:?}!",
|
||||
reply_surbs.len(),
|
||||
@@ -264,7 +264,9 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
|
||||
(reply_surbs, false)
|
||||
}
|
||||
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
|
||||
RepliableMessageContent::AdditionalSurbs(content) => {
|
||||
let reply_surbs = content.reply_surbs;
|
||||
|
||||
trace!(
|
||||
"received additional {} reply surbs from {:?}!",
|
||||
reply_surbs.len(),
|
||||
@@ -272,9 +274,37 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
);
|
||||
(reply_surbs, true)
|
||||
}
|
||||
RepliableMessageContent::Heartbeat {
|
||||
additional_reply_surbs,
|
||||
} => {
|
||||
RepliableMessageContent::Heartbeat(content) => {
|
||||
let additional_reply_surbs = content.additional_reply_surbs;
|
||||
error!("received a repliable heartbeat message - we don't know how to handle it yet (and we won't know until future PRs)");
|
||||
(additional_reply_surbs, false)
|
||||
}
|
||||
RepliableMessageContent::DataV2(content) => {
|
||||
let reply_surbs = content.reply_surbs;
|
||||
let message = content.message;
|
||||
|
||||
trace!(
|
||||
"received message that also contained additional {} reply surbs from {:?}!",
|
||||
reply_surbs.len(),
|
||||
msg.sender_tag
|
||||
);
|
||||
|
||||
reconstructed.push(ReconstructedMessage::new(message, msg.sender_tag));
|
||||
|
||||
(reply_surbs, false)
|
||||
}
|
||||
RepliableMessageContent::AdditionalSurbsV2(content) => {
|
||||
let reply_surbs = content.reply_surbs;
|
||||
|
||||
trace!(
|
||||
"received additional {} reply surbs from {:?}!",
|
||||
reply_surbs.len(),
|
||||
msg.sender_tag
|
||||
);
|
||||
(reply_surbs, true)
|
||||
}
|
||||
RepliableMessageContent::HeartbeatV2(content) => {
|
||||
let additional_reply_surbs = content.additional_reply_surbs;
|
||||
error!("received a repliable heartbeat message - we don't know how to handle it yet (and we won't know until future PRs)");
|
||||
(additional_reply_surbs, false)
|
||||
}
|
||||
@@ -536,7 +566,7 @@ pub(crate) struct ReceivedMessagesBufferController<R: MessageReceiver> {
|
||||
|
||||
impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferController<R> {
|
||||
pub(crate) fn new(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
query_receiver: ReceivedBufferRequestReceiver,
|
||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
use crate::config::GroupBy;
|
||||
use log::{debug, error};
|
||||
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
|
||||
use nym_network_defaults::var_names::EXPLORER_API;
|
||||
use nym_topology::{
|
||||
provider_trait::{async_trait, TopologyProvider},
|
||||
NymTopology,
|
||||
};
|
||||
use nym_validator_client::client::NodeId;
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use std::collections::HashMap;
|
||||
use tap::TapOptional;
|
||||
use url::Url;
|
||||
|
||||
pub use nym_country_group::CountryGroup;
|
||||
|
||||
fn create_explorer_client() -> Option<ExplorerClient> {
|
||||
let Ok(explorer_api_url) = std::env::var(EXPLORER_API) else {
|
||||
error!("Missing EXPLORER_API");
|
||||
return None;
|
||||
};
|
||||
|
||||
let Ok(explorer_api_url) = explorer_api_url.parse() else {
|
||||
error!("Failed to parse EXPLORER_API");
|
||||
return None;
|
||||
};
|
||||
|
||||
log::debug!("Using explorer-api url: {}", explorer_api_url);
|
||||
let Ok(client) = nym_explorer_client::ExplorerClient::new(explorer_api_url) else {
|
||||
error!("Failed to create explorer-api client");
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(client)
|
||||
}
|
||||
|
||||
fn group_mixnodes_by_country_code(
|
||||
mixnodes: Vec<PrettyDetailedMixNodeBond>,
|
||||
) -> HashMap<CountryGroup, Vec<NodeId>> {
|
||||
mixnodes
|
||||
.into_iter()
|
||||
.fold(HashMap::<CountryGroup, Vec<NodeId>>::new(), |mut acc, m| {
|
||||
if let Some(ref location) = m.location {
|
||||
let country_code = location.two_letter_iso_country_code.clone();
|
||||
let group_code = CountryGroup::new(country_code.as_str());
|
||||
let mixnodes = acc.entry(group_code).or_default();
|
||||
mixnodes.push(m.mix_id);
|
||||
}
|
||||
acc
|
||||
})
|
||||
}
|
||||
|
||||
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
|
||||
let mixnode_distribution = mixnodes
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v.len()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
debug!("Mixnode distribution - {}", mixnode_distribution);
|
||||
}
|
||||
|
||||
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
|
||||
if topology.ensure_minimally_routable().is_err() {
|
||||
error!("Layer is missing in topology!");
|
||||
return Err(());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[deprecated(note = "use NymApiTopologyProvider instead as explorer API will soon be removed")]
|
||||
pub struct GeoAwareTopologyProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient,
|
||||
filter_on: GroupBy,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl GeoAwareTopologyProvider {
|
||||
pub fn new(mut nym_api_urls: Vec<Url>, filter_on: GroupBy) -> GeoAwareTopologyProvider {
|
||||
log::info!(
|
||||
"Creating geo-aware topology provider with filter on {}",
|
||||
filter_on
|
||||
);
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
GeoAwareTopologyProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient::new(
|
||||
nym_api_urls[0].clone(),
|
||||
),
|
||||
filter_on,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_topology(&self) -> Option<NymTopology> {
|
||||
let rewarded_set = self
|
||||
.validator_client
|
||||
.get_current_rewarded_set()
|
||||
.await
|
||||
.inspect_err(|err| error!("failed to get current rewarded set: {err}"))
|
||||
.ok()?;
|
||||
|
||||
let mut topology = NymTopology::new_empty(rewarded_set);
|
||||
|
||||
let mixnodes = match self
|
||||
.validator_client
|
||||
.get_all_basic_active_mixing_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self
|
||||
.validator_client
|
||||
.get_all_basic_entry_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
// Also fetch mixnodes cached by explorer-api, with the purpose of getting their
|
||||
// geolocation.
|
||||
debug!("Fetching mixnodes from explorer-api...");
|
||||
let explorer_client = create_explorer_client()?;
|
||||
let Ok(mixnodes_from_explorer_api) = explorer_client.get_mixnodes().await else {
|
||||
error!("failed to get mixnodes from explorer-api");
|
||||
return None;
|
||||
};
|
||||
|
||||
debug!("Fetching gateways from explorer-api...");
|
||||
let Ok(gateways_from_explorer_api) = explorer_client.get_gateways().await else {
|
||||
error!("failed to get mixnodes from explorer-api");
|
||||
return None;
|
||||
};
|
||||
|
||||
// Determine what we should filter around
|
||||
let filter_on = match self.filter_on {
|
||||
GroupBy::CountryGroup(group) => group,
|
||||
GroupBy::NymAddress(recipient) => {
|
||||
// Convert recipient into a country group by extracting out the gateway part and
|
||||
// using that as the country code.
|
||||
let gateway = recipient.gateway().to_base58_string();
|
||||
|
||||
// Lookup the location of this gateway by using the location data from the
|
||||
// explorer-api
|
||||
let gateway_location = gateways_from_explorer_api
|
||||
.iter()
|
||||
.find(|g| g.gateway.identity_key == gateway)
|
||||
.and_then(|g| g.location.clone())
|
||||
.map(|location| location.two_letter_iso_country_code)
|
||||
.tap_none(|| error!("No location found for the gateway: {}", gateway))?;
|
||||
debug!(
|
||||
"Filtering on nym-address: {}, with location: {}",
|
||||
recipient, gateway_location
|
||||
);
|
||||
|
||||
CountryGroup::new(&gateway_location)
|
||||
}
|
||||
};
|
||||
debug!("Filter group: {}", filter_on);
|
||||
|
||||
// Partition mixnodes_from_explorer_api according to the value of
|
||||
// two_letter_iso_country_code.
|
||||
// NOTE: we construct the full distribution here, but only use the one we're interested in.
|
||||
// The reason we this instead of a straight filter is that this opens up the possibility to
|
||||
// complement a small grouping with mixnodes from adjecent countries.
|
||||
let mixnode_distribution = group_mixnodes_by_country_code(mixnodes_from_explorer_api);
|
||||
log_mixnode_distribution(&mixnode_distribution);
|
||||
|
||||
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&filter_on) else {
|
||||
error!("no mixnodes found for: {}", filter_on);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mixnodes = mixnodes
|
||||
.into_iter()
|
||||
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
topology.add_skimmed_nodes(&mixnodes);
|
||||
topology.add_skimmed_nodes(&gateways);
|
||||
|
||||
// TODO: return real error type
|
||||
check_layer_integrity(topology.clone()).ok()?;
|
||||
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl TopologyProvider for GeoAwareTopologyProvider {
|
||||
// this will be manually refreshed on a timer specified inside mixnet client config
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl TopologyProvider for GeoAwareTopologyProvider {
|
||||
// this will be manually refreshed on a timer specified inside mixnet client config
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_topology().await
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,8 @@ use tokio::time::sleep;
|
||||
use wasmtimer::tokio::sleep;
|
||||
|
||||
mod accessor;
|
||||
pub mod geo_aware_provider;
|
||||
pub mod nym_api_provider;
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use geo_aware_provider::GeoAwareTopologyProvider;
|
||||
pub use nym_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
|
||||
pub use nym_topology::provider_trait::TopologyProvider;
|
||||
|
||||
|
||||
@@ -70,6 +70,10 @@ impl NymApiTopologyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable_bincode(&mut self) {
|
||||
self.validator_client.use_bincode = false;
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::mix_traffic::transceiver::ErasedGatewayError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
|
||||
use nym_gateway_client::error::GatewayClientError;
|
||||
use nym_topology::node::RoutingNodeError;
|
||||
use nym_topology::{NodeId, NymTopologyError};
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::error::ClientCoreError;
|
||||
use crate::init::types::RegistrationResult;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::{debug, info, trace, warn};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_topology::node::RoutingNode;
|
||||
use nym_validator_client::client::IdentityKeyRef;
|
||||
@@ -52,7 +52,7 @@ const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
// The abstraction that some of these helpers use
|
||||
pub trait ConnectableGateway {
|
||||
fn node_id(&self) -> NodeId;
|
||||
fn identity(&self) -> identity::PublicKey;
|
||||
fn identity(&self) -> ed25519::PublicKey;
|
||||
fn clients_address(&self, prefer_ipv6: bool) -> Option<String>;
|
||||
fn is_wss(&self) -> bool;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ impl ConnectableGateway for RoutingNode {
|
||||
self.node_id
|
||||
}
|
||||
|
||||
fn identity(&self) -> identity::PublicKey {
|
||||
fn identity(&self) -> ed25519::PublicKey {
|
||||
self.identity_key
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ pub(super) fn get_specified_gateway(
|
||||
must_use_tls: bool,
|
||||
) -> Result<RoutingNode, ClientCoreError> {
|
||||
log::debug!("Requesting specified gateway: {}", gateway_identity);
|
||||
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
|
||||
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
let gateway = gateways
|
||||
@@ -312,9 +312,9 @@ pub(super) fn get_specified_gateway(
|
||||
}
|
||||
|
||||
pub(super) async fn register_with_gateway(
|
||||
gateway_id: identity::PublicKey,
|
||||
gateway_id: ed25519::PublicKey,
|
||||
gateway_listener: Url,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
our_identity: Arc<ed25519::KeyPair>,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
) -> Result<RegistrationResult, ClientCoreError> {
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::init::{setup_gateway, use_loaded_gateway_details};
|
||||
use nym_client_core_gateways_storage::{
|
||||
GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_client::client::InitGatewayClient;
|
||||
use nym_gateway_requests::shared_key::SharedGatewayKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
@@ -26,14 +26,14 @@ use url::Url;
|
||||
|
||||
pub enum SelectedGateway {
|
||||
Remote {
|
||||
gateway_id: identity::PublicKey,
|
||||
gateway_id: ed25519::PublicKey,
|
||||
|
||||
gateway_owner_address: Option<AccountId>,
|
||||
|
||||
gateway_listener: Url,
|
||||
},
|
||||
Custom {
|
||||
gateway_id: identity::PublicKey,
|
||||
gateway_id: ed25519::PublicKey,
|
||||
additional_data: Option<Vec<u8>>,
|
||||
},
|
||||
}
|
||||
@@ -77,7 +77,7 @@ impl SelectedGateway {
|
||||
gateway_id: String,
|
||||
additional_data: Option<Vec<u8>>,
|
||||
) -> Result<Self, ClientCoreError> {
|
||||
let gateway_id = identity::PublicKey::from_base58_string(&gateway_id)
|
||||
let gateway_id = ed25519::PublicKey::from_base58_string(&gateway_id)
|
||||
.map_err(|source| ClientCoreError::MalformedGatewayIdentity { gateway_id, source })?;
|
||||
|
||||
Ok(SelectedGateway::Custom {
|
||||
@@ -86,7 +86,7 @@ impl SelectedGateway {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn gateway_id(&self) -> &identity::PublicKey {
|
||||
pub fn gateway_id(&self) -> &ed25519::PublicKey {
|
||||
match self {
|
||||
SelectedGateway::Remote { gateway_id, .. } => gateway_id,
|
||||
SelectedGateway::Custom { gateway_id, .. } => gateway_id,
|
||||
@@ -142,7 +142,7 @@ impl InitialisationResult {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gateway_id(&self) -> identity::PublicKey {
|
||||
pub fn gateway_id(&self) -> ed25519::PublicKey {
|
||||
self.gateway_registration.details.gateway_id()
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ impl GatewaySetup {
|
||||
}
|
||||
|
||||
/// new gateway setup performed by each client that's inbuilt in a gateway (like NR or IPR)
|
||||
pub fn new_inbuilt(identity: identity::PublicKey) -> Self {
|
||||
pub fn new_inbuilt(identity: ed25519::PublicKey) -> Self {
|
||||
GatewaySetup::New {
|
||||
specification: GatewaySelectionSpecification::Custom {
|
||||
gateway_identity: identity.to_base58_string(),
|
||||
|
||||
@@ -17,7 +17,7 @@ use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCred
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_credentials::CredentialSpendingData;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway_requests::registration::handshake::client_handshake;
|
||||
use nym_gateway_requests::{
|
||||
BinaryRequest, ClientControlRequest, ClientRequest, GatewayProtocolVersionExt,
|
||||
@@ -57,7 +57,7 @@ pub(crate) mod websockets;
|
||||
use websockets::connect_async;
|
||||
|
||||
pub struct GatewayConfig {
|
||||
pub gateway_identity: identity::PublicKey,
|
||||
pub gateway_identity: ed25519::PublicKey,
|
||||
|
||||
// currently a dead field
|
||||
pub gateway_owner: Option<String>,
|
||||
@@ -67,7 +67,7 @@ pub struct GatewayConfig {
|
||||
|
||||
impl GatewayConfig {
|
||||
pub fn new(
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_identity: ed25519::PublicKey,
|
||||
gateway_owner: Option<String>,
|
||||
gateway_listener: String,
|
||||
) -> Self {
|
||||
@@ -93,8 +93,8 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
authenticated: bool,
|
||||
bandwidth: ClientBandwidth,
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_identity: ed25519::PublicKey,
|
||||
local_identity: Arc<ed25519::KeyPair>,
|
||||
shared_key: Option<Arc<SharedGatewayKey>>,
|
||||
connection: SocketState,
|
||||
packet_router: PacketRouter,
|
||||
@@ -117,7 +117,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
pub fn new(
|
||||
cfg: GatewayClientConfig,
|
||||
gateway_config: GatewayConfig,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
local_identity: Arc<ed25519::KeyPair>,
|
||||
// TODO: make it mandatory. if you don't want to pass it, use `new_init`
|
||||
shared_key: Option<Arc<SharedGatewayKey>>,
|
||||
packet_router: PacketRouter,
|
||||
@@ -145,7 +145,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gateway_identity(&self) -> identity::PublicKey {
|
||||
pub fn gateway_identity(&self) -> ed25519::PublicKey {
|
||||
self.gateway_identity
|
||||
}
|
||||
|
||||
@@ -1063,8 +1063,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
// for initialisation we do not need credential storage. Though it's still a bit weird we have to set the generic...
|
||||
pub fn new_init(
|
||||
gateway_listener: Url,
|
||||
gateway_identity: identity::PublicKey,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_identity: ed25519::PublicKey,
|
||||
local_identity: Arc<ed25519::KeyPair>,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
) -> Self {
|
||||
log::trace!("Initialising gateway client");
|
||||
|
||||
@@ -345,25 +345,47 @@ impl<C, S> Client<C, S> {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NymApiClient {
|
||||
pub use_bincode: bool,
|
||||
pub nym_api: nym_api::Client,
|
||||
// TODO: perhaps if we really need it at some (currently I don't see any reasons for it)
|
||||
// we could re-implement the communication with the REST API on port 1317
|
||||
}
|
||||
|
||||
impl From<nym_api::Client> for NymApiClient {
|
||||
fn from(nym_api: nym_api::Client) -> Self {
|
||||
NymApiClient {
|
||||
use_bincode: false,
|
||||
nym_api,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have to allow the use of deprecated method here as they're calling the deprecated trait methods
|
||||
#[allow(deprecated)]
|
||||
impl NymApiClient {
|
||||
pub fn new(api_url: Url) -> Self {
|
||||
let nym_api = nym_api::Client::new(api_url, None);
|
||||
|
||||
NymApiClient { nym_api }
|
||||
NymApiClient {
|
||||
use_bincode: true,
|
||||
nym_api,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn new_with_timeout(api_url: Url, timeout: std::time::Duration) -> Self {
|
||||
let nym_api = nym_api::Client::new(api_url, Some(timeout));
|
||||
|
||||
NymApiClient { nym_api }
|
||||
NymApiClient {
|
||||
use_bincode: true,
|
||||
nym_api,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_bincode(mut self, use_bincode: bool) -> Self {
|
||||
self.use_bincode = use_bincode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn new_with_user_agent(api_url: Url, user_agent: impl Into<UserAgent>) -> Self {
|
||||
@@ -373,7 +395,10 @@ impl NymApiClient {
|
||||
.build::<ValidatorClientError>()
|
||||
.expect("failed to build nym api client");
|
||||
|
||||
NymApiClient { nym_api }
|
||||
NymApiClient {
|
||||
use_bincode: false,
|
||||
nym_api,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn api_url(&self) -> &Url {
|
||||
@@ -410,7 +435,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_entry_assigned_nodes(false, Some(page), None)
|
||||
.get_basic_entry_assigned_nodes(false, Some(page), None, self.use_bincode)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -436,7 +461,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_active_mixing_assigned_nodes(false, Some(page), None)
|
||||
.get_basic_active_mixing_assigned_nodes(false, Some(page), None, self.use_bincode)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -462,7 +487,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_mixing_capable_nodes(false, Some(page), None)
|
||||
.get_basic_mixing_capable_nodes(false, Some(page), None, self.use_bincode)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -485,7 +510,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_nodes(false, Some(page), None)
|
||||
.get_basic_nodes(false, Some(page), None, self.use_bincode)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
|
||||
@@ -318,6 +318,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
use_bincode: bool,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
@@ -333,7 +334,11 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
if use_bincode {
|
||||
params.push(("output", "bincode".to_string()))
|
||||
}
|
||||
|
||||
self.get_response(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
@@ -355,6 +360,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
use_bincode: bool,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
@@ -370,7 +376,11 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
if use_bincode {
|
||||
params.push(("output", "bincode".to_string()))
|
||||
}
|
||||
|
||||
self.get_response(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
@@ -392,6 +402,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
use_bincode: bool,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
@@ -407,7 +418,11 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
if use_bincode {
|
||||
params.push(("output", "bincode".to_string()))
|
||||
}
|
||||
|
||||
self.get_response(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
@@ -427,6 +442,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
use_bincode: bool,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
@@ -442,7 +458,11 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
if use_bincode {
|
||||
params.push(("output", "bincode".to_string()))
|
||||
}
|
||||
|
||||
self.get_response(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
|
||||
@@ -15,7 +15,7 @@ use nym_credentials::{
|
||||
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures, EpochVerificationKey,
|
||||
};
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use tempfile::NamedTempFile;
|
||||
@@ -83,7 +83,7 @@ async fn issue_client_ticketbook(
|
||||
);
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(credentials_store).await;
|
||||
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
|
||||
let private_id_key: ed25519::PrivateKey = nym_pemstore::load_key(private_id_key)?;
|
||||
utils::issue_credential(
|
||||
&client,
|
||||
&persistent_storage,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_types::helpers::ConsoleSigningOutput;
|
||||
use nym_validator_client::nyxd::error::NyxdError;
|
||||
use std::path::PathBuf;
|
||||
@@ -34,14 +34,14 @@ pub struct SignArgs {
|
||||
|
||||
pub async fn sign(args: SignArgs) -> Result<(), NyxdError> {
|
||||
eprintln!(">>> loading: {}", args.private_key.display());
|
||||
let private_identity_key: identity::PrivateKey =
|
||||
let private_identity_key: ed25519::PrivateKey =
|
||||
nym_pemstore::load_key(args.private_key).expect("failed to load key");
|
||||
|
||||
print_signed_msg(&private_identity_key, &args.base58_msg, args.output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_signed_msg(private_key: &identity::PrivateKey, raw_msg: &str, output: OutputFormat) {
|
||||
fn print_signed_msg(private_key: &ed25519::PrivateKey, raw_msg: &str, output: OutputFormat) {
|
||||
let trimmed = raw_msg.trim();
|
||||
eprintln!(">>> attempting to sign: {trimmed}");
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
[package]
|
||||
name = "nym-country-group"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tracing.workspace = true
|
||||
@@ -1,158 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroup {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
// We map country codes into group, which initially are continent codes to a first approximation,
|
||||
// but we do it manually to reserve the right to tweak this distribution for our purposes.
|
||||
// NOTE: I did this quickly, and it's not a complete list of all countries, but only those that
|
||||
// were present in the network at the time. Please add more as needed.
|
||||
pub fn new(country_code: &str) -> Self {
|
||||
let country_code = country_code.to_uppercase();
|
||||
use CountryGroup::*;
|
||||
match country_code.as_ref() {
|
||||
// Europe
|
||||
"AT" => Europe,
|
||||
"BG" => Europe,
|
||||
"CH" => Europe,
|
||||
"CY" => Europe,
|
||||
"CZ" => Europe,
|
||||
"DE" => Europe,
|
||||
"DK" => Europe,
|
||||
"ES" => Europe,
|
||||
"FI" => Europe,
|
||||
"FR" => Europe,
|
||||
"GB" => Europe,
|
||||
"GR" => Europe,
|
||||
"IE" => Europe,
|
||||
"IT" => Europe,
|
||||
"LT" => Europe,
|
||||
"LU" => Europe,
|
||||
"LV" => Europe,
|
||||
"MD" => Europe,
|
||||
"MT" => Europe,
|
||||
"NL" => Europe,
|
||||
"NO" => Europe,
|
||||
"PL" => Europe,
|
||||
"RO" => Europe,
|
||||
"SE" => Europe,
|
||||
"SK" => Europe,
|
||||
"TR" => Europe,
|
||||
"UA" => Europe,
|
||||
|
||||
// North America
|
||||
"CA" => NorthAmerica,
|
||||
"MX" => NorthAmerica,
|
||||
"US" => NorthAmerica,
|
||||
|
||||
// South America
|
||||
"AR" => SouthAmerica,
|
||||
"BR" => SouthAmerica,
|
||||
"CL" => SouthAmerica,
|
||||
"CO" => SouthAmerica,
|
||||
"CR" => SouthAmerica,
|
||||
"GT" => SouthAmerica,
|
||||
|
||||
// Oceania
|
||||
"AU" => Oceania,
|
||||
|
||||
// Asia
|
||||
"AM" => Asia,
|
||||
"BH" => Asia,
|
||||
"CN" => Asia,
|
||||
"GE" => Asia,
|
||||
"HK" => Asia,
|
||||
"ID" => Asia,
|
||||
"IL" => Asia,
|
||||
"IN" => Asia,
|
||||
"JP" => Asia,
|
||||
"KH" => Asia,
|
||||
"KR" => Asia,
|
||||
"KZ" => Asia,
|
||||
"MY" => Asia,
|
||||
"RU" => Asia,
|
||||
"SG" => Asia,
|
||||
"TH" => Asia,
|
||||
"VN" => Asia,
|
||||
|
||||
// Africa
|
||||
"SC" => Africa,
|
||||
"UG" => Africa,
|
||||
"ZA" => Africa,
|
||||
|
||||
// And group level codes work too
|
||||
"EU" => Europe,
|
||||
"NA" => NorthAmerica,
|
||||
"SA" => SouthAmerica,
|
||||
"OC" => Oceania,
|
||||
"AS" => Asia,
|
||||
"AF" => Africa,
|
||||
|
||||
// And some aliases
|
||||
"EUROPE" => Europe,
|
||||
"NORTHAMERICA" => NorthAmerica,
|
||||
"SOUTHAMERICA" => SouthAmerica,
|
||||
"OCEANIA" => Oceania,
|
||||
"ASIA" => Asia,
|
||||
"AFRICA" => Africa,
|
||||
|
||||
_ => {
|
||||
info!("Unknown country code: {country_code}");
|
||||
Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CountryGroup {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe => write!(f, "EU"),
|
||||
NorthAmerica => write!(f, "NA"),
|
||||
SouthAmerica => write!(f, "SA"),
|
||||
Oceania => write!(f, "OC"),
|
||||
Asia => write!(f, "AS"),
|
||||
Africa => write!(f, "AF"),
|
||||
Unknown => write!(f, "Unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for CountryGroup {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let group = CountryGroup::new(s);
|
||||
if group == CountryGroup::Unknown {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
#[allow(unused)]
|
||||
fn known(self) -> Option<CountryGroup> {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
|
||||
Unknown => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,21 @@ impl MemoryEcachTicketbookManager {
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) async fn contains_ticketbook(&self, ticketbook: &IssuedTicketBook) -> bool {
|
||||
let ser = ticketbook.pack();
|
||||
let search_data = Zeroizing::new(ser.data);
|
||||
self.inner
|
||||
.read()
|
||||
.await
|
||||
.ticketbooks
|
||||
.iter()
|
||||
.any(|ticketbook| {
|
||||
let ser = ticketbook.1.ticketbook.pack();
|
||||
let data = Zeroizing::new(ser.data);
|
||||
search_data.eq(&data)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn get_ticketbooks_info(&self) -> Vec<BasicTicketbookInformation> {
|
||||
let guard = self.inner.read().await;
|
||||
|
||||
|
||||
@@ -95,6 +95,23 @@ impl SqliteEcashTicketbookManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn contains_ticketbook_data(&self, data: &[u8]) -> Result<bool, sqlx::Error> {
|
||||
let exists = sqlx::query(
|
||||
r#"
|
||||
SELECT 1
|
||||
FROM ecash_ticketbook
|
||||
WHERE ticketbook_data = ?
|
||||
|
||||
"#,
|
||||
)
|
||||
.bind(data)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?
|
||||
.is_some();
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_ticketbooks_info(
|
||||
&self,
|
||||
) -> Result<Vec<BasicTicketbookInformation>, sqlx::Error> {
|
||||
|
||||
@@ -70,6 +70,13 @@ impl Storage for EphemeralStorage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn contains_issued_ticketbook(
|
||||
&self,
|
||||
ticketbook: &IssuedTicketBook,
|
||||
) -> Result<bool, StorageError> {
|
||||
Ok(self.storage_manager.contains_ticketbook(ticketbook).await)
|
||||
}
|
||||
|
||||
async fn get_ticketbooks_info(
|
||||
&self,
|
||||
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError> {
|
||||
|
||||
@@ -145,6 +145,16 @@ impl Storage for PersistentStorage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn contains_issued_ticketbook(
|
||||
&self,
|
||||
ticketbook: &IssuedTicketBook,
|
||||
) -> Result<bool, Self::StorageError> {
|
||||
let ser = ticketbook.pack();
|
||||
let data = Zeroizing::new(ser.data);
|
||||
|
||||
Ok(self.storage_manager.contains_ticketbook_data(&data).await?)
|
||||
}
|
||||
|
||||
async fn get_ticketbooks_info(
|
||||
&self,
|
||||
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError> {
|
||||
|
||||
@@ -37,6 +37,11 @@ pub trait Storage: Clone + Send + Sync {
|
||||
ticketbook: &IssuedTicketBook,
|
||||
) -> Result<(), Self::StorageError>;
|
||||
|
||||
async fn contains_issued_ticketbook(
|
||||
&self,
|
||||
ticketbook: &IssuedTicketBook,
|
||||
) -> Result<bool, Self::StorageError>;
|
||||
|
||||
async fn get_ticketbooks_info(
|
||||
&self,
|
||||
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError>;
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_credentials_interface::{
|
||||
BlindedSignature, KeyPairUser, PartialWallet, TicketType, VerificationKeyAuth,
|
||||
WalletSignatures, WithdrawalRequest,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_ecash_contract_common::deposit::DepositId;
|
||||
use nym_ecash_time::{ecash_default_expiration_date, ecash_today, EcashTime};
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -27,7 +27,7 @@ pub struct IssuanceTicketBook {
|
||||
deposit_id: DepositId,
|
||||
|
||||
/// base58 encoded private key ensuring the depositer requested these attributes
|
||||
signing_key: identity::PrivateKey,
|
||||
signing_key: ed25519::PrivateKey,
|
||||
|
||||
/// ecash keypair related to the credential
|
||||
ecash_keypair: KeyPairUser,
|
||||
@@ -43,7 +43,7 @@ impl IssuanceTicketBook {
|
||||
pub fn new<M: AsRef<[u8]>>(
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
signing_key: ed25519::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Self {
|
||||
//this expiration date will get fed to the ecash library, force midnight to be set
|
||||
@@ -59,7 +59,7 @@ impl IssuanceTicketBook {
|
||||
pub fn new_with_expiration<M: AsRef<[u8]>>(
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
signing_key: ed25519::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
) -> Self {
|
||||
@@ -93,7 +93,7 @@ impl IssuanceTicketBook {
|
||||
message
|
||||
}
|
||||
|
||||
fn request_signature(&self, signing_request: &CredentialSigningData) -> identity::Signature {
|
||||
fn request_signature(&self, signing_request: &CredentialSigningData) -> ed25519::Signature {
|
||||
let message = Self::request_plaintext(&signing_request.withdrawal_request, self.deposit_id);
|
||||
self.signing_key.sign(message)
|
||||
}
|
||||
@@ -127,7 +127,7 @@ impl IssuanceTicketBook {
|
||||
self.deposit_id
|
||||
}
|
||||
|
||||
pub fn identity_key(&self) -> &identity::PrivateKey {
|
||||
pub fn identity_key(&self) -> &ed25519::PrivateKey {
|
||||
&self.signing_key
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::ecash::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
|
||||
use nym_credentials_interface::CompactEcashError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::x25519::KeyRecoveryError;
|
||||
use nym_validator_client::ValidatorClientError;
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ pub mod bs58_ed25519_pubkey {
|
||||
}
|
||||
|
||||
pub mod bs58_ed25519_signature {
|
||||
use crate::asymmetric::identity::Signature;
|
||||
use crate::asymmetric::ed25519::Signature;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(
|
||||
@@ -1,8 +1,13 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod encryption;
|
||||
pub mod identity;
|
||||
pub mod ed25519;
|
||||
pub mod x25519;
|
||||
|
||||
pub use encryption as x25519;
|
||||
pub use identity as ed25519;
|
||||
// don't break existing imports
|
||||
// but deprecate them
|
||||
#[deprecated(note = "use ed25519 instead")]
|
||||
pub use ed25519 as identity;
|
||||
|
||||
#[deprecated(note = "use x25519 instead")]
|
||||
pub use x25519 as encryption;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::asymmetric::encryption;
|
||||
use crate::asymmetric::x25519;
|
||||
use crate::hkdf;
|
||||
use cipher::{Key, KeyIvInit, StreamCipher};
|
||||
use digest::crypto_common::BlockSizeUser;
|
||||
@@ -15,14 +15,14 @@ use rand::{CryptoRng, RngCore};
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new_ephemeral_shared_key<C, D, R>(
|
||||
rng: &mut R,
|
||||
remote_key: &encryption::PublicKey,
|
||||
) -> (encryption::KeyPair, Key<C>)
|
||||
remote_key: &x25519::PublicKey,
|
||||
) -> (x25519::KeyPair, Key<C>)
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
let ephemeral_keypair = x25519::KeyPair::new(rng);
|
||||
|
||||
// after performing diffie-hellman we don't care about the private component anymore
|
||||
let dh_result = ephemeral_keypair.private_key().diffie_hellman(remote_key);
|
||||
@@ -43,8 +43,8 @@ where
|
||||
|
||||
/// Recompute shared key using remote public key and local private key.
|
||||
pub fn recompute_shared_key<C, D>(
|
||||
remote_key: &encryption::PublicKey,
|
||||
local_key: &encryption::PrivateKey,
|
||||
remote_key: &x25519::PublicKey,
|
||||
local_key: &x25519::PrivateKey,
|
||||
) -> Key<C>
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::registration::handshake::state::State;
|
||||
use crate::SharedGatewayKey;
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{Sink, Stream};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
@@ -48,8 +48,8 @@ impl Future for GatewayHandshake<'_> {
|
||||
pub fn client_handshake<'a, S, R>(
|
||||
rng: &'a mut R,
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
gateway_pubkey: identity::PublicKey,
|
||||
identity: &'a ed25519::KeyPair,
|
||||
gateway_pubkey: ed25519::PublicKey,
|
||||
expects_credential_usage: bool,
|
||||
derive_aes256_gcm_siv_key: bool,
|
||||
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
|
||||
@@ -78,7 +78,7 @@ where
|
||||
pub fn gateway_handshake<'a, S, R>(
|
||||
rng: &'a mut R,
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
identity: &'a ed25519::KeyPair,
|
||||
received_init_payload: Vec<u8>,
|
||||
shutdown: TaskClient,
|
||||
) -> GatewayHandshake<'a>
|
||||
|
||||
@@ -14,11 +14,7 @@ use crate::{
|
||||
use futures::{Sink, SinkExt, Stream, StreamExt};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_crypto::symmetric::aead::random_nonce;
|
||||
use nym_crypto::{
|
||||
asymmetric::{encryption, identity},
|
||||
generic_array::typenum::Unsigned,
|
||||
hkdf,
|
||||
};
|
||||
use nym_crypto::{generic_array::typenum::Unsigned, hkdf};
|
||||
use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
|
||||
use rand::{thread_rng, CryptoRng, RngCore};
|
||||
use std::any::{type_name, Any};
|
||||
@@ -74,14 +70,14 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
pub(crate) fn new(
|
||||
rng: &'a mut R,
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
remote_pubkey: Option<identity::PublicKey>,
|
||||
identity: &'a ed25519::KeyPair,
|
||||
remote_pubkey: Option<ed25519::PublicKey>,
|
||||
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
|
||||
) -> Self
|
||||
where
|
||||
R: CryptoRng + RngCore,
|
||||
{
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
let ephemeral_keypair = x25519::KeyPair::new(rng);
|
||||
State {
|
||||
ws_stream,
|
||||
rng,
|
||||
@@ -113,7 +109,7 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn local_ephemeral_key(&self) -> &encryption::PublicKey {
|
||||
pub(crate) fn local_ephemeral_key(&self) -> &x25519::PublicKey {
|
||||
self.ephemeral_keypair.public_key()
|
||||
}
|
||||
|
||||
@@ -150,7 +146,7 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
|
||||
pub(crate) fn derive_shared_key(
|
||||
&mut self,
|
||||
remote_ephemeral_key: &encryption::PublicKey,
|
||||
remote_ephemeral_key: &x25519::PublicKey,
|
||||
initiator_salt: Option<&[u8]>,
|
||||
) {
|
||||
let dh_result = self
|
||||
@@ -189,7 +185,7 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
// assuming x is local and y is remote
|
||||
pub(crate) fn prepare_key_material_sig(
|
||||
&self,
|
||||
remote_ephemeral_key: &encryption::PublicKey,
|
||||
remote_ephemeral_key: &x25519::PublicKey,
|
||||
) -> Result<MaterialExchange, HandshakeError> {
|
||||
let plaintext: Vec<_> = self
|
||||
.ephemeral_keypair
|
||||
@@ -243,7 +239,7 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
)?;
|
||||
|
||||
// now verify signature itself
|
||||
let signature = identity::Signature::from_bytes(&decrypted_signature)
|
||||
let signature = ed25519::Signature::from_bytes(&decrypted_signature)
|
||||
.map_err(|_| HandshakeError::InvalidSignature)?;
|
||||
|
||||
// g^y || g^x, if y is remote and x is local
|
||||
@@ -261,7 +257,7 @@ impl<'a, S, R> State<'a, S, R> {
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn update_remote_identity(&mut self, remote_pubkey: identity::PublicKey) {
|
||||
pub(crate) fn update_remote_identity(&mut self, remote_pubkey: ed25519::PublicKey) {
|
||||
self.remote_pubkey = Some(remote_pubkey)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json", "gzip"] }
|
||||
bincode = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json", "gzip", "deflate", "brotli", "zstd"] }
|
||||
http.workspace = true
|
||||
url = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
@@ -26,11 +27,11 @@ bytes = { workspace = true }
|
||||
encoding_rs = { workspace = true }
|
||||
mime = { workspace = true }
|
||||
|
||||
|
||||
nym-http-api-common = { path = "../http-api-common", default-features = false }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
||||
hickory-resolver = { workspace = true, features = ["dns-over-https-rustls", "webpki-roots"] }
|
||||
hickory-resolver = { workspace = true, features = ["https-ring", "tls-ring", "webpki-roots"] }
|
||||
|
||||
# for request timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
@@ -39,3 +40,4 @@ features = ["tokio"]
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["rt", "macros"] }
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ use std::{
|
||||
};
|
||||
|
||||
use hickory_resolver::{
|
||||
config::{LookupIpStrategy, NameServerConfigGroup, ResolverConfig, ResolverOpts},
|
||||
error::{ResolveError, ResolveErrorKind},
|
||||
config::{LookupIpStrategy, NameServerConfigGroup, ResolverConfig, ServerOrderingStrategy},
|
||||
lookup_ip::{LookupIp, LookupIpIntoIter},
|
||||
TokioAsyncResolver,
|
||||
name_server::TokioConnectionProvider,
|
||||
ResolveError, TokioResolver,
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
use reqwest::dns::{Addrs, Name, Resolve, Resolving};
|
||||
@@ -92,8 +92,8 @@ pub struct HickoryDnsResolver {
|
||||
// Since we might not have been called in the context of a
|
||||
// Tokio Runtime in initialization, so we must delay the actual
|
||||
// construction of the resolver.
|
||||
state: Arc<OnceCell<TokioAsyncResolver>>,
|
||||
fallback: Arc<OnceCell<TokioAsyncResolver>>,
|
||||
state: Arc<OnceCell<TokioResolver>>,
|
||||
fallback: Arc<OnceCell<TokioResolver>>,
|
||||
dont_use_shared: bool,
|
||||
}
|
||||
|
||||
@@ -118,11 +118,8 @@ impl Resolve for HickoryDnsResolver {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// on failure use the fall back system configured DNS resolver
|
||||
match e.kind() {
|
||||
ResolveErrorKind::NoRecordsFound { .. } => {}
|
||||
_ => {
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
}
|
||||
if !e.is_no_records_found() {
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
}
|
||||
let resolver = fallback.get_or_try_init(|| {
|
||||
// using a closure here is slightly gross, but this makes sure that if the
|
||||
@@ -166,11 +163,8 @@ impl HickoryDnsResolver {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// on failure use the fall back system configured DNS resolver
|
||||
match e.kind() {
|
||||
ResolveErrorKind::NoRecordsFound { .. } => {}
|
||||
_ => {
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
}
|
||||
if !e.is_no_records_found() {
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
}
|
||||
let resolver = self
|
||||
.fallback
|
||||
@@ -190,7 +184,7 @@ impl HickoryDnsResolver {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_resolver(&self) -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
fn new_resolver(&self) -> Result<TokioResolver, HickoryDnsError> {
|
||||
if self.dont_use_shared {
|
||||
new_resolver()
|
||||
} else {
|
||||
@@ -198,7 +192,7 @@ impl HickoryDnsResolver {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_resolver_system(&self) -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
fn new_resolver_system(&self) -> Result<TokioResolver, HickoryDnsError> {
|
||||
if self.dont_use_shared {
|
||||
new_resolver_system()
|
||||
} else {
|
||||
@@ -212,29 +206,30 @@ impl HickoryDnsResolver {
|
||||
|
||||
/// Create a new resolver with a custom DoT based configuration. The options are overridden to look
|
||||
/// up for both IPv4 and IPv6 addresses to work with "happy eyeballs" algorithm.
|
||||
fn new_resolver() -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
fn new_resolver() -> Result<TokioResolver, HickoryDnsError> {
|
||||
let mut name_servers = NameServerConfigGroup::quad9_tls();
|
||||
name_servers.merge(NameServerConfigGroup::quad9_https());
|
||||
name_servers.merge(NameServerConfigGroup::cloudflare_tls());
|
||||
name_servers.merge(NameServerConfigGroup::cloudflare_https());
|
||||
|
||||
let config = ResolverConfig::from_parts(None, Vec::new(), name_servers);
|
||||
let mut resolver_builder =
|
||||
TokioResolver::builder_with_config(config, TokioConnectionProvider::default());
|
||||
|
||||
let mut opts = ResolverOpts::default();
|
||||
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
// Would like to enable this when 0.25 stabilizes
|
||||
// opts.server_ordering_strategy = ServerOrderingStrategy::RoundRobin;
|
||||
resolver_builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
resolver_builder.options_mut().server_ordering_strategy = ServerOrderingStrategy::RoundRobin;
|
||||
|
||||
Ok(TokioAsyncResolver::tokio(config, opts))
|
||||
Ok(resolver_builder.build())
|
||||
}
|
||||
|
||||
/// Create a new resolver with the default configuration, which reads from the system DNS config
|
||||
/// (i.e. `/etc/resolve.conf` in unix). The options are overridden to look up for both IPv4 and IPv6
|
||||
/// addresses to work with "happy eyeballs" algorithm.
|
||||
fn new_resolver_system() -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
let (config, mut opts) = hickory_resolver::system_conf::read_system_conf()?;
|
||||
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
Ok(TokioAsyncResolver::tokio(config, opts))
|
||||
fn new_resolver_system() -> Result<TokioResolver, HickoryDnsError> {
|
||||
let mut resolver_builder = TokioResolver::builder_tokio()?;
|
||||
resolver_builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
|
||||
Ok(resolver_builder.build())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -144,10 +144,13 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::{instrument, warn};
|
||||
use tracing::{debug, instrument, warn};
|
||||
use url::Url;
|
||||
|
||||
use bytes::Bytes;
|
||||
use http::header::CONTENT_TYPE;
|
||||
use http::HeaderMap;
|
||||
use mime::Mime;
|
||||
pub use reqwest::IntoUrl;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::net::SocketAddr;
|
||||
@@ -210,11 +213,8 @@ pub enum HttpClientError<E: Display = String> {
|
||||
#[error("failed to resolve request. status: '{status}', additional error message: {error}")]
|
||||
EndpointFailure { status: StatusCode, error: E },
|
||||
|
||||
#[error("failed to decode response body: {source} from {content}")]
|
||||
ResponseDecodeFailure {
|
||||
source: serde_json::Error,
|
||||
content: String,
|
||||
},
|
||||
#[error("failed to decode response body: {message} from {content}")]
|
||||
ResponseDecodeFailure { message: String, content: String },
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[error("the request has timed out")]
|
||||
@@ -265,14 +265,18 @@ impl ClientBuilder {
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let reqwest_client_builder = {
|
||||
let r = reqwest::ClientBuilder::new();
|
||||
|
||||
// Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which
|
||||
// `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."`
|
||||
// Note: I believe the manual enable calls for the compression methods are extra
|
||||
// as the various compression features for `reqwest` crate should be enabled
|
||||
// just by including the feature which:
|
||||
// `"Enable[s] auto decompression by checking the Content-Encoding response header."`
|
||||
//
|
||||
// I am going to leave it here anyways so that gzip decompression is attempted even if
|
||||
// that feature is removed.
|
||||
r.gzip(true)
|
||||
// I am going to leave these here anyways so that removing a decompression method
|
||||
// from the features list will throw an error if it is not also removed here.
|
||||
reqwest::ClientBuilder::new()
|
||||
.gzip(true)
|
||||
.deflate(true)
|
||||
.brotli(true)
|
||||
.zstd(true)
|
||||
};
|
||||
|
||||
ClientBuilder {
|
||||
@@ -535,11 +539,6 @@ impl ApiClientCore for Client {
|
||||
|
||||
let mut request = self.reqwest_client.request(method.clone(), url);
|
||||
|
||||
// Indicate that compressed responses are preferred, but if not supported other encodings are fine.
|
||||
// TODO: Down the road we can be more selective about adding this, but it's inclusion here guarantees
|
||||
// that we use compression when available.
|
||||
request = request.header(reqwest::header::ACCEPT_ENCODING, "gzip;q=1.0, *;q=0.5");
|
||||
|
||||
if let Some(body) = json_body {
|
||||
request = request.json(body);
|
||||
}
|
||||
@@ -698,11 +697,29 @@ pub trait ApiClient: ApiClientCore {
|
||||
/// defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the response
|
||||
/// into the provided type `T`.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
// TODO: deprecate in favour of get_response that works based on mime type in the response
|
||||
async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
V: AsRef<str> + Sync,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
self.get_response(path, params).await
|
||||
}
|
||||
|
||||
/// 'get' data from the segment-defined path, e.g. `["api", "v1", "mixnodes"]`, with tuple
|
||||
/// defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the response
|
||||
/// into the provided type `T` based on the content type header
|
||||
async fn get_response<T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
@@ -877,14 +894,10 @@ fn sanitize_url<K: AsRef<str>, V: AsRef<str>>(
|
||||
url
|
||||
}
|
||||
|
||||
fn decode_as_text(bytes: &bytes::Bytes, headers: HeaderMap) -> String {
|
||||
fn decode_as_text(bytes: &bytes::Bytes, headers: &HeaderMap) -> String {
|
||||
use encoding_rs::{Encoding, UTF_8};
|
||||
use mime::Mime;
|
||||
|
||||
let content_type = headers
|
||||
.get(http::header::CONTENT_TYPE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.and_then(|value| value.parse::<Mime>().ok());
|
||||
let content_type = try_get_mime_type(headers);
|
||||
|
||||
let encoding_name = content_type
|
||||
.as_ref()
|
||||
@@ -897,7 +910,7 @@ fn decode_as_text(bytes: &bytes::Bytes, headers: HeaderMap) -> String {
|
||||
text.into_owned()
|
||||
}
|
||||
|
||||
/// Attempt to parse a json object from an HTTP response
|
||||
/// Attempt to parse a response object from an HTTP response
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn parse_response<T, E>(res: Response, allow_empty: bool) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
@@ -919,16 +932,7 @@ where
|
||||
// internally reqwest is first retrieving bytes and then performing parsing via serde_json
|
||||
// (and similarly does the same thing for text())
|
||||
let full = res.bytes().await?;
|
||||
match serde_json::from_slice(&full) {
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => {
|
||||
let content = decode_as_text(&full, headers);
|
||||
Err(HttpClientError::ResponseDecodeFailure {
|
||||
source: err,
|
||||
content,
|
||||
})
|
||||
}
|
||||
}
|
||||
decode_raw_response(&headers, full)
|
||||
} else if res.status() == StatusCode::NOT_FOUND {
|
||||
Err(HttpClientError::NotFound)
|
||||
} else {
|
||||
@@ -947,6 +951,71 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_as_json<T, E>(headers: &HeaderMap, content: Bytes) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
E: DeserializeOwned + Display,
|
||||
{
|
||||
match serde_json::from_slice(&content) {
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => {
|
||||
let content = decode_as_text(&content, headers);
|
||||
Err(HttpClientError::ResponseDecodeFailure {
|
||||
message: err.to_string(),
|
||||
content,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_as_bincode<T, E>(headers: &HeaderMap, content: Bytes) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
E: DeserializeOwned + Display,
|
||||
{
|
||||
use bincode::Options;
|
||||
|
||||
let opts = nym_http_api_common::make_bincode_serializer();
|
||||
match opts.deserialize(&content) {
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => {
|
||||
let content = decode_as_text(&content, headers);
|
||||
Err(HttpClientError::ResponseDecodeFailure {
|
||||
message: err.to_string(),
|
||||
content,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_raw_response<T, E>(headers: &HeaderMap, content: Bytes) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
E: DeserializeOwned + Display,
|
||||
{
|
||||
// if content type header is missing, fallback to our old default, json
|
||||
let mime = try_get_mime_type(headers).unwrap_or(mime::APPLICATION_JSON);
|
||||
|
||||
debug!("attempting to parse response as {mime}");
|
||||
|
||||
// unfortunately we can't use stronger typing for subtype as "bincode" is not a defined mime type
|
||||
match (mime.type_(), mime.subtype().as_str()) {
|
||||
(mime::APPLICATION, "json") => decode_as_json(headers, content),
|
||||
(mime::APPLICATION, "bincode") => decode_as_bincode(headers, content),
|
||||
(_, _) => {
|
||||
debug!("unrecognised mime type {mime}. falling back to json decoding...");
|
||||
decode_as_json(headers, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_mime_type(headers: &HeaderMap) -> Option<Mime> {
|
||||
headers
|
||||
.get(CONTENT_TYPE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.and_then(|value| value.parse::<Mime>().ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -11,20 +11,44 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum-client-ip.workspace = true
|
||||
axum.workspace = true
|
||||
bytes = { workspace = true }
|
||||
colored.workspace = true
|
||||
futures = { workspace = true }
|
||||
mime = { workspace = true }
|
||||
axum = { workspace = true, optional = true }
|
||||
axum-client-ip = { workspace = true, optional = true }
|
||||
bincode = { workspace = true }
|
||||
bytes = { workspace = true, optional = true }
|
||||
colored = { workspace = true, optional = true }
|
||||
futures = { workspace = true, optional = true }
|
||||
mime = { workspace = true, optional = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
serde_yaml = { workspace = true }
|
||||
subtle.workspace = true
|
||||
tower = { workspace = true }
|
||||
serde_yaml = { workspace = true, optional = true }
|
||||
subtle = { workspace = true, optional = true }
|
||||
time = { workspace = true, optional = true, features = ["macros"] }
|
||||
tower = { workspace = true, optional = true }
|
||||
tracing.workspace = true
|
||||
utoipa = { workspace = true, optional = true }
|
||||
zeroize = { workspace = true }
|
||||
zeroize = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
output = [
|
||||
"axum",
|
||||
"bytes",
|
||||
"mime",
|
||||
"serde_yaml",
|
||||
"time",
|
||||
"time/formatting"
|
||||
]
|
||||
|
||||
middleware = [
|
||||
"axum",
|
||||
"axum-client-ip",
|
||||
"colored",
|
||||
"futures",
|
||||
"subtle",
|
||||
"tower",
|
||||
"zeroize"
|
||||
]
|
||||
|
||||
utoipa = ["dep:utoipa"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,92 +1,20 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2023-2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::http::{header, HeaderValue, StatusCode};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "middleware")]
|
||||
pub mod middleware;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
Yaml(Yaml<T>),
|
||||
}
|
||||
#[cfg(feature = "output")]
|
||||
pub mod response;
|
||||
|
||||
impl<T> IntoResponse for FormattedResponse<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn into_response(self) -> Response {
|
||||
match self {
|
||||
FormattedResponse::Json(json_response) => json_response.into_response(),
|
||||
FormattedResponse::Yaml(yaml_response) => yaml_response.into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
// don't break existing imports
|
||||
#[cfg(feature = "output")]
|
||||
pub use response::*;
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Output {
|
||||
#[default]
|
||||
Json,
|
||||
Yaml,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::IntoParams, utoipa::ToSchema))]
|
||||
#[serde(default)]
|
||||
pub struct OutputParams {
|
||||
pub output: Option<Output>,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn to_response<T: Serialize>(self, data: T) -> FormattedResponse<T> {
|
||||
match self {
|
||||
Output::Json => FormattedResponse::Json(Json(data)),
|
||||
Output::Yaml => FormattedResponse::Yaml(Yaml(data)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[must_use]
|
||||
pub struct Yaml<T>(pub T);
|
||||
|
||||
impl<T> From<T> for Yaml<T> {
|
||||
fn from(inner: T) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResponse for Yaml<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
// replicates axum's Json
|
||||
fn into_response(self) -> Response {
|
||||
let mut buf = BytesMut::with_capacity(128).writer();
|
||||
match serde_yaml::to_writer(&mut buf, &self.0) {
|
||||
Ok(()) => (
|
||||
[(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("application/yaml"),
|
||||
)],
|
||||
buf.into_inner().freeze(),
|
||||
)
|
||||
.into_response(),
|
||||
Err(err) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
[(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
|
||||
)],
|
||||
err.to_string(),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
}
|
||||
// be explicit about those values because bincode uses different defaults in different places
|
||||
pub fn make_bincode_serializer() -> impl ::bincode::Options {
|
||||
use ::bincode::Options;
|
||||
::bincode::DefaultOptions::new()
|
||||
.with_little_endian()
|
||||
.with_varint_encoding()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::response::{error_response, ResponseWrapper};
|
||||
use axum::http::header::IntoHeaderName;
|
||||
use axum::http::{header, HeaderValue};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[must_use]
|
||||
pub struct Bincode<T>(pub(crate) ResponseWrapper<T>);
|
||||
|
||||
impl<T> From<T> for Bincode<T> {
|
||||
fn from(response: T) -> Self {
|
||||
Bincode(ResponseWrapper::new(response).with_header(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("application/bincode"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Bincode<T> {
|
||||
pub(crate) fn with_header(
|
||||
mut self,
|
||||
name: impl IntoHeaderName,
|
||||
value: impl Into<HeaderValue>,
|
||||
) -> Self {
|
||||
self.0.headers.insert(name, value.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResponse for Bincode<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
// replicates axum's Json
|
||||
fn into_response(self) -> Response {
|
||||
use bincode::Options;
|
||||
let mut buf = BytesMut::with_capacity(128).writer();
|
||||
|
||||
match crate::make_bincode_serializer().serialize_into(&mut buf, &self.0.data) {
|
||||
Ok(()) => (self.0.headers, buf.into_inner().freeze()).into_response(),
|
||||
Err(err) => error_response(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::response::{error_response, ResponseWrapper};
|
||||
use axum::http::header::IntoHeaderName;
|
||||
use axum::http::{header, HeaderValue};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::Serialize;
|
||||
use utoipa::gen::serde_json;
|
||||
|
||||
// don't use axum's Json directly as we need to be able to define custom headers
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[must_use]
|
||||
pub struct Json<T>(pub(crate) ResponseWrapper<T>);
|
||||
|
||||
impl<T> From<T> for Json<T> {
|
||||
fn from(response: T) -> Self {
|
||||
Json(ResponseWrapper::new(response).with_header(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Json<T> {
|
||||
pub(crate) fn with_header(
|
||||
mut self,
|
||||
name: impl IntoHeaderName,
|
||||
value: impl Into<HeaderValue>,
|
||||
) -> Self {
|
||||
self.0.headers.insert(name, value.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResponse for Json<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn into_response(self) -> Response {
|
||||
let mut buf = BytesMut::with_capacity(128).writer();
|
||||
|
||||
match serde_json::to_writer(&mut buf, &self.0.data) {
|
||||
Ok(()) => (self.0.headers, buf.into_inner().freeze()).into_response(),
|
||||
Err(err) => error_response(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::http::header::IntoHeaderName;
|
||||
use axum::http::{header, HeaderMap, HeaderValue, StatusCode};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use time::format_description::BorrowedFormatItem;
|
||||
use time::macros::{format_description, offset};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub mod bincode;
|
||||
pub mod json;
|
||||
pub mod yaml;
|
||||
|
||||
pub use json::Json;
|
||||
pub use yaml::Yaml;
|
||||
|
||||
pub use bincode::Bincode;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct ResponseWrapper<T> {
|
||||
data: T,
|
||||
headers: HeaderMap,
|
||||
}
|
||||
|
||||
impl<T> ResponseWrapper<T> {
|
||||
pub(crate) fn new(response: T) -> ResponseWrapper<T> {
|
||||
ResponseWrapper {
|
||||
data: response,
|
||||
headers: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn with_header(
|
||||
mut self,
|
||||
name: impl IntoHeaderName,
|
||||
value: impl Into<HeaderValue>,
|
||||
) -> Self {
|
||||
self.headers.insert(name, value.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
Yaml(Yaml<T>),
|
||||
Bincode(Bincode<T>),
|
||||
}
|
||||
|
||||
impl<T> FormattedResponse<T> {
|
||||
pub fn into_inner(self) -> T {
|
||||
match self {
|
||||
FormattedResponse::Json(inner) => inner.0.data,
|
||||
FormattedResponse::Yaml(inner) => inner.0.data,
|
||||
FormattedResponse::Bincode(inner) => inner.0.data,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_header(
|
||||
self,
|
||||
name: impl IntoHeaderName,
|
||||
value: impl Into<HeaderValue>,
|
||||
) -> FormattedResponse<T> {
|
||||
match self {
|
||||
FormattedResponse::Json(inner) => {
|
||||
FormattedResponse::Json(inner.with_header(name, value))
|
||||
}
|
||||
FormattedResponse::Yaml(inner) => {
|
||||
FormattedResponse::Yaml(inner.with_header(name, value))
|
||||
}
|
||||
FormattedResponse::Bincode(inner) => {
|
||||
FormattedResponse::Bincode(inner.with_header(name, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `expires` header on the response to the provided expiration.
|
||||
/// Internally it will perform conversions to make sure the value is set in GMT offset,
|
||||
/// e.g. `Expires: Wed, 21 Oct 2015 07:28:00 GMT`
|
||||
#[must_use]
|
||||
pub fn with_expires_header(self, expiration: OffsetDateTime) -> FormattedResponse<T> {
|
||||
// as per RFC-7234 (section 5.3) EXPIRES header has to use value formatted
|
||||
// as defined in RFC-7231 (section 7.1.1.1)
|
||||
// (preferred format (IMF-fixdate) uses RFC-5322 (section 3.3)
|
||||
let formatted = format_rfc5352(expiration);
|
||||
|
||||
// SAFETY: our formatted datetime doesn't contain forbidden characters
|
||||
#[allow(clippy::unwrap_used)]
|
||||
self.with_header(header::EXPIRES, HeaderValue::try_from(formatted).unwrap())
|
||||
}
|
||||
|
||||
/// Work similarly to `with_expires_header`, but rather than setting explicit expiration value,
|
||||
/// it adds the provided time delta to the current time instead.
|
||||
#[must_use]
|
||||
pub fn with_expires_header_delta(self, expires_in: Duration) -> FormattedResponse<T> {
|
||||
self.with_expires_header(OffsetDateTime::now_utc() + expires_in)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResponse for FormattedResponse<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn into_response(self) -> Response {
|
||||
match self {
|
||||
FormattedResponse::Json(json_response) => json_response.into_response(),
|
||||
FormattedResponse::Yaml(yaml_response) => yaml_response.into_response(),
|
||||
FormattedResponse::Bincode(bincode_response) => bincode_response.into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Output {
|
||||
#[default]
|
||||
Json,
|
||||
Yaml,
|
||||
Bincode,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::IntoParams, utoipa::ToSchema))]
|
||||
#[serde(default)]
|
||||
pub struct OutputParams {
|
||||
pub output: Option<Output>,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn to_response<T: Serialize>(self, data: T) -> FormattedResponse<T> {
|
||||
match self {
|
||||
Output::Json => FormattedResponse::Json(Json::from(data)),
|
||||
Output::Yaml => FormattedResponse::Yaml(Yaml::from(data)),
|
||||
Output::Bincode => FormattedResponse::Bincode(Bincode::from(data)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn error_response<E: ToString>(err: E) -> Response {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
[(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
|
||||
)],
|
||||
err.to_string(),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
// SAFETY: this hardcoded datetime formatter is valid
|
||||
#[allow(clippy::unwrap_used)]
|
||||
fn format_rfc5352(datetime: OffsetDateTime) -> String {
|
||||
// the time must be using GMT (UTC) offset
|
||||
let normalised = datetime.to_offset(offset!(UTC));
|
||||
normalised.format(&rfc5322()).unwrap()
|
||||
}
|
||||
|
||||
// NOTE: this function is purposely not made public as it cannot guarantee caller
|
||||
// has correctly ensured their date is using correct GMT offset
|
||||
fn rfc5322() -> &'static [BorrowedFormatItem<'static>] {
|
||||
// D, d M Y H:i:s T
|
||||
format_description!(
|
||||
"[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT"
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::response::format_rfc5352;
|
||||
use time::macros::datetime;
|
||||
|
||||
#[test]
|
||||
fn rfc5322_formatting() {
|
||||
let utc_date = datetime!(2021-08-23 12:13:14 UTC);
|
||||
let non_utc_date = datetime!(2021-08-23 12:13:14 -1);
|
||||
|
||||
assert_eq!("Mon, 23 Aug 2021 12:13:14 GMT", format_rfc5352(utc_date));
|
||||
assert_eq!(
|
||||
"Mon, 23 Aug 2021 13:13:14 GMT",
|
||||
format_rfc5352(non_utc_date)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::response::{error_response, ResponseWrapper};
|
||||
use axum::http::header::IntoHeaderName;
|
||||
use axum::http::{header, HeaderValue};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[must_use]
|
||||
pub struct Yaml<T>(pub(crate) ResponseWrapper<T>);
|
||||
|
||||
impl<T> From<T> for Yaml<T> {
|
||||
fn from(response: T) -> Self {
|
||||
Yaml(ResponseWrapper::new(response).with_header(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("application/yaml"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Yaml<T> {
|
||||
pub(crate) fn with_header(
|
||||
mut self,
|
||||
name: impl IntoHeaderName,
|
||||
value: impl Into<HeaderValue>,
|
||||
) -> Self {
|
||||
self.0.headers.insert(name, value.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResponse for Yaml<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
// replicates axum's Json
|
||||
fn into_response(self) -> Response {
|
||||
let mut buf = BytesMut::with_capacity(128).writer();
|
||||
match serde_yaml::to_writer(&mut buf, &self.0.data) {
|
||||
Ok(()) => (self.0.headers, buf.into_inner().freeze()).into_response(),
|
||||
Err(err) => error_response(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
@@ -200,7 +200,7 @@ impl fmt::Display for IpPacketRequestData {
|
||||
}
|
||||
|
||||
impl IpPacketRequestData {
|
||||
pub fn add_signature(&mut self, signature: identity::Signature) -> Option<identity::Signature> {
|
||||
pub fn add_signature(&mut self, signature: ed25519::Signature) -> Option<ed25519::Signature> {
|
||||
match self {
|
||||
IpPacketRequestData::StaticConnect(request) => {
|
||||
request.signature = Some(signature);
|
||||
@@ -269,11 +269,11 @@ impl StaticConnectRequest {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SignedStaticConnectRequest {
|
||||
pub request: StaticConnectRequest,
|
||||
pub signature: Option<identity::Signature>,
|
||||
pub signature: Option<ed25519::Signature>,
|
||||
}
|
||||
|
||||
impl SignedRequest for SignedStaticConnectRequest {
|
||||
fn identity(&self) -> Option<&identity::PublicKey> {
|
||||
fn identity(&self) -> Option<&ed25519::PublicKey> {
|
||||
Some(self.request.reply_to.identity())
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ impl SignedRequest for SignedStaticConnectRequest {
|
||||
})
|
||||
}
|
||||
|
||||
fn signature(&self) -> Option<&identity::Signature> {
|
||||
fn signature(&self) -> Option<&ed25519::Signature> {
|
||||
self.signature.as_ref()
|
||||
}
|
||||
|
||||
@@ -333,11 +333,11 @@ impl DynamicConnectRequest {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SignedDynamicConnectRequest {
|
||||
pub request: DynamicConnectRequest,
|
||||
pub signature: Option<identity::Signature>,
|
||||
pub signature: Option<ed25519::Signature>,
|
||||
}
|
||||
|
||||
impl SignedRequest for SignedDynamicConnectRequest {
|
||||
fn identity(&self) -> Option<&identity::PublicKey> {
|
||||
fn identity(&self) -> Option<&ed25519::PublicKey> {
|
||||
Some(self.request.reply_to.identity())
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ impl SignedRequest for SignedDynamicConnectRequest {
|
||||
})
|
||||
}
|
||||
|
||||
fn signature(&self) -> Option<&identity::Signature> {
|
||||
fn signature(&self) -> Option<&ed25519::Signature> {
|
||||
self.signature.as_ref()
|
||||
}
|
||||
|
||||
@@ -382,11 +382,11 @@ impl DisconnectRequest {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SignedDisconnectRequest {
|
||||
pub request: DisconnectRequest,
|
||||
pub signature: Option<identity::Signature>,
|
||||
pub signature: Option<ed25519::Signature>,
|
||||
}
|
||||
|
||||
impl SignedRequest for SignedDisconnectRequest {
|
||||
fn identity(&self) -> Option<&identity::PublicKey> {
|
||||
fn identity(&self) -> Option<&ed25519::PublicKey> {
|
||||
Some(self.request.reply_to.identity())
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ impl SignedRequest for SignedDisconnectRequest {
|
||||
})
|
||||
}
|
||||
|
||||
fn signature(&self) -> Option<&identity::Signature> {
|
||||
fn signature(&self) -> Option<&ed25519::Signature> {
|
||||
self.signature.as_ref()
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ pub enum MixProcessingError {
|
||||
#[error("failed to recover the expected SURB-Ack packet: {0}")]
|
||||
MalformedSurbAck(#[from] SurbAckRecoveryError),
|
||||
|
||||
#[error("the received packet was set to use the very old and very much deprecated 'VPN' mode")]
|
||||
ReceivedOldTypeVpnPacket,
|
||||
|
||||
#[error("failed to process received Nym packet: {0}")]
|
||||
NymPacketProcessingError(#[from] PacketProcessingError),
|
||||
}
|
||||
|
||||
@@ -37,32 +37,3 @@ impl TicketTypeRepr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constants for bloom filter for double spending detection
|
||||
//Chosen for FP of
|
||||
//Calculator at https://hur.st/bloomfilter/
|
||||
pub const ECASH_DS_BLOOMFILTER_PARAMS: BloomfilterParameters = BloomfilterParameters {
|
||||
num_hashes: 10,
|
||||
bitmap_size: 1_500_000_000,
|
||||
sip_keys: [
|
||||
(12345678910111213141, 1415926535897932384),
|
||||
(7182818284590452353, 3571113171923293137),
|
||||
],
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct BloomfilterParameters {
|
||||
pub num_hashes: u32,
|
||||
pub bitmap_size: u64,
|
||||
pub sip_keys: [(u64, u64); 2],
|
||||
}
|
||||
|
||||
impl BloomfilterParameters {
|
||||
pub const fn byte_size(&self) -> u64 {
|
||||
self.bitmap_size / 8
|
||||
}
|
||||
|
||||
pub const fn default_ecash() -> Self {
|
||||
ECASH_DS_BLOOMFILTER_PARAMS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::error::NetworkTestingError;
|
||||
use crate::TestMessage;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_sphinx::acknowledgements::identifier::recover_identifier;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||
@@ -31,7 +31,7 @@ impl<T> From<FragmentIdentifier> for Received<T> {
|
||||
}
|
||||
|
||||
pub struct TestPacketProcessor<T, R: MessageReceiver = SphinxMessageReceiver> {
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
ack_key: Arc<AckKey>,
|
||||
|
||||
/// Structure responsible for decrypting and recovering plaintext message from received ciphertexts.
|
||||
@@ -42,7 +42,7 @@ pub struct TestPacketProcessor<T, R: MessageReceiver = SphinxMessageReceiver> {
|
||||
|
||||
impl<T> TestPacketProcessor<T, SphinxMessageReceiver> {
|
||||
pub fn new_sphinx_processor(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
ack_key: Arc<AckKey>,
|
||||
) -> Self {
|
||||
Self::new(local_encryption_keypair, ack_key)
|
||||
@@ -53,7 +53,7 @@ impl<T, R> TestPacketProcessor<T, R>
|
||||
where
|
||||
R: MessageReceiver,
|
||||
{
|
||||
pub fn new(local_encryption_keypair: Arc<encryption::KeyPair>, ack_key: Arc<AckKey>) -> Self {
|
||||
pub fn new(local_encryption_keypair: Arc<x25519::KeyPair>, ack_key: Arc<AckKey>) -> Self {
|
||||
TestPacketProcessor {
|
||||
local_encryption_keypair,
|
||||
ack_key,
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::processor::{Received, TestPacketProcessor};
|
||||
use crate::{log_err, log_info, log_warn};
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::receiver::{MessageReceiver, SphinxMessageReceiver};
|
||||
use nym_task::TaskClient;
|
||||
@@ -29,7 +29,7 @@ pub struct SimpleMessageReceiver<T, R: MessageReceiver = SphinxMessageReceiver>
|
||||
|
||||
impl<T> SimpleMessageReceiver<T, SphinxMessageReceiver> {
|
||||
pub fn new_sphinx_receiver(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
ack_key: Arc<AckKey>,
|
||||
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
||||
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
||||
@@ -49,7 +49,7 @@ impl<T> SimpleMessageReceiver<T, SphinxMessageReceiver> {
|
||||
|
||||
impl<T, R: MessageReceiver> SimpleMessageReceiver<T, R> {
|
||||
pub fn new(
|
||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
ack_key: Arc<AckKey>,
|
||||
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
||||
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
||||
|
||||
@@ -39,6 +39,10 @@ pub struct NodeTester<R> {
|
||||
/// Average delay an acknowledgement packet is going to get delay at a single mixnode.
|
||||
average_ack_delay: Duration,
|
||||
|
||||
/// Specify whether any constructed packets should use the legacy format,
|
||||
/// where the payload keys are explicitly attached rather than using the seeds
|
||||
use_legacy_sphinx_format: bool,
|
||||
|
||||
// while acks are going to be ignored they still need to be constructed
|
||||
// so that the gateway would be able to correctly process and forward the message
|
||||
ack_key: Arc<AckKey>,
|
||||
@@ -57,6 +61,7 @@ where
|
||||
deterministic_route_selection: bool,
|
||||
average_packet_delay: Duration,
|
||||
average_ack_delay: Duration,
|
||||
use_legacy_sphinx_format: bool,
|
||||
ack_key: Arc<AckKey>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -67,6 +72,7 @@ where
|
||||
deterministic_route_selection,
|
||||
average_packet_delay,
|
||||
average_ack_delay,
|
||||
use_legacy_sphinx_format,
|
||||
ack_key,
|
||||
}
|
||||
}
|
||||
@@ -245,6 +251,10 @@ where
|
||||
impl<R: CryptoRng + Rng> FragmentPreparer for NodeTester<R> {
|
||||
type Rng = R;
|
||||
|
||||
fn use_legacy_sphinx_format(&self) -> bool {
|
||||
self.use_legacy_sphinx_format
|
||||
}
|
||||
|
||||
fn deterministic_route_selection(&self) -> bool {
|
||||
self.deterministic_route_selection
|
||||
}
|
||||
|
||||
@@ -363,6 +363,7 @@ impl MetricsController {
|
||||
buffer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_writer(&self, writer: &mut dyn std::io::Write) {
|
||||
let metrics = self.gather();
|
||||
match writer.write_all(&metrics) {
|
||||
@@ -371,6 +372,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn register_int_gauge<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_int_gauge(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
@@ -378,6 +380,7 @@ impl MetricsController {
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn register_float_gauge<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_float_gauge(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
@@ -385,6 +388,7 @@ impl MetricsController {
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn register_int_counter<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_int_counter(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
@@ -392,6 +396,7 @@ impl MetricsController {
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn register_histogram<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -404,6 +409,7 @@ impl MetricsController {
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&self, name: &str, value: i64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.set(value);
|
||||
@@ -413,6 +419,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_float(&self, name: &str, value: f64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.set_float(value);
|
||||
@@ -422,6 +429,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_to_histogram(&self, name: &str, value: f64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.add_histogram_observation(value);
|
||||
@@ -431,12 +439,14 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn start_timer(&self, name: &str) -> Option<HistogramTimer> {
|
||||
self.registry_index
|
||||
.get(name)
|
||||
.and_then(|metric| metric.start_timer())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn inc(&self, name: &str) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.inc();
|
||||
@@ -446,6 +456,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn inc_by(&self, name: &str, value: i64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.inc_by(value);
|
||||
@@ -455,6 +466,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn maybe_register_and_set<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -468,6 +480,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn maybe_register_and_set_float<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -481,6 +494,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn maybe_register_and_add_to_histogram<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -495,6 +509,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn maybe_register_and_inc<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
if !self.inc(name) {
|
||||
let help = help.into();
|
||||
@@ -503,6 +518,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn maybe_register_and_inc_by<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -516,6 +532,7 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn register_metric(&self, metric: impl Into<Metric>) {
|
||||
let m = metric.into();
|
||||
let fq_name = m.fq_name();
|
||||
|
||||
@@ -8,7 +8,7 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
log = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_distr = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
|
||||
@@ -37,19 +37,27 @@ pub enum SurbAckRecoveryError {
|
||||
}
|
||||
|
||||
impl SurbAck {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn construct<R>(
|
||||
rng: &mut R,
|
||||
use_legacy_sphinx_format: bool,
|
||||
recipient: &Recipient,
|
||||
ack_key: &AckKey,
|
||||
marshaled_fragment_id: [u8; 5],
|
||||
average_delay: time::Duration,
|
||||
topology: &NymRouteProvider,
|
||||
packet_type: PacketType,
|
||||
disable_mix_hops: bool,
|
||||
) -> Result<Self, NymTopologyError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let route = topology.random_route_to_egress(rng, recipient.gateway())?;
|
||||
let route = if disable_mix_hops {
|
||||
topology.empty_route_to_egress(recipient.gateway())?
|
||||
} else {
|
||||
topology.random_route_to_egress(rng, recipient.gateway())?
|
||||
};
|
||||
|
||||
let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len());
|
||||
let destination = recipient.as_sphinx_destination();
|
||||
|
||||
@@ -57,8 +65,6 @@ impl SurbAck {
|
||||
let packet_size = match packet_type {
|
||||
PacketType::Outfox => surb_ack_payload.len().max(MIN_PACKET_SIZE),
|
||||
PacketType::Mix => PacketSize::AckPacket.payload_size(),
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => PacketSize::AckPacket.payload_size(),
|
||||
};
|
||||
|
||||
let surb_ack_packet = match packet_type {
|
||||
@@ -69,14 +75,7 @@ impl SurbAck {
|
||||
Some(packet_size),
|
||||
)?,
|
||||
PacketType::Mix => NymPacket::sphinx_build(
|
||||
packet_size,
|
||||
surb_ack_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
use_legacy_sphinx_format,
|
||||
packet_size,
|
||||
surb_ack_payload,
|
||||
&route,
|
||||
@@ -106,8 +105,6 @@ impl SurbAck {
|
||||
PacketSize::OutfoxAckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN
|
||||
}
|
||||
PacketType::Mix => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +136,6 @@ impl SurbAck {
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(&b[address_offset..])?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
#[allow(deprecated)]
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
};
|
||||
|
||||
Ok((address, packet))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// it's already destructed).
|
||||
|
||||
use crate::nodes::{NodeIdentity, NODE_IDENTITY_SIZE};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_sphinx_types::Destination;
|
||||
use serde::de::{Error as SerdeError, Unexpected, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
@@ -15,11 +15,11 @@ use thiserror::Error;
|
||||
|
||||
// Not entirely sure whether this is the correct place for those, but let's see how it's going
|
||||
// to work out
|
||||
pub type ClientEncryptionKey = encryption::PublicKey;
|
||||
const CLIENT_ENCRYPTION_KEY_SIZE: usize = encryption::PUBLIC_KEY_SIZE;
|
||||
pub type ClientEncryptionKey = x25519::PublicKey;
|
||||
const CLIENT_ENCRYPTION_KEY_SIZE: usize = x25519::PUBLIC_KEY_SIZE;
|
||||
|
||||
pub type ClientIdentity = identity::PublicKey;
|
||||
const CLIENT_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH;
|
||||
pub type ClientIdentity = ed25519::PublicKey;
|
||||
const CLIENT_IDENTITY_SIZE: usize = ed25519::PUBLIC_KEY_LENGTH;
|
||||
|
||||
pub type RecipientBytes = [u8; Recipient::LEN];
|
||||
|
||||
@@ -29,13 +29,13 @@ pub enum RecipientFormattingError {
|
||||
MalformedRecipientError { reason: String },
|
||||
|
||||
#[error("recipient's identity key is malformed: {0}")]
|
||||
MalformedIdentityError(identity::Ed25519RecoveryError),
|
||||
MalformedIdentityError(ed25519::Ed25519RecoveryError),
|
||||
|
||||
#[error("recipient's encryption key is malformed: {0}")]
|
||||
MalformedEncryptionKeyError(#[from] encryption::KeyRecoveryError),
|
||||
MalformedEncryptionKeyError(#[from] x25519::KeyRecoveryError),
|
||||
|
||||
#[error("recipient gateway's identity key is malformed: {0}")]
|
||||
MalformedGatewayError(identity::Ed25519RecoveryError),
|
||||
MalformedGatewayError(ed25519::Ed25519RecoveryError),
|
||||
}
|
||||
|
||||
// TODO: this should a different home... somewhere, but where?
|
||||
@@ -249,9 +249,9 @@ mod tests {
|
||||
fn string_conversion_works() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let client_id_pair = identity::KeyPair::new(&mut rng);
|
||||
let client_enc_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_id_pair = identity::KeyPair::new(&mut rng);
|
||||
let client_id_pair = ed25519::KeyPair::new(&mut rng);
|
||||
let client_enc_pair = x25519::KeyPair::new(&mut rng);
|
||||
let gateway_id_pair = ed25519::KeyPair::new(&mut rng);
|
||||
|
||||
let recipient = Recipient::new(
|
||||
*client_id_pair.public_key(),
|
||||
@@ -281,9 +281,9 @@ mod tests {
|
||||
fn bytes_conversion_works() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let client_id_pair = identity::KeyPair::new(&mut rng);
|
||||
let client_enc_pair = encryption::KeyPair::new(&mut rng);
|
||||
let gateway_id_pair = identity::KeyPair::new(&mut rng);
|
||||
let client_id_pair = ed25519::KeyPair::new(&mut rng);
|
||||
let client_enc_pair = x25519::KeyPair::new(&mut rng);
|
||||
let gateway_id_pair = ed25519::KeyPair::new(&mut rng);
|
||||
|
||||
let recipient = Recipient::new(
|
||||
*client_id_pair.public_key(),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! Currently, that routing information is an IP address, but in principle it can be anything
|
||||
//! for as long as it's going to fit in the field.
|
||||
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_sphinx_types::{NodeAddressBytes, NODE_ADDRESS_LENGTH};
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
@@ -16,8 +16,8 @@ use thiserror::Error;
|
||||
|
||||
// Not entirely sure whether this is the correct place for those, but let's see how it's going
|
||||
// to work out
|
||||
pub type NodeIdentity = identity::PublicKey;
|
||||
pub const NODE_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH;
|
||||
pub type NodeIdentity = ed25519::PublicKey;
|
||||
pub const NODE_IDENTITY_SIZE: usize = ed25519::PUBLIC_KEY_LENGTH;
|
||||
|
||||
/// MAX_UNPADDED_LEN represents maximum length an unpadded address could have.
|
||||
/// In this case it's an ipv6 socket address (with version prefix)
|
||||
@@ -199,7 +199,7 @@ impl TryFrom<NodeAddressBytes> for NymNodeRoutingAddress {
|
||||
type Error = NymNodeRoutingAddressError;
|
||||
|
||||
fn try_from(value: NodeAddressBytes) -> Result<Self, Self::Error> {
|
||||
Self::try_from_bytes(value.as_bytes_ref())
|
||||
Self::try_from_bytes(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ rand = { workspace = true }
|
||||
bs58 = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["stream_cipher", "rand"] }
|
||||
nym-sphinx-addressing = { path = "../addressing" }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user