Compare commits

..

15 Commits

Author SHA1 Message Date
durch da3b4d7991 Final cleanup 2023-05-27 11:11:55 +02:00
durch 2c95a1086d Fix lock files 2023-05-27 11:02:15 +02:00
durch b7ca9381f3 Happy clippy 2023-05-27 11:02:01 +02:00
durch 73d9d3fc6a Wrap up rebase 2023-05-27 11:02:01 +02:00
durch 2577235a3d Cleanup and fmt 2023-05-27 11:02:00 +02:00
durch 19c4b3255c More work on the reciever end, and outfox format 2023-05-27 11:01:25 +02:00
durch 4d837a0402 SurbAcks 2023-05-27 10:59:50 +02:00
durch 149c1d40a0 Speed up from_plaintext 2023-05-27 10:59:15 +02:00
durch 7228a95b19 Client tweaks 2023-05-27 10:59:14 +02:00
durch 4490f15fcd Rebase on develop
commit 342883fcbe
Author: durch <durch@users.noreply.github.com>
Date:   Thu Apr 27 09:17:18 2023 +0200

    Put back PacketType 1

commit 61a0ee5a19
Author: Tommy Verrall <tommyvez@protonmail.com>
Date:   Wed Apr 26 16:37:29 2023 +0100

    change output for cpu-cycle management logs

commit 3956109c7e
Author: Tommy Verrall <tommy@nymtech.net>
Date:   Wed Apr 26 12:13:22 2023 +0100

    change the workflow file to build with cpucycles

commit 8d725b13c5
Author: durch <durch@users.noreply.github.com>
Date:   Mon Apr 24 13:14:58 2023 +0200

    Outfox client compat

commit 4d166c389b
Author: durch <durch@users.noreply.github.com>
Date:   Fri Apr 21 00:30:46 2023 +0200

    Address PR comments

commit 145c3c1223
Author: durch <durch@users.noreply.github.com>
Date:   Fri Apr 21 00:12:35 2023 +0200

    Rename PacketMode

commit cbd654d6fd
Author: Drazen Urch <drazen@urch.eu>
Date:   Thu Apr 20 23:59:40 2023 +0200

    Outfox rest compat (#3333)

    * Outfox forwarding compat

    * Tidy up interface

    * PacketSize compat

commit e7be91a94c
Author: durch <durch@users.noreply.github.com>
Date:   Wed Apr 19 16:36:48 2023 +0200

    Remove serde cruft

commit 582e7d566a
Author: durch <durch@users.noreply.github.com>
Date:   Wed Apr 19 16:24:09 2023 +0200

    Outfox framing

commit 6464da5f01
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 22:23:02 2023 +0200

    Framing compat

commit d5e77e499b
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 18:18:54 2023 +0200

    Framed encoding serde POC

commit f086f9c35a
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 16:54:21 2023 +0200

    Experiment with serde
2023-05-27 10:58:29 +02:00
durch 1029590f97 Address PR comments 2023-05-27 10:57:50 +02:00
Drazen Urch a985136dfa Outfox rest compat (#3333)
* Outfox forwarding compat

* Tidy up interface

* PacketSize compat
2023-05-27 10:57:50 +02:00
durch 7e78733866 Outfox framing 2023-05-27 10:57:50 +02:00
durch 6acce42a5e Framed encoding serde POC 2023-05-27 10:57:50 +02:00
durch 8ab4988c40 Experiment with serde 2023-05-27 10:57:50 +02:00
1240 changed files with 21256 additions and 79429 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
name: 'Documentation' name: 'Documentation'
about: Suggest a fix or enhancement to the documentation or developer portal content about: Suggest a fix or enhancement to the documentation or developer portal content
title: "[DOCS]" title: "[DOCS]"
labels: documentation, needs-triage labels: documentation
assignees: mfahampshire assignees: mfahampshire
--- ---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feature request name: Feature request
about: Suggest an enhancement to the product about: Suggest an enhancement to the product
title: "[Feature Request]" title: "[Feature Request]"
labels: enhancement, needs-triage labels: enhancement
assignees: '' assignees: ''
--- ---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Report name: Report
about: To help identify and reproduce issues about: To help identify and reproduce issues
title: "[Issue]" title: "[Issue]"
labels: bug, bug-needs-triage, qa, needs-triage labels: bug, bug-needs-triage, qa
assignees: tommyv1987 assignees: tommyv1987
--- ---
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- name: install npm - name: install npm
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
run: npm install run: npm install
working-directory: .github/workflows/support-files working-directory: .github/workflows/support-files
@@ -63,7 +63,7 @@ jobs:
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.69.0 toolchain: stable
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -74,7 +74,7 @@ jobs:
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.69.0 toolchain: stable
target: wasm32-unknown-unknown target: wasm32-unknown-unknown
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
@@ -107,8 +107,6 @@ jobs:
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_service_provider_directory.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_name_service.wasm $OUTPUT_DIR
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Build - name: Build
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: "16"
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: "16"
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -1,25 +0,0 @@
name: Check Contract Schema
on:
push:
paths:
- 'contracts/**'
- 'common/**'
pull_request:
paths:
- 'contracts/**'
- 'common/**'
jobs:
check-schema:
name: Generate and check schema
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Generate the schema
run: make contract-schema
- name: Check for diff
run: git diff --exit-code
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: "16"
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: "16"
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
+138
View File
@@ -0,0 +1,138 @@
name: Nym Connect - Android APK Build
on:
workflow_dispatch:
push:
branches:
- "release/nc-android-v[0-9].[0-9].[0-9]*"
jobs:
build:
name: Build APK
runs-on: custom-runner-linux
env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.1.8937393
NDK_HOME: ${{ github.workspace }}/android-sdk/ndk/25.1.8937393
SDK_PLATFORM_VERSION: android-33
SDK_BUILDTOOLS_VERSION: 33.0.1
steps:
- name: Install Dependencies (Linux)
# https://next--tauri.netlify.app/next/guides/getting-started/prerequisites/linux/#1-system-dependencies
run: |
sudo apt-get update
sudo apt-get -y install \
build-essential \
unzip \
curl \
wget \
libssl-dev \
squashfs-tools \
librsvg2-dev
- name: Checkout
uses: actions/checkout@v3
- name: Install Java
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Install Android SDK manager
# https://developer.android.com/studio/command-line/sdkmanager
run: |
curl -sS https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -o cmdline-tools.zip
unzip cmdline-tools.zip
mkdir -p $ANDROID_HOME/cmdline-tools/latest
mv cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest
rm -rf cmdline-tools
- name: Install Android S/NDK
run: |
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
"platforms;$SDK_PLATFORM_VERSION" \
"platform-tools" \
"ndk;$NDK_VERSION" \
"build-tools;$SDK_BUILDTOOLS_VERSION"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
# TODO this step takes a considerable amount of time
# We could avoid to compile from source tauri-cli and use instead
# pre-compiled binary provided by the node package `@tauri-apps/cli`
# But when using the later the build fails for some reason
# so keep installing and using tauri-cli
- name: Install tauri cli
run: cargo install tauri-cli --version "^2.0.0-alpha.2"
- name: Install rust android targets
run: |
rustup target add aarch64-linux-android \
armv7-linux-androideabi \
i686-linux-android \
x86_64-linux-android
- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install yarn
run: |
npm i -g yarn
yarn --version
- name: Build frontend code
run: |
yarn install --frozen-lockfile
yarn build
yarn workspace @nym/nym-connect-mobile webpack:prod
- name: Build APK
working-directory: nym-connect/mobile
env:
# NODE_TAURI_CLI=${{ github.workspace }}/nym-connect/mobile/node_modules/.bin/tauri
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
WRY_ANDROID_PACKAGE: net.nymtech.nym_connect
WRY_ANDROID_LIBRARY: nym_connect
# TODO build with release profile (--release), it will requires
# to sign the APK. For now build with debug profile to avoid that
# TODO build using `yarn tauri`, provide NODE_TAURI_CLI, see TODO notes above
run: cargo tauri android build --debug --apk --split-per-abi -t aarch64
# TODO add the version number to APK name
- name: Rename APK artifact
run: |
mkdir apk/
mv nym-connect/mobile/src-tauri/gen/android/nym_connect/app/build/outputs/apk/arm64/debug/app-arm64-debug.apk \
apk/nym-connect-arm64-debug.apk
mv nym-connect/mobile/src-tauri/gen/android/nym_connect/app/build/outputs/apk/x86_64/debug/app-x86_64-debug.apk \
apk/nym-connect-x86_64-debug.apk
- name: Upload APK artifact
uses: actions/upload-artifact@v3
with:
name: nc-apk-debug
path: |
apk/nym-connect-arm64-debug.apk
apk/nym-connect-x86_64-debug.apk
# publish:
# name: Publish APK
# needs: build
# runs-on: ubuntu-latest
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# - name: Download binary artifact
# uses: actions/download-artifact@v3
# with:
# name: nc-apk-debug
# path: apk
# # TODO add a step to upload the APK somewhere
# - name: Publish
# uses: ???
+2 -13
View File
@@ -20,22 +20,11 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Yarn - name: Install Yarn
run: npm install -g yarn run: npm install -g yarn
- name: Install Rust stable - run: yarn
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install project dependencies
run: cd ../.. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
continue-on-error: true continue-on-error: true
- name: Set environment from the example - name: Set environment from the example
run: cp .env.sample .env run: cp .env.sample .env
- run: yarn storybook:build - run: yarn storybook:build
+3 -3
View File
@@ -48,12 +48,12 @@ jobs:
RUSTFLAGS: '-C link-arg=-s' RUSTFLAGS: '-C link-arg=-s'
with: with:
command: build command: build
args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown args: --manifest-path contracts/Cargo.toml --workspace --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --lib --manifest-path contracts/Cargo.toml args: --manifest-path contracts/Cargo.toml
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
@@ -64,4 +64,4 @@ jobs:
if: ${{ matrix.rust != 'nightly' }} if: ${{ matrix.rust != 'nightly' }}
with: with:
command: clippy command: clippy
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
@@ -0,0 +1,24 @@
name: Linting for Network Explorer (eslint/prettier)
on:
pull_request:
paths:
- 'explorer/**'
defaults:
run:
working-directory: explorer
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Run ESLint
# GitHub should automatically annotate the PR
run: yarn && yarn lint
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
continue-on-error: true continue-on-error: true
+1 -1
View File
@@ -152,7 +152,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
@@ -15,36 +15,19 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: wasm32-unknown-unknown
- name: Install wasm-pack
run: |
export WASM_PACK_VERSION="v0.12.1"
curl -LO https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
tar xvzf wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz -C $HOME/.cargo/bin --strip-components=1
rm wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
- name: Install the Apple developer certificate for code signing - name: Install the Apple developer certificate for code signing
env: env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -68,15 +51,11 @@ jobs:
security list-keychain -d user -s $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it - name: Install app dependencies and build it
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -88,15 +67,13 @@ jobs:
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn && yarn build run: yarn && yarn build
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: nym-connect_1.0.0_x64.dmg name: nym-connect_1.0.0_x64.dmg
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
retention-days: 30 retention-days: 30
- name: Clean up keychain - name: Clean up keychain
@@ -104,39 +81,10 @@ jobs:
run: | run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release - name: Upload to release based on tag name
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/dmg/*.dmg nym-connect/desktop/target/release/bundle/dmg/*.dmg
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz* nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${semver}_x64.dmg " >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: MacOS
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -33,25 +26,19 @@ jobs:
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
continue-on-error: true continue-on-error: true
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
@@ -61,49 +48,18 @@ jobs:
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: nym-connect.AppImage.tar.gz name: nym-connect.AppImage.tar.gz
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
retention-days: 30 retention-days: 30
- id: create-release - name: Upload to release based on tag name
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/appimage/*.AppImage nym-connect/desktop/target/release/bundle/appimage/*.AppImage
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz* nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${semver}_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [windows10] platform: [windows10]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- name: Clean up first - name: Clean up first
continue-on-error: true continue-on-error: true
@@ -46,10 +39,10 @@ jobs:
Remove-Item -path certificate -include tempCert.txt 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) Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -57,21 +50,15 @@ jobs:
toolchain: stable toolchain: stable
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000 run: yarn --network-timeout 100000
- name: Build and sign it - name: Build and sign it
shell: bash
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
@@ -79,50 +66,19 @@ jobs:
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn build run: yarn build
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: nym-connect_1.0.0_x64_en-US.msi name: nym-connect_1.0.0_x64_en-US.msi
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_x64_en-US.msi path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
retention-days: 30 retention-days: 30
- id: create-release - name: Upload to release based on tag name
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/msi/*.msi nym-connect/desktop/target/release/bundle/msi/*.msi
nym-connect/desktop/target/release/bundle/msi/*.msi.zip* nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${semver}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Windows
secrets: inherit
+8 -174
View File
@@ -2,17 +2,17 @@ name: Publish Nym binaries
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
add_tokio_unstable: add_tokio_unstable:
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"' description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
required: true required: true
default: false default: false
type: boolean type: boolean
release: release:
types: [created] types: [created]
env: env:
NETWORK: mainnet NETWORK: mainnet
jobs: jobs:
publish-nym: publish-nym:
@@ -21,33 +21,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }}
client_version: ${{ steps.binary-versions.outputs.client_version }}
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
continue-on-error: true continue-on-error: true
- name: Sets env vars for tokio if set in manual dispatch inputs - name: Sets env vars for tokio if set in manual dispatch inputs
run: | run: |
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
@@ -80,8 +62,7 @@ jobs:
target/release/nym-cli target/release/nym-cli
retention-days: 30 retention-days: 30
- id: create-release - name: Upload to release based on tag name
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
@@ -95,150 +76,3 @@ jobs:
target/release/nym-network-requester target/release/nym-network-requester
target/release/nym-network-statistics target/release/nym-network-statistics
target/release/nym-cli target/release/nym-cli
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-binaries-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
- id: binary-hashes
name: Generate binary hashes
run: |
echo "client_hash=${{ hashFiles('target/release/nym-client') }}" >> "$GITHUB_OUTPUT"
echo "mixnode_hash=${{ hashFiles('target/release/nym-mixnode') }}" >> "$GITHUB_OUTPUT"
echo "gateway_hash=${{ hashFiles('target/release/nym-gateway') }}" >> "$GITHUB_OUTPUT"
echo "socks5_hash=${{ hashFiles('target/release/nym-socks5-client') }}" >> "$GITHUB_OUTPUT"
echo "netreq_hash=${{ hashFiles('target/release/nym-network-requester') }}" >> "$GITHUB_OUTPUT"
echo "cli_hash=${{ hashFiles('target/release/nym-cli') }}" >> "$GITHUB_OUTPUT"
echo "netstat_hash=${{ hashFiles('target/release/nym-network-statistics') }}" >> "$GITHUB_OUTPUT"
- id: binary-versions
name: Get binary versions
run: |
v=$(rg '^version = "(.*)"' -or '$1' clients/native/Cargo.toml) && echo "client_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' mixnode/Cargo.toml) && echo "mixnode_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' gateway/Cargo.toml) && echo "gateway_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' clients/socks5/Cargo.toml) && echo "socks5_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-requester/Cargo.toml) && echo "netreq_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.client_version }}
filename: nym-client
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
name: Client
category: binaries
secrets: inherit
push-release-data-mixnode:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.mixnode_version }}
filename: nym-mixnode
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
name: Mixnode
category: binaries
secrets: inherit
push-release-data-gateway:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.gateway_version }}
filename: nym-gateway
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
name: Gateway
category: binaries
secrets: inherit
push-release-data-socks5:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.socks5_version }}
filename: nym-socks5-client
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
name: Socks5 Client
category: binaries
secrets: inherit
push-release-data-network-requester:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netreq_version }}
filename: nym-network-requester
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
name: Network Requester
category: binaries
secrets: inherit
push-release-data-cli:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.cli_version }}
filename: nym-cli
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
name: Cli
category: binaries
secrets: inherit
push-release-data-network-stat:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netstat_version }}
filename: nym-network-statistics
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
name: Network Statistics
category: binaries
secrets: inherit
+6 -46
View File
@@ -15,22 +15,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -58,15 +51,11 @@ jobs:
security list-keychain -d user -s $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it - name: Install app dependencies and build it
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -91,40 +80,11 @@ jobs:
if: ${{ always() }} if: ${{ always() }}
run: | run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
name: Upload to release based on tag name - name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
files: | files: |
nym-wallet/target/release/bundle/dmg/*.dmg nym-wallet/target/release/bundle/dmg/*.dmg
nym-wallet/target/release/bundle/macos/*.app.tar.gz* nym-wallet/target/release/bundle/macos/*.app.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${semver}_x64.dmg" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: MacOS
secrets: inherit
@@ -1,6 +1,5 @@
name: Publish Nym Wallet (Ubuntu) name: Publish Nym Wallet (Ubuntu)
on: on:
workflow_dispatch:
release: release:
types: [created] types: [created]
@@ -15,15 +14,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -33,24 +25,19 @@ jobs:
sudo apt-get install -y webkit2gtk-4.0 sudo apt-get install -y webkit2gtk-4.0
continue-on-error: true continue-on-error: true
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
@@ -60,48 +47,9 @@ jobs:
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Upload to release based on tag name
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
retention-days: 30
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with: with:
files: | files: |
nym-wallet/target/release/bundle/appimage/*.AppImage nym-wallet/target/release/bundle/appimage/*.AppImage
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz* nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${semver}_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [windows10] platform: [windows10]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- name: Clean up first - name: Clean up first
continue-on-error: true continue-on-error: true
@@ -46,10 +39,10 @@ jobs:
Remove-Item -path certificate -include tempCert.txt 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) Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -57,21 +50,15 @@ jobs:
toolchain: stable toolchain: stable
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000 run: yarn --network-timeout 100000
- name: Build and sign it - name: Build and sign it
shell: bash
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
@@ -88,40 +75,10 @@ jobs:
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
retention-days: 30 retention-days: 30
- id: create-release - name: Upload to release based on tag name
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
files: | files: |
nym-wallet/target/release/bundle/msi/*.msi nym-wallet/target/release/bundle/msi/*.msi
nym-wallet/target/release/bundle/msi/*.msi.zip* nym-wallet/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${semver}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Windows
secrets: inherit
+1 -7
View File
@@ -16,15 +16,9 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build dependencies - name: Build dependencies
run: yarn && yarn build run: yarn && yarn build
- name: Build storybook - name: Build storybook
+2 -2
View File
@@ -34,10 +34,10 @@ jobs:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install yarn for building application - name: Install yarn for building application
run: yarn install run: yarn install
-111
View File
@@ -1,111 +0,0 @@
name: Nyms5 Android
# unsigned APKs only, supported archs:
# - arm64-v8a (arm64)
# - x86_64
on:
workflow_dispatch:
push:
tags:
- nyms5-android-v*
jobs:
build:
name: Build APK
runs-on: custom-runner-linux
env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.2.9519653
NDK_HOME: ${{ github.workspace }}/android-sdk/ndk/25.2.9519653
SDK_PLATFORM_VERSION: android-33
SDK_BUILDTOOLS_VERSION: 33.0.2
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Java
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Install Android SDK manager
# https://developer.android.com/studio/command-line/sdkmanager
run: |
curl -sS https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -o cmdline-tools.zip
unzip cmdline-tools.zip
mkdir -p $ANDROID_HOME/cmdline-tools/latest
mv cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest
rm -rf cmdline-tools
- name: Install Android S/NDK
run: |
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
"platforms;$SDK_PLATFORM_VERSION" \
"platform-tools" \
"ndk;$NDK_VERSION" \
"build-tools;$SDK_BUILDTOOLS_VERSION"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.70.0
- name: Install rust android targets
run: |
rustup target add aarch64-linux-android \
x86_64-linux-android
- name: Build lib nym-socks5-listener
working-directory: sdk/lib/socks5-listener/
env:
RELEASE: true
RUSTFLAGS: "-C link-args=-Wl,--hash-style=gnu"
# build for arm64 and x86_64
run: ./build-android.sh aarch64 x86_64
- name: Build APKs (unsigned)
working-directory: nym-connect/native/android
env:
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
SENTRY_AUTH_TOKEN: ${{ secrets.NYMS5_ANDROID_SENTRY_AUTH_TOKEN }}
# build for arm64 and x86_64
run: |
echo "auth.token=$SENTRY_AUTH_TOKEN" | tee -a sentry.properties
./gradlew :app:assembleArch64Debug
./gradlew :app:assembleArch64Release
- name: Prepare APKs
run: |
mkdir apk
mv nym-connect/native/android/app/build/outputs/apk/arch64/debug/app-arch64-debug.apk \
apk/nyms5-arch64-debug.apk
mv nym-connect/native/android/app/build/outputs/apk/arch64/release/app-arch64-release-unsigned.apk \
apk/nyms5-arch64-release.apk
- name: Upload APKs
uses: actions/upload-artifact@v3
with:
name: nyms5-apk-arch64
path: |
apk/nyms5-arch64-debug.apk
apk/nyms5-arch64-release.apk
gh-release:
name: Publish APK (GH release)
needs: build
runs-on: custom-runner-linux
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Download binary artifact
uses: actions/download-artifact@v3
with:
name: nyms5-apk-arch64
path: apk
- name: Release
uses: softprops/action-gh-release@v1
with:
files: |
apk/nyms5-arch64-debug.apk
apk/nyms5-arch64-release.apk
-212
View File
@@ -1,212 +0,0 @@
name: Push release data
env:
strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders'
strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters'
on:
workflow_call:
inputs:
release_tag:
required: true
description: Release tag
type: string
release_id:
required: true
description: Release ID
type: string
release_date:
required: true
description: Release date
type: string
download_base_url:
required: true
description: Download base URL
type: string
changelog_url:
required: true
description: Changelog URL
type: string
archive_url:
required: false
description: Binary archive URL
type: string
sig_url:
required: false
description: Archive signature URL
type: string
version:
required: true
description: Release version (semver)
type: string
filename:
required: true
description: Binary file name
type: string
file_hash:
required: true
description: Binary hash (sha256)
type: string
name:
required: true
description: Name
type: string
category:
required: true
description: Category
type: string
platform:
required: false
description: Platform
type: string
workflow_dispatch:
inputs:
# ⚠ since inputs are limited to 10 max for workflow_dispatch
# some properties were omitted
version:
required: true
description: Release version (semver)
type: string
default: '1.0.0'
release_id:
required: true
description: Release ID
type: string
default: '1234'
release_date:
required: true
description: Release date
type: string
default: '2023-06-26T10:09:16Z'
download_base_url:
required: true
description: Download base URL
type: string
default: 'https://github.com/nymtech/nym/releases/download/nym-wallet-v1.0.0'
changelog_url:
required: true
description: Changelog URL
type: string
default: 'https://github.com/nymtech/nym/blob/nym-wallet-v1.0.0/nym-wallet/CHANGELOG.md'
filename:
required: true
description: Binary file name
type: string
default: 'nym-wallet_1.0.0_amd64.AppImage'
file_hash:
required: true
description: Binary hash (sha256)
type: string
default: 'xxx'
name:
required: true
description: Name
type: string
default: 'Wallet'
category:
required: true
description: Category
default: 'wallet'
type: choice
options:
- wallet
- connect
- binaries
platform:
required: false
description: Platform
default: 'Ubuntu'
type: choice
options:
- Ubuntu
- Windows
- MacOS
jobs:
push-download-data:
name: Push download data to Strapi
runs-on: custom-runner-linux
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_download_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadBaseUrl": "${{ inputs.download_base_url }}",
"changelogUrl": "${{ inputs.changelog_url }}",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"name": "${{ inputs.name }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
push-update-data:
name: Push update data to Strapi
runs-on: custom-runner-linux
# only push update data for tauri apps (desktop wallet and NC)
if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }}
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_updater_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadUrl": "${{ inputs.archive_url }}",
"changelog": "See ${{ inputs.changelog_url }} for the changelog",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
-50
View File
@@ -1,50 +0,0 @@
name: Typescript SDK docs
on:
push:
paths:
- "sdk/typescript/**"
pull_request:
paths:
- "sdk/typescript/**"
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Setup yarn
run: npm install -g yarn
- name: Install
run: yarn
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ts-packages
NYM_PROJECT_NAME: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-35
View File
@@ -1,35 +0,0 @@
name: Publish SDK to NPM
on:
workflow_dispatch:
jobs:
publish:
runs-on: [custom-runner-linux]
steps:
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: 'https://registry.npmjs.org'
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install dependencies
run: yarn
- name: Build and publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
working-directory: ./sdk/typescript/packages/sdk
run: scripts/publish.sh
+1 -1
View File
@@ -1 +1 @@
18 16
@@ -10,7 +10,7 @@ async function addToContextAndValidate(context) {
async function getMessageBody(context) { async function getMessageBody(context) {
try { try {
const source = fs const source = fs
.readFileSync("./notifications/deny.message").toString(); .readFileSync("deny.message").toString();
return source; return source;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
+52 -60
View File
@@ -3,70 +3,62 @@ name: CI for linting Typescript
on: on:
push: push:
paths: paths:
- "ts-packages/**" - 'ts-packages/**'
- "sdk/typescript/**" - 'sdk/typescript/**'
- "nym-connect/desktop/src/**" - 'nym-connect/desktop/src/**'
- "nym-connect/desktop/package.json" - 'nym-connect/desktop/package.json'
- "nym-connect/mobile/src/**" - 'nym-connect/mobile/src/**'
- "nym-connect/mobile/package.json" - 'nym-connect/mobile/package.json'
- "nym-wallet/src/**" - 'nym-wallet/src/**'
- "nym-wallet/package.json" - 'nym-wallet/package.json'
- "explorer/**"
pull_request: pull_request:
paths: paths:
- "ts-packages/**" - 'ts-packages/**'
- "sdk/typescript/**" - 'sdk/typescript/**'
- "nym-connect/desktop/src/**" - 'nym-connect/desktop/src/**'
- "nym-connect/desktop/package.json" - 'nym-connect/desktop/package.json'
- "nym-connect/mobile/src/**" - 'nym-connect/mobile/src/**'
- "nym-connect/mobile/package.json" - 'nym-connect/mobile/package.json'
- "nym-wallet/src/**" - 'nym-wallet/src/**'
- "nym-wallet/package.json" - 'nym-wallet/package.json'
- "explorer/**"
jobs: jobs:
build: build:
runs-on: custom-runner-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
continue-on-error: true continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Setup yarn
uses: actions-rs/toolchain@v1 run: npm install -g yarn
with: - name: Install
toolchain: stable run: yarn
- name: Install wasm-pack - name: Build packages
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: yarn build
- name: Setup yarn - name: Lint
run: npm install -g yarn run: yarn lint && yarn tsc
- name: Install - name: Matrix - Node Install
run: yarn run: npm install
- name: Build packages working-directory: .github/workflows/support-files
run: yarn build - name: Matrix - Send Notification
- name: Lint env:
run: yarn lint && yarn tsc NYM_NOTIFICATION_KIND: ts-packages
- name: Matrix - Node Install NYM_PROJECT_NAME: "ts-packages"
run: npm install NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
working-directory: .github/workflows/support-files NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
- name: Matrix - Send Notification GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
env: GIT_BRANCH: "${GITHUB_REF##*/}"
NYM_NOTIFICATION_KIND: ts-packages IS_SUCCESS: "${{ job.status == 'success' }}"
NYM_PROJECT_NAME: "ts-packages" MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}" MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}" MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
GIT_BRANCH: "${GITHUB_REF##*/}" MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}" uses: docker://keybaseio/client:stable-node
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}" with:
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}" args: .github/workflows/support-files/notifications/entry_point.sh
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-97
View File
@@ -4,103 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [Unreleased]
## [v1.1.24] (2023-08-08)
- Latency based gateway selection is serial and slow ([#3710])
- Network-requester: strip comments from allow lists ([#3625])
- Remove (or start maintaining) `upgrade` commands from all binaries ([#3600])
- Set sphinx as default packet type ([#3748])
- Apply fix from feature/ephemera to develop too (#3698) ([#3742])
- Feature/coco demos ([#3732])
- Add updates to community list projects ([#3722])
- Add geo-aware mixnet topology provider ([#3713])
- Add updates to community list projects ([#3711])
[#3710]: https://github.com/nymtech/nym/issues/3710
[#3625]: https://github.com/nymtech/nym/issues/3625
[#3600]: https://github.com/nymtech/nym/issues/3600
[#3748]: https://github.com/nymtech/nym/pull/3748
[#3742]: https://github.com/nymtech/nym/pull/3742
[#3732]: https://github.com/nymtech/nym/pull/3732
[#3722]: https://github.com/nymtech/nym/pull/3722
[#3713]: https://github.com/nymtech/nym/pull/3713
[#3711]: https://github.com/nymtech/nym/pull/3711
## [v1.1.23] (2023-07-04)
- nym-cli: add client identity key signing support ([#3576])
- Feature/node tester package ([#3634])
- Add medium toggle to socks5 client ([#3615])
- Don't fully turn off background task when cover traffic is disabled ([#3596])
[#3576]: https://github.com/nymtech/nym/issues/3576
[#3634]: https://github.com/nymtech/nym/pull/3634
[#3615]: https://github.com/nymtech/nym/pull/3615
[#3596]: https://github.com/nymtech/nym/pull/3596
## [v1.1.22] (2023-06-20)
- CLI tool for querying network-requesters ([#3539])
- Statically link OpenSSL ([#3510])
- NymConnect - add sentry.io reporting ([#3421])
- init command does not change version number in config.toml ([#3336])
- [Bug] Config version does not correspond to binary version ([#3434])
[#3539]: https://github.com/nymtech/nym/issues/3539
[#3510]: https://github.com/nymtech/nym/issues/3510
[#3421]: https://github.com/nymtech/nym/issues/3421
[#3336]: https://github.com/nymtech/nym/issues/3336
[#3434]: https://github.com/nymtech/nym/issues/3434
## [v1.1.21] (2023-06-13)
- mixFetch: Change socks5 `SendRequest` to include OrderedMessage index as a field rather than making it serialized inside the `data` field
([#3534])
- Explorer - add more data columns to the Service Provider section: ([#3474])
- network-requester: support report if they run an open proxy using `ControlRequest` API ([#3461])
- Refactor client configs (London discussion) ([#3444])
- Increase `DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE` to 2000 to improve reliability ([#3433])
- socks5: sender waits for lanes to clear even though the connection is closed ([#3366])
- version bump for variables ([#3545])
[#3534]: https://github.com/nymtech/nym/issues/3534
[#3474]: https://github.com/nymtech/nym/issues/3474
[#3461]: https://github.com/nymtech/nym/issues/3461
[#3444]: https://github.com/nymtech/nym/issues/3444
[#3433]: https://github.com/nymtech/nym/issues/3433
[#3366]: https://github.com/nymtech/nym/issues/3366
[#3545]: https://github.com/nymtech/nym/pull/3545
## [v1.1.20] (2023-06-06)
- Explorer - Fix SP supported apps list ([#3458])
- Investigate if we need to lower `SHUTDOWN_TIMEOUT` in socks5 to zero (or almost zero) ([#3438])
- Explorer - show all gateways in the default view regardless of the version number ([#3427])
- service-provider-directory: add signature check when announcing ([#3360])
- Support functionality for nym-name-service (nym-api, nym-cli, etc) ([#3355])
- Edit the nym-network-requester to support the enabled-credentials-mode flag ([#3101])
- [BUG] network requester documentation update ([#3493])
- removing hardcoded version numbers ([#3485])
- [BUG] network requester documentation update ([#3481])
- [BUG] network requester documentation update ([#3469])
- Sign when announcing service providers to the directory contract ([#3459])
- mixnode documentation update ([#3435])
- updated readme with new developer chat links + new docs links ([#3141])
[#3458]: https://github.com/nymtech/nym/issues/3458
[#3438]: https://github.com/nymtech/nym/issues/3438
[#3427]: https://github.com/nymtech/nym/issues/3427
[#3360]: https://github.com/nymtech/nym/issues/3360
[#3355]: https://github.com/nymtech/nym/issues/3355
[#3101]: https://github.com/nymtech/nym/issues/3101
[#3493]: https://github.com/nymtech/nym/pull/3493
[#3485]: https://github.com/nymtech/nym/pull/3485
[#3481]: https://github.com/nymtech/nym/pull/3481
[#3469]: https://github.com/nymtech/nym/pull/3469
[#3459]: https://github.com/nymtech/nym/pull/3459
[#3435]: https://github.com/nymtech/nym/pull/3435
[#3141]: https://github.com/nymtech/nym/pull/3141
## [v1.1.19] (2023-05-16) ## [v1.1.19] (2023-05-16)
- nym-name-service endpoint in nym-api ([#3403]) - nym-name-service endpoint in nym-api ([#3403])
Generated
+344 -939
View File
File diff suppressed because it is too large Load Diff
+12 -26
View File
@@ -74,7 +74,6 @@ members = [
"common/types", "common/types",
"common/wasm-utils", "common/wasm-utils",
"explorer-api", "explorer-api",
"explorer-api/explorer-api-requests",
"gateway", "gateway",
"gateway/gateway-requests", "gateway/gateway-requests",
"integrations/bity", "integrations/bity",
@@ -88,7 +87,6 @@ members = [
"nym-api/nym-api-requests", "nym-api/nym-api-requests",
"nym-outfox", "nym-outfox",
"tools/nym-cli", "tools/nym-cli",
"tools/nym-nr-query",
"tools/ts-rs-cli" "tools/ts-rs-cli"
] ]
@@ -103,7 +101,7 @@ default-members = [
"explorer-api", "explorer-api",
] ]
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-browser-extension/storage", "cpu-cycles"] exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
[workspace.package] [workspace.package]
authors = ["Nym Technologies SA"] authors = ["Nym Technologies SA"]
@@ -114,42 +112,30 @@ edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.71"
async-trait = "0.1.64" async-trait = "0.1.64"
anyhow = "1.0.71"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
cfg-if = "1.0.0" cfg-if = "1.0.0"
cosmwasm-derive = "=1.3.0" cosmwasm-derive = "=1.0.0"
cosmwasm-schema = "=1.3.0" cosmwasm-schema = "=1.0.0"
cosmwasm-std = "=1.3.0" cosmwasm-std = "=1.0.0"
# use 0.5.0 as that's the version used by cosmwasm-std 1.3.0 cosmwasm-storage = "=1.0.0"
# (and ideally we don't want to pull the same dependency twice) cw-utils = "=0.13.4"
serde-json-wasm = "=0.5.0" cw-storage-plus = "=0.13.4"
cosmwasm-storage = "=1.3.0" cw2 = { version = "=0.13.4" }
cosmrs = "=0.14.0" cw3 = { version = "=0.13.4" }
# same version as used by cosmrs cw3-fixed-multisig = { version = "=0.13.4" }
cw-utils = "=1.0.1" cw4 = { version = "=0.13.4" }
cw-storage-plus = "=1.1.0"
cw2 = { version = "=1.1.0" }
cw3 = { version = "=1.1.0" }
cw4 = { version = "=1.1.0" }
cw-controllers = { version = "=1.1.0" }
dotenvy = "0.15.6" dotenvy = "0.15.6"
generic-array = "0.14.7" generic-array = "0.14.7"
getrandom = "0.2.10"
k256 = "0.13"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4" log = "0.4"
once_cell = "1.7.2" once_cell = "1.7.2"
rand = "0.8.5" rand = "0.8.5"
reqwest = "0.11.18"
serde = "1.0.152" serde = "1.0.152"
serde_json = "1.0.91" serde_json = "1.0.91"
tap = "1.0.1" tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38" thiserror = "1.0.38"
tokio = "1.24.1" tokio = "1.24.1"
url = "2.2" url = "2.2"
zeroize = "1.6.0" zeroize = "1.6.0"
# wasm-related dependencies
wasmtimer = "0.2.0"
+2 -5
View File
@@ -73,7 +73,7 @@ endef
# Generate targets for the various cargo workspaces # Generate targets for the various cargo workspaces
$(eval $(call add_cargo_workspace,main,.)) $(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown)) $(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown)) $(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,)) $(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop)) $(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
@@ -104,7 +104,7 @@ NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
wasm: wasm-build wasm-opt wasm: wasm-build wasm-opt
wasm-build: wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
wasm-opt: wasm-opt:
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT) wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
@@ -112,9 +112,6 @@ wasm-opt:
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT) wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
contract-schema:
$(MAKE) -C contracts schema
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Misc # Misc
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
+5 -8
View File
@@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices. * nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing"). * nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer. * nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework. * nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)
[![Build Status](https://img.shields.io/github/actions/workflow/status/nymtech/nym/build.yml?branch=develop&style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop) [![Build Status](https://img.shields.io/github/actions/workflow/status/nymtech/nym/build.yml?branch=develop&style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
@@ -21,8 +21,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
### Building ### Building
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html). Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/building-nym.html).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html). Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
### Developing ### Developing
@@ -32,11 +32,7 @@ For Typescript components, please see [ts-packages](./ts-packages).
### Developer chat ### Developer chat
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team. You can chat with us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes place in the **#dev** channel. Node operators should be in the **#node-operators** channel.
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](https://discord.gg/nym)
### Rewards ### Rewards
@@ -84,3 +80,4 @@ where `s'` is stake `s` scaled over total token circulating supply.
### Licensing and copyright information ### Licensing and copyright information
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files. This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
-53
View File
@@ -1,53 +0,0 @@
<svg
width="100%"
height="100%"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_421_13045)">
<path
d="M40 80C62.0914 80 80 62.0914 80 40C80 17.9086 62.0914 0 40 0C17.9086 0 0 17.9086 0 40C0 62.0914 17.9086 80 40 80Z"
fill="black"
/>
<path
d="M40 77.2636C60.5801 77.2636 77.2636 60.5801 77.2636 40C77.2636 19.4199 60.5801 2.73645 40 2.73645C19.4199 2.73645 2.73645 19.4199 2.73645 40C2.73645 60.5801 19.4199 77.2636 40 77.2636Z"
fill="white"
/>
<path
d="M24.0224 32.471H23.9776V32.5084V45.5775L18.4673 32.4934L18.4598 32.471H18.4299H15.3047H11.7981H11.7607V32.5084V47.4916V47.529H11.7981H15.3047H15.3421V47.4916V34.4L20.8748 47.5065L20.8822 47.529H20.9121H24.0224H27.5215H27.5589V47.4916V32.5084V32.471H27.5215H24.0224Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.8965 32.39H27.64V47.6101H20.8238L20.7989 47.5352L15.4232 34.8006V47.6101H11.6797V32.39H18.5183L18.5432 32.4649L23.8965 45.1761V32.39ZM23.9776 45.5776L18.4673 32.4935L18.4598 32.471H11.7608V47.529H15.3421V34.4L20.8748 47.5065L20.8823 47.529H27.5589V32.471H23.9776V45.5776Z"
fill="black"
/>
<path
d="M68.2019 32.471H61.5178H61.4804L61.4729 32.5009L58.0486 45.6374L54.6169 32.5009L54.6094 32.471H54.5795H47.8804H47.8355V32.5084V47.4916V47.529H47.8804H51.3795H51.4169V47.4916V34.5047L54.8038 47.499L54.8112 47.529H54.8486H61.2337H61.2636L61.2711 47.499L64.658 34.5047V47.4916V47.529H64.6954H68.2019H68.2393V47.4916V32.5084V32.471H68.2019Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M61.4171 32.39H68.3204V47.6101H64.5769V35.1372L61.3497 47.5187L61.3495 47.5195L61.3269 47.6101H54.7479L54.7253 47.5195L54.7251 47.5187L51.4979 35.1372V47.6101H47.7545V32.39H54.6727L54.6953 32.4804L54.6955 32.4813L58.0485 45.3163L61.3943 32.4813L61.3945 32.4805L61.4171 32.39ZM58.0486 45.6374L54.6168 32.5009L54.6094 32.471H47.8355V47.529H51.4168V34.5047L54.8038 47.4991L54.8112 47.529H61.2636L61.2711 47.4991L64.658 34.5047V47.529H68.2393V32.471H61.4804L61.4729 32.5009L58.0486 45.6374Z"
fill="black"
/>
<path
d="M42.0711 32.471H42.0486L42.0412 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H33.4804H29.4355H29.3608L29.3982 32.5308L35.9851 43.9402V47.4916V47.529H36.0225H39.529H39.5664V47.4916V43.9402L46.1533 32.5308L46.1907 32.471H46.1159H42.0711Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M41.9985 32.39H46.337L46.2228 32.5726L39.6475 43.9619V47.6101H35.904V43.9619L29.3286 32.5726L29.2145 32.39H33.5529L33.5817 32.4475L37.7868 39.7181L41.9697 32.4476L41.9985 32.39ZM42.0411 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H29.3608L29.3981 32.5308L35.9851 43.9402V47.529H39.5664V43.9402L46.1533 32.5308L46.1907 32.471H42.0486L42.0411 32.486Z"
fill="black"
/>
</g>
<defs>
<clipPath id="clip0_421_13045">
<rect width="80" height="80" fill="white" />
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

+1 -3
View File
@@ -12,14 +12,12 @@ serde = { workspace = true, features = ["derive"] }
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" } nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" } nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" } nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" } nym-credential-storage = { path = "../../common/credential-storage" }
nym-bin-common = { path = "../../common/bin-common"} nym-bin-common = { path = "../../common/bin-common"}
nym-network-defaults = { path = "../../common/network-defaults" } nym-network-defaults = { path = "../../common/network-defaults" }
nym-pemstore = { path = "../../common/pemstore" } nym-pemstore = { path = "../../common/pemstore" }
nym-validator-client = { path = "../../common/client-libs/validator-client" } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
+3 -3
View File
@@ -15,9 +15,9 @@ The credential binary is still experimental software. The infrastructure for usi
From the project's root directory, run: From the project's root directory, run:
``` ```
cargo build -p nym-credential-client cargo build -p credential
``` ```
which generates the `nym-credential-client` binary in `target/debug/nym-credential-client`. which generates the `credential` binary in `target/debug/credential`.
### Running ### Running
@@ -25,7 +25,7 @@ which generates the `nym-credential-client` binary in `target/debug/nym-credenti
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so: For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
``` ```
./target/debug/nym-credential-client --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000 ./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
``` ```
More information regarding how to run the binary can be found by running it with the `--help` argument. More information regarding how to run the binary can be found by running it with the `--help` argument.
+6 -8
View File
@@ -1,4 +1,4 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
mod commands; mod commands;
@@ -9,14 +9,13 @@ use commands::*;
use error::Result; use error::Result;
use log::*; use log::*;
use nym_bin_common::completions::fig_generate; use nym_bin_common::completions::fig_generate;
use nym_config::DEFAULT_DATA_DIR; use nym_config::{CRED_DB_FILE_NAME, DATA_DIR};
use nym_network_defaults::{setup_env, NymNetworkDetails}; use nym_network_defaults::{setup_env, NymNetworkDetails};
use std::process::exit; use std::process::exit;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use clap::{CommandFactory, Parser}; use clap::{CommandFactory, Parser};
use nym_bin_common::logging::setup_logging; use nym_bin_common::logging::setup_logging;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_validator_client::nyxd::traits::DkgQueryClient; use nym_validator_client::nyxd::traits::DkgQueryClient;
use nym_validator_client::nyxd::{Coin, CosmWasmClient}; use nym_validator_client::nyxd::{Coin, CosmWasmClient};
use nym_validator_client::Config; use nym_validator_client::Config;
@@ -72,11 +71,10 @@ async fn main() -> Result<()> {
match args.command { match args.command {
Command::Run(r) => { Command::Run(r) => {
// we assume the structure of <home-dir>/data let db_path = r
let data_dir = r.client_home_directory.join(DEFAULT_DATA_DIR); .client_home_directory
let paths = CommonClientPaths::new_default(data_dir); .join(DATA_DIR)
let db_path = paths.credentials_database; .join(CRED_DB_FILE_NAME);
let shared_storage = let shared_storage =
nym_credential_storage::initialise_persistent_storage(db_path).await; nym_credential_storage::initialise_persistent_storage(db_path).await;
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?; let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.24" version = "1.1.19"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
@@ -48,7 +48,7 @@ nym-sphinx = { path = "../../common/nymsphinx" }
nym-pemstore = { path = "../../common/pemstore" } nym-pemstore = { path = "../../common/pemstore" }
nym-task = { path = "../../common/task" } nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" } nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
nym-client-websocket-requests = { path = "websocket-requests" } nym-client-websocket-requests = { path = "websocket-requests" }
[dev-dependencies] [dev-dependencies]
+101 -92
View File
@@ -1,104 +1,99 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::persistence::ClientPaths; use crate::client::config::template::config_template;
use crate::client::config::template::CONFIG_TEMPLATE; use nym_client_core::config::ClientCoreConfigTrait;
use nym_bin_common::logging::LoggingSettings;
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nym_config::{ use nym_config::{NymConfig, OptionalSet};
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
OptionalSet, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use std::io;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
pub use nym_client_core::config::Config as BaseClientConfig; pub use nym_client_core::config::Config as BaseConfig;
pub use nym_client_core::config::MISSING_VALUE;
pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig}; pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig};
pub mod old_config_v1_1_13; pub mod old_config_v1_1_13;
pub mod old_config_v1_1_20;
pub mod old_config_v1_1_20_2;
mod persistence;
mod template; mod template;
const DEFAULT_CLIENTS_DIR: &str = "clients"; #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
#[serde(deny_unknown_fields)]
/// Derive default path to clients's config directory. pub enum SocketType {
/// It should get resolved to `$HOME/.nym/mixnodes/<id>/config` WebSocket,
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf { None,
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_CLIENTS_DIR)
.join(id)
.join(DEFAULT_CONFIG_DIR)
} }
/// Derive default path to client's config file. impl SocketType {
/// It should get resolved to `$HOME/.nym/clients/<id>/config/config.toml` pub fn from_string<S: Into<String>>(val: S) -> Self {
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf { let mut upper = val.into();
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME) upper.make_ascii_uppercase();
match upper.as_ref() {
"WEBSOCKET" | "WS" => SocketType::WebSocket,
_ => SocketType::None,
}
}
pub fn is_websocket(&self) -> bool {
matches!(self, SocketType::WebSocket)
}
} }
/// Derive default path to client's data directory where files, such as keys, are stored. #[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
/// It should get resolved to `$HOME/.nym/clients/<id>/data` #[serde(deny_unknown_fields)]
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_CLIENTS_DIR)
.join(id)
.join(DEFAULT_DATA_DIR)
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Config { pub struct Config {
#[serde(flatten)] #[serde(flatten)]
pub base: BaseClientConfig, base: BaseConfig<Config>,
pub socket: Socket, socket: Socket,
// pub paths: CommonClientPathfinder,
pub storage_paths: ClientPaths,
pub logging: LoggingSettings,
} }
impl NymConfigTemplate for Config { impl NymConfig for Config {
fn template() -> &'static str { fn template() -> &'static str {
CONFIG_TEMPLATE config_template()
}
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.get_nym_root_directory()
}
fn config_directory(&self) -> PathBuf {
self.root_directory()
.join(self.base.get_id())
.join("config")
}
fn data_directory(&self) -> PathBuf {
self.root_directory().join(self.base.get_id()).join("data")
}
}
impl ClientCoreConfigTrait for Config {
fn get_gateway_endpoint(&self) -> &nym_client_core::config::GatewayEndpointConfig {
self.base.get_gateway_endpoint()
} }
} }
impl Config { impl Config {
pub fn new<S: AsRef<str>>(id: S) -> Self { pub fn new<S: Into<String>>(id: S) -> Self {
Config { Config {
base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")), base: BaseConfig::new(id),
storage_paths: ClientPaths::new_default(default_data_directory(id.as_ref())),
logging: Default::default(),
socket: Default::default(), socket: Default::default(),
} }
} }
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
pub fn default_location(&self) -> PathBuf {
default_config_filepath(&self.base.client.id)
}
pub fn save_to_default_location(&self) -> io::Result<()> {
let config_save_location: PathBuf = self.default_location();
save_formatted_config_to_file(self, config_save_location)
}
pub fn validate(&self) -> bool { pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet) // no other sections have explicit requirements (yet)
self.base.validate() self.base.validate()
@@ -128,10 +123,39 @@ impl Config {
self self
} }
// getters
pub fn get_config_file_save_location(&self) -> PathBuf {
self.config_directory().join(Self::config_file_name())
}
pub fn get_base(&self) -> &BaseConfig<Self> {
&self.base
}
pub fn get_base_mut(&mut self) -> &mut BaseConfig<Self> {
&mut self.base
}
pub fn get_debug_settings(&self) -> &DebugConfig {
self.get_base().get_debug_config()
}
pub fn get_socket_type(&self) -> SocketType {
self.socket.socket_type
}
pub fn get_listening_ip(&self) -> IpAddr {
self.socket.host
}
pub fn get_listening_port(&self) -> u16 {
self.socket.listening_port
}
// poor man's 'builder' method // poor man's 'builder' method
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
where where
F: Fn(BaseClientConfig, T) -> BaseClientConfig, F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
{ {
self.base = f(self.base, val); self.base = f(self.base, val);
self self
@@ -141,7 +165,7 @@ impl Config {
// (plz, lets refactor it) // (plz, lets refactor it)
pub fn with_optional_ext<F, T>(mut self, f: F, val: Option<T>) -> Self pub fn with_optional_ext<F, T>(mut self, f: F, val: Option<T>) -> Self
where where
F: Fn(BaseClientConfig, T) -> BaseClientConfig, F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
{ {
self.base = self.base.with_optional(f, val); self.base = self.base.with_optional(f, val);
self self
@@ -149,7 +173,7 @@ impl Config {
pub fn with_optional_env_ext<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self pub fn with_optional_env_ext<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
where where
F: Fn(BaseClientConfig, T) -> BaseClientConfig, F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
T: FromStr, T: FromStr,
<T as FromStr>::Err: Debug, <T as FromStr>::Err: Debug,
{ {
@@ -165,7 +189,7 @@ impl Config {
parser: G, parser: G,
) -> Self ) -> Self
where where
F: Fn(BaseClientConfig, T) -> BaseClientConfig, F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
G: Fn(&str) -> T, G: Fn(&str) -> T,
{ {
self.base = self.base.with_optional_custom_env(f, val, env_var, parser); self.base = self.base.with_optional_custom_env(f, val, env_var, parser);
@@ -173,34 +197,19 @@ impl Config {
} }
} }
// define_optional_set_inner!(Config, base, BaseClientConfig);
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
#[serde(deny_unknown_fields)]
pub enum SocketType {
WebSocket,
None,
}
impl SocketType {
pub fn is_websocket(&self) -> bool {
matches!(self, SocketType::WebSocket)
}
}
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(default, deny_unknown_fields)] #[serde(default, deny_unknown_fields)]
pub struct Socket { pub struct Socket {
pub socket_type: SocketType, socket_type: SocketType,
pub host: IpAddr, host: IpAddr,
pub listening_port: u16, listening_port: u16,
} }
impl Default for Socket { impl Default for Socket {
fn default() -> Self { fn default() -> Self {
Socket { Socket {
socket_type: SocketType::WebSocket, socket_type: SocketType::WebSocket,
host: IpAddr::V4(Ipv4Addr::LOCALHOST), host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT, listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
} }
} }
@@ -1,33 +1,58 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::old_config_v1_1_20::{ConfigV1_1_20, SocketV1_1_20}; use crate::client::config::{Config, Socket};
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13; use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig; use nym_config::NymConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Deserialize, PartialEq, Serialize)] #[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct OldConfigV1_1_13 { pub struct OldConfigV1_1_13 {
#[serde(flatten)] #[serde(flatten)]
pub base: OldBaseConfigV1_1_13<OldConfigV1_1_13>, base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
pub socket: SocketV1_1_20, socket: Socket,
} }
impl MigrationNymConfig for OldConfigV1_1_13 { impl NymConfig for OldConfigV1_1_13 {
fn template() -> &'static str {
// not intended to be used
unimplemented!()
}
fn default_root_directory() -> PathBuf { fn default_root_directory() -> PathBuf {
dirs::home_dir() dirs::home_dir()
.expect("Failed to evaluate $HOME value") .expect("Failed to evaluate $HOME value")
.join(".nym") .join(".nym")
.join("clients") .join("clients")
} }
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.client.nym_root_directory.clone()
}
fn config_directory(&self) -> PathBuf {
self.root_directory()
.join(&self.base.client.id)
.join("config")
}
fn data_directory(&self) -> PathBuf {
self.root_directory()
.join(&self.base.client.id)
.join("data")
}
} }
impl From<OldConfigV1_1_13> for ConfigV1_1_20 { impl From<OldConfigV1_1_13> for Config {
fn from(value: OldConfigV1_1_13) -> Self { fn from(value: OldConfigV1_1_13) -> Self {
ConfigV1_1_20 { Config {
base: value.base.into(), base: value.base.into(),
socket: value.socket, socket: value.socket,
} }
@@ -1,115 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::old_config_v1_1_20_2::{
ClientPathsV1_1_20_2, ConfigV1_1_20_2, SocketTypeV1_1_20_2, SocketV1_1_20_2,
};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
use nym_client_core::config::old_config_v1_1_20_2::{
ClientV1_1_20_2, ConfigV1_1_20_2 as BaseConfigV1_1_20_2,
};
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
#[serde(deny_unknown_fields)]
pub enum SocketTypeV1_1_20 {
WebSocket,
None,
}
impl From<SocketTypeV1_1_20> for SocketTypeV1_1_20_2 {
fn from(value: SocketTypeV1_1_20) -> Self {
match value {
SocketTypeV1_1_20::WebSocket => SocketTypeV1_1_20_2::WebSocket,
SocketTypeV1_1_20::None => SocketTypeV1_1_20_2::None,
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1_1_20 {
#[serde(flatten)]
pub base: BaseConfigV1_1_20<ConfigV1_1_20>,
pub socket: SocketV1_1_20,
}
impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
fn from(value: ConfigV1_1_20) -> Self {
ConfigV1_1_20_2 {
base: BaseConfigV1_1_20_2 {
client: ClientV1_1_20_2 {
version: value.base.client.version,
id: value.base.client.id,
disabled_credentials_mode: value.base.client.disabled_credentials_mode,
nyxd_urls: value.base.client.nyxd_urls,
nym_api_urls: value.base.client.nym_api_urls,
gateway_endpoint: value.base.client.gateway_endpoint.into(),
},
debug: value.base.debug.into(),
},
socket: value.socket.into(),
storage_paths: ClientPathsV1_1_20_2 {
common_paths: CommonClientPathsV1_1_20_2 {
keys: ClientKeysPaths {
private_identity_key_file: value.base.client.private_identity_key_file,
public_identity_key_file: value.base.client.public_identity_key_file,
private_encryption_key_file: value.base.client.private_encryption_key_file,
public_encryption_key_file: value.base.client.public_encryption_key_file,
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
ack_key_file: value.base.client.ack_key_file,
},
credentials_database: value.base.client.database_path,
reply_surb_database: value.base.client.reply_surb_database_path,
},
},
logging: LoggingSettings::default(),
}
}
}
impl MigrationNymConfig for ConfigV1_1_20 {
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("clients")
}
}
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct SocketV1_1_20 {
socket_type: SocketTypeV1_1_20,
host: IpAddr,
listening_port: u16,
}
impl From<SocketV1_1_20> for SocketV1_1_20_2 {
fn from(value: SocketV1_1_20) -> Self {
SocketV1_1_20_2 {
socket_type: value.socket_type.into(),
host: value.host,
listening_port: value.listening_port,
}
}
}
impl Default for SocketV1_1_20 {
fn default() -> Self {
SocketV1_1_20 {
socket_type: SocketTypeV1_1_20::WebSocket,
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
}
}
}
@@ -1,103 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::persistence::ClientPaths;
use crate::client::config::{default_config_filepath, Config, Socket, SocketType};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2;
use nym_client_core::config::GatewayEndpointConfig;
use nym_config::read_config_from_toml_file;
use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use serde::{Deserialize, Serialize};
use std::io;
use std::net::{IpAddr, Ipv4Addr};
use std::path::Path;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct ClientPathsV1_1_20_2 {
#[serde(flatten)]
pub common_paths: CommonClientPathsV1_1_20_2,
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct ConfigV1_1_20_2 {
#[serde(flatten)]
pub base: BaseConfigV1_1_20_2,
pub socket: SocketV1_1_20_2,
pub storage_paths: ClientPathsV1_1_20_2,
pub logging: LoggingSettings,
}
impl ConfigV1_1_20_2 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
// in this upgrade, gateway endpoint configuration was moved out of the config file,
// so its returned to be stored elsewhere.
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
let gateway_details = self.base.client.gateway_endpoint.clone().into();
let config = Config {
base: self.base.into(),
socket: self.socket.into(),
storage_paths: ClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default(),
},
logging: self.logging,
};
(config, gateway_details)
}
}
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
#[serde(deny_unknown_fields)]
pub enum SocketTypeV1_1_20_2 {
WebSocket,
None,
}
impl From<SocketTypeV1_1_20_2> for SocketType {
fn from(value: SocketTypeV1_1_20_2) -> Self {
match value {
SocketTypeV1_1_20_2::WebSocket => SocketType::WebSocket,
SocketTypeV1_1_20_2::None => SocketType::None,
}
}
}
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct SocketV1_1_20_2 {
pub socket_type: SocketTypeV1_1_20_2,
pub host: IpAddr,
pub listening_port: u16,
}
impl From<SocketV1_1_20_2> for Socket {
fn from(value: SocketV1_1_20_2) -> Self {
Socket {
socket_type: value.socket_type.into(),
host: value.host,
listening_port: value.listening_port,
}
}
}
impl Default for SocketV1_1_20_2 {
fn default() -> Self {
SocketV1_1_20_2 {
socket_type: SocketTypeV1_1_20_2::WebSocket,
host: IpAddr::V4(Ipv4Addr::LOCALHOST),
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
}
}
}
@@ -1,20 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_client_core::config::disk_persistence::CommonClientPaths;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct ClientPaths {
#[serde(flatten)]
pub common_paths: CommonClientPaths,
}
impl ClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
ClientPaths {
common_paths: CommonClientPaths::new_default(base_data_directory),
}
}
}
+36 -22
View File
@@ -1,11 +1,12 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// While using normal toml marshalling would have been way simpler with less overhead, pub(crate) fn config_template() -> &'static str {
// I think it's useful to have comments attached to the saved config file to explain behaviour of // While using normal toml marshalling would have been way simpler with less overhead,
// particular fields. // I think it's useful to have comments attached to the saved config file to explain behaviour of
// Note: any changes to the template must be reflected in the appropriate structs. // particular fields.
pub(crate) const CONFIG_TEMPLATE: &str = r#" // Note: any changes to the template must be reflected in the appropriate structs.
r#"
# This is a TOML config file. # This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
@@ -36,37 +37,50 @@ nym_api_urls = [
{{/each}} {{/each}}
] ]
[storage_paths]
# Path to file containing private identity key. # Path to file containing private identity key.
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}' private_identity_key_file = '{{ client.private_identity_key_file }}'
# Path to file containing public identity key. # Path to file containing public identity key.
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}' public_identity_key_file = '{{ client.public_identity_key_file }}'
# Path to file containing private encryption key. # Path to file containing private encryption key.
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}' private_encryption_key_file = '{{ client.private_encryption_key_file }}'
# Path to file containing public encryption key. # Path to file containing public encryption key.
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' public_encryption_key_file = '{{ client.public_encryption_key_file }}'
# Path to the database containing bandwidth credentials
database_path = '{{ client.database_path }}'
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
reply_surb_database_path = '{{ client.reply_surb_database_path }}'
##### additional client config options #####
# A gateway specific, optional, base58 stringified shared key used for # A gateway specific, optional, base58 stringified shared key used for
# communication with particular gateway. # communication with particular gateway.
keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
# Path to file containing key used for encrypting and decrypting the content of an # Path to file containing key used for encrypting and decrypting the content of an
# acknowledgement so that nobody besides the client knows which packet it refers to. # acknowledgement so that nobody besides the client knows which packet it refers to.
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' ack_key_file = '{{ client.ack_key_file }}'
##### advanced configuration options #####
# Path to the database containing bandwidth credentials # Absolute path to the home Nym Clients directory.
credentials_database = '{{ storage_paths.credentials_database }}' nym_root_directory = '{{ client.nym_root_directory }}'
[client.gateway_endpoint]
# ID of the gateway from which the client should be fetching messages.
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
# Address of the gateway owner to which the client should send messages.
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
# Address of the gateway listener to which all client requests should be sent.
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
# Path to the file containing information about gateway used by this client,
# i.e. details such as its public key, owner address or the network information.
gateway_details = '{{ storage_paths.gateway_details }}'
##### socket config options ##### ##### socket config options #####
@@ -106,5 +120,5 @@ average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
[debug.cover_traffic] [debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}' loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
"#
"#; }
+41 -22
View File
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config; use crate::client::config::Config;
@@ -6,15 +6,19 @@ use crate::error::ClientError;
use crate::websocket; use crate::websocket;
use futures::channel::mpsc; use futures::channel::mpsc;
use log::*; use log::*;
use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config; use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::base_client::non_wasm_helpers::create_bandwidth_controller;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::base_client::{ use nym_client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, ClientState, non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
}; };
use nym_client_core::client::inbound_messages::InputMessage; use nym_client_core::client::inbound_messages::InputMessage;
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::client::received_buffer::{ use nym_client_core::client::received_buffer::{
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver, ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
}; };
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
@@ -42,6 +46,17 @@ impl SocketClient {
SocketClient { config } SocketClient { config }
} }
async fn create_bandwidth_controller(
config: &Config,
) -> BandwidthController<Client<QueryNyxdClient>, PersistentStorage> {
let storage = nym_credential_storage::initialise_persistent_storage(
config.get_base().get_database_path(),
)
.await;
create_bandwidth_controller(config.get_base(), storage)
}
fn start_websocket_listener( fn start_websocket_listener(
config: &Config, config: &Config,
client_input: ClientInput, client_input: ClientInput,
@@ -78,7 +93,7 @@ impl SocketClient {
Some(packet_type), Some(packet_type),
); );
websocket::Listener::new(config.socket.host, config.socket.listening_port) websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
.start(websocket_handler, shutdown); .start(websocket_handler, shutdown);
} }
@@ -91,38 +106,42 @@ impl SocketClient {
res res
} }
async fn initialise_storage(&self) -> Result<OnDiskPersistent, ClientError> { fn key_store(&self) -> OnDiskKeys {
Ok(OnDiskPersistent::from_paths( let pathfinder = ClientKeyPathfinder::new_from_config(self.config.get_base());
self.config.storage_paths.common_paths.clone(), OnDiskKeys::new(pathfinder)
&self.config.base.debug,
)
.await?)
} }
// TODO: see if this could also be shared with socks5 client / nym-sdk maybe // TODO: see if this could also be shared with socks5 client / nym-sdk maybe
async fn create_base_client_builder(&self) -> Result<NativeClientBuilder, ClientError> { async fn create_base_client_builder(&self) -> Result<NativeClientBuilder, ClientError> {
// don't create dkg client for the bandwidth controller if credentials are disabled // don't create bandwidth controller if credentials are disabled
let dkg_query_client = if self.config.base.client.disabled_credentials_mode { let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() {
None None
} else { } else {
Some(default_query_dkg_client_from_config(&self.config.base)) Some(Self::create_bandwidth_controller(&self.config).await)
}; };
let storage = self.initialise_storage().await?; let base_client = BaseClientBuilder::new_from_base_config(
self.config.get_base(),
let base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client); self.key_store(),
bandwidth_controller,
non_wasm_helpers::setup_fs_reply_surb_backend(
self.config.get_base().get_reply_surb_database_path(),
&self.config.get_debug_settings().reply_surbs,
)
.await?,
);
Ok(base_client) Ok(base_client)
} }
pub async fn start_socket(self) -> Result<TaskManager, ClientError> { pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
if !self.config.socket.socket_type.is_websocket() { if !self.config.get_socket_type().is_websocket() {
return Err(ClientError::InvalidSocketMode); return Err(ClientError::InvalidSocketMode);
} }
let base_builder = self.create_base_client_builder().await?; let base_builder = self.create_base_client_builder().await?;
let packet_type = self.config.base.debug.traffic.packet_type; let packet_type = self.config.get_base().get_packet_type();
let mut started_client = base_builder.start_base().await?; let mut started_client = base_builder.start_base(packet_type).await?;
let self_address = started_client.address; let self_address = started_client.address;
let client_input = started_client.client_input.register_producer(); let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer(); let client_output = started_client.client_output.register_consumer();
@@ -145,13 +164,13 @@ impl SocketClient {
} }
pub async fn start_direct(self) -> Result<DirectClient, ClientError> { pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
if self.config.socket.socket_type.is_websocket() { if self.config.get_socket_type().is_websocket() {
return Err(ClientError::InvalidSocketMode); return Err(ClientError::InvalidSocketMode);
} }
let base_builder = self.create_base_client_builder().await?; let base_builder = self.create_base_client_builder().await?;
let packet_type = self.config.base.debug.traffic.packet_type; let packet_type = self.config.get_base().get_packet_type();
let mut started_client = base_builder.start_base().await?; let mut started_client = base_builder.start_base(packet_type).await?;
let address = started_client.address; let address = started_client.address;
let client_input = started_client.client_input.register_producer(); let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer(); let client_output = started_client.client_output.register_consumer();
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
+37 -47
View File
@@ -1,10 +1,7 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::{ use crate::commands::try_upgrade_v1_1_13_config;
default_config_directory, default_config_filepath, default_data_directory,
};
use crate::commands::try_upgrade_config;
use crate::{ use crate::{
client::config::Config, client::config::Config,
commands::{override_config, OverrideConfig}, commands::{override_config, OverrideConfig},
@@ -12,16 +9,13 @@ use crate::{
}; };
use clap::Args; use clap::Args;
use nym_bin_common::output_format::OutputFormat; use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig; use nym_config::NymConfig;
use nym_client_core::init::GatewaySetup;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::net::IpAddr; use std::net::IpAddr;
use std::{fs, io};
use tap::TapFallible; use tap::TapFallible;
#[derive(Args, Clone)] #[derive(Args, Clone)]
@@ -103,15 +97,15 @@ impl From<Init> for OverrideConfig {
pub struct InitResults { pub struct InitResults {
#[serde(flatten)] #[serde(flatten)]
client_core: nym_client_core::init::InitResults, client_core: nym_client_core::init::InitResults,
client_listening_port: u16, client_listening_port: String,
client_address: String, client_address: String,
} }
impl InitResults { impl InitResults {
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self { fn new(config: &Config, address: &Recipient) -> Self {
Self { Self {
client_core: nym_client_core::init::InitResults::new(&config.base, address, gateway), client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
client_listening_port: config.socket.listening_port, client_listening_port: config.get_listening_port().to_string(),
client_address: address.to_string(), client_address: address.to_string(),
} }
} }
@@ -125,26 +119,18 @@ impl Display for InitResults {
} }
} }
fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
eprintln!("Initialising client..."); eprintln!("Initialising client...");
let id = &args.id; let id = &args.id;
let already_init = if default_config_filepath(id).exists() { let already_init = Config::default_config_file_path(id).exists();
if already_init {
// in case we're using old config, try to upgrade it // in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op) // (if we're using the current version, it's a no-op)
try_upgrade_config(id)?; try_upgrade_v1_1_13_config(id)?;
eprintln!("Client \"{id}\" was already initialised before"); eprintln!("Client \"{id}\" was already initialised before");
true }
} else {
init_paths(id)?;
false
};
// Usually you only register with the gateway on the first init, however you can force // Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted. // re-registering if wanted.
@@ -160,44 +146,48 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
// Attempt to use a user-provided gateway, if possible // Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway; let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
);
// Load and potentially override config // Load and potentially override config
let config = override_config(Config::new(id), OverrideConfig::from(args.clone())); let mut config = override_config(Config::new(id), OverrideConfig::from(args.clone()));
// Setup gateway by either registering a new one, or creating a new config from the selected // Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration. // one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); let key_store = OnDiskKeys::from_config(config.get_base());
let details_store = let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let init_details = nym_client_core::init::setup_gateway(
&gateway_setup,
&key_store, &key_store,
&details_store,
register_gateway, register_gateway,
Some(&config.base.client.nym_api_urls), user_chosen_gateway_id,
config.get_base(),
args.latency_based_selection,
) )
.await .await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?; .tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
let config_save_location = config.default_location(); config.get_base_mut().set_gateway_endpoint(gateway);
config.save_to_default_location().tap_err(|_| {
config.save_to_file(None).tap_err(|_| {
log::error!("Failed to save the config file"); log::error!("Failed to save the config file");
})?; })?;
eprintln!(
"Saved configuration file to {}",
config_save_location.display()
);
let address = init_details.client_address()?; print_saved_config(&config);
eprintln!("Client configuration completed.\n"); let address =
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
let init_results = InitResults::new(&config, &address, &init_details.gateway_details); let init_results = InitResults::new(&config, &address);
println!("{}", args.output.format(&init_results)); println!("{}", args.output.format(&init_results));
Ok(()) Ok(())
} }
fn print_saved_config(config: &Config) {
let config_save_location = config.get_config_file_save_location();
eprintln!("Saved configuration file to {config_save_location:?}");
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
log::debug!(
"Gateway listener: {}",
config.get_base().get_gateway_listener()
);
eprintln!("Client configuration completed.\n");
}
+24 -149
View File
@@ -2,32 +2,24 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
use crate::client::config::old_config_v1_1_20::ConfigV1_1_20; use crate::client::config::{BaseConfig, Config};
use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
use crate::client::config::{BaseClientConfig, Config};
use crate::error::ClientError;
use clap::CommandFactory; use clap::CommandFactory;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{error, info}; use log::info;
use nym_bin_common::bin_info; use nym_bin_common::build_information::BinaryBuildInformation;
use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::client::base_client::storage::gateway_details::{ use nym_config::{NymConfig, OptionalSet};
OnDiskGatewayDetails, PersistedGatewayDetails,
};
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet;
use std::error::Error; use std::error::Error;
use std::net::IpAddr; use std::net::IpAddr;
pub(crate) mod build_info;
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade;
lazy_static! { lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print(); pub static ref PRETTY_BUILD_INFORMATION: String =
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
} }
// Helper for passing LONG_VERSION to clap // Helper for passing LONG_VERSION to clap
@@ -42,10 +34,6 @@ pub(crate) struct Cli {
#[clap(short, long)] #[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>, pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[clap(long)]
pub(crate) no_banner: bool,
#[clap(subcommand)] #[clap(subcommand)]
command: Commands, command: Commands,
} }
@@ -54,12 +42,10 @@ pub(crate) struct Cli {
pub(crate) enum Commands { pub(crate) enum Commands {
/// Initialise a Nym client. Do this first! /// Initialise a Nym client. Do this first!
Init(init::Init), Init(init::Init),
/// Run the Nym client with provided configuration client optionally overriding set parameters /// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run), Run(run::Run),
/// Try to upgrade the client
/// Show build information of this binary Upgrade(upgrade::Upgrade),
BuildInfo(build_info::BuildInfo),
/// Generate shell completions /// Generate shell completions
Completions(ArgShell), Completions(ArgShell),
@@ -80,13 +66,13 @@ pub(crate) struct OverrideConfig {
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
let bin_name = "nym-native-client"; let bin_name = "nym-native-client";
match args.command { match &args.command {
Commands::Init(m) => init::execute(&m).await?, Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?, Commands::Run(m) => run::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m), Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
} }
@@ -96,151 +82,40 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
config config
.with_optional(Config::with_disabled_socket, args.disable_socket) .with_optional(Config::with_disabled_socket, args.disable_socket)
.with_base( .with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
BaseClientConfig::with_high_default_traffic_volume, .with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
args.fastmode,
)
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional(Config::with_host, args.host) .with_optional(Config::with_host, args.host)
.with_optional_custom_env_ext( .with_optional_custom_env_ext(
BaseClientConfig::with_custom_nym_apis, BaseConfig::with_custom_nym_apis,
args.nym_apis, args.nym_apis,
nym_network_defaults::var_names::NYM_API, nym_network_defaults::var_names::NYM_API,
nym_config::parse_urls, nym_config::parse_urls,
) )
.with_optional_custom_env_ext( .with_optional_custom_env_ext(
BaseClientConfig::with_custom_nyxd, BaseConfig::with_custom_nyxd,
args.nyxd_urls, args.nyxd_urls,
nym_network_defaults::var_names::NYXD, nym_network_defaults::var_names::NYXD,
nym_config::parse_urls, nym_config::parse_urls,
) )
.with_optional_ext( .with_optional_ext(
BaseClientConfig::with_disabled_credentials, BaseConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b), args.enabled_credentials_mode.map(|b| !b),
) )
} }
fn persist_gateway_details( fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
config: &Config, // explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
details: GatewayEndpointConfig,
) -> Result<(), ClientError> {
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
ClientError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source),
})
})?;
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
details_store
.store_to_disk(&persisted_details)
.map_err(|source| {
ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError {
source: Box::new(source),
})
})
}
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, ClientError> {
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else { let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade // if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day // or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false); return Ok(());
}; };
info!("It seems the client is using <= v1.1.13 config template."); info!("It seems the client is using <= v1.1.13 config template.");
info!("It is going to get updated to the current specification."); info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20 = old_config.into(); let updated: Config = old_config.into();
let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); updated.save_to_file(None)
let (updated, gateway_config) = updated_step2.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, ClientError> {
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20 config template.");
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20_2 = old_config.into();
let (updated, gateway_config) = updated_step1.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, ClientError> {
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification.");
let (updated, gateway_config) = old_config.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_config(id: &str) -> Result<(), ClientError> {
if try_upgrade_v1_1_13_config(id)? {
return Ok(());
}
if try_upgrade_v1_1_20_config(id)? {
return Ok(());
}
if try_upgrade_v1_1_20_2_config(id)? {
return Ok(());
}
Ok(())
}
fn try_load_current_config(id: &str) -> Result<Config, ClientError> {
// try to load the config as is
if let Ok(cfg) = Config::read_from_default_path(id) {
return if !cfg.validate() {
Err(ClientError::ConfigValidationFailure)
} else {
Ok(cfg)
};
}
// we couldn't load it - try upgrading it from older revisions
try_upgrade_config(id)?;
let config = match Config::read_from_default_path(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
return Err(ClientError::FailedToLoadConfig(id.to_string()));
}
};
if !config.validate() {
return Err(ClientError::ConfigValidationFailure);
}
Ok(config)
} }
#[cfg(test)] #[cfg(test)]
+29 -7
View File
@@ -1,7 +1,10 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config; use std::error::Error;
use std::net::IpAddr;
use crate::commands::try_upgrade_v1_1_13_config;
use crate::{ use crate::{
client::{config::Config, SocketClient}, client::{config::Config, SocketClient},
commands::{override_config, OverrideConfig}, commands::{override_config, OverrideConfig},
@@ -10,9 +13,8 @@ use crate::{
use clap::Args; use clap::Args;
use log::*; use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible; use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_config::NymConfig;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use std::error::Error;
use std::net::IpAddr;
#[derive(Args, Clone)] #[derive(Args, Clone)]
pub(crate) struct Run { pub(crate) struct Run {
@@ -80,7 +82,7 @@ impl From<Run> for OverrideConfig {
// network version. It might do so in the future. // network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool { fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION"); let binary_version = env!("CARGO_PKG_VERSION");
let config_version = &cfg.base.client.version; let config_version = cfg.get_base().get_version();
if binary_version == config_version { if binary_version == config_version {
true true
} else { } else {
@@ -96,10 +98,30 @@ fn version_check(cfg: &Config) -> bool {
} }
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
eprintln!("Starting client {}...", args.id); let id = &args.id;
let mut config = try_load_current_config(&args.id)?; // in case we're using old config, try to upgrade it
config = override_config(config, OverrideConfig::from(args.clone())); // (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
return Err(Box::new(ClientError::FailedToLoadConfig(id.to_string())));
}
};
if !config.validate() {
return Err(Box::new(ClientError::ConfigValidationFailure));
}
let override_config_fields = OverrideConfig::from(args.clone());
config = override_config(config, override_config_fields);
if config.get_base_mut().set_empty_fields_to_defaults() {
warn!("some of the core config options were left unset. the default values are going to get used instead.");
}
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
+146
View File
@@ -0,0 +1,146 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::{Config, MISSING_VALUE};
use nym_bin_common::version_checker::Version;
use nym_config::NymConfig;
use clap::Args;
use std::fmt::Display;
use std::process;
#[allow(dead_code)]
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
print_failed_upgrade(from_version, to_version);
process::exit(1)
}
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!("\n==================\nTrying to upgrade client from {from} to {to} ...");
}
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!("Upgrade from {from} to {to} failed!\n==================\n");
}
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!("Upgrade from {from} to {to} was successful!\n==================\n");
}
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!(
"Cannot perform upgrade from {config_version} to {package_version}. Your version is too old to perform the upgrade.!"
);
process::exit(1)
}
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {config_version} to {current_version}. Please let the developers know about this issue if you expected it to work!");
process::exit(1)
}
#[derive(Args, Clone)]
pub(crate) struct Upgrade {
/// Id of the nym-client we want to upgrade
#[clap(long)]
id: String,
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {version}. This is not supported!"
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
process::exit(1)
}
version
}
fn minor_0_12_upgrade(
mut config: Config,
_matches: &Upgrade,
config_version: &Version,
package_version: &Version,
) -> Config {
let to_version = if package_version.major == 0 && package_version.minor == 12 {
package_version.clone()
} else {
Version::new(0, 12, 0)
};
print_start_upgrade(config_version, &to_version);
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
print_successful_upgrade(config_version, to_version);
config
}
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
loop {
let config_version = parse_config_version(&config);
if &config_version == package_version {
println!("You're using the most recent version!");
return;
}
config = match config_version.major {
0 => match config_version.minor {
9 | 10 => outdated_upgrade(&config_version, package_version),
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
_ => unsupported_upgrade(&config_version, package_version),
},
_ => unsupported_upgrade(&config_version, package_version),
}
}
}
pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let id = &args.id;
let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.get_base().get_version() == MISSING_VALUE {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
// here be upgrade path to 0.9.X and beyond based on version number from config
do_upgrade(existing_config, args, &package_version)
}
+4 -7
View File
@@ -14,13 +14,10 @@ pub mod websocket;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse(); let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref()); setup_env(args.config_env_file.as_ref());
commands::execute(&args).await
if !args.no_banner {
maybe_print_banner(crate_name!(), crate_version!());
}
setup_logging();
commands::execute(args).await
} }
+5 -6
View File
@@ -117,11 +117,10 @@ impl Handler {
let Ok(base_length) = self let Ok(base_length) = self
.lane_queue_lengths .lane_queue_lengths
.lock() .lock()
.map(|guard| guard.get(&conn_lane).unwrap_or_default()) .map(|guard| guard.get(&conn_lane).unwrap_or_default()) else {
else {
// I'd argue we should panic here as this error it not recoverable // I'd argue we should panic here as this error it not recoverable
error!("The lane queue length lock is poisoned!!"); error!("The lane queue length lock is poisoned!!");
return None; return None
}; };
// get the number of pending replies waiting for reply surbs // get the number of pending replies waiting for reply surbs
@@ -175,7 +174,7 @@ impl Handler {
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
return None; return None
}; };
self.get_lane_queue_length(connection_id).await self.get_lane_queue_length(connection_id).await
@@ -207,7 +206,7 @@ impl Handler {
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
return None; return None
}; };
self.get_lane_queue_length(connection_id).await self.get_lane_queue_length(connection_id).await
@@ -234,7 +233,7 @@ impl Handler {
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
return None; return None
}; };
self.get_lane_queue_length(connection_id).await self.get_lane_queue_length(connection_id).await
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// all variable size data is always prefixed with u64 length // all variable size data is always prefixed with u64 length
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// all variable size data is always prefixed with u64 length // all variable size data is always prefixed with u64 length
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::error::ErrorKind; use crate::error::ErrorKind;
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.24" version = "1.1.19"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] 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" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
+37 -50
View File
@@ -1,25 +1,20 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::commands::try_upgrade_config; use crate::commands::try_upgrade_v1_1_13_config;
use crate::config::{
default_config_directory, default_config_filepath, default_data_directory, Config,
};
use crate::{ use crate::{
commands::{override_config, OverrideConfig}, commands::{override_config, OverrideConfig},
error::Socks5ClientError, error::Socks5ClientError,
}; };
use clap::Args; use clap::Args;
use nym_bin_common::output_format::OutputFormat; use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig; use nym_config::NymConfig;
use nym_client_core::init::GatewaySetup;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::config::Config;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::{fs, io};
use tap::TapFallible; use tap::TapFallible;
#[derive(Args, Clone)] #[derive(Args, Clone)]
@@ -94,8 +89,6 @@ impl From<Init> for OverrideConfig {
use_anonymous_replies: init_config.use_reply_surbs, use_anonymous_replies: init_config.use_reply_surbs,
fastmode: init_config.fastmode, fastmode: init_config.fastmode,
no_cover: init_config.no_cover, no_cover: init_config.no_cover,
geo_routing: None,
medium_toggle: false,
nyxd_urls: init_config.nyxd_urls, nyxd_urls: init_config.nyxd_urls,
enabled_credentials_mode: init_config.enabled_credentials_mode, enabled_credentials_mode: init_config.enabled_credentials_mode,
outfox: false, outfox: false,
@@ -107,19 +100,15 @@ impl From<Init> for OverrideConfig {
pub struct InitResults { pub struct InitResults {
#[serde(flatten)] #[serde(flatten)]
client_core: nym_client_core::init::InitResults, client_core: nym_client_core::init::InitResults,
socks5_listening_port: u16, socks5_listening_port: String,
client_address: String, client_address: String,
} }
impl InitResults { impl InitResults {
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self { fn new(config: &Config, address: &Recipient) -> Self {
Self { Self {
client_core: nym_client_core::init::InitResults::new( client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
&config.core.base, socks5_listening_port: config.get_socks5().get_listening_port().to_string(),
address,
gateway,
),
socks5_listening_port: config.core.socks5.listening_port,
client_address: address.to_string(), client_address: address.to_string(),
} }
} }
@@ -133,27 +122,19 @@ impl Display for InitResults {
} }
} }
fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
eprintln!("Initialising client..."); eprintln!("Initialising client...");
let id = &args.id; let id = &args.id;
let provider_address = &args.provider; let provider_address = &args.provider;
let already_init = if default_config_filepath(id).exists() { let already_init = Config::default_config_file_path(id).exists();
if already_init {
// in case we're using old config, try to upgrade it // in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op) // (if we're using the current version, it's a no-op)
try_upgrade_config(id)?; try_upgrade_v1_1_13_config(id)?;
eprintln!("SOCKS5 client \"{id}\" was already initialised before"); eprintln!("SOCKS5 client \"{id}\" was already initialised before");
true }
} else {
init_paths(id)?;
false
};
// Usually you only register with the gateway on the first init, however you can force // Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted. // re-registering if wanted.
@@ -169,47 +150,53 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
// Attempt to use a user-provided gateway, if possible // Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway; let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
);
// Load and potentially override config // Load and potentially override config
let config = override_config( let mut config = override_config(
Config::new(id, &provider_address.to_string()), Config::new(id, &provider_address.to_string()),
OverrideConfig::from(args.clone()), OverrideConfig::from(args.clone()),
); );
// Setup gateway by either registering a new one, or creating a new config from the selected // Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration. // one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); let key_store = OnDiskKeys::from_config(config.get_base());
let details_store = let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let init_details = nym_client_core::init::setup_gateway(
&gateway_setup,
&key_store, &key_store,
&details_store,
register_gateway, register_gateway,
Some(&config.core.base.client.nym_api_urls), user_chosen_gateway_id,
config.get_base(),
args.latency_based_selection,
) )
.await .await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?; .tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
config.get_base_mut().set_gateway_endpoint(gateway);
// TODO: ask the service provider we specified for its interface version and set it in the config // TODO: ask the service provider we specified for its interface version and set it in the config
let config_save_location = config.default_location(); config.save_to_file(None).tap_err(|_| {
config.save_to_default_location().tap_err(|_| {
log::error!("Failed to save the config file"); log::error!("Failed to save the config file");
})?; })?;
eprintln!(
"Saved configuration file to {}",
config_save_location.display()
);
let address = init_details.client_address()?; print_saved_config(&config);
let init_results = InitResults::new(&config, &address, &init_details.gateway_details); let address =
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
let init_results = InitResults::new(&config, &address);
println!("{}", args.output.format(&init_results)); println!("{}", args.output.format(&init_results));
Ok(()) Ok(())
} }
fn print_saved_config(config: &Config) {
let config_save_location = config.get_config_file_save_location();
eprintln!("Saved configuration file to {:?}", config_save_location);
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
log::debug!(
"Gateway listener: {}",
config.get_base().get_gateway_listener()
);
eprintln!("Client configuration completed.\n");
}
+30 -182
View File
@@ -1,34 +1,25 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::config::old_config_v1_1_13::OldConfigV1_1_13;
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
use crate::config::{BaseClientConfig, Config};
use crate::error::Socks5ClientError;
use clap::CommandFactory; use clap::CommandFactory;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{error, info}; use log::info;
use nym_bin_common::bin_info; use nym_bin_common::build_information::BinaryBuildInformation;
use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::client::base_client::storage::gateway_details::{ use nym_config::{NymConfig, OptionalSet};
OnDiskGatewayDetails, PersistedGatewayDetails, use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
}; use nym_socks5_client_core::config::{BaseConfig, Config};
use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_sphinx::params::PacketType;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{GatewayEndpointConfig, TopologyStructure};
use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType};
use std::error::Error; use std::error::Error;
pub(crate) mod build_info;
pub mod init; pub mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade;
lazy_static! { lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print(); pub static ref PRETTY_BUILD_INFORMATION: String =
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
} }
// Helper for passing LONG_VERSION to clap // Helper for passing LONG_VERSION to clap
@@ -43,10 +34,6 @@ pub(crate) struct Cli {
#[clap(short, long)] #[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>, pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[clap(long)]
pub(crate) no_banner: bool,
#[clap(subcommand)] #[clap(subcommand)]
command: Commands, command: Commands,
} }
@@ -59,8 +46,8 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters /// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run), Run(run::Run),
/// Show build information of this binary /// Try to upgrade the client
BuildInfo(build_info::BuildInfo), Upgrade(upgrade::Upgrade),
/// Generate shell completions /// Generate shell completions
Completions(ArgShell), Completions(ArgShell),
@@ -76,20 +63,18 @@ pub(crate) struct OverrideConfig {
use_anonymous_replies: Option<bool>, use_anonymous_replies: Option<bool>,
fastmode: bool, fastmode: bool,
no_cover: bool, no_cover: bool,
geo_routing: Option<CountryGroup>,
medium_toggle: bool,
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
outfox: bool, outfox: bool,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
let bin_name = "nym-socks5-client"; let bin_name = "nym-socks5-client";
match args.command { match &args.command {
Commands::Init(m) => init::execute(&m).await?, Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?, Commands::Run(m) => run::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m), Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
} }
@@ -97,184 +82,47 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
} }
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
let disable_cover_traffic_with_keepalive = args.medium_toggle;
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 || args.geo_routing.is_some() {
// TODO: rethink the default group. I just picked one for now.
TopologyStructure::GeoAware(args.geo_routing.unwrap_or(CountryGroup::Europe))
} else {
TopologyStructure::default()
};
let packet_type = if args.outfox { let packet_type = if args.outfox {
PacketType::Outfox PacketType::Outfox
} else { } else {
PacketType::Mix PacketType::Mix
}; };
config config
.with_base( .with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
BaseClientConfig::with_high_default_traffic_volume, .with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
args.fastmode, .with_base(BaseConfig::with_packet_type, packet_type)
)
.with_base(
// NOTE: This interacts with disabling cover traffic fully, so we want to this to be set before
BaseClientConfig::with_disabled_cover_traffic_with_keepalive,
disable_cover_traffic_with_keepalive,
)
.with_base(
BaseClientConfig::with_secondary_packet_size,
secondary_packet_size,
)
.with_base(BaseClientConfig::with_no_per_hop_delays, no_per_hop_delays)
// 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_optional(Config::with_anonymous_replies, args.use_anonymous_replies) .with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional_base_custom_env( .with_optional_custom_env_ext(
BaseClientConfig::with_custom_nym_apis, BaseConfig::with_custom_nym_apis,
args.nym_apis, args.nym_apis,
nym_network_defaults::var_names::NYM_API, nym_network_defaults::var_names::NYM_API,
nym_config::parse_urls, nym_config::parse_urls,
) )
.with_optional_base_custom_env( .with_optional_custom_env_ext(
BaseClientConfig::with_custom_nyxd, BaseConfig::with_custom_nyxd,
args.nyxd_urls, args.nyxd_urls,
nym_network_defaults::var_names::NYXD, nym_network_defaults::var_names::NYXD,
nym_config::parse_urls, nym_config::parse_urls,
) )
.with_optional_base( .with_optional_ext(
BaseClientConfig::with_disabled_credentials, BaseConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b), args.enabled_credentials_mode.map(|b| !b),
) )
} }
fn persist_gateway_details( fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
config: &Config, // explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
details: GatewayEndpointConfig,
) -> Result<(), Socks5ClientError> {
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source),
})
})?;
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
details_store
.store_to_disk(&persisted_details)
.map_err(|source| {
Socks5ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError {
source: Box::new(source),
})
})
}
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> {
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else { let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade // if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day // or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false); return Ok(());
}; };
info!("It seems the client is using <= v1.1.13 config template."); info!("It seems the client is using <= v1.1.13 config template.");
info!("It is going to get updated to the current specification."); info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20 = old_config.into(); let updated: Config = old_config.into();
let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); updated.save_to_file(None)
let (updated, gateway_config) = updated_step2.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, Socks5ClientError> {
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20 config template.");
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20_2 = old_config.into();
let (updated, gateway_config) = updated_step1.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, Socks5ClientError> {
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification.");
let (updated, gateway_config) = old_config.upgrade();
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> {
if try_upgrade_v1_1_13_config(id)? {
return Ok(());
}
if try_upgrade_v1_1_20_config(id)? {
return Ok(());
}
if try_upgrade_v1_1_20_2_config(id)? {
return Ok(());
}
Ok(())
}
fn try_load_current_config(id: &str) -> Result<Config, Socks5ClientError> {
// try to load the config as is
if let Ok(cfg) = Config::read_from_default_path(id) {
return if !cfg.validate() {
Err(Socks5ClientError::ConfigValidationFailure)
} else {
Ok(cfg)
};
}
// we couldn't load it - try upgrading it from older revisions
try_upgrade_config(id)?;
let config = match Config::read_from_default_path(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
return Err(Socks5ClientError::FailedToLoadConfig(id.to_string()));
}
};
if !config.validate() {
return Err(Socks5ClientError::ConfigValidationFailure);
}
Ok(config)
} }
#[cfg(test)] #[cfg(test)]
+38 -32
View File
@@ -1,8 +1,7 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config; use crate::commands::try_upgrade_v1_1_13_config;
use crate::config::Config;
use crate::{ use crate::{
commands::{override_config, OverrideConfig}, commands::{override_config, OverrideConfig},
error::Socks5ClientError, error::Socks5ClientError,
@@ -11,9 +10,9 @@ use clap::Args;
use log::*; use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible; use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_config::NymConfig;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::NymClient; use nym_socks5_client_core::{config::Config, NymClient};
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
#[derive(Args, Clone)] #[derive(Args, Clone)]
@@ -22,6 +21,10 @@ pub(crate) struct Run {
#[clap(long)] #[clap(long)]
id: String, id: String,
/// Custom path to the nym-mixnet-client configuration file
#[clap(long)]
config: Option<String>,
/// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. /// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
/// While this is going to hide its actual address information, it will make the actual communication /// While this is going to hide its actual address information, it will make the actual communication
/// slower and consume nearly double the bandwidth as it will require sending reply SURBs. /// slower and consume nearly double the bandwidth as it will require sending reply SURBs.
@@ -61,15 +64,6 @@ pub(crate) struct Run {
#[clap(long, hide = true)] #[clap(long, hide = true)]
no_cover: bool, no_cover: bool,
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
#[clap(long, hide = true, value_parser = validate_country_group)]
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)]
medium_toggle: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway /// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement. /// with bandwidth credential requirement.
#[clap(long, hide = true)] #[clap(long, hide = true)]
@@ -87,8 +81,6 @@ impl From<Run> for OverrideConfig {
use_anonymous_replies: run_config.use_anonymous_replies, use_anonymous_replies: run_config.use_anonymous_replies,
fastmode: run_config.fastmode, fastmode: run_config.fastmode,
no_cover: run_config.no_cover, no_cover: run_config.no_cover,
geo_routing: run_config.geo_routing,
medium_toggle: run_config.medium_toggle,
nyxd_urls: run_config.nyxd_urls, nyxd_urls: run_config.nyxd_urls,
enabled_credentials_mode: run_config.enabled_credentials_mode, enabled_credentials_mode: run_config.enabled_credentials_mode,
outfox: run_config.outfox, outfox: run_config.outfox,
@@ -96,23 +88,17 @@ 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)),
}
}
// this only checks compatibility between config the binary. It does not take into consideration // this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future. // network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool { fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION"); let binary_version = env!("CARGO_PKG_VERSION");
let config_version = &cfg.core.base.client.version; let config_version = cfg.get_base().get_version();
if binary_version == config_version { if binary_version == config_version {
true true
} else { } else {
warn!( warn!(
"The socks5-client binary has different version than what is specified in config file! {binary_version} and {config_version}", "The mixnode binary has different version than what is specified in config file! {} and {}",
binary_version, config_version
); );
if is_minor_version_compatible(binary_version, config_version) { if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command"); info!("but they are still semver compatible. However, consider running the `upgrade` command");
@@ -125,18 +111,38 @@ fn version_check(cfg: &Config) -> bool {
} }
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.id); let id = &args.id;
let mut config = try_load_current_config(&args.id)?; // in case we're using old config, try to upgrade it
config = override_config(config, OverrideConfig::from(args.clone())); // (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
return Err(Box::new(Socks5ClientError::FailedToLoadConfig(
id.to_string(),
)));
}
};
if !config.validate() {
return Err(Box::new(Socks5ClientError::ConfigValidationFailure));
}
let override_config_fields = OverrideConfig::from(args.clone());
config = override_config(config, override_config_fields);
if config.get_base_mut().set_empty_fields_to_defaults() {
warn!("some of the core config options were left unset. the default values are going to get used instead.");
}
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck)); return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
} }
let storage = let storage = OnDiskPersistent::from_config(config.get_base()).await?;
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug) NymClient::new(config, storage).run_forever().await
.await?;
NymClient::new(config.core, storage).run_forever().await
} }
+158
View File
@@ -0,0 +1,158 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_bin_common::version_checker::Version;
use nym_config::NymConfig;
use nym_socks5_client_core::config::{Config, MISSING_VALUE};
use clap::Args;
use std::{fmt::Display, process};
#[allow(dead_code)]
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
print_failed_upgrade(from_version, to_version);
process::exit(1)
}
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!(
"\n==================\nTrying to upgrade client from {} to {} ...",
from, to
);
}
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!(
"Upgrade from {} to {} failed!\n==================\n",
from, to
);
}
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!(
"Upgrade from {} to {} was successful!\n==================\n",
from, to
);
}
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!(
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
config_version, package_version
);
process::exit(1)
}
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
process::exit(1)
}
#[derive(Args, Clone)]
pub(crate) struct Upgrade {
/// Id of the nym-client we want to upgrade
#[clap(long)]
id: String,
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {}. This is not supported!",
version
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade to a non-released version {}. This is not supported!",
version
);
process::exit(1)
}
version
}
fn minor_0_12_upgrade(
mut config: Config,
_args: &Upgrade,
config_version: &Version,
package_version: &Version,
) -> Config {
let to_version = if package_version.major == 0 && package_version.minor == 12 {
package_version.clone()
} else {
Version::new(0, 12, 0)
};
print_start_upgrade(config_version, &to_version);
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
print_successful_upgrade(config_version, to_version);
config
}
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
loop {
let config_version = parse_config_version(&config);
if &config_version == package_version {
println!("You're using the most recent version!");
return;
}
config = match config_version.major {
0 => match config_version.minor {
9 | 10 => outdated_upgrade(&config_version, package_version),
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
_ => unsupported_upgrade(&config_version, package_version),
},
_ => unsupported_upgrade(&config_version, package_version),
}
}
}
pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let id = &args.id;
let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.get_base().get_version() == MISSING_VALUE {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
// here be upgrade path to 0.9.X and beyond based on version number from config
do_upgrade(existing_config, args, &package_version)
}
-160
View File
@@ -1,160 +0,0 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::SocksClientPaths;
use crate::config::template::CONFIG_TEMPLATE;
use nym_bin_common::logging::LoggingSettings;
use nym_config::{
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::io;
use std::path::{Path, PathBuf};
use std::str::FromStr;
pub use nym_client_core::config::Config as BaseClientConfig;
pub use nym_socks5_client_core::config::Config as CoreConfig;
pub mod old_config_v1_1_13;
pub mod old_config_v1_1_20;
pub mod old_config_v1_1_20_2;
mod persistence;
mod template;
const DEFAULT_SOCKS5_CLIENTS_DIR: &str = "socks5-clients";
/// Derive default path to clients's config directory.
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/config`
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_SOCKS5_CLIENTS_DIR)
.join(id)
.join(DEFAULT_CONFIG_DIR)
}
/// Derive default path to client's config file.
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/config/config.toml`
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
}
/// Derive default path to client's data directory where files, such as keys, are stored.
/// It should get resolved to `$HOME/.nym/socks5-clients/<id>/data`
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_SOCKS5_CLIENTS_DIR)
.join(id)
.join(DEFAULT_DATA_DIR)
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub core: CoreConfig,
pub storage_paths: SocksClientPaths,
pub logging: LoggingSettings,
}
impl NymConfigTemplate for Config {
fn template() -> &'static str {
CONFIG_TEMPLATE
}
}
impl Config {
pub fn new<S: AsRef<str>>(id: S, provider_mix_address: S) -> Self {
Config {
core: CoreConfig::new(
id.as_ref(),
env!("CARGO_PKG_VERSION"),
provider_mix_address.as_ref(),
),
storage_paths: SocksClientPaths::new_default(default_data_directory(id.as_ref())),
logging: Default::default(),
}
}
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
pub fn default_location(&self) -> PathBuf {
default_config_filepath(&self.core.base.client.id)
}
pub fn save_to_default_location(&self) -> io::Result<()> {
let config_save_location: PathBuf = self.default_location();
save_formatted_config_to_file(self, config_save_location)
}
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.core.validate()
}
pub fn with_port(mut self, port: u16) -> Self {
self.core.socks5.listening_port = port;
self
}
pub fn with_anonymous_replies(mut self, anonymous_replies: bool) -> Self {
self.core.socks5.send_anonymously = anonymous_replies;
self
}
// poor man's 'builder' method
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
{
self.core = self.core.with_base(f, val);
self
}
pub fn with_optional_base<F, T>(mut self, f: F, val: Option<T>) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
{
self.core = self.core.with_optional_base(f, val);
self
}
#[allow(unused)]
pub fn with_optional_base_env<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
T: FromStr,
<T as FromStr>::Err: Debug,
{
self.core = self.core.with_optional_base_env(f, val, env_var);
self
}
pub fn with_optional_base_custom_env<F, T, G>(
mut self,
f: F,
val: Option<T>,
env_var: &str,
parser: G,
) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
G: Fn(&str) -> T,
{
self.core = self
.core
.with_optional_base_custom_env(f, val, env_var, parser);
self
}
}
@@ -1,38 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::old_config_v1_1_20::{ConfigV1_1_20, Socks5V1_1_20};
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
use nym_config::must_get_home;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldConfigV1_1_13 {
#[serde(flatten)]
pub base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
pub socks5: Socks5V1_1_20,
}
impl MigrationNymConfig for OldConfigV1_1_13 {
fn default_root_directory() -> PathBuf {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let base_dir = must_get_home();
#[cfg(any(target_os = "android", target_os = "ios"))]
let base_dir = PathBuf::from("/tmp");
base_dir.join(".nym").join("socks5-clients")
}
}
impl From<OldConfigV1_1_13> for ConfigV1_1_20 {
fn from(value: OldConfigV1_1_13) -> Self {
ConfigV1_1_20 {
base: value.base.into(),
socks5: value.socks5,
}
}
}
@@ -1,137 +0,0 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::old_config_v1_1_20_2::{
ConfigV1_1_20_2, CoreConfigV1_1_20_2, SocksClientPathsV1_1_20_2,
};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
use nym_client_core::config::old_config_v1_1_20_2::ClientV1_1_20_2;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
use nym_config::must_get_home;
use nym_socks5_client_core::config::old_config_v1_1_20_2::{
BaseClientConfigV1_1_20_2, Socks5DebugV1_1_20_2, Socks5V1_1_20_2,
};
use nym_socks5_client_core::config::{ProviderInterfaceVersion, Socks5ProtocolVersion};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::path::PathBuf;
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
const DEFAULT_PER_REQUEST_SURBS: u32 = 3;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1_1_20 {
#[serde(flatten)]
pub base: BaseConfigV1_1_20<ConfigV1_1_20>,
pub socks5: Socks5V1_1_20,
}
impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
fn from(value: ConfigV1_1_20) -> Self {
ConfigV1_1_20_2 {
core: CoreConfigV1_1_20_2 {
base: BaseClientConfigV1_1_20_2 {
client: ClientV1_1_20_2 {
version: value.base.client.version,
id: value.base.client.id,
disabled_credentials_mode: value.base.client.disabled_credentials_mode,
nyxd_urls: value.base.client.nyxd_urls,
nym_api_urls: value.base.client.nym_api_urls,
gateway_endpoint: value.base.client.gateway_endpoint.into(),
},
debug: value.base.debug.into(),
},
socks5: value.socks5.into(),
},
storage_paths: SocksClientPathsV1_1_20_2 {
common_paths: CommonClientPathsV1_1_20_2 {
keys: ClientKeysPaths {
private_identity_key_file: value.base.client.private_identity_key_file,
public_identity_key_file: value.base.client.public_identity_key_file,
private_encryption_key_file: value.base.client.private_encryption_key_file,
public_encryption_key_file: value.base.client.public_encryption_key_file,
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
ack_key_file: value.base.client.ack_key_file,
},
credentials_database: value.base.client.database_path,
reply_surb_database: value.base.client.reply_surb_database_path,
},
},
logging: LoggingSettings::default(),
}
}
}
impl MigrationNymConfig for ConfigV1_1_20 {
fn default_root_directory() -> PathBuf {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let base_dir = must_get_home();
#[cfg(any(target_os = "android", target_os = "ios"))]
let base_dir = PathBuf::from("/tmp");
base_dir.join(".nym").join("socks5-clients")
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Socks5V1_1_20 {
pub listening_port: u16,
pub provider_mix_address: String,
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
pub provider_interface_version: ProviderInterfaceVersion,
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
pub socks5_protocol_version: Socks5ProtocolVersion,
#[serde(default)]
pub send_anonymously: bool,
#[serde(default)]
pub socks5_debug: Socks5DebugV1_1_20,
}
impl From<Socks5V1_1_20> for Socks5V1_1_20_2 {
fn from(value: Socks5V1_1_20) -> Self {
Socks5V1_1_20_2 {
listening_port: value.listening_port,
provider_mix_address: value.provider_mix_address,
provider_interface_version: value.provider_interface_version,
socks5_protocol_version: value.socks5_protocol_version,
send_anonymously: value.send_anonymously,
socks5_debug: value.socks5_debug.into(),
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Socks5DebugV1_1_20 {
connection_start_surbs: u32,
per_request_surbs: u32,
}
impl From<Socks5DebugV1_1_20> for Socks5DebugV1_1_20_2 {
fn from(value: Socks5DebugV1_1_20) -> Self {
Socks5DebugV1_1_20_2 {
connection_start_surbs: value.connection_start_surbs,
per_request_surbs: value.per_request_surbs,
}
}
}
impl Default for Socks5DebugV1_1_20 {
fn default() -> Self {
Socks5DebugV1_1_20 {
connection_start_surbs: DEFAULT_CONNECTION_START_SURBS,
per_request_surbs: DEFAULT_PER_REQUEST_SURBS,
}
}
}
@@ -1,54 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::SocksClientPaths;
use crate::config::{default_config_filepath, Config};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::GatewayEndpointConfig;
use nym_config::read_config_from_toml_file;
pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2;
use serde::{Deserialize, Serialize};
use std::io;
use std::path::Path;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct SocksClientPathsV1_1_20_2 {
#[serde(flatten)]
pub common_paths: CommonClientPathsV1_1_20_2,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1_1_20_2 {
pub core: CoreConfigV1_1_20_2,
pub storage_paths: SocksClientPathsV1_1_20_2,
pub logging: LoggingSettings,
}
impl ConfigV1_1_20_2 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
// in this upgrade, gateway endpoint configuration was moved out of the config file,
// so its returned to be stored elsewhere.
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
let gateway_details = self.core.base.client.gateway_endpoint.clone().into();
let config = Config {
core: self.core.into(),
storage_paths: SocksClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default(),
},
logging: self.logging,
};
(config, gateway_details)
}
}
-20
View File
@@ -1,20 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_client_core::config::disk_persistence::CommonClientPaths;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct SocksClientPaths {
#[serde(flatten)]
pub common_paths: CommonClientPaths,
}
impl SocksClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
SocksClientPaths {
common_paths: CommonClientPaths::new_default(base_data_directory),
}
}
}
-114
View File
@@ -1,114 +0,0 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields.
// Note: any changes to the template must be reflected in the appropriate structs.
pub(crate) const CONFIG_TEMPLATE: &str = r#"
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base client config options #####
[core.client]
# Version of the client for which this configuration was created.
version = '{{ core.client.version }}'
# Human readable ID of this particular client.
id = '{{ core.client.id }}'
# Indicates whether this client is running in a disabled credentials mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
disabled_credentials_mode = {{ core.client.disabled_credentials_mode }}
# Addresses to nyxd validators via which the client can communicate with the chain.
nyxd_urls = [
{{#each core.client.nyxd_urls }}
'{{this}}',
{{/each}}
]
# Addresses to APIs running on validator from which the client gets the view of the network.
nym_api_urls = [
{{#each core.client.nym_api_urls }}
'{{this}}',
{{/each}}
]
[storage_paths]
# Path to file containing private identity key.
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
# Path to file containing public identity key.
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
# Path to file containing private encryption key.
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
# Path to file containing public encryption key.
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
# A gateway specific, optional, base58 stringified shared key used for
# communication with particular gateway.
keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}'
# Path to file containing key used for encrypting and decrypting the content of an
# acknowledgement so that nobody besides the client knows which packet it refers to.
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
# Path to the database containing bandwidth credentials
credentials_database = '{{ storage_paths.credentials_database }}'
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
# Path to the file containing information about gateway used by this client,
# i.e. details such as its public key, owner address or the network information.
gateway_details = '{{ storage_paths.gateway_details }}'
##### socket config options #####
[core.socks5]
# The mix address of the provider to which all requests are going to be sent.
provider_mix_address = '{{ core.socks5.provider_mix_address }}'
# The port on which the client will be listening for incoming requests
listening_port = {{ core.socks5.listening_port }}
# Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
# While this is going to hide its actual address information, it will make the actual communication
# slower and consume nearly double the bandwidth as it will require sending reply SURBs.
#
# Note that some service providers might not support this.
send_anonymously = {{ core.socks5.send_anonymously }}
##### logging configuration options #####
[logging]
# TODO
##### debug configuration options #####
# The following options should not be modified unless you know EXACTLY what you are doing
# as if set incorrectly, they may impact your anonymity.
# [core.socks5.socks5_debug]
[core.debug]
[core.debug.traffic]
average_packet_delay = '{{ core.debug.traffic.average_packet_delay }}'
message_sending_average_delay = '{{ core.debug.traffic.message_sending_average_delay }}'
[core.debug.acknowledgements]
average_ack_delay = '{{ core.debug.acknowledgements.average_ack_delay }}'
[core.debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ core.debug.cover_traffic.loop_cover_traffic_average_delay }}'
"#;
+4 -8
View File
@@ -8,18 +8,14 @@ use nym_bin_common::logging::{maybe_print_banner, setup_logging};
use nym_network_defaults::setup_env; use nym_network_defaults::setup_env;
mod commands; mod commands;
mod config;
pub mod error; pub mod error;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse(); let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref()); setup_env(args.config_env_file.as_ref());
commands::execute(&args).await
if !args.no_banner {
maybe_print_banner(crate_name!(), crate_version!());
}
setup_logging();
commands::execute(args).await
} }
+1 -1
View File
@@ -1 +1 @@
18 16
+18 -19
View File
@@ -3,11 +3,11 @@
"version": "0.19.0", "version": "0.19.0",
"description": "A TypeScript client for interacting with smart contracts in Nym validators", "description": "A TypeScript client for interacting with smart contracts in Nym validators",
"repository": "https://github.com/nymtech/nym", "repository": "https://github.com/nymtech/nym",
"main": "dist/index.js", "main": "./dist/index.js",
"types": "dist/index.d.ts", "types": "./dist/index.d.ts",
"scripts": { "scripts": {
"build": "rollup -c ./rollup.config.mjs", "build": "rollup -c ./rollup.config.mjs",
"build:types": "rollup-type-bundler --dist ./dist", "build:types": "rollup-type-bundler --dist ./dist/nym-validator-client",
"build:prod": "sh ./scripts/build-prod.sh", "build:prod": "sh ./scripts/build-prod.sh",
"test": "ts-mocha -p ./tsconfig.test.json ./src/tests/**/*.test.ts", "test": "ts-mocha -p ./tsconfig.test.json ./src/tests/**/*.test.ts",
"testmock": "ts-mocha -p ./tsconfig.test.json ./src/tests/mock/*.test.ts", "testmock": "ts-mocha -p ./tsconfig.test.json ./src/tests/mock/*.test.ts",
@@ -29,23 +29,16 @@
], ],
"license": "Apache-2.0", "license": "Apache-2.0",
"devDependencies": { "devDependencies": {
"@cosmjs/cosmwasm-stargate": "^0.29.5",
"@cosmjs/crypto": "^0.29.5",
"@cosmjs/math": "^0.29.5",
"@cosmjs/proto-signing": "^0.29.5",
"@cosmjs/stargate": "^0.29.5",
"@cosmjs/tendermint-rpc": "^0.29.5",
"@favware/rollup-type-bundler": "^2.0.0", "@favware/rollup-type-bundler": "^2.0.0",
"@nymproject/types": "^1.0.0", "@nymproject/types": "^1.0.0",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-json": "^6.0.0", "@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^11.0.0", "@rollup/plugin-typescript": "^11.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"rollup": "^3.17.2",
"rollup-plugin-dts": "^5.2.0",
"@typescript-eslint/eslint-plugin": "^5.7.0", "@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0", "@typescript-eslint/parser": "^5.7.0",
"axios": "^1.3.3",
"cosmjs-types": "^0.4.1",
"dotenv": "^16.0.3",
"eslint": "^7.18.0", "eslint": "^7.18.0",
"eslint-config-airbnb": "^19.0.2", "eslint-config-airbnb": "^19.0.2",
"eslint-config-airbnb-typescript": "^16.1.0", "eslint-config-airbnb-typescript": "^16.1.0",
@@ -54,15 +47,21 @@
"eslint-plugin-import": "^2.25.4", "eslint-plugin-import": "^2.25.4",
"eslint-plugin-mocha": "^10.0.3", "eslint-plugin-mocha": "^10.0.3",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"expect": "^28.1.3",
"mocha": "^10.0.0", "mocha": "^10.0.0",
"moq.ts": "^7.3.4",
"prettier": "^2.8.7", "prettier": "^2.8.7",
"rollup": "^3.17.2",
"rollup-plugin-dts": "^5.2.0",
"rollup-plugin-node-polyfills": "^0.2.1",
"ts-mocha": "^10.0.0", "ts-mocha": "^10.0.0",
"typedoc": "^0.22.13", "typedoc": "^0.22.13",
"typescript": "^4.6.2" "typescript": "^4.6.2",
"cosmjs-types": "^0.4.1",
"dotenv": "^16.0.3",
"expect": "^28.1.3",
"moq.ts": "^7.3.4",
"@cosmjs/cosmwasm-stargate": "^0.29.5",
"@cosmjs/crypto": "^0.29.5",
"@cosmjs/math": "^0.29.5",
"@cosmjs/proto-signing": "^0.29.5",
"@cosmjs/stargate": "^0.29.5",
"@cosmjs/tendermint-rpc": "^0.29.5",
"axios": "^1.3.3"
} }
} }
+4 -4
View File
@@ -1,15 +1,15 @@
import typescript from '@rollup/plugin-typescript'; import typescript from '@rollup/plugin-typescript';
import nodePolyfills from 'rollup-plugin-node-polyfills'; import resolve from '@rollup/plugin-node-resolve';
import json from '@rollup/plugin-json'; import json from '@rollup/plugin-json';
import commonjs from '@rollup/plugin-commonjs'; import commonjs from '@rollup/plugin-commonjs';
export default [ export default [
{ {
input: 'src/index.ts', input: './src/index.ts',
output: { output: {
dir: 'dist', dir: 'dist/nym-validator-client',
format: 'cjs', format: 'cjs',
}, },
plugins: [nodePolyfills(), typescript(), commonjs(), json()], plugins: [resolve(), typescript(), commonjs(), json()],
}, },
]; ];
+1 -1
View File
@@ -21,7 +21,7 @@ node ./scripts/buildPackageJson.mjs
# Copy README # Copy README
cp README.md dist/ cp README.md dist/nym-validator-client
# move the output outside of the yarn/npm workspaces # move the output outside of the yarn/npm workspaces
@@ -17,4 +17,4 @@ const packageJson = {
types, types,
}; };
fs.writeFileSync('./dist/package.json', JSON.stringify(packageJson, null, 2)); fs.writeFileSync('./dist/nym-validator-client/package.json', JSON.stringify(packageJson, null, 2));
+3 -12
View File
@@ -45,6 +45,7 @@ import {
} from '@nymproject/types'; } from '@nymproject/types';
import QueryClient from './query-client'; import QueryClient from './query-client';
import SigningClient, { ISigningClient } from './signing-client'; import SigningClient, { ISigningClient } from './signing-client';
// import { DelegationBlock } from './types/shared';
export interface INymClient { export interface INymClient {
readonly mixnetContract: string; readonly mixnetContract: string;
@@ -625,17 +626,7 @@ export default class ValidatorClient implements INymClient {
// SIMULATE // SIMULATE
public async simulateSend({ public async simulateSend(signingAddress: string, from: string, to: string, amount: Coin[]) {
signingAddress, return (this.client as SigningClient).simulateSend(signingAddress, from, to, amount);
from,
to,
amount,
}: {
signingAddress: string;
from: string;
to: string;
amount: Coin[];
}) {
return (this.client as ISigningClient).simulateSend(signingAddress, from, to, amount);
} }
} }
@@ -22,12 +22,9 @@ describe('Simualtions', () => {
}); });
it('can simulate sending tokens', async () => { it('can simulate sending tokens', async () => {
const res = await client.simulateSend({ const res = await client.simulateSend(client.address, client.address, client.address, [
signingAddress: client.address, { amount: '400000', denom: 'unym' },
from: client.address, ]);
to: client.address,
amount: [{ amount: '400000', denom: 'unym' }],
});
expect(typeof res).toBe('number'); expect(typeof res).toBe('number');
}).timeout(10000); }).timeout(10000);
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"outDir": "dist", "outDir": "./dist/nym-validator-client",
"module": "ES2020", "module": "ES2020",
"target": "es2021", "target": "es2021",
"allowJs": false, "allowJs": false,
+262 -623
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "nym-client-wasm" name = "nym-client-wasm"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.1.1" version = "1.1.0"
edition = "2021" edition = "2021"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"] keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
license = "Apache-2.0" license = "Apache-2.0"
@@ -33,7 +33,7 @@ wasm-bindgen-futures = "0.4"
thiserror = "1.0.40" thiserror = "1.0.40"
zeroize = "1.6.0" zeroize = "1.6.0"
wasmtimer = { version = "0.2.0", features = ["tokio"] } wasm-timer = { git = "https://github.com/mmsinclair/wasm-timer", rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"}
# internal # internal
nym-node-tester-utils = { path = "../../common/node-tester-utils" } nym-node-tester-utils = { path = "../../common/node-tester-utils" }
-3
View File
@@ -3,6 +3,3 @@ clippy:
test: test:
wasm-pack test --node wasm-pack test --node
wasm-build:
wasm-pack build
@@ -8,7 +8,6 @@
}, },
"scripts": { "scripts": {
"build": "webpack --config webpack.config.js", "build": "webpack --config webpack.config.js",
"build:wasm": "cd ../ && make wasm-build",
"start": "webpack-dev-server --port 8001" "start": "webpack-dev-server --port 8001"
}, },
"repository": { "repository": {
@@ -37,4 +36,4 @@
"dependencies": { "dependencies": {
"@nymproject/nym-client-wasm": "file:../pkg" "@nymproject/nym-client-wasm": "file:../pkg"
} }
} }
+264 -302
View File
@@ -12,371 +12,333 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
importScripts("nym_client_wasm.js"); importScripts('nym_client_wasm.js');
console.log("Initializing worker"); console.log('Initializing worker');
// wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts` // wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts`
const { const {
NymNodeTester, NymNodeTester,
WasmGateway, WasmGateway,
WasmMixNode, WasmMixNode,
WasmNymTopology, WasmNymTopology,
default_debug, default_debug,
NymClientBuilder, NymClientBuilder,
NymClient, NymClient,
set_panic_hook, set_panic_hook,
Config, Config,
GatewayEndpointConfig, GatewayEndpointConfig,
ClientStorage, ClientStorage,
current_network_topology, current_network_topology,
make_key, make_key,
make_key2, make_key2
} = wasm_bindgen; } = wasm_bindgen;
let client = null; let client = null;
let tester = null; let tester = null;
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
function dummyTopology() { function dummyTopology() {
const l1Mixnode = new WasmMixNode( const l1Mixnode = new WasmMixNode(
1, 1,
"n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47", 'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47',
"178.79.143.65", '178.79.143.65',
1789, 1789,
"4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz", '4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz',
"8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG", '8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG',
1, 1,
"1.10.0" '1.10.0',
); );
const l2Mixnode = new WasmMixNode( const l2Mixnode = new WasmMixNode(
2, 2,
"n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70", 'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70',
"109.74.197.180", '109.74.197.180',
1789, 1789,
"7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK", '7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK',
"GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN", 'GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN',
2, 2,
"1.10.0" '1.10.0',
); );
const l3Mixnode = new WasmMixNode( const l3Mixnode = new WasmMixNode(
3, 3,
"n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77", 'n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77',
"176.58.101.80", '176.58.101.80',
1789, 1789,
"FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R", 'FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R',
"DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD", 'DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD',
3, 3,
"1.10.0" '1.10.0',
); );
const gateway = new WasmGateway( const gateway = new WasmGateway(
"n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts", 'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts',
"85.159.212.96", '85.159.212.96',
1789, 1789,
9000, 9000,
"336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9", '336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
"BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL", 'BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL',
"1.10.1" '1.10.1',
); );
const mixnodes = new Map(); const mixnodes = new Map();
mixnodes.set(1, [l1Mixnode]); mixnodes.set(1, [l1Mixnode]);
mixnodes.set(2, [l2Mixnode]); mixnodes.set(2, [l2Mixnode]);
mixnodes.set(3, [l3Mixnode]); mixnodes.set(3, [l3Mixnode]);
const gateways = [gateway];
return new WasmNymTopology(mixnodes, gateways); const gateways = [gateway];
return new WasmNymTopology(mixnodes, gateways)
} }
function printAndDisplayTestResult(result) { function printAndDisplayTestResult(result) {
result.log_details(); result.log_details();
self.postMessage({ self.postMessage({
kind: "DisplayTesterResults", kind: 'DisplayTesterResults',
args: { args: {
score: result.score(), score: result.score(),
sentPackets: result.sent_packets, sentPackets: result.sent_packets,
receivedPackets: result.received_packets, receivedPackets: result.received_packets,
receivedAcks: result.received_acks, receivedAcks: result.received_acks,
duplicatePackets: result.duplicate_packets, duplicatePackets: result.duplicate_packets,
duplicateAcks: result.duplicate_acks, duplicateAcks: result.duplicate_acks,
}, },
}); });
} }
async function testWithTester() { async function testWithTester() {
// A) construct with hardcoded topology const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
const topology = dummyTopology();
const nodeTester = await new NymNodeTester(topology, preferredGateway);
// B) first get topology directly from nym-api // A) construct with hardcoded topology
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api'; const topology = dummyTopology()
// const topology = await current_network_topology(validator) const nodeTester = await new NymNodeTester(topology, dummyGateway);
// const nodeTester = await new NymNodeTester(topology, preferredGateway);
//
// C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers)
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
// const nodeTester = await NymNodeTester.new_with_api(validator, preferredGateway)
// B) first get topology directly from nym-api // B) first get topology directly from nym-api
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api'; // const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
// const topology = await current_network_topology(validator) // const topology = await current_network_topology(validator)
// const nodeTester = await new NymNodeTester(topology, undefined, preferredGateway); // const nodeTester = await new NymNodeTester(topology, dummyGateway);
// //
// C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers) // C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers)
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api'; // const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
// const nodeTester = await NymNodeTester.new_with_api(validator, undefined, preferredGateway) // const nodeTester = await NymNodeTester.new_with_api(validator, dummyGateway)
// D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
// const topology = dummyTopology()
// const nodeTester = await new NymNodeTester(topology);
self.onmessage = async (event) => { // D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
if (event.data && event.data.kind) { // const topology = dummyTopology()
switch (event.data.kind) { // const nodeTester = await new NymNodeTester(topology);
case "TestPacket": {
const { mixnodeIdentity } = event.data.args;
console.log("starting node test...");
let result = await nodeTester.test_node(mixnodeIdentity); self.onmessage = async event => {
printAndDisplayTestResult(result); if (event.data && event.data.kind) {
switch (event.data.kind) {
case 'TestPacket': {
const {mixnodeIdentity} = event.data.args;
console.log("starting node test...");
let result = await nodeTester.test_node(mixnodeIdentity);
printAndDisplayTestResult(result)
}
}
} }
} };
}
};
}
async function testerReconnection() {
const validator = "https://qwerty-validator-api.qa.nymte.ch/api";
const nodeTester = await NymNodeTester.new_with_api(validator);
self.onmessage = async (event) => {
if (event.data && event.data.kind) {
switch (event.data.kind) {
case "TestPacket": {
const { mixnodeIdentity } = event.data.args;
console.log("starting node test...");
let result1 = await nodeTester.test_node(mixnodeIdentity);
console.log("sleeping for 5s");
await new Promise((r) => setTimeout(r, 5000));
await nodeTester.disconnect_from_gateway();
console.log("sleeping for 5s");
await new Promise((r) => setTimeout(r, 5000));
await nodeTester.reconnect_to_gateway();
let result2 = await nodeTester.test_node(mixnodeIdentity);
printAndDisplayTestResult(result1);
printAndDisplayTestResult(result2);
}
}
}
};
} }
async function testWithNymClient() { async function testWithNymClient() {
const topology = dummyTopology(); const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
const topology = dummyTopology()
let received = 0; let received = 0
const onMessageHandler = (message) => { const onMessageHandler = (message) => {
received += 1; received += 1;
self.postMessage({
kind: 'ReceiveMessage',
args: {
message,
senderTag: undefined,
isTestPacket: true,
},
});
// it's really up to the user to create proper callback here...
console.log(`received ${received} packets so far`)
};
console.log('Instantiating WASM client...');
let clientBuilder = NymClientBuilder.new_tester(topology, onMessageHandler, dummyGateway)
console.log('Web worker creating WASM client...');
let local_client = await clientBuilder.start_client();
console.log('WASM client running!');
const selfAddress = local_client.self_address();
// set the global (I guess we don't have to anymore?)
client = local_client;
console.log(`Client address is ${selfAddress}`);
self.postMessage({ self.postMessage({
kind: "ReceiveMessage", kind: 'Ready',
args: { args: {
message, selfAddress,
senderTag: undefined, },
isTestPacket: true,
},
}); });
// it's really up to the user to create proper callback here... // Set callback to handle messages passed to the worker.
console.log(`received ${received} packets so far`); self.onmessage = async event => {
}; console.log(event)
if (event.data && event.data.kind) {
console.log("Instantiating WASM client..."); switch (event.data.kind) {
case 'SendMessage': {
let clientBuilder = NymClientBuilder.new_tester( const {message, recipient} = event.data.args;
topology, let uint8Array = new TextEncoder().encode(message);
onMessageHandler, await client.send_regular_message(uint8Array, recipient);
preferredGateway break;
); }
case 'TestPacket': {
console.log("Web worker creating WASM client..."); const {mixnodeIdentity} = event.data.args;
let local_client = await clientBuilder.start_client(); const req = await client.try_construct_test_packet_request(mixnodeIdentity);
console.log("WASM client running!"); await client.change_hardcoded_topology(req.injectable_topology());
await client.try_send_test_packets(req);
const selfAddress = local_client.self_address(); break;
}
// set the global (I guess we don't have to anymore?) }
client = local_client;
console.log(`Client address is ${selfAddress}`);
self.postMessage({
kind: "Ready",
args: {
selfAddress,
},
});
// Set callback to handle messages passed to the worker.
self.onmessage = async (event) => {
console.log(event);
if (event.data && event.data.kind) {
switch (event.data.kind) {
case "SendMessage": {
const { message, recipient } = event.data.args;
let uint8Array = new TextEncoder().encode(message);
await client.send_regular_message(uint8Array, recipient);
break;
} }
case "TestPacket": { };
const { mixnodeIdentity } = event.data.args;
const req = await client.try_construct_test_packet_request(
mixnodeIdentity
);
await client.change_hardcoded_topology(req.injectable_topology());
await client.try_send_test_packets(req);
break;
}
}
}
};
} }
async function normalNymClientUsage() { async function normalNymClientUsage() {
self.postMessage({ kind: "DisableMagicTestButton" }); self.postMessage({kind: 'DisableMagicTestButton'});
// only really useful if you want to adjust some settings like traffic rate // only really useful if you want to adjust some settings like traffic rate
// (if not needed you can just pass a null) // (if not needed you can just pass a null)
const debug = default_debug(); const debug = default_debug();
debug.disable_main_poisson_packet_distribution = true; debug.disable_main_poisson_packet_distribution = true;
debug.disable_loop_cover_traffic_stream = true; debug.disable_loop_cover_traffic_stream = true;
debug.use_extended_packet_size = false; debug.use_extended_packet_size = false;
// debug.average_packet_delay_ms = BigInt(10); // debug.average_packet_delay_ms = BigInt(10);
// debug.average_ack_delay_ms = BigInt(10); // debug.average_ack_delay_ms = BigInt(10);
// debug.ack_wait_addition_ms = BigInt(3000); // debug.ack_wait_addition_ms = BigInt(3000);
// debug.ack_wait_multiplier = 10; // debug.ack_wait_multiplier = 10;
debug.topology_refresh_rate_ms = BigInt(60000); debug.topology_refresh_rate_ms = BigInt(60000)
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9"; const dummyGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
const validator = "https://qwerty-validator-api.qa.nymte.ch/api"; const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
const config = new Config("my-awesome-wasm-client", validator, debug); const config = new Config('my-awesome-wasm-client', validator, dummyGateway, debug);
const onMessageHandler = (message) => { const onMessageHandler = (message) => {
console.log(message); console.log(message);
self.postMessage({
kind: 'ReceiveMessage',
args: {
message,
},
});
};
console.log('Instantiating WASM client...');
let localClient = await new NymClient(config, onMessageHandler)
console.log('WASM client running!');
const selfAddress = localClient.self_address();
// set the global (I guess we don't have to anymore?)
client = localClient;
console.log(`Client address is ${selfAddress}`);
self.postMessage({ self.postMessage({
kind: "ReceiveMessage", kind: 'Ready',
args: { args: {
message, selfAddress,
}, },
}); });
};
console.log("Instantiating WASM client..."); // Set callback to handle messages passed to the worker.
self.onmessage = async event => {
let localClient = await new NymClient(config, onMessageHandler); console.log(event)
console.log("WASM client running!"); if (event.data && event.data.kind) {
switch (event.data.kind) {
const selfAddress = localClient.self_address(); case 'SendMessage': {
const {message, recipient} = event.data.args;
// set the global (I guess we don't have to anymore?) let uint8Array = new TextEncoder().encode(message);
client = localClient; await client.send_regular_message(uint8Array, recipient);
break;
console.log(`Client address is ${selfAddress}`); }
self.postMessage({ }
kind: "Ready",
args: {
selfAddress,
},
});
// Set callback to handle messages passed to the worker.
self.onmessage = async (event) => {
console.log(event);
if (event.data && event.data.kind) {
switch (event.data.kind) {
case "SendMessage": {
const { message, recipient } = event.data.args;
let uint8Array = new TextEncoder().encode(message);
await client.send_regular_message(uint8Array, recipient);
break;
} }
} };
}
};
} }
async function messWithStorage() { async function messWithStorage() {
self.onmessage = async (event) => { self.onmessage = async event => {
if (event.data && event.data.kind) { if (event.data && event.data.kind) {
switch (event.data.kind) { switch (event.data.kind) {
case "TestPacket": { case 'TestPacket': {
const { mixnodeIdentity } = event.data.args; const { mixnodeIdentity } = event.data.args;
console.log("button clicked...", mixnodeIdentity); console.log("button clicked...", mixnodeIdentity);
let id1 = "one"; let id1 = "one";
let id2 = "two"; let id2 = "two";
console.log("making store1 NO-ENC"); console.log("making store1 NO-ENC");
let _storage1 = await ClientStorage.new_unencrypted(id1); let _storage1 = await ClientStorage.new_unencrypted(id1);
console.log("making store2 ENC"); console.log("making store2 ENC")
let _storage2 = await new ClientStorage(id2, "my-secret-password"); let _storage2 = await new ClientStorage(id2, "my-secret-password");
// //
// //
// //
// console.log("attempting to use store1 WITH PASSWORD") // console.log("attempting to use store1 WITH PASSWORD")
// let _storage1_alt = await new ClientStorage(id1, "password"); // let _storage1_alt = await new ClientStorage(id1, "password");
// //
// //
// //
// console.log("attempting to use store2 WITHOUT PASSWORD") // console.log("attempting to use store2 WITHOUT PASSWORD")
// let _storage2_alt = await ClientStorage.new_unencrypted(id2); // let _storage2_alt = await ClientStorage.new_unencrypted(id2);
// //
// //
// //
// console.log("attempting to use store2 with WRONG PASSWORD") // console.log("attempting to use store2 with WRONG PASSWORD")
// let _storage2_bad = await new ClientStorage(id2, "bad-password") // let _storage2_bad = await new ClientStorage(id2, "bad-password")
//
// console.log("read1: ", await storage1.read()); //
// console.log("read2: ", await storage2.read()); // console.log("read1: ", await storage1.read());
// // console.log("read2: ", await storage2.read());
// console.log("store1: ", await storage1.store("FOOMP")); //
// // console.log("store1: ", await storage1.store("FOOMP"));
// console.log("read1: ", await storage1.read()); //
// console.log("read2: ", await storage2.read()); // console.log("read1: ", await storage1.read());
// console.log("read2: ", await storage2.read());
}
}
} }
} };
}
};
} }
async function main() { async function main() {
// load WASM package // load WASM package
await wasm_bindgen("nym_client_wasm_bg.wasm"); await wasm_bindgen('nym_client_wasm_bg.wasm');
console.log("Loaded WASM"); console.log('Loaded WASM');
// sets up better stack traces in case of in-rust panics // sets up better stack traces in case of in-rust panics
set_panic_hook(); set_panic_hook();
// show reconnection capabilities // run test on simplified and dedicated tester:
// await testerReconnection() // await testWithTester()
// run test on simplified and dedicated tester: // hook-up the whole client for testing
await testWithTester(); // await testWithNymClient()
// 'Normal' client setup (to send 'normal' messages) // 'Normal' client setup (to send 'normal' messages)
// await normalNymClientUsage() await normalNymClientUsage()
} }
// Let's get started! // Let's get started!
main(); main();
+87 -74
View File
@@ -4,52 +4,76 @@
// due to expansion of #[wasm_bindgen] macro on `Debug` Config struct // due to expansion of #[wasm_bindgen] macro on `Debug` Config struct
#![allow(clippy::drop_non_drop)] #![allow(clippy::drop_non_drop)]
// another issue due to #[wasm_bindgen] and `Copy` trait // another issue due to #[wasm_bindgen] and `Copy` trait
#![allow(dropping_copy_types)] #![allow(clippy::drop_copy)]
use nym_client_core::config::{ use nym_client_core::config::{
Acknowledgements as ConfigAcknowledgements, Config as BaseClientConfig, Acknowledgements as ConfigAcknowledgements, CoverTraffic as ConfigCoverTraffic,
CoverTraffic as ConfigCoverTraffic, DebugConfig as ConfigDebug, DebugConfig as ConfigDebug, GatewayConnection as ConfigGatewayConnection,
GatewayConnection as ConfigGatewayConnection, ReplySurbs as ConfigReplySurbs, ReplySurbs as ConfigReplySurbs, Topology as ConfigTopology, Traffic as ConfigTraffic,
Topology as ConfigTopology, Traffic as ConfigTraffic,
}; };
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use nym_validator_client::client::IdentityKey;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use url::Url;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Deserialize, PartialEq, Serialize)] #[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Config { pub struct Config {
pub(crate) base: BaseClientConfig, /// ID specifies the human readable ID of this particular client.
pub(crate) id: String,
pub(crate) nym_api_url: Option<Url>,
pub(crate) disabled_credentials_mode: bool,
/// Information regarding how the client should choose gateway.
/// If unspecified, the client will attempt to load the config from the storage.
pub(crate) gateway: Option<IdentityKey>,
pub(crate) debug: ConfigDebug,
pub(crate) packet_type: PacketType,
} }
#[wasm_bindgen] #[wasm_bindgen]
impl Config { impl Config {
#[wasm_bindgen(constructor)] #[wasm_bindgen(constructor)]
pub fn new(id: String, validator_server: String, debug: Option<DebugWasm>) -> Self { pub fn new(
id: String,
validator_server: String,
packet_type: Option<String>,
gateway: Option<IdentityKey>,
debug: Option<Debug>,
) -> Self {
let packet_type = if let Some(packet_type) = packet_type {
match packet_type.as_str() {
"outfox" => PacketType::Outfox,
_ => PacketType::Mix,
}
} else {
PacketType::Mix
};
Config { Config {
base: BaseClientConfig::new(id, env!("CARGO_PKG_VERSION").to_string()) id,
.with_custom_nyxd(vec![validator_server nym_api_url: Some(
validator_server
.parse() .parse()
.expect("provided url was malformed")]) .expect("provided url was malformed"),
.with_debug_config(debug.map(Into::into).unwrap_or_default()), ),
} disabled_credentials_mode: true,
} gateway,
debug: debug.map(Into::into).unwrap_or_default(),
pub(crate) fn new_tester_config<S: Into<String>>(id: S) -> Self { packet_type,
Config {
base: BaseClientConfig::new(id.into(), env!("CARGO_PKG_VERSION").to_string())
.with_disabled_credentials(true)
.with_disabled_cover_traffic(true)
.with_disabled_topology_refresh(true),
} }
} }
} }
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct TrafficWasm { pub struct Traffic {
/// The parameter of Poisson distribution determining how long, on average, /// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node. /// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value /// So for a packet going through three mix nodes, on average, it will take three times this value
@@ -68,23 +92,14 @@ pub struct TrafficWasm {
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size. /// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
pub use_extended_packet_size: bool, pub use_extended_packet_size: bool,
/// Controls whether the sent packets should use outfox as opposed to the default sphinx.
pub use_outfox: bool,
} }
impl From<TrafficWasm> for ConfigTraffic { impl From<Traffic> for ConfigTraffic {
fn from(traffic: TrafficWasm) -> Self { fn from(traffic: Traffic) -> Self {
let use_extended_packet_size = traffic let use_extended_packet_size = traffic
.use_extended_packet_size .use_extended_packet_size
.then(|| PacketSize::ExtendedPacket32); .then(|| PacketSize::ExtendedPacket32);
let packet_type = if traffic.use_outfox {
PacketType::Outfox
} else {
PacketType::Mix
};
ConfigTraffic { ConfigTraffic {
average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms), average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms),
message_sending_average_delay: Duration::from_millis( message_sending_average_delay: Duration::from_millis(
@@ -94,28 +109,27 @@ impl From<TrafficWasm> for ConfigTraffic {
.disable_main_poisson_packet_distribution, .disable_main_poisson_packet_distribution,
primary_packet_size: PacketSize::RegularPacket, primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: use_extended_packet_size, secondary_packet_size: use_extended_packet_size,
packet_type, packet_type: None,
} }
} }
} }
impl From<ConfigTraffic> for TrafficWasm { impl From<ConfigTraffic> for Traffic {
fn from(traffic: ConfigTraffic) -> Self { fn from(traffic: ConfigTraffic) -> Self {
TrafficWasm { Traffic {
average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u64, average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u64,
message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis() message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis()
as u64, as u64,
disable_main_poisson_packet_distribution: traffic disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution, .disable_main_poisson_packet_distribution,
use_extended_packet_size: traffic.secondary_packet_size.is_some(), use_extended_packet_size: traffic.secondary_packet_size.is_some(),
use_outfox: traffic.packet_type == PacketType::Outfox,
} }
} }
} }
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct CoverTrafficWasm { pub struct CoverTraffic {
/// The parameter of Poisson distribution determining how long, on average, /// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent. /// it is going to take for another loop cover traffic message to be sent.
pub loop_cover_traffic_average_delay_ms: u64, pub loop_cover_traffic_average_delay_ms: u64,
@@ -129,8 +143,8 @@ pub struct CoverTrafficWasm {
pub disable_loop_cover_traffic_stream: bool, pub disable_loop_cover_traffic_stream: bool,
} }
impl From<CoverTrafficWasm> for ConfigCoverTraffic { impl From<CoverTraffic> for ConfigCoverTraffic {
fn from(cover_traffic: CoverTrafficWasm) -> Self { fn from(cover_traffic: CoverTraffic) -> Self {
ConfigCoverTraffic { ConfigCoverTraffic {
loop_cover_traffic_average_delay: Duration::from_millis( loop_cover_traffic_average_delay: Duration::from_millis(
cover_traffic.loop_cover_traffic_average_delay_ms, cover_traffic.loop_cover_traffic_average_delay_ms,
@@ -141,9 +155,9 @@ impl From<CoverTrafficWasm> for ConfigCoverTraffic {
} }
} }
impl From<ConfigCoverTraffic> for CoverTrafficWasm { impl From<ConfigCoverTraffic> for CoverTraffic {
fn from(cover_traffic: ConfigCoverTraffic) -> Self { fn from(cover_traffic: ConfigCoverTraffic) -> Self {
CoverTrafficWasm { CoverTraffic {
loop_cover_traffic_average_delay_ms: cover_traffic loop_cover_traffic_average_delay_ms: cover_traffic
.loop_cover_traffic_average_delay .loop_cover_traffic_average_delay
.as_millis() as u64, .as_millis() as u64,
@@ -155,14 +169,14 @@ impl From<ConfigCoverTraffic> for CoverTrafficWasm {
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct GatewayConnectionWasm { pub struct GatewayConnection {
/// How long we're willing to wait for a response to a message sent to the gateway, /// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it. /// before giving up on it.
pub gateway_response_timeout_ms: u64, pub gateway_response_timeout_ms: u64,
} }
impl From<GatewayConnectionWasm> for ConfigGatewayConnection { impl From<GatewayConnection> for ConfigGatewayConnection {
fn from(gateway_connection: GatewayConnectionWasm) -> Self { fn from(gateway_connection: GatewayConnection) -> Self {
ConfigGatewayConnection { ConfigGatewayConnection {
gateway_response_timeout: Duration::from_millis( gateway_response_timeout: Duration::from_millis(
gateway_connection.gateway_response_timeout_ms, gateway_connection.gateway_response_timeout_ms,
@@ -171,9 +185,9 @@ impl From<GatewayConnectionWasm> for ConfigGatewayConnection {
} }
} }
impl From<ConfigGatewayConnection> for GatewayConnectionWasm { impl From<ConfigGatewayConnection> for GatewayConnection {
fn from(gateway_connection: ConfigGatewayConnection) -> Self { fn from(gateway_connection: ConfigGatewayConnection) -> Self {
GatewayConnectionWasm { GatewayConnection {
gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis() gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis()
as u64, as u64,
} }
@@ -182,7 +196,7 @@ impl From<ConfigGatewayConnection> for GatewayConnectionWasm {
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct AcknowledgementsWasm { pub struct Acknowledgements {
/// The parameter of Poisson distribution determining how long, on average, /// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node. /// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value /// So for an ack going through three mix nodes, on average, it will take three times this value
@@ -200,8 +214,8 @@ pub struct AcknowledgementsWasm {
pub ack_wait_addition_ms: u64, pub ack_wait_addition_ms: u64,
} }
impl From<AcknowledgementsWasm> for ConfigAcknowledgements { impl From<Acknowledgements> for ConfigAcknowledgements {
fn from(acknowledgements: AcknowledgementsWasm) -> Self { fn from(acknowledgements: Acknowledgements) -> Self {
ConfigAcknowledgements { ConfigAcknowledgements {
average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms), average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms),
ack_wait_multiplier: acknowledgements.ack_wait_multiplier, ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
@@ -210,9 +224,9 @@ impl From<AcknowledgementsWasm> for ConfigAcknowledgements {
} }
} }
impl From<ConfigAcknowledgements> for AcknowledgementsWasm { impl From<ConfigAcknowledgements> for Acknowledgements {
fn from(acknowledgements: ConfigAcknowledgements) -> Self { fn from(acknowledgements: ConfigAcknowledgements) -> Self {
AcknowledgementsWasm { Acknowledgements {
average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u64, average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u64,
ack_wait_multiplier: acknowledgements.ack_wait_multiplier, ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u64, ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u64,
@@ -222,7 +236,7 @@ impl From<ConfigAcknowledgements> for AcknowledgementsWasm {
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct TopologyWasm { pub struct Topology {
/// The uniform delay every which clients are querying the directory server /// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through. /// to try to obtain a compatible network topology to send sphinx packets through.
pub topology_refresh_rate_ms: u64, pub topology_refresh_rate_ms: u64,
@@ -238,22 +252,21 @@ pub struct TopologyWasm {
pub disable_refreshing: bool, pub disable_refreshing: bool,
} }
impl From<TopologyWasm> for ConfigTopology { impl From<Topology> for ConfigTopology {
fn from(topology: TopologyWasm) -> Self { fn from(topology: Topology) -> Self {
ConfigTopology { ConfigTopology {
topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms), topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms),
topology_resolution_timeout: Duration::from_millis( topology_resolution_timeout: Duration::from_millis(
topology.topology_resolution_timeout_ms, topology.topology_resolution_timeout_ms,
), ),
disable_refreshing: topology.disable_refreshing, disable_refreshing: topology.disable_refreshing,
topology_structure: Default::default(),
} }
} }
} }
impl From<ConfigTopology> for TopologyWasm { impl From<ConfigTopology> for Topology {
fn from(topology: ConfigTopology) -> Self { fn from(topology: ConfigTopology) -> Self {
TopologyWasm { Topology {
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64, topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64, topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
disable_refreshing: topology.disable_refreshing, disable_refreshing: topology.disable_refreshing,
@@ -263,7 +276,7 @@ impl From<ConfigTopology> for TopologyWasm {
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct ReplySurbsWasm { pub struct ReplySurbs {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times. /// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs. /// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize, pub minimum_reply_surb_storage_threshold: usize,
@@ -297,8 +310,8 @@ pub struct ReplySurbsWasm {
pub maximum_reply_key_age_ms: u64, pub maximum_reply_key_age_ms: u64,
} }
impl From<ReplySurbsWasm> for ConfigReplySurbs { impl From<ReplySurbs> for ConfigReplySurbs {
fn from(reply_surbs: ReplySurbsWasm) -> Self { fn from(reply_surbs: ReplySurbs) -> Self {
ConfigReplySurbs { ConfigReplySurbs {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold, minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold, maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
@@ -318,9 +331,9 @@ impl From<ReplySurbsWasm> for ConfigReplySurbs {
} }
} }
impl From<ConfigReplySurbs> for ReplySurbsWasm { impl From<ConfigReplySurbs> for ReplySurbs {
fn from(reply_surbs: ConfigReplySurbs) -> Self { fn from(reply_surbs: ConfigReplySurbs) -> Self {
ReplySurbsWasm { ReplySurbs {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold, minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold, maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size, minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
@@ -342,28 +355,28 @@ impl From<ConfigReplySurbs> for ReplySurbsWasm {
// just a helper structure to more easily pass through the JS boundary // just a helper structure to more easily pass through the JS boundary
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct DebugWasm { pub struct Debug {
/// Defines all configuration options related to traffic streams. /// Defines all configuration options related to traffic streams.
pub traffic: TrafficWasm, pub traffic: Traffic,
/// Defines all configuration options related to cover traffic stream(s). /// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTrafficWasm, pub cover_traffic: CoverTraffic,
/// Defines all configuration options related to the gateway connection. /// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnectionWasm, pub gateway_connection: GatewayConnection,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts. /// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: AcknowledgementsWasm, pub acknowledgements: Acknowledgements,
/// Defines all configuration options related topology, such as refresh rates or timeouts. /// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: TopologyWasm, pub topology: Topology,
/// Defines all configuration options related to reply SURBs. /// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbsWasm, pub reply_surbs: ReplySurbs,
} }
impl From<DebugWasm> for ConfigDebug { impl From<Debug> for ConfigDebug {
fn from(debug: DebugWasm) -> Self { fn from(debug: Debug) -> Self {
ConfigDebug { ConfigDebug {
traffic: debug.traffic.into(), traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(), cover_traffic: debug.cover_traffic.into(),
@@ -375,9 +388,9 @@ impl From<DebugWasm> for ConfigDebug {
} }
} }
impl From<ConfigDebug> for DebugWasm { impl From<ConfigDebug> for Debug {
fn from(debug: ConfigDebug) -> Self { fn from(debug: ConfigDebug) -> Self {
DebugWasm { Debug {
traffic: debug.traffic.into(), traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(), cover_traffic: debug.cover_traffic.into(),
gateway_connection: debug.gateway_connection.into(), gateway_connection: debug.gateway_connection.into(),
@@ -389,6 +402,6 @@ impl From<ConfigDebug> for DebugWasm {
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn default_debug() -> DebugWasm { pub fn default_debug() -> Debug {
ConfigDebug::default().into() ConfigDebug::default().into()
} }
+91 -50
View File
@@ -7,7 +7,7 @@ use crate::client::response_pusher::ResponsePusher;
use crate::constants::NODE_TESTER_CLIENT_ID; use crate::constants::NODE_TESTER_CLIENT_ID;
use crate::error::WasmClientError; use crate::error::WasmClientError;
use crate::helpers::{ use crate::helpers::{
parse_recipient, parse_sender_tag, setup_from_topology, setup_gateway_from_api, choose_gateway, gateway_from_topology, parse_recipient, parse_sender_tag,
setup_reply_surb_storage_backend, setup_reply_surb_storage_backend,
}; };
use crate::storage::traits::FullWasmClientStorage; use crate::storage::traits::FullWasmClientStorage;
@@ -15,11 +15,14 @@ use crate::storage::ClientStorage;
use crate::topology::WasmNymTopology; use crate::topology::WasmNymTopology;
use js_sys::Promise; use js_sys::Promise;
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient}; use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::base_client::{ use nym_client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, ClientState, BaseClientBuilder, ClientInput, ClientOutput, ClientState, CredentialsToggle,
}; };
use nym_client_core::client::inbound_messages::InputMessage; use nym_client_core::client::inbound_messages::InputMessage;
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; use nym_client_core::client::replies::reply_storage::browser_backend;
use nym_client_core::config::{CoverTraffic, DebugConfig, Topology, Traffic};
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
use nym_task::TaskManager; use nym_task::TaskManager;
@@ -27,7 +30,7 @@ use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
use nym_topology::NymTopology; use nym_topology::NymTopology;
use nym_validator_client::client::IdentityKey; use nym_validator_client::client::IdentityKey;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use rand::RngCore; use rand::{thread_rng, RngCore};
use std::sync::Arc; use std::sync::Arc;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise; use wasm_bindgen_futures::future_to_promise;
@@ -50,18 +53,24 @@ pub struct NymClient {
// even though we don't use graceful shutdowns, other components rely on existence of this struct // even though we don't use graceful shutdowns, other components rely on existence of this struct
// and if it's dropped, everything will start going offline // and if it's dropped, everything will start going offline
_task_manager: TaskManager, _task_manager: TaskManager,
packet_type: Option<PacketType>,
packet_type: PacketType,
} }
#[wasm_bindgen] #[wasm_bindgen]
pub struct NymClientBuilder { pub struct NymClientBuilder {
config: Config, config: Config,
custom_topology: Option<NymTopology>, custom_topology: Option<NymTopology>,
preferred_gateway: Option<IdentityKey>,
storage_passphrase: Option<String>, storage_passphrase: Option<String>,
reply_surb_storage_backend: browser_backend::Backend,
on_message: js_sys::Function, on_message: js_sys::Function,
// unimplemented:
bandwidth_controller:
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
disabled_credentials: bool,
packet_type: Option<PacketType>,
} }
#[wasm_bindgen] #[wasm_bindgen]
@@ -70,15 +79,17 @@ impl NymClientBuilder {
pub fn new( pub fn new(
config: Config, config: Config,
on_message: js_sys::Function, on_message: js_sys::Function,
preferred_gateway: Option<IdentityKey>,
storage_passphrase: Option<String>, storage_passphrase: Option<String>,
) -> Self { ) -> Self {
NymClientBuilder { NymClientBuilder {
reply_surb_storage_backend: setup_reply_surb_storage_backend(config.debug.reply_surbs),
config, config,
custom_topology: None, custom_topology: None,
storage_passphrase, storage_passphrase,
on_message, on_message,
preferred_gateway, bandwidth_controller: None,
disabled_credentials: true,
packet_type: None,
} }
} }
@@ -97,14 +108,40 @@ impl NymClientBuilder {
} }
} }
let full_config = Config::new_tester_config(NODE_TESTER_CLIENT_ID); let full_config = Config {
id: NODE_TESTER_CLIENT_ID.to_string(),
nym_api_url: None,
disabled_credentials_mode: true,
gateway,
debug: DebugConfig {
traffic: Traffic {
disable_main_poisson_packet_distribution: true,
..Default::default()
},
cover_traffic: CoverTraffic {
disable_loop_cover_traffic_stream: true,
..Default::default()
},
topology: Topology {
disable_refreshing: true,
..Default::default()
},
..Default::default()
},
packet_type: PacketType::Mix,
};
NymClientBuilder { NymClientBuilder {
reply_surb_storage_backend: setup_reply_surb_storage_backend(
full_config.debug.reply_surbs,
),
config: full_config, config: full_config,
custom_topology: Some(topology.into()), custom_topology: Some(topology.into()),
on_message, on_message,
bandwidth_controller: None,
disabled_credentials: true,
storage_passphrase: None, storage_passphrase: None,
preferred_gateway: gateway, packet_type: None,
} }
} }
@@ -120,48 +157,59 @@ impl NymClientBuilder {
} }
} }
fn initialise_storage(config: &Config, base_storage: ClientStorage) -> FullWasmClientStorage {
FullWasmClientStorage {
keys_and_gateway_store: base_storage,
reply_storage: setup_reply_surb_storage_backend(config.base.debug.reply_surbs),
credential_storage: EphemeralCredentialStorage::default(),
}
}
async fn start_client_async(mut self) -> Result<NymClient, WasmClientError> { async fn start_client_async(mut self) -> Result<NymClient, WasmClientError> {
console_log!("Starting the wasm client"); console_log!("Starting the wasm client");
let nym_api_endpoints = self.config.base.client.nym_api_urls.clone(); let disabled_credentials = if self.disabled_credentials {
CredentialsToggle::Disabled
} else {
CredentialsToggle::Enabled
};
let nym_api_endpoints = match &self.config.nym_api_url {
Some(endpoint) => vec![endpoint.clone()],
None => Vec::new(),
};
// TODO: this will have to be re-used for surbs. but this is a problem for another PR. // TODO: this will have to be re-used for surbs. but this is a problem for another PR.
let client_store = let client_store =
ClientStorage::new_async(&self.config.base.client.id, self.storage_passphrase.take()) ClientStorage::new_async(&self.config.id, self.storage_passphrase.take()).await?;
.await?;
let user_chosen = self.preferred_gateway.clone();
// if we provided hardcoded topology, get gateway from it, otherwise get it the 'standard' way // if we provided hardcoded topology, get gateway from it, otherwise get it the 'standard' way
if let Some(topology) = &self.custom_topology { let gateway_endpoint = if let Some(topology) = &self.custom_topology {
setup_from_topology(user_chosen, topology, &client_store).await? gateway_from_topology(
&mut thread_rng(),
self.config.gateway.as_deref(),
topology,
&client_store,
)
.await?
} else { } else {
setup_gateway_from_api(&client_store, user_chosen, &nym_api_endpoints).await? choose_gateway(
&client_store,
self.config.gateway.clone(),
&nym_api_endpoints,
)
.await?
}; };
let packet_type = self.config.base.debug.traffic.packet_type;
let storage = Self::initialise_storage(&self.config, client_store);
let maybe_topology_provider = self.topology_provider(); let maybe_topology_provider = self.topology_provider();
let mut base_builder: BaseClientBuilder<_, FullWasmClientStorage> = let mut base_builder: BaseClientBuilder<_, FullWasmClientStorage> = BaseClientBuilder::new(
BaseClientBuilder::<FakeClient<DirectSigningNyxdClient>, _>::new( &gateway_endpoint,
&self.config.base, &self.config.debug,
storage, client_store,
None, self.bandwidth_controller,
); self.reply_surb_storage_backend,
disabled_credentials,
nym_api_endpoints,
);
if let Some(topology_provider) = maybe_topology_provider { if let Some(topology_provider) = maybe_topology_provider {
base_builder = base_builder.with_topology_provider(topology_provider); base_builder = base_builder.with_topology_provider(topology_provider);
} }
let mut started_client = base_builder.start_base().await?; let packet_type = self.config.packet_type;
let mut started_client = base_builder.start_base(packet_type).await?;
let self_address = started_client.address.to_string(); let self_address = started_client.address.to_string();
let client_input = started_client.client_input.register_producer(); let client_input = started_client.client_input.register_producer();
@@ -175,7 +223,7 @@ impl NymClientBuilder {
client_state: Arc::new(started_client.client_state), client_state: Arc::new(started_client.client_state),
_full_topology: None, _full_topology: None,
_task_manager: started_client.task_manager, _task_manager: started_client.task_manager,
packet_type, packet_type: self.packet_type,
}) })
} }
@@ -189,10 +237,9 @@ impl NymClient {
async fn _new( async fn _new(
config: Config, config: Config,
on_message: js_sys::Function, on_message: js_sys::Function,
preferred_gateway: Option<IdentityKey>,
storage_passphrase: Option<String>, storage_passphrase: Option<String>,
) -> Result<NymClient, WasmClientError> { ) -> Result<NymClient, WasmClientError> {
NymClientBuilder::new(config, on_message, preferred_gateway, storage_passphrase) NymClientBuilder::new(config, on_message, storage_passphrase)
.start_client_async() .start_client_async()
.await .await
} }
@@ -202,11 +249,10 @@ impl NymClient {
pub fn new( pub fn new(
config: Config, config: Config,
on_message: js_sys::Function, on_message: js_sys::Function,
preferred_gateway: Option<IdentityKey>,
storage_passphrase: Option<String>, storage_passphrase: Option<String>,
) -> Promise { ) -> Promise {
future_to_promise(async move { future_to_promise(async move {
Self::_new(config, on_message, preferred_gateway, storage_passphrase) Self::_new(config, on_message, storage_passphrase)
.await .await
.into_promise_result() .into_promise_result()
}) })
@@ -273,7 +319,7 @@ impl NymClient {
let lane = TransmissionLane::General; let lane = TransmissionLane::General;
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type)); let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
self.client_input.send_message(input_msg) self.client_input.send_message(input_msg)
} }
@@ -300,13 +346,8 @@ impl NymClient {
let lane = TransmissionLane::General; let lane = TransmissionLane::General;
let input_msg = InputMessage::new_anonymous( let input_msg =
recipient, InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
message,
reply_surbs,
lane,
Some(self.packet_type),
);
self.client_input.send_message(input_msg) self.client_input.send_message(input_msg)
} }
@@ -324,7 +365,7 @@ impl NymClient {
let lane = TransmissionLane::General; let lane = TransmissionLane::General;
let input_msg = InputMessage::new_reply(sender_tag, message, lane, Some(self.packet_type)); let input_msg = InputMessage::new_reply(sender_tag, message, lane, self.packet_type);
self.client_input.send_message(input_msg) self.client_input.send_message(input_msg)
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::storage::error::ClientStorageError; use crate::storage::errors::ClientStorageError;
use crate::topology::WasmTopologyError; use crate::topology::WasmTopologyError;
use js_sys::Promise; use js_sys::Promise;
use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::config::GatewayEndpointConfig;
+84 -33
View File
@@ -7,21 +7,22 @@ use crate::topology::WasmNymTopology;
use js_sys::Promise; use js_sys::Promise;
use nym_client_core::client::replies::reply_storage::browser_backend; use nym_client_core::client::replies::reply_storage::browser_backend;
use nym_client_core::config; use nym_client_core::config;
use nym_client_core::init::helpers::current_gateways; use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::init::{setup_gateway_from, GatewaySetup, InitialisationDetails}; use nym_client_core::init::GatewaySetup;
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_topology::{gateway, NymTopology}; use nym_topology::NymTopology;
use nym_validator_client::client::IdentityKey; use nym_validator_client::client::{IdentityKey, IdentityKeyRef};
use nym_validator_client::NymApiClient; use nym_validator_client::NymApiClient;
use rand::thread_rng; use rand::{CryptoRng, Rng};
use url::Url; use url::Url;
use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen_futures::future_to_promise; use wasm_bindgen_futures::future_to_promise;
use wasm_utils::PromisableResult; use wasm_utils::{console_log, PromisableResult};
// don't get too excited about the name, under the hood it's just a big fat placeholder // don't get too excited about the name, under the hood it's just a big fat placeholder
// with no disk_persistence // with no persistence
pub(crate) fn setup_reply_surb_storage_backend( pub(crate) fn setup_reply_surb_storage_backend(
config: config::ReplySurbs, config: config::ReplySurbs,
) -> browser_backend::Backend { ) -> browser_backend::Backend {
@@ -78,37 +79,87 @@ pub fn current_network_topology(nym_api_url: String) -> Promise {
}) })
} }
async fn setup_gateway( pub(crate) async fn choose_gateway(
client_store: &ClientStorage,
chosen_gateway: Option<IdentityKey>,
gateways: &[gateway::Node],
) -> Result<InitialisationDetails, WasmClientError> {
let setup = if client_store.has_full_gateway_info().await? {
GatewaySetup::MustLoad
} else {
GatewaySetup::new_fresh(chosen_gateway.clone(), None)
};
setup_gateway_from(&setup, client_store, client_store, false, Some(gateways))
.await
.map_err(Into::into)
}
pub(crate) async fn setup_gateway_from_api(
client_store: &ClientStorage, client_store: &ClientStorage,
chosen_gateway: Option<IdentityKey>, chosen_gateway: Option<IdentityKey>,
nym_apis: &[Url], nym_apis: &[Url],
) -> Result<InitialisationDetails, WasmClientError> { ) -> Result<GatewayEndpointConfig, WasmClientError> {
let mut rng = thread_rng(); let existing_gateway_config = client_store.read_gateway_config().await?;
let gateways = current_gateways(&mut rng, nym_apis).await?;
setup_gateway(client_store, chosen_gateway, &gateways).await console_log!("loaded: {:?}", existing_gateway_config);
if let Some(existing) = existing_gateway_config {
if let Some(provided) = &chosen_gateway {
if provided != &existing.gateway_id {
return Err(WasmClientError::AlreadyRegistered {
gateway_config: existing,
});
}
}
return Ok(existing);
};
// if NOTHING is specified nor available, choose gateway randomly.
let setup = GatewaySetup::new(None, chosen_gateway, None);
let config = setup.try_get_gateway_details(nym_apis).await?;
// perform registration + persist the new gateway info
// TODO: this is actually quite bad. we shouldn't be persisting gateway info here since we did not have persisted
// the shared key yet. this will only happen when we start the base client itself.
// but unfortunately, we can't do much more until we do a bit more refactoring.
client_store.store_gateway_config(&config).await?;
console_log!("stored: {:?}", config);
Ok(config)
} }
pub(crate) async fn setup_from_topology( pub(crate) async fn gateway_from_topology<R: Rng + CryptoRng>(
explicit_gateway: Option<IdentityKey>, rng: &mut R,
explicit_gateway: Option<IdentityKeyRef<'_>>,
topology: &NymTopology, topology: &NymTopology,
client_store: &ClientStorage, client_store: &ClientStorage,
) -> Result<InitialisationDetails, WasmClientError> { ) -> Result<GatewayEndpointConfig, WasmClientError> {
let gateways = topology.gateways(); let existing_gateway_config = client_store.read_gateway_config().await?;
setup_gateway(client_store, explicit_gateway, gateways).await console_log!("loaded: {:?}", existing_gateway_config);
let new_gateway: GatewayEndpointConfig = if let Some(provided) = explicit_gateway {
if let Some(existing) = existing_gateway_config {
// we have stored gateway info and explicitly provided identity key
//
// check if they match, otherwise return an error
return if provided != existing.gateway_id {
Err(WasmClientError::AlreadyRegistered {
gateway_config: existing,
})
} else {
Ok(existing)
};
} else {
// we have explicitly provided identity key and didn't have any prior stored data
//
// try to grab details from the topology
let gateway_identity = identity::PublicKey::from_base58_string(provided)
.map_err(|source| WasmClientError::InvalidGatewayIdentity { source })?;
if let Some(gateway) = topology.get_gateway(&gateway_identity) {
gateway.clone().into()
} else {
return Err(WasmClientError::NonExistentGateway {
gateway_identity: gateway_identity.to_base58_string(),
});
}
}
} else if let Some(existing) = existing_gateway_config {
// we have stored data and didn't provide anything separately - use what's stored!
return Ok(existing);
} else {
// we don't have anything stored nor we have provided anything
//
// just grab random gateway from our topology
topology.random_gateway(rng)?.clone().into()
};
console_log!("storing: {:?}", new_gateway);
client_store.store_gateway_config(&new_gateway).await?;
Ok(new_gateway)
} }
@@ -16,9 +16,6 @@ pub enum ClientStorageError {
#[error("{typ} cryptographic key is not available in storage")] #[error("{typ} cryptographic key is not available in storage")]
CryptoKeyNotInStorage { typ: String }, CryptoKeyNotInStorage { typ: String },
#[error("the prior gateway details are not available in the storage")]
GatewayDetailsNotInStorage,
} }
impl From<ClientStorageError> for JsValue { impl From<ClientStorageError> for JsValue {
+13 -47
View File
@@ -1,10 +1,9 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config; use crate::storage::errors::ClientStorageError;
use crate::storage::error::ClientStorageError;
use js_sys::Promise; use js_sys::Promise;
use nym_client_core::client::base_client::storage::gateway_details::PersistedGatewayDetails; use nym_client_core::config::GatewayEndpointConfig;
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_gateway_client::SharedKeys; use nym_gateway_client::SharedKeys;
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
@@ -15,7 +14,7 @@ use wasm_utils::storage::{IdbVersionChangeEvent, WasmStorage};
use wasm_utils::PromisableResult; use wasm_utils::PromisableResult;
use zeroize::Zeroizing; use zeroize::Zeroizing;
pub(crate) mod error; pub(crate) mod errors;
pub(crate) mod traits; pub(crate) mod traits;
const STORAGE_NAME_PREFIX: &str = "wasm-client-storage"; const STORAGE_NAME_PREFIX: &str = "wasm-client-storage";
@@ -28,11 +27,11 @@ mod v1 {
pub const CORE_STORE: &str = "core"; pub const CORE_STORE: &str = "core";
// keys // keys
pub const CONFIG: &str = "config"; // TODO: to replace with FULL config
pub const GATEWAY_DETAILS: &str = "gateway_details"; pub const GATEWAY_CONFIG: &str = "gateway_config";
pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair"; pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair";
pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_keypair"; pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_key";
// TODO: for those we could actually use the subtle crypto storage // TODO: for those we could actually use the subtle crypto storage
pub const AES128CTR_ACK_KEY: &str = "aes128ctr_ack_key"; pub const AES128CTR_ACK_KEY: &str = "aes128ctr_ack_key";
@@ -111,32 +110,15 @@ impl ClientStorage {
}) })
} }
// TODO: persist client's config pub(crate) async fn read_gateway_config(
#[allow(dead_code)] &self,
pub(crate) async fn read_config(&self) -> Result<Option<Config>, ClientStorageError> { ) -> Result<Option<GatewayEndpointConfig>, ClientStorageError> {
self.inner self.inner
.read_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG)) .read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_CONFIG))
.await .await
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) async fn may_read_gateway_details(
&self,
) -> Result<Option<PersistedGatewayDetails>, ClientStorageError> {
self.inner
.read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_DETAILS))
.await
.map_err(Into::into)
}
pub(crate) async fn must_read_gateway_details(
&self,
) -> Result<PersistedGatewayDetails, ClientStorageError> {
self.may_read_gateway_details()
.await?
.ok_or(ClientStorageError::GatewayDetailsNotInStorage)
}
async fn may_read_identity_keypair( async fn may_read_identity_keypair(
&self, &self,
) -> Result<Option<identity::KeyPair>, ClientStorageError> { ) -> Result<Option<identity::KeyPair>, ClientStorageError> {
@@ -262,33 +244,17 @@ impl ClientStorage {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) async fn store_gateway_details( pub(crate) async fn store_gateway_config(
&self, &self,
gateway_endpoint: &PersistedGatewayDetails, gateway_endpoint: &GatewayEndpointConfig,
) -> Result<(), ClientStorageError> { ) -> Result<(), ClientStorageError> {
self.inner self.inner
.store_value( .store_value(
v1::CORE_STORE, v1::CORE_STORE,
JsValue::from_str(v1::GATEWAY_DETAILS), JsValue::from_str(v1::GATEWAY_CONFIG),
gateway_endpoint, gateway_endpoint,
) )
.await .await
.map_err(Into::into) .map_err(Into::into)
} }
// TODO: persist client's config
#[allow(dead_code)]
pub(crate) async fn store_config(&self, config: &Config) -> Result<(), ClientStorageError> {
self.inner
.store_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG), config)
.await
.map_err(Into::into)
}
pub(crate) async fn has_full_gateway_info(&self) -> Result<bool, ClientStorageError> {
let has_keys = self.may_read_gateway_shared_key().await?.is_some();
let has_details = self.may_read_gateway_details().await?.is_some();
Ok(has_keys && has_details)
}
} }
+7 -32
View File
@@ -1,12 +1,9 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::storage::error::ClientStorageError; use crate::storage::errors::ClientStorageError;
use crate::storage::ClientStorage; use crate::storage::ClientStorage;
use async_trait::async_trait; use async_trait::async_trait;
use nym_client_core::client::base_client::storage::gateway_details::{
GatewayDetailsStore, PersistedGatewayDetails,
};
use nym_client_core::client::base_client::storage::MixnetClientStorage; use nym_client_core::client::base_client::storage::MixnetClientStorage;
use nym_client_core::client::key_manager::persistence::KeyStore; use nym_client_core::client::key_manager::persistence::KeyStore;
use nym_client_core::client::key_manager::KeyManager; use nym_client_core::client::key_manager::KeyManager;
@@ -17,9 +14,9 @@ use wasm_utils::console_log;
// temporary until other variants are properly implemented (probably it should get changed into `ClientStorage` // temporary until other variants are properly implemented (probably it should get changed into `ClientStorage`
// implementing all traits and everything getting combined // implementing all traits and everything getting combined
pub struct FullWasmClientStorage { pub struct FullWasmClientStorage {
pub(crate) keys_and_gateway_store: ClientStorage, key_store: ClientStorage,
pub(crate) reply_storage: browser_backend::Backend, reply_storage: browser_backend::Backend,
pub(crate) credential_storage: EphemeralCredentialStorage, credential_storage: EphemeralCredentialStorage,
} }
impl MixnetClientStorage for FullWasmClientStorage { impl MixnetClientStorage for FullWasmClientStorage {
@@ -27,14 +24,12 @@ impl MixnetClientStorage for FullWasmClientStorage {
type ReplyStore = browser_backend::Backend; type ReplyStore = browser_backend::Backend;
type CredentialStore = EphemeralCredentialStorage; type CredentialStore = EphemeralCredentialStorage;
type GatewayDetailsStore = ClientStorage; fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore) {
(self.key_store, self.reply_storage, self.credential_storage)
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) {
(self.reply_storage, self.credential_storage)
} }
fn key_store(&self) -> &Self::KeyStore { fn key_store(&self) -> &Self::KeyStore {
&self.keys_and_gateway_store &self.key_store
} }
fn reply_store(&self) -> &Self::ReplyStore { fn reply_store(&self) -> &Self::ReplyStore {
@@ -44,10 +39,6 @@ impl MixnetClientStorage for FullWasmClientStorage {
fn credential_store(&self) -> &Self::CredentialStore { fn credential_store(&self) -> &Self::CredentialStore {
&self.credential_storage &self.credential_storage
} }
fn gateway_details_store(&self) -> &Self::GatewayDetailsStore {
&self.keys_and_gateway_store
}
} }
#[async_trait(?Send)] #[async_trait(?Send)]
@@ -83,19 +74,3 @@ impl KeyStore for ClientStorage {
.await .await
} }
} }
#[async_trait(?Send)]
impl GatewayDetailsStore for ClientStorage {
type StorageError = ClientStorageError;
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
self.must_read_gateway_details().await
}
async fn store_gateway_details(
&self,
details: &PersistedGatewayDetails,
) -> Result<(), Self::StorageError> {
self.store_gateway_details(details).await
}
}
@@ -10,7 +10,6 @@ use std::collections::HashSet;
use std::time::Duration; use std::time::Duration;
use tokio::sync::MutexGuard as AsyncMutexGuard; use tokio::sync::MutexGuard as AsyncMutexGuard;
use wasm_utils::{console_error, console_log, console_warn}; use wasm_utils::{console_error, console_log, console_warn};
use wasmtimer::tokio::sleep;
pub(crate) struct EphemeralTestReceiver<'a> { pub(crate) struct EphemeralTestReceiver<'a> {
sent_packets: u32, sent_packets: u32,
@@ -91,7 +90,7 @@ impl<'a> EphemeralTestReceiver<'a> {
} }
pub(crate) async fn perform_test(mut self) -> NodeTestResult { pub(crate) async fn perform_test(mut self) -> NodeTestResult {
let mut timeout_fut = sleep(self.timeout_duration); let mut timeout_fut = wasm_timer::Delay::new(self.timeout_duration);
loop { loop {
tokio::select! { tokio::select! {
-38
View File
@@ -4,9 +4,6 @@
// due to expansion of #[wasm_bindgen] macro on NodeTestResult // due to expansion of #[wasm_bindgen] macro on NodeTestResult
#![allow(clippy::drop_non_drop)] #![allow(clippy::drop_non_drop)]
use crate::error::WasmClientError;
use crate::tester::LockedGatewayClient;
use js_sys::Promise;
use nym_node_tester_utils::processor::Received; use nym_node_tester_utils::processor::Received;
use nym_node_tester_utils::receiver::ReceivedReceiver; use nym_node_tester_utils::receiver::ReceivedReceiver;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -15,7 +12,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard}; use tokio::sync::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{console_log, console_warn}; use wasm_utils::{console_log, console_warn};
#[derive(Clone)] #[derive(Clone)]
@@ -111,37 +107,3 @@ impl Drop for TestMarker {
self.value.store(false, Ordering::SeqCst) self.value.store(false, Ordering::SeqCst)
} }
} }
pub(crate) trait GatewayReconnection {
fn disconnect_from_gateway(&self) -> Promise;
fn reconnect_to_gateway(&self) -> Promise;
}
impl GatewayReconnection for LockedGatewayClient {
fn disconnect_from_gateway(&self) -> Promise {
let this = self.clone();
future_to_promise(async move {
let mut guard = this.lock().await;
guard
.disconnect()
.await
.map_err(|err| JsValue::from(WasmClientError::from(err)))?;
Ok(JsValue::undefined())
})
}
fn reconnect_to_gateway(&self) -> Promise {
let this = self.clone();
future_to_promise(async move {
let mut guard = this.lock().await;
guard
.try_reconnect()
.await
.map_err(|err| JsValue::from(WasmClientError::from(err)))?;
Ok(JsValue::undefined())
})
}
}
+32 -56
View File
@@ -3,11 +3,11 @@
use crate::constants::NODE_TESTER_ID; use crate::constants::NODE_TESTER_ID;
use crate::error::WasmClientError; use crate::error::WasmClientError;
use crate::helpers::{current_network_topology_async, setup_from_topology}; use crate::helpers::{current_network_topology_async, gateway_from_topology};
use crate::storage::ClientStorage; use crate::storage::ClientStorage;
use crate::tester::ephemeral_receiver::EphemeralTestReceiver; use crate::tester::ephemeral_receiver::EphemeralTestReceiver;
use crate::tester::helpers::{ use crate::tester::helpers::{
GatewayReconnection, NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt, NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt,
}; };
use crate::topology::WasmNymTopology; use crate::topology::WasmNymTopology;
use futures::channel::mpsc; use futures::channel::mpsc;
@@ -15,7 +15,7 @@ use js_sys::Promise;
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient}; use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
use nym_bandwidth_controller::BandwidthController; use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::key_manager::ManagedKeys; use nym_client_core::client::key_manager::ManagedKeys;
use nym_client_core::init::InitialisationDetails; use nym_client_core::config::GatewayEndpointConfig;
use nym_credential_storage::ephemeral_storage::EphemeralStorage; use nym_credential_storage::ephemeral_storage::EphemeralStorage;
use nym_gateway_client::GatewayClient; use nym_gateway_client::GatewayClient;
use nym_node_tester_utils::receiver::SimpleMessageReceiver; use nym_node_tester_utils::receiver::SimpleMessageReceiver;
@@ -28,6 +28,7 @@ use nym_task::TaskManager;
use nym_topology::NymTopology; use nym_topology::NymTopology;
use nym_validator_client::client::IdentityKey; use nym_validator_client::client::IdentityKey;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use rand::{CryptoRng, Rng};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::{Arc, Mutex as SyncMutex}; use std::sync::{Arc, Mutex as SyncMutex};
@@ -73,7 +74,6 @@ pub struct NymNodeTester {
#[wasm_bindgen] #[wasm_bindgen]
pub struct NymNodeTesterBuilder { pub struct NymNodeTesterBuilder {
gateway: Option<IdentityKey>, gateway: Option<IdentityKey>,
id: Option<String>,
base_topology: NymTopology, base_topology: NymTopology,
@@ -95,11 +95,9 @@ impl NymNodeTesterBuilder {
#[wasm_bindgen(constructor)] #[wasm_bindgen(constructor)]
pub fn new( pub fn new(
base_topology: WasmNymTopology, base_topology: WasmNymTopology,
id: Option<String>,
gateway: Option<IdentityKey>, gateway: Option<IdentityKey>,
) -> NymNodeTesterBuilder { ) -> NymNodeTesterBuilder {
NymNodeTesterBuilder { NymNodeTesterBuilder {
id,
gateway, gateway,
base_topology: base_topology.into(), base_topology: base_topology.into(),
bandwidth_controller: None, bandwidth_controller: None,
@@ -108,51 +106,43 @@ impl NymNodeTesterBuilder {
async fn _new_with_api( async fn _new_with_api(
api_url: String, api_url: String,
id: Option<String>,
gateway: Option<IdentityKey>, gateway: Option<IdentityKey>,
) -> Result<Self, WasmClientError> { ) -> Result<Self, WasmClientError> {
let topology = current_network_topology_async(api_url).await?; let topology = current_network_topology_async(api_url).await?;
Ok(NymNodeTesterBuilder::new(topology, id, gateway)) Ok(NymNodeTesterBuilder::new(topology, gateway))
} }
pub fn new_with_api( pub fn new_with_api(gateway: Option<IdentityKey>, api_url: String) -> Promise {
api_url: String,
id: Option<String>,
gateway: Option<IdentityKey>,
) -> Promise {
future_to_promise(async move { future_to_promise(async move {
Self::_new_with_api(api_url, id, gateway) Self::_new_with_api(api_url, gateway)
.await .await
.into_promise_result() .into_promise_result()
}) })
} }
async fn gateway_info( async fn gateway_info<R: Rng + CryptoRng>(
&self, &self,
rng: &mut R,
client_store: &ClientStorage, client_store: &ClientStorage,
) -> Result<InitialisationDetails, WasmClientError> { ) -> Result<GatewayEndpointConfig, WasmClientError> {
if let Ok(loaded) = InitialisationDetails::try_load(client_store, client_store).await { gateway_from_topology(
Ok(loaded) rng,
} else { self.gateway.as_deref(),
setup_from_topology(self.gateway.clone(), &self.base_topology, client_store).await &self.base_topology,
} client_store,
)
.await
} }
async fn _setup_client(mut self) -> Result<NymNodeTester, WasmClientError> { async fn _setup_client(mut self) -> Result<NymNodeTester, WasmClientError> {
let mut rng = OsRng;
let task_manager = TaskManager::default(); let task_manager = TaskManager::default();
let storage_id = if let Some(client_id) = &self.id { let client_store = ClientStorage::new_async(NODE_TESTER_ID, None).await?;
format!("{NODE_TESTER_ID}-{client_id}")
} else {
NODE_TESTER_ID.to_owned()
};
let client_store = ClientStorage::new_async(&storage_id, None).await?; let gateway_endpoint = self.gateway_info(&mut rng, &client_store).await?;
let init_details = self.gateway_info(&client_store).await?;
let gateway_endpoint = init_details.gateway_details;
let gateway_identity = gateway_endpoint.try_get_gateway_identity_key()?; let gateway_identity = gateway_endpoint.try_get_gateway_identity_key()?;
let managed_keys = init_details.managed_keys; let mut managed_keys = ManagedKeys::load_or_generate(&mut rng, &client_store).await;
let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded(); let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded();
let (ack_sender, ack_receiver) = mpsc::unbounded(); let (ack_sender, ack_receiver) = mpsc::unbounded();
@@ -161,7 +151,7 @@ impl NymNodeTesterBuilder {
gateway_endpoint.gateway_listener, gateway_endpoint.gateway_listener,
managed_keys.identity_keypair(), managed_keys.identity_keypair(),
gateway_identity, gateway_identity,
Some(managed_keys.must_get_gateway_shared_key()), managed_keys.gateway_shared_key(),
mixnet_message_sender, mixnet_message_sender,
ack_sender, ack_sender,
Duration::from_secs(10), Duration::from_secs(10),
@@ -170,11 +160,14 @@ impl NymNodeTesterBuilder {
); );
gateway_client.set_disabled_credentials_mode(true); gateway_client.set_disabled_credentials_mode(true);
gateway_client.authenticate_and_start().await?; let shared_keys = gateway_client.authenticate_and_start().await?;
managed_keys
.deal_with_gateway_key(shared_keys, &client_store)
.await?;
// TODO: make those values configurable later // TODO: make those values configurable later
let tester = NodeTester::new( let tester = NodeTester::new(
OsRng, rng,
self.base_topology, self.base_topology,
Some(address(&managed_keys, gateway_identity)), Some(address(&managed_keys, gateway_identity)),
PacketSize::default(), PacketSize::default(),
@@ -248,46 +241,29 @@ async fn test_mixnode(
impl NymNodeTester { impl NymNodeTester {
#[wasm_bindgen(constructor)] #[wasm_bindgen(constructor)]
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub fn new( pub fn new(topology: WasmNymTopology, gateway: Option<IdentityKey>) -> Promise {
topology: WasmNymTopology,
id: Option<String>,
gateway: Option<IdentityKey>,
) -> Promise {
console_log!("constructing node tester!"); console_log!("constructing node tester!");
NymNodeTesterBuilder::new(topology, id, gateway).setup_client() NymNodeTesterBuilder::new(topology, gateway).setup_client()
} }
async fn _new_with_api( async fn _new_with_api(
api_url: String, api_url: String,
id: Option<String>,
gateway: Option<IdentityKey>, gateway: Option<IdentityKey>,
) -> Result<Self, WasmClientError> { ) -> Result<Self, WasmClientError> {
NymNodeTesterBuilder::_new_with_api(api_url, id, gateway) NymNodeTesterBuilder::_new_with_api(api_url, gateway)
.await? .await?
._setup_client() ._setup_client()
.await .await
} }
pub fn new_with_api( pub fn new_with_api(api_url: String, gateway: Option<IdentityKey>) -> Promise {
api_url: String,
id: Option<String>,
gateway: Option<IdentityKey>,
) -> Promise {
future_to_promise(async move { future_to_promise(async move {
Self::_new_with_api(api_url, id, gateway) Self::_new_with_api(api_url, gateway)
.await .await
.into_promise_result() .into_promise_result()
}) })
} }
pub fn disconnect_from_gateway(&self) -> Promise {
self.gateway_client.disconnect_from_gateway()
}
pub fn reconnect_to_gateway(&self) -> Promise {
self.gateway_client.reconnect_to_gateway()
}
fn prepare_test_packets( fn prepare_test_packets(
&self, &self,
mixnode_identity: String, mixnode_identity: String,
+1 -1
View File
@@ -101,7 +101,7 @@ impl AsyncFileWatcher {
} }
let Some(filters) = &self.filters else { let Some(filters) = &self.filters else {
return true; return true
}; };
for filter in filters { for filter in filters {
+2 -1
View File
@@ -18,6 +18,7 @@ nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric"
nym-network-defaults = { path = "../network-defaults" } nym-network-defaults = { path = "../network-defaults" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false } nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
path = "../client-libs/validator-client" path = "../client-libs/validator-client"
features = ["signing"] features = ["nyxd-client"]

Some files were not shown because too many files have changed in this diff Show More