Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3142493cd1 |
@@ -2994,7 +2994,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "extension-storage"
|
||||
version = "1.2.4-rc.2"
|
||||
version = "1.2.4-rc.1"
|
||||
dependencies = [
|
||||
"bip39",
|
||||
"console_error_panic_hook",
|
||||
@@ -5568,7 +5568,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mix-fetch-wasm"
|
||||
version = "1.2.4-rc.2"
|
||||
version = "1.2.4-rc.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -6270,7 +6270,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client-wasm"
|
||||
version = "1.2.4-rc.2"
|
||||
version = "1.2.4-rc.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
@@ -6667,15 +6667,12 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-exit-policy",
|
||||
"nym-network-requester",
|
||||
"nym-sdk",
|
||||
"nym-service-providers-common",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
@@ -6975,7 +6972,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-tester-wasm"
|
||||
version = "1.2.4-rc.2"
|
||||
version = "1.2.4-rc.1"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod update_config;
|
||||
pub mod update_cost_params;
|
||||
pub mod vesting_update_config;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
@@ -21,5 +20,7 @@ pub enum MixnetOperatorsMixnodeSettingsCommands {
|
||||
/// Update mixnode configuration for a mixnode bonded with locked tokens
|
||||
VestingUpdateConfig(vesting_update_config::Args),
|
||||
/// Update mixnode cost parameters
|
||||
UpdateCostParameters(update_cost_params::Args),
|
||||
UpdateCostParameters,
|
||||
/// Update mixnode cost parameters for a mixnode bonded with locked tokens
|
||||
VestingUpdateCostParameters,
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use cosmwasm_std::Uint128;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::{MixNodeCostParams, Percent};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::CosmWasmCoin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(
|
||||
long,
|
||||
help = "input your profit margin as follows; (so it would be 10, rather than 0.1)"
|
||||
)]
|
||||
pub profit_margin_percent: Option<u8>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
|
||||
)]
|
||||
pub interval_operating_cost: Option<u128>,
|
||||
}
|
||||
|
||||
pub async fn update_cost_params(args: Args, client: SigningClient) {
|
||||
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||
|
||||
let cost_params = MixNodeCostParams {
|
||||
profit_margin_percent: Percent::from_percentage_value(
|
||||
args.profit_margin_percent.unwrap_or(10) as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
interval_operating_cost: CosmWasmCoin {
|
||||
denom: denom.into(),
|
||||
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
|
||||
},
|
||||
};
|
||||
|
||||
info!("Starting mixnode params updating!");
|
||||
let res = client
|
||||
.update_mixnode_cost_params(cost_params, None)
|
||||
.await
|
||||
.expect("failed to update cost params");
|
||||
|
||||
info!("Cost params result: {:?}", res)
|
||||
}
|
||||
@@ -25,20 +25,12 @@ pub const DEFAULT_CONFIG_FILENAME: &str = "config.toml";
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn must_get_home() -> PathBuf {
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
home_dir.into()
|
||||
} else {
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn may_get_home() -> Option<PathBuf> {
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
Some(home_dir.into())
|
||||
} else {
|
||||
dirs::home_dir()
|
||||
}
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
pub trait NymConfigTemplate: Serialize {
|
||||
|
||||
@@ -134,15 +134,13 @@ impl TunDevice {
|
||||
nat_table.nat_table.insert(src_addr, tag);
|
||||
}
|
||||
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.tun.write_all(&packet),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| {
|
||||
log::error!("iface: write error: {err}");
|
||||
})
|
||||
.ok();
|
||||
self.tun
|
||||
.write_all(&packet)
|
||||
.await
|
||||
.tap_err(|err| {
|
||||
log::error!("iface: write error: {err}");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
// Receive reponse packets from the wild internet
|
||||
@@ -165,25 +163,14 @@ impl TunDevice {
|
||||
match self.routing_mode {
|
||||
// This is how wireguard does it, by consulting the AllowedIPs table.
|
||||
RoutingMode::AllowedIps(ref peers_by_ip) => {
|
||||
let Ok(peers) = tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
peers_by_ip.peers_by_ip.as_ref().lock(),
|
||||
)
|
||||
.await
|
||||
else {
|
||||
log::error!("Failed to lock peer");
|
||||
return;
|
||||
};
|
||||
|
||||
let peers = peers_by_ip.peers_by_ip.as_ref().lock().await;
|
||||
if let Some(peer_tx) = peers.longest_match(dst_addr).map(|(_, tx)| tx) {
|
||||
log::info!("Forward packet to wg tunnel");
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
peer_tx.send(Event::Ip(packet.to_vec().into())),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| log::error!("Failed to forward packet to wg tunnel: {err}"))
|
||||
.ok();
|
||||
peer_tx
|
||||
.send(Event::Ip(packet.to_vec().into()))
|
||||
.await
|
||||
.tap_err(|err| log::error!("{err}"))
|
||||
.ok();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -192,13 +179,11 @@ impl TunDevice {
|
||||
RoutingMode::Nat(ref nat_table) => {
|
||||
if let Some(tag) = nat_table.nat_table.get(&dst_addr) {
|
||||
log::info!("Forward packet with tag: {tag}");
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.tun_task_response_tx.send((*tag, packet.to_vec())),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| log::error!("Failed to foward packet with tag: {err}"))
|
||||
.ok();
|
||||
self.tun_task_response_tx
|
||||
.send((*tag, packet.to_vec()))
|
||||
.await
|
||||
.tap_err(|err| log::error!("{err}"))
|
||||
.ok();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -216,32 +201,20 @@ impl TunDevice {
|
||||
len = self.tun.read(&mut buf) => match len {
|
||||
Ok(len) => {
|
||||
let packet = &buf[..len];
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.handle_tun_read(packet)
|
||||
)
|
||||
.await
|
||||
.tap_err(|_err| log::error!("Failed: handle_tun_read timeout"))
|
||||
.ok();
|
||||
self.handle_tun_read(packet).await;
|
||||
},
|
||||
Err(err) => {
|
||||
log::info!("iface: read error: {err}");
|
||||
// break;
|
||||
break;
|
||||
}
|
||||
},
|
||||
// Writing to the TUN device
|
||||
Some(data) = self.tun_task_rx.recv() => {
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.handle_tun_write(data)
|
||||
)
|
||||
.await
|
||||
.tap_err(|_err| log::error!("Failed: handle_tun_write timeout"))
|
||||
.ok();
|
||||
self.handle_tun_write(data).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
// log::info!("TUN device shutting down");
|
||||
log::info!("TUN device shutting down");
|
||||
}
|
||||
|
||||
pub fn start(self) {
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
- [NymConnect X Monero](tutorials/monero.md)
|
||||
- [NymConnect X Matrix](tutorials/matrix.md)
|
||||
- [NymConnect X Telegram](tutorials/telegram.md)
|
||||
- [NymConnect X Electrum](tutorials/electrum.md)
|
||||
- [NymConnect X Firo wallet](tutorials/firo.md)
|
||||
|
||||
# Code Examples
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 101 KiB |
@@ -10,6 +10,3 @@ We expect to see the following for submissions:
|
||||
- If a UI-based solution:
|
||||
- How to run it locally? We are happy to also accept staging deployments as part of the submission (e.g. via Vercel) but this does not replace being able to run it locally.
|
||||
- Please make sure that your application works on commonly reproducible system environments (e.g. if you’re developing on Artix Linux please check for the necessary dependencies for more common-place OSes such as Debian, or Arch). If you are developing on Windows please make sure that it works on non-Windows machines also. Where possible please try to include build and install instructions for a variety of OSes.
|
||||
|
||||
## How to submit?
|
||||
Please follow the instructions [here](https://github.com/nymtech/nym/discussions/4143).
|
||||
@@ -1,36 +0,0 @@
|
||||
# Electrum Wallet NymConnect Integration
|
||||
|
||||
Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as a backend wallet for various crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin.
|
||||
|
||||
## How can I use Bitcoin over the Nym mixnet?
|
||||
|
||||
> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
### NymConnect Installation
|
||||
|
||||
NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.
|
||||
|
||||
1. [Download](https://nymtech.net/download/nymconnect) NymConnect
|
||||
2. On Linux and Mac, make executable by opening terminal in the same directory and run:
|
||||
|
||||
```sh
|
||||
chmod +x ./nym-connect_<VERSION>
|
||||
```
|
||||
|
||||
3. Start the application
|
||||
4. Click on `Connect` button to initialise the connection with the Mixnet
|
||||
5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard
|
||||
6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application
|
||||
|
||||
### Electrum Bitcoin wallet via NymConnect
|
||||
|
||||
|
||||
To download Electrum visit the [official webpage](https://electrum.org/#download). To connect to the Mixnet follow these steps:
|
||||
|
||||
7. Start and connect [NymConnect](./electrum.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html))
|
||||
2. Start your Electrum Bitcoin wallet
|
||||
3. Go to: *Tools* -> *Network* -> *Proxy*
|
||||
4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application
|
||||
5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
|
||||
|
||||

|
||||
@@ -1,36 +0,0 @@
|
||||
# Firo-Electrum Wallet NymConnect Integration
|
||||
|
||||
[Firo](https://github.com/firoorg/firo#firo) (formerly Zcoin) is a privacy focused, zk-proof based cryptocurrency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/).
|
||||
|
||||
## How can I use Firo over the Nym Mixnet?
|
||||
|
||||
> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
### NymConnect Installation
|
||||
|
||||
NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.
|
||||
|
||||
1. [Download](https://nymtech.net/download/nymconnect) NymConnect
|
||||
2. On Linux and Mac, make executable by opening terminal in the same directory and run:
|
||||
|
||||
```sh
|
||||
chmod +x ./nym-connect_<VERSION>
|
||||
```
|
||||
|
||||
3. Start the application
|
||||
4. Click on `Connect` button to initialise the connection with the Mixnet
|
||||
5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard
|
||||
6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application
|
||||
|
||||
### Firo Electrum wallet via NymConnect
|
||||
|
||||
|
||||
To download Firo Electrum wallet visit the [Firo's repository](https://github.com/firoorg/firo) or [Github release page](https://github.com/firoorg/electrum-firo/releases/tag/4.1.5.2). To connect to the Mixnet follow these steps:
|
||||
|
||||
7. Start and connect [NymConnect](./firo.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html))
|
||||
8. Start your Firo Electrum wallet
|
||||
9. Go to: *Tools* -> *Network* -> *Proxy*
|
||||
10. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application
|
||||
11. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
|
||||
|
||||

|
||||
@@ -16,7 +16,7 @@ Here’s how to configure Telegram with NymConnect:
|
||||
For more releases, check out [Github](https://github.com/nymtech/nym/tags). NymConnect is available for Linux, Windows, and MacOS.
|
||||
On Linux make sure NymConnect is executable. Opening a terminal in the same directory and run:
|
||||
```sh
|
||||
chmod +x ./<VERSION>
|
||||
chmod +x ./<YOUR-NYM-CONNECT-VERSION>.AppImage
|
||||
```
|
||||
2. **Start NymConnect**
|
||||
Telegram is added to NymConnect by default.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Introduction
|
||||
|
||||
This is Nym's technical documentation, containing information and setup guides about the various pieces of Nym software such as different Mixnet infrastructure nodes, application clients, and existing applications like the desktop wallet and Mixnet explorer.
|
||||
This is Nym's technical documentation, containing information and setup guides about the various pieces of Nym software such as different mixnet infrastructure nodes, application clients, and existing applications like the desktop wallet and mixnet explorer.
|
||||
|
||||
If you are new to Nym and want to learn about the Mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/) where you can find also our [FAQ section](https://nymtech.net/developers/faq/general-faq.html).
|
||||
If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/) where you can find also our [FAQ section](https://nymtech.net/developers/faq/general-faq.md).
|
||||
|
||||
If you are looking for information and setup guides for the various pieces of Nym Mixnet infrastructure (Mix Nodes, Gateways and Network Requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
|
||||
If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
|
||||
|
||||
If you're specifically looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more - make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
|
||||
If you're specically looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more - make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
|
||||
|
||||
## Popular pages
|
||||
**Network Architecture:**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Binaries
|
||||
|
||||
- [Pre-built Binaries](binaries/pre-built-binaries.md)
|
||||
<!-- - [Binary Initialisation and Configuration](binaries/init-and-config.md) -->
|
||||
- [Binary Initialisation and Configuration](binaries/init-and-config.md)
|
||||
- [Building from Source](binaries/building-nym.md)
|
||||
<!-- - [Version Compatibility Table](binaries/version-compatiblity.md) -->
|
||||
|
||||
|
||||
@@ -4,31 +4,3 @@ The [Github releases page](https://github.com/nymtech/nym/releases) has pre-buil
|
||||
|
||||
If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself.
|
||||
|
||||
## Setup Binaries
|
||||
|
||||
> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
### Download Binary
|
||||
|
||||
1. Open [Github releases page](https://github.com/nymtech/nym/releases) and right click on the binary you want
|
||||
2. Select `Copy Link`
|
||||
3. Open your VPS terminal in a directory where you want to download Nym binaries.
|
||||
4. Download binary by running `wget <BINARY_LINK>` where `<BINARY_LINK>` shall be in your clipboard from point \# 2.
|
||||
|
||||
### Make Executable
|
||||
|
||||
5. Run command:
|
||||
```sh
|
||||
chmod +x <BINARY>
|
||||
# for example: chmod +x nym-mixnode
|
||||
```
|
||||
### Run Binary
|
||||
|
||||
Now you can use your binary, initialise and run your Nym Node. Follow the guide according to the type of your binary.
|
||||
|
||||
**Node setup and usage guides:**
|
||||
|
||||
* [Mix nodes](../nodes/mix-node-setup.md)
|
||||
* [Gateways](../nodes/gateway-setup.md)
|
||||
* [Network requesters](../nodes/network-requester-setup.md)
|
||||
* [Validators](../nodes/validator-setup.md)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## Nym Nodes
|
||||
## Mixnet nodes
|
||||
|
||||
### What determines the rewards when running a Mix Node?
|
||||
### What determines the rewards when running a mix node?
|
||||
|
||||
The stake required for a Mix Node to achieve maximum rewards is called Mix Node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in Mix Nodes.
|
||||
The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes.
|
||||
|
||||
The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes.
|
||||
|
||||
This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more Mix Nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system.
|
||||
This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more mix nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system.
|
||||
|
||||
For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a Mix Node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023.
|
||||
For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023.
|
||||
|
||||
### Which VPS providers would you recommend?
|
||||
|
||||
Consider in which jurisdiction you reside and where do you want to run a Mix Node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Linode, Ghandi, Flokinet and Exoscale. Do your own research and share with the community.
|
||||
Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Linode, Ghandi, Flokinet and Exoscale. Do your own research and share with the community.
|
||||
|
||||
<!---### Why is a mix node setup on a self-hosted machine so tricky?--->
|
||||
|
||||
@@ -22,17 +22,17 @@ Consider in which jurisdiction you reside and where do you want to run a Mix Nod
|
||||
|
||||
The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80).
|
||||
|
||||
### Why a Mix Node and a Gateway cannot be bonded with the same wallet?
|
||||
### Why a mix node and a gateway cannot be bond to the same wallet?
|
||||
|
||||
Because of the way the smart contract works we keep it one-node one-address at the moment.
|
||||
|
||||
### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards?
|
||||
|
||||
Right now only Mix Nodes are rewarded. We're working on Gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do Mix Nodes.
|
||||
Right now only mix nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do mix nodes.
|
||||
|
||||
### Are Mix Nodes whitelisted?
|
||||
### Are mixnodes whitelisted?
|
||||
|
||||
Nope, anyone can run a Mix Node. Purely reliant on the node's reputation (self stake + delegations) & routing score.
|
||||
Nope, anyone can run a mix node. Purely reliant on the node's reputation (self stake + delegations) & routing score.
|
||||
|
||||
## Validators and tokens
|
||||
|
||||
@@ -44,14 +44,6 @@ Nope, anyone can run a Mix Node. Purely reliant on the node's reputation (self s
|
||||
### What's the difference between NYM and NYX?
|
||||
--->
|
||||
|
||||
### Why some Nyx blockchain operations take one hour and others are instant?
|
||||
|
||||
This is based on the definition in [Nym's CosmWasm](https://github.com/nymtech/nym/tree/develop/common/cosmwasm-smart-contracts) smart contracts code.
|
||||
|
||||
Whatever is defined as [a pending epoch event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L35-L103) will get resolved at the end of the current epoch.
|
||||
|
||||
And whatever is defined as [a pending interval event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L145-L172) will get resolved at the end of the current interval.
|
||||
|
||||
### Can I run a validator?
|
||||
|
||||
We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation.
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
> -- Harry Halpin, Nym CEO
|
||||
|
||||
<br>
|
||||
|
||||
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
|
||||
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](./mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
|
||||
|
||||
If any questions are not answered or it's not clear for you in which stage project Smoosh is right now, please reach out in Node Operators [Matrix room](https://matrix.to/#/#operators:nymtech.chat).
|
||||
|
||||
@@ -15,36 +14,33 @@ If any questions are not answered or it's not clear for you in which stage proje
|
||||
|
||||
As we shared in our blog post article [*What does it take to build the wolds most powerful VPN*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6), project Smoosh is:
|
||||
|
||||
> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym Nodes so that the same operator can serve alternately as Mix Node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards.
|
||||
> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as mix node, gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards.
|
||||
> By simplifying the components, adding VPN features and supporting new node operators, the aim is to widen the geographical coverage of nodes and have significant redundancy, meaning plenty of operators to be able to meet demand. This requires strong token economic incentives as well as training and support for new node operators.
|
||||
|
||||
## Technical Questions
|
||||
|
||||
### What are the changes?
|
||||
|
||||
Project Smoosh will have four steps, please follow the table below to track the dynamic progress:
|
||||
Project smoosh will have three steps:
|
||||
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** Combine the `nym-gateway` and `nym-network-requester` into one binary | ✅ done |
|
||||
| **2.** Create [Exit Gateway](../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) | ✅ done |
|
||||
| **3.** Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`. | 🛠️ in progress |
|
||||
| **4.** Adjust reward scheme to incentivise and reward Exit Gateways as a part of `nym-node` binary, implementing [zkNym credentials](https://youtu.be/nLmdsZ1BsQg?t=1717). | 🛠️ in progress |
|
||||
1. Combine the `gateway` and `network-requester` into one binary ✅
|
||||
2. Create [Exit Gateway](../legal/exit-gateway.md): Take the gateway binary including network requester combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) ✅
|
||||
3. Combine all the nodes in the Nym Mixnet into one binary, that is `mixnode`, `gateway` (entry and exit) and `network-requester`.
|
||||
|
||||
These steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Node (`nym-node`) binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc)
|
||||
These three steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Mixnet node binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc)
|
||||
|
||||
### What does it mean for Nym nodes operators?
|
||||
|
||||
We are exploring two potential methods for implementing binary functionality in practice and will provide information in advance. The options are:
|
||||
|
||||
1. Make a selection button (command/argument/flag) for operators to choose whether they want their node to provide all or just some of the functions nodes have in the Nym Mixnet. Nodes functioning as Exit Gateways (in that epoch) will then have bigger rewards due to their larger risk exposure and overhead work with the setup.
|
||||
1. Make a selection button (command/argument/flag) for operators to choose whether they want their node to provide all or just some of the functions nodes have in the Nym Mixnet. Nodes functioning as exit gateways (in that epoch) will then have bigger rewards due to their larger risk exposure and overhead work with the setup.
|
||||
|
||||
2. All nodes will be required to have the Exit Gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as Exit Gateway sometimes as Mix node or Entry Gateway adjusted according the network demand by an algorithm.
|
||||
2. All nodes will be required to have the exit gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as exit gateway sometimes as mix node or entry gateway adjusted according the network demand by an algorithm.
|
||||
|
||||
### Where can I read more about the Exit Gateway setup?
|
||||
### Where can I read more about the exit gateway setup?
|
||||
|
||||
We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around Exit Gateway.
|
||||
We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around exit gateway.
|
||||
|
||||
### What is the change from allow list to deny list?
|
||||
|
||||
@@ -52,17 +48,15 @@ The operators running Gateways would have to “open” their nodes to a wider r
|
||||
|
||||
### How will the Exit policy be implemented?
|
||||
|
||||
Follow the dynamic progress of exit policy implementation on Gateways below:
|
||||
The progression of exit policy on Gateways will have three steps:
|
||||
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering is disabled and the [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network Requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. | ✅ done |
|
||||
| **2.** The exit policy is part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag. | 🛠️ in progress |
|
||||
| **3.** The exit policy is the only option. The `allowed.list` is completely removed. | 🛠️ in progress |
|
||||
1. By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering will be disabled and the current [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. ✅
|
||||
2. Relatively soon the exit policy will be part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag.
|
||||
3. Further down the line, it will be the only option. Then the `allowed.list` will be completely removed.
|
||||
|
||||
Keep in mind the table above only relates to changes happening on Gateways. For the Project Smoosh progress refer to the [table above](./smoosh-faq.md#what-are-the-changes). Whether Exit Gateway functionality will be optional or mandatory part of every active Nym Node depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators).
|
||||
Keep in mind this only relates to changes happening on Gateway and Network Requester side. Whether this will be optional or mandatory depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators).
|
||||
|
||||
### Can I run a Mix Node only?
|
||||
### Can I run a mix node only?
|
||||
|
||||
It depends which [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators) will ultimately be used. In case of the first - yes. In case of the second option, all the nodes will be setup with Exit Gateway functionality turned on.
|
||||
|
||||
@@ -74,7 +68,7 @@ For any specifics on Nym token economics and Nym Mixnet reward system, please re
|
||||
|
||||
### What are the incentives for the node operator?
|
||||
|
||||
In the original setup there were no incentives to run a `nym-network-requester` binary. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic ([`Nym API`](https://github.com/nymtech/nym/tree/master/nym-api) will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
|
||||
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic ([`Nym API`](https://github.com/nymtech/nym/tree/master/nym-api) will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
|
||||
|
||||
### How does this change the token economics?
|
||||
|
||||
@@ -84,9 +78,9 @@ The token economics will stay the same as they are, same goes for the reward alg
|
||||
|
||||
This depends on [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators) chosen. In case of \#1, it will look like this:
|
||||
|
||||
As each operator can choose what roles their nodes provide, the nodes which work as open Gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of Gateways may be exposed to more complication and possible legal risks.
|
||||
As each operator can choose what roles their nodes provide, the nodes which work as open gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of gateways may be exposed to more complication and possible legal risks.
|
||||
|
||||
The nodes which are initialized to run as Mix Nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix Node.
|
||||
The nodes which are initialized to run as mix nodes and gateways will be chosen to be on top of the active set before the ones working only as a mix node.
|
||||
|
||||
I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work.
|
||||
|
||||
@@ -94,21 +88,21 @@ In either way, Nym will share all the specifics beforehand.
|
||||
|
||||
### How will be the staking and inflation after project Smoosh?
|
||||
|
||||
Nym will run tests to count how much payment comes from the users of the Mixnet and if that covers the reward payments. If not, we may need to keep inflation on to secure incentives for high quality Gateways in the early stage of the transition.
|
||||
Nym will run tests to count how much payment comes from the users of the Mixnet and if that covers the reward payments. If not, we may need to keep inflation on to secure incentives for high quality gateways in the early stage of the transition.
|
||||
|
||||
### When project smooth will be launched, it would be the mixmining pool that will pay for the Gateway rewards based on amount of traffic routed ?
|
||||
### When project smooth will be launched, it would be the mixmining pool that will pay for the gateway rewards based on amount of traffic routed ?
|
||||
|
||||
Yes, the same pool. Nym's aim is to do minimal modifications. The only real modification on the smart contract side will be to get into top X of 'active set' operators will need to have open Gateway function enabled.
|
||||
Yes, the same pool. Nym's aim is to do minimal modifications. The only real modification on the smart contract side will be to get into top X of 'active set' operators will need to have open gateway function enabled.
|
||||
|
||||
### What does this mean for the current delegators?
|
||||
|
||||
From an operator standpoint, it shall just be a standard Nym upgrade, a new option to run the Gateway software on your node. Delegators should not have to re-delegate.
|
||||
From an operator standpoint, it shall just be a standard Nym upgrade, a new option to run the gateway software on your node. Delegators should not have to re-delegate.
|
||||
|
||||
## Legal Questions
|
||||
|
||||
### Are there any legal concerns for the operators?
|
||||
|
||||
So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix Nodes, it's very safe as they have "no idea" what packets they are mixing.
|
||||
So far the general line is that running a gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For mix nodes, it's very safe as they have "no idea" what packets they are mixing.
|
||||
|
||||
There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../legal/exit-gateway.md).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Introduction
|
||||
|
||||
This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym Mixnet infrastructure (Mix Node, Gateway and Network Requester) and Nyx blockchain validators.
|
||||
This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym mixnet infrastructure (mix node, gateway and network requester) and Nyx blockchain validators.
|
||||
|
||||
If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/).
|
||||
|
||||
@@ -9,17 +9,18 @@ If you want to dive deeper into Nym's architecture, clients, nodes, and SDK exam
|
||||
|
||||
## Popular pages
|
||||
**Binary Information**
|
||||
* [Building Nym](binaries/building-nym.md)
|
||||
* [Pre-built Binaries](binaries/pre-built-binaries.md)
|
||||
* [Building Nym](./binaries/building-nym.md)
|
||||
* [Pre-built Binaries](./binaries/pre-built-binaries.md)
|
||||
* [Init & Configuration](./binaries/init-and-config.md)
|
||||
|
||||
**Node setup and usage guides:**
|
||||
* [Mix nodes](nodes/mix-node-setup.md)
|
||||
* [Gateways](nodes/gateway-setup.md)
|
||||
* [Network requesters](nodes/network-requester-setup.md)
|
||||
* [Validators](nodes/validator-setup.md)
|
||||
* [Mix nodes](./nodes/mix-node-setup.md)
|
||||
* [Gateways](./nodes/gateway-setup.md)
|
||||
* [Network requesters](./nodes/network-requester-setup.md)
|
||||
* [Validators](./nodes/validator-setup.md)
|
||||
|
||||
**Maintenance, troubleshooting and FAQ**
|
||||
* [Maintenance](nodes/maintenance.md)
|
||||
* [Troubleshooting](nodes/troubleshooting.md)
|
||||
* [FAQ](faq/mixnodes-faq.md)
|
||||
* [Maintenance](./nodes/maintenance.md)
|
||||
* [Troubleshooting](./nodes/troubleshooting.md)
|
||||
* [FAQ](./faq/mixnodes-faq.md)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ This page is a part of Nym Community Legal Forum and its content is composed by
|
||||
|
||||
This document presents an initiative to further support Nym’s mission of allowing privacy for everyone everywhere. This would be achieved with the support of Nym node operators operating Gateways and opening these to any online service. Such setup needs a **clear policy**, one which will remain the **same for all operators** running Nym nodes. The [proposed **Exit policy**](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) is a combination of two existing safeguards: [Tor Null ‘deny’ list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php).
|
||||
|
||||
All the technical changes on the side of Nym nodes - ***Project Smoosh*** - are described in the [FAQ section](../faq/smoosh-faq.md).
|
||||
All the technical changes on the side of Nym nodes - ***Project Smoosh** - are described in the [FAQ section](../faq/smoosh-faq.md).
|
||||
|
||||
```admonish warning
|
||||
Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the operator channels ([Element](https://matrix.to/#/#operators:nymtech.chat), [Discord](https://discord.com/invite/nym), [Telegram](https://t.me/nymchan_help_chat)) to share best practices and experiences.
|
||||
@@ -17,13 +17,13 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions
|
||||
|
||||
## Summary
|
||||
|
||||
* This document outlines a plan to change Nym Gateways from operating with an ‘allow’ to a ‘deny’ list to enable broader uptake and usage of the Nym Mixnet. It provides operators with an overview of the plan, pros and cons, legal as well as technical advice.
|
||||
* This document outlines a plan to change Nym Gateways from operating with an ‘allow’ to a ‘deny’ list to enable broader uptake and usage of the Nym mixnet. It provides operators with an overview of the plan, pros and cons, legal as well as technical advice.
|
||||
|
||||
* Nym is committed to ensuring privacy for all users, regardless of their location and for the broadest possible range of online services. In order to achieve this aim, the Nym Mixnet needs to increase its usability across a broad range of apps and services.
|
||||
* Nym is committed to ensuring privacy for all users, regardless of their location and for the broadest possible range of online services. In order to achieve this aim, the Nym mixnet needs to increase its usability across a broad range of apps and services.
|
||||
|
||||
* Currently, Nym Gateway nodes only enable access to apps and services that are on an ‘allow’ list that is maintained by the core team.
|
||||
|
||||
* To decentralise and enable privacy for a broader range of services, this initiative will have to transition from the current ‘allow’ list to a ‘deny’ list - [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). In accordance with the [Tor Null 'deny' list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php), which are two established safeguards.
|
||||
* To decentralise and enable privacy for a broader range of services, this initiative will have to transition from the current ‘allow’ list to a ‘deny’ list - [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). In accordance with the [Tor Null 'deny' list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php), which are two established safeguards.
|
||||
|
||||
* This will enhance the usage and appeal of Nym products for end users. As a result, increased usage will ultimately lead to higher revenues for Nym operators.
|
||||
|
||||
@@ -40,7 +40,7 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions
|
||||
|
||||
To offer a better and more private everyday experience for its users, Nym would like them to use any online services they please, without limiting its access to a few messaging apps or crypto wallets.
|
||||
|
||||
To achieve this, operators running Exit Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt).
|
||||
To achieve this, operators running exit gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt).
|
||||
|
||||
## Pros and cons of the initiative
|
||||
|
||||
@@ -64,23 +64,23 @@ The new setup: Running nodes supporting traffic of any online service (with safe
|
||||
| Operational | | - Higher operational overhead, such as dealing with DMCA / abuse complaints, managing the VPS provider questions, or helping the community to maintain the denylist <br>- Administrative overhead if running nodes as a company or an entity |
|
||||
| Legal | | - Ideally requires to check legal environment with local privacy association or lawyer | Financial | - Higher revenue potential for operators due to the increase in network usage | - If not running VPS with an unlimited bandwidth plan, higher costs due to higher network usage |
|
||||
|
||||
## Exit Gateways: New setup
|
||||
## Exit gateways: New setup
|
||||
|
||||
In our previous technical setup, Network Requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network Requester operator.
|
||||
In our previous technical setup, network requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network requester operator.
|
||||
|
||||
This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of Network Requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts.
|
||||
This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of network requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts.
|
||||
|
||||
The principal change in the new configuration is to make this short allow list more permissive. Nym's [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app).
|
||||
The principal change in the new configuration is to make this short allow list more permissive. Nym's [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app).
|
||||
|
||||
As of now we the Gateways will be defaulted to a combination of [Tor Null ‘deny’ list](https://tornull.org/) (note: Not affiliated with Tor) - reproduction permitted under Creative Commons Attribution 3.0 United States License which is IP-based, e.g., `ExitPolicy reject 5.188.10.0/23:*` and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php). Whether we will stick with this list, do modifications or compile another one is still a subject of discussion. In all cases, this policy will remain the same for all the nodes, without any option to modify it by Nym node operators to secure stable and reliable service for the end users.
|
||||
As of now we the gateways will be defaulted to a combination of [Tor Null ‘deny’ list](https://tornull.org/) (note: Not affiliated with Tor) - reproduction permitted under Creative Commons Attribution 3.0 United States License which is IP-based, e.g., `ExitPolicy reject 5.188.10.0/23:*` and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php). Whether we will stick with this list, do modifications or compile another one is still a subject of discussion. In all cases, this policy will remain the same for all the nodes, without any option to modify it by Nym node operators to secure stable and reliable service for the end users.
|
||||
|
||||
For exit relays on ports 80 and 443, the Gateways will exhibit an HTML page resembling the one proposed by [Tor](https://gitlab.torproject.org/tpo/core/tor/-/raw/HEAD/contrib/operator-tools/tor-exit-notice.html). By doing so, the operator will be able to disclose details regarding their Gateway, including the currently configured exit policy, all without the need for direct correspondence with regulatory or law enforcement agencies. It also makes the behavior of Exit Gateways transparent and even computable (a possible feature would be to offer a machine readable form of the notice in JSON or YAML).
|
||||
For exit relays on ports 80 and 443, the gateways will exhibit an HTML page resembling the one proposed by [Tor](https://gitlab.torproject.org/tpo/core/tor/-/raw/HEAD/contrib/operator-tools/tor-exit-notice.html). By doing so, the operator will be able to disclose details regarding their gateway, including the currently configured exit policy, all without the need for direct correspondence with regulatory or law enforcement agencies. It also makes the behaviour of exit gateways transparent and even computable (a possible feature would be to offer a machine readable form of the notice in JSON or YAML).
|
||||
|
||||
We also recommend operators to check the technical advice from [Tor](https://community.torproject.org/relay/setup/exit/).
|
||||
|
||||
## Tor legal advice
|
||||
|
||||
Giving the legal similarity between Nym Exit Gateways and Tor Exit Relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page.
|
||||
Giving the legal similarity between Nym exit gateways and Tor exit relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page.
|
||||
|
||||
Note that Tor states:
|
||||
> This FAQ is for informational purposes only and does not constitute legal advice.
|
||||
@@ -88,7 +88,7 @@ Note that Tor states:
|
||||
*Check legal advice prior to running an exit relay*
|
||||
|
||||
* Understand the risks associated with running an exit relay; E.g., know legal paragraphs relevant in the country of operations:
|
||||
- US [DMCA 512](https://www.law.cornell.edu/uscode/text/17/512); see [EFF's Legal FAQ for Tor Operators](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq) (a very good and relevant read for other countries as well)
|
||||
- US [DMCA 512](https://www.law.cornell.edu/uscode/text/17/512); see [EFF's Legal FAQ for TOr Operators](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq) (a very good and relevant read for other countries as well)
|
||||
- Germany’s [TeleMedienGesetz 8](http://www.gesetze-im-internet.de/tmg/__8.html) and [15](http://www.gesetze-im-internet.de/tmg/__15.html)
|
||||
- Netherlands: [Artikel 6:196c BW](http://wetten.overheid.nl/BWBR0005289/Boek6/Titel3/Afdeling4A/Artikel196c/)
|
||||
- Austria: [E-Commerce-Gesetz 13](http://www.ris.bka.gv.at/Dokument.wxe?Abfrage=Bundesnormen&Dokumentnummer=NOR40025809)
|
||||
@@ -96,7 +96,7 @@ Note that Tor states:
|
||||
* Top 3 advice
|
||||
- Have an abuse response letter
|
||||
- Run relay from a location that is not home
|
||||
- Read through the legal resources that Tor-supportive lawyers put together: [www.eff.org/pages/legal-faq-tor-relay-operators](https://www.eff.org/pages/legal-faq-tor-relay-operators) or [www.noisebridge.net/wiki/Noisebridge_Tor/FBI](https://www.noisebridge.net/wiki/Noisebridge_Tor/FBI)
|
||||
- Read through the legal resources that Tor-supportive lawyers put together: https://www.eff.org/pages/legal-faq-tor-relay-operators or https://www.noisebridge.net/wiki/Noisebridge_Tor/FBI
|
||||
* Consult a lawyer / local digital rights association / the EFF prior to operating an exit relay, especially in a place where exit relay operators have been harassed or not operating before. Note that Tor DOES NOT provide legal advice for specific countries. It only provides general advice (itself or in partnership), eventually skewed towards [US audiences](https://www.eff.org/pages/legal-faq-tor-relay-operators).
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `n
|
||||
|
||||
## Preliminary steps
|
||||
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Gateway.
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your gateway.
|
||||
|
||||
|
||||
## Gateway setup
|
||||
@@ -50,7 +50,7 @@ You can also check the various arguments required for individual commands with:
|
||||
|
||||
## Initialising your Gateway
|
||||
|
||||
As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with inbuilt Network Requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries.
|
||||
As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with in-build Network requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries.
|
||||
|
||||
```admonish warning
|
||||
Before you start an Exit Gateway, read our [Operators Legal Forum](../legal/exit-gateway.md) page and [*Project Smoosh FAQ*](../faq/smoosh-faq.md).
|
||||
@@ -60,21 +60,19 @@ Before you start an Exit Gateway, read our [Operators Legal Forum](../legal/exit
|
||||
There has been an ongoing development with dynamic upgrades. Follow the status of the Project Smoosh [changes](../faq/smoosh-faq.md#what-are-the-changes) and the progression state of exit policy [implementation](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented) to be up to date with the current design.
|
||||
```
|
||||
|
||||
**Note:** Due to the development towards Exit Gateway functionality the `--host` flag has been replaced with `--listening-address`, this is the IP address which is used for receiving sphinx packets and listening to client data. Another flag `--public-ips` is required; it’s a comma separated list of IP’s that are announced to the `nym-api`, it is usually the address which is used for bonding.
|
||||
|
||||
### Initialising Exit Gateway
|
||||
|
||||
An operator can initialise the Exit Gateway functionality by adding Network Requester with the new exit policy option:
|
||||
An operator can initialise the Exit Gateway functionality by adding Network requester with the new exit policy option:
|
||||
|
||||
```
|
||||
./nym-gateway init --id <ID> --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" --with-network-requester --with-exit-policy true
|
||||
./nym-gateway init --id <ID> --host $(curl -4 https://ifconfig.me) --with-network-requester --with-exit-policy true
|
||||
```
|
||||
|
||||
If we follow the previous example with `<ID>` chosen `superexitgateway`, adding the `--with-network-requester` and `--with-exit-policy` flags, the outcome will be:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id superexitgateway --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" --with-network-requester --with-exit-policy true -->
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id superexitgateway --host $(curl -4 https://ifconfig.me) --with-network-requester --with-exit-policy true -->
|
||||
```
|
||||
~~~
|
||||
|
||||
@@ -82,9 +80,9 @@ You can see that the printed information besides *identity* and *sphinx keys* al
|
||||
|
||||
Additionally
|
||||
|
||||
#### Add Network Requester to an existing Gateway
|
||||
#### Add Network requester to an existing Gateway
|
||||
|
||||
If you already [upgraded](./maintenance.md#upgrading-your-node) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network Requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`.
|
||||
If you already [upgraded](./maintenance.md#upgrading-your-node) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`.
|
||||
|
||||
See the options:
|
||||
|
||||
@@ -104,7 +102,7 @@ To setup Exit Gateway functionality with our new [exit policy](https://nymtech.n
|
||||
./nym-gateway setup-network-requester --enabled true --with-exit-policy true --id <ID>
|
||||
```
|
||||
|
||||
Say we have a Gateway with `<ID>` as `new-gateway`, originally initialised and ran without the Exit Gateway functionality. To change the setup, run:
|
||||
Say we have a gateway with `<ID>` as `new-gateway`, originally initialised and ran without the Exit Gateway functionality. To change the setup, run:
|
||||
|
||||
|
||||
```
|
||||
@@ -114,7 +112,7 @@ Say we have a Gateway with `<ID>` as `new-gateway`, originally initialised and r
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun rm -rf $HOME/.nym/gateways/new-gateway -->
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id new-gateway --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" && ../../../../target/release/nym-gateway setup-network-requester --enabled true --with-exit-policy true --id new-gateway -->
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id new-gateway --host $(curl -4 https://ifconfig.me) && ../../../../target/release/nym-gateway setup-network-requester --enabled true --with-exit-policy true --id new-gateway -->
|
||||
```
|
||||
~~~
|
||||
|
||||
@@ -122,13 +120,13 @@ In case there are any unexpected problems, you can also change it manually by ed
|
||||
|
||||
```
|
||||
[network_requester]
|
||||
# Specifies whether Network Requester service is enabled in this process.
|
||||
# Specifies whether network requester service is enabled in this process.
|
||||
enabled = true
|
||||
```
|
||||
|
||||
Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit Gateway.
|
||||
Save, exit and restart your gateway. Now you are an operator of post-smooshed Exit gateway.
|
||||
|
||||
#### Enable Nym exit policy to an existing Gateway with Network Requester functionality
|
||||
#### Enable Nym exit policy to an existing Gateway with Network requester functionality
|
||||
|
||||
In case you already added Network Requester functionality to your Gateway as described above but haven't enabled the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) there is an easy tweak to do so and turn your node into [Nym Exit Gateway](../faq/smoosh-faq.md#what-are-the-changes).
|
||||
|
||||
@@ -136,18 +134,18 @@ Open the config file stored at `.nym/gateways/<ID>/config/network_requester_conf
|
||||
```sh
|
||||
use_deprecated_allow_list = false
|
||||
```
|
||||
Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit gateway.
|
||||
Save, exit and restart your gateway. Now you are an operator of post-smooshed Exit gateway.
|
||||
|
||||
```admonish info
|
||||
All information about Network Requester part of your Exit Gateway is in `/home/user/.nym/gateways/<ID>/config/network_requester_config.toml`.
|
||||
All information about network requester part of your Exit Gateway is in `/home/user/.nym/gateways/<ID>/config/network_requester_config.toml`.
|
||||
```
|
||||
|
||||
For now you can run Gateway without Network Requester or with and without the new exit policy. This will soon change as we inform in our [Project Smoosh FAQ](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented).
|
||||
For now you can run Gateway without Network requester or with and without the new exit policy. This will soon change as we inform in our [Project Smoosh FAQ](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented).
|
||||
|
||||
To read more about the configuration like whitelisted outbound requesters in `allowed.list` and other useful information, see the page [*Network Requester whitelist*](network-requester-setup.md#using-your-network-requester).
|
||||
To read more about the configuration like whitelisted outbound requesters in `allowed.list` and other useful information, see the page [*Network requester whitelist*](network-requester-setup.md#using-your-network-requester).
|
||||
|
||||
|
||||
#### Initialising Gateway without Network Requester
|
||||
#### Initialising Gateway without Network requester
|
||||
|
||||
In case you don't want to run your Gateway with the Exit Gateway functionality, you still can run a simple Gateway.
|
||||
|
||||
@@ -163,50 +161,42 @@ To check available configuration options use:
|
||||
```
|
||||
~~~
|
||||
|
||||
The following command returns a Gateway on your current IP with the `<ID>` of `simple-gateway`:
|
||||
The following command returns a gateway on your current IP with the `<ID>` of `simple-gateway`:
|
||||
|
||||
```
|
||||
./nym-gateway init --id simple-gateway --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)"
|
||||
./nym-gateway init --id simple-gateway --host $(curl -4 https://ifconfig.me)
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id simple-gateway --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" -->
|
||||
<!-- cmdrun ../../../../target/release/nym-gateway init --id simple-gateway --host $(curl -4 https://ifconfig.me) -->
|
||||
```
|
||||
~~~
|
||||
|
||||
The `$(curl -4 https://ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually if you wish. If you do this, remember to enter your IP **without** any port information.
|
||||
|
||||
## Running your Gateway
|
||||
|
||||
The `run` command starts the Gateway:
|
||||
|
||||
```
|
||||
./nym-gateway run --id <ID>
|
||||
```
|
||||
|
||||
|
||||
## Bonding your Gateway
|
||||
### Bonding your gateway
|
||||
|
||||
```admonish info
|
||||
Before you bond your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your Gateway can be reached from the outside. You can also setup [WSS on your Gateway](./maintenance.md#run-web-secure-socket-wss-on-gateway) and [automate](./maintenance.md#vps-setup-and-automation) your Gateway to simplify the operation overhead. We highly recommend to run ny of these steps before bonding to prevent disruption of your Gateway's routing score later on.
|
||||
Before you bond and re-run your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your gateway can be reached from the outside. You can also setup WSS on your Gateway, the steps are on the [Maintenance page](./maintenance.md#configure-your-firewall) below.
|
||||
```
|
||||
|
||||
### Via the Desktop wallet (recommended)
|
||||
#### Via the Desktop wallet
|
||||
|
||||
You can bond your Gateway via the Desktop wallet. Make sure your Gateway is running and follow the steps below:
|
||||
You can bond your gateway via the Desktop wallet.
|
||||
|
||||
1. Open your wallet, and head to the `Bonding` page, then select the node type `Gateway` and input your node details. Press `Next`.
|
||||
|
||||
2. Enter the `Amount`, `Operating cost` and press `Next`.
|
||||
|
||||
3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature `<PAYLOAD_GENERATED_BY_THE_WALLET>` and paste it as a value of `--contract-msg` in the following command:
|
||||
3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it.
|
||||
|
||||
```
|
||||
./nym-gateway sign --id <YOUR_ID> --contract-msg <PAYLOAD_GENERATED_BY_THE_WALLET>
|
||||
```
|
||||
|
||||
It will look something like this (as `<YOUR_ID>` we used `supergateway`):
|
||||
It will look something like this:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
@@ -219,38 +209,40 @@ It will look something like this (as `<YOUR_ID>` we used `supergateway`):
|
||||
|_| |_|\__, |_| |_| |_|
|
||||
|___/
|
||||
|
||||
(nym-gateway - version v1.1.<XX>)
|
||||
(nym-gateway - version v1.1.31)
|
||||
|
||||
|
||||
>>> attempting to sign 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a
|
||||
>>> decoding the message...
|
||||
>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"gateway-bonding","content":{"sender":"n1ewmme88q22l8syvgshqma02jv0vqrug9zq9dy8","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"gateway":{"host":"62.240.134.189","mix_port":1789,"clients_port":9000,"location":"62.240.134.189","sphinx_key":"FKbuN7mPdoCG9jA3CkAfXxC5X4rHhqeMVtmfRtJ3cFZd","identity_key":"3RoAhR8gEdfBETMjm2vbMFzKddxXDdE9ygBAnJHWqSzD","version":"1.1.13"}}}}
|
||||
>>> The base58-encoded signature is:
|
||||
2SPDjLjX4b6XEtkgG7yD8Znsb1xycL1edFvRK4JcVnPsM9k6HXEUUeVS6rswRiYxoj1bMgiRKyPDwiksiuyxu8Xi
|
||||
```
|
||||
~~~
|
||||
|
||||
* Copy the resulting signature:
|
||||
|
||||
```sh
|
||||
# >>> The base58-encoded signature is:
|
||||
```
|
||||
>>> The base58-encoded signature is:
|
||||
2SPDjLjX4b6XEtkgG7yD8Znsb1xycL1edFvRK4JcVnPsM9k6HXEUUeVS6rswRiYxoj1bMgiRKyPDwiksiuyxu8Xi
|
||||
```
|
||||
|
||||
* And paste it into the wallet nodal, press `Next` and confirm the transaction.
|
||||
|
||||

|
||||
*This image is just an example, copy-paste your own base58-encoded signature*
|
||||

|
||||
|
||||
* Your Gateway is now bonded.
|
||||
* Your gateway is now bonded.
|
||||
|
||||
> You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks.
|
||||
|
||||
### Via the CLI (power users)
|
||||
#### Via the CLI (power users)
|
||||
If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs.
|
||||
|
||||
If you want to bond your Gateway via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs.
|
||||
### Running your gateway
|
||||
The `run` command starts the gateway:
|
||||
|
||||
```
|
||||
./nym-gateway run --id <ID>
|
||||
```
|
||||
## Maintenance
|
||||
|
||||
For Gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation, WSS setup and more, see the [maintenance page](./maintenance.md)
|
||||
For gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md)
|
||||
|
||||
|
||||
@@ -16,38 +16,27 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu
|
||||
|
||||
## Upgrading your node
|
||||
|
||||
> The process is the similar for Mix Node, Gateway and Network Requester. In the following steps we use a placeholder `<NODE>` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included.
|
||||
> The process is the similar for mix node, gateway and network requester. In the following steps we use a placeholder `<NODE>` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included.
|
||||
|
||||
Upgrading your node is a two-step process:
|
||||
* Updating the binary and `~/.nym/<NODE>/<YOUR_ID>/config/config.toml` on your VPS
|
||||
* Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**.
|
||||
|
||||
### Step 1: Upgrading your binary
|
||||
Follow these steps to upgrade your Node binary and update its config file:
|
||||
* Pause your node process.
|
||||
- if you see the terminal window with your node, press `ctrl + c`
|
||||
- if you run it as `systemd` service, run: `systemctl stop nym-<NODE>.service`
|
||||
* Replace the existing `<NODE>` binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)).
|
||||
* Re-run `init` with the same values as you used initially for your `<NODE>` ([Mix Node](./mix-node-setup.md#initialising-your-mix-node), [Gateway](./gateway-setup.md#initialising-your-gateway)) . **This will just update the config file, it will not overwrite existing keys**.
|
||||
* Restart your node process with the new binary:
|
||||
- if your node is not automitized, just `run` your `<NODE>` with `./nym-<NODE> run --id <ID>`. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway).
|
||||
- if you automatized your node via systemd (recommended) run:
|
||||
```sh
|
||||
systemctl daemon-reload # to pickup the new unit file
|
||||
systemctl start nym-<NODE>.service
|
||||
journalctl -f -u <NODE>.service # to monitor log of you node
|
||||
```
|
||||
Follow these steps to upgrade your mix node binary and update its config file:
|
||||
* pause your mix node process.
|
||||
* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)).
|
||||
* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**.
|
||||
* restart your mix node process with the new binary.
|
||||
|
||||
If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539).
|
||||
|
||||
> In case of a Network Requester this is all, the following step is only for Mix Nodes and Gateways.
|
||||
> In case of a network requester this is all all, the following step is only for mix nodes and gateways.
|
||||
|
||||
### Step 2: Updating your node information in the smart contract
|
||||
Follow these steps to update the information about your `<NODE>` which is publicly available from the [`nym-api`](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [Mixnet explorer](https://explorer.nymtech.net).
|
||||
Follow these steps to update the information about your `<NODE>` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net).
|
||||
|
||||
You can either do this graphically via the Desktop Wallet, or the CLI.
|
||||
|
||||
### Updating node information via the Desktop Wallet (recommended)
|
||||
### Updating node information via the Desktop Wallet
|
||||
* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner:
|
||||
|
||||

|
||||
@@ -64,9 +53,9 @@ If you want to bond your `<NODE>` via the CLI, then check out the [relevant sect
|
||||
|
||||
In the previous version of the network-requester, users were required to run a nym-client along side it to function. As of `v1.1.10`, the network-requester now has a nym client embedded into the binary, so it can run standalone.
|
||||
|
||||
If you are running an existing Network Requester registered with nym-connect, upgrading requires you move your old keys over to the new Network Requester configuration. We suggest following these instructions carefully to ensure a smooth transition.
|
||||
If you are running an existing network requester registered with nym-connect, upgrading requires you move your old keys over to the new network requester configuration. We suggest following these instructions carefully to ensure a smooth transition.
|
||||
|
||||
Initiate the new Network Requester:
|
||||
Initiate the new network requester:
|
||||
|
||||
```sh
|
||||
nym-network-requester init --id <YOUR_ID>
|
||||
@@ -195,13 +184,13 @@ exit 0
|
||||
|
||||
```
|
||||
|
||||
Although your Gateway is Now ready to use its `wss_port`, your server may not be ready - the following commands will allow you to set up a properly configured firewall using `ufw`:
|
||||
Although your gateway is Now ready to use its `wss_port`, your server may not be ready - the following commands will allow you to set up a properly configured firewall using `ufw`:
|
||||
|
||||
```sh
|
||||
ufw allow 9001/tcp
|
||||
```
|
||||
|
||||
Lastly don't forget to restart your Gateway, now the API will render the WSS details for this Gateway:
|
||||
Lastly don't forget to restart your Gateway, now the API will render the WSS details for this gateway:
|
||||
|
||||
|
||||
### WSS on a new Gateway
|
||||
@@ -214,7 +203,7 @@ Another flag `--public-ips` is required; it's a comma separated list of IP’s t
|
||||
|
||||
If the operator wishes to run WSS, an optional `--hostname` flag is also required, that can be something like `mainnet-gateway2.nymtech.net`. Make sure to enable all necessary [ports](maintenance.md#configure-your-firewall) on the Gateway.
|
||||
|
||||
The Gateway will then be accessible on something like: *http://85.159.211.99:8080/api/v1/swagger/index.html*
|
||||
The gateway will then be accessible on something like: *http://85.159.211.99:8080/api/v1/swagger/index.html*
|
||||
|
||||
Are you seeing something like: *this node attempted to announce an invalid public address: 0.0.0.0.*?
|
||||
|
||||
@@ -247,7 +236,7 @@ sudo ufw status
|
||||
Finally open your `<NODE>` p2p port, as well as ports for ssh and ports for verloc and measurement pings:
|
||||
|
||||
```sh
|
||||
# for Mix Node, Gateway and Network Requester
|
||||
# for mix node, gateway and network requester
|
||||
sudo ufw allow 1789,1790,8000,9000,9001,22/tcp
|
||||
|
||||
# In case of reverse proxy for the Gateway swagger page add:
|
||||
@@ -268,7 +257,7 @@ For more information about your node's port configuration, check the [port refer
|
||||
|
||||
### Automating your node with nohup, tmux and systemd
|
||||
|
||||
Although it’s not totally necessary, it's useful to have the Mix Node automatically start at system boot time.
|
||||
Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time.
|
||||
|
||||
#### nohup
|
||||
|
||||
@@ -298,7 +287,7 @@ In case it didn't work for your distribution, see how to build `tmux` from [vers
|
||||
|
||||
**Running tmux**
|
||||
|
||||
No when you installed tmux on your VPS, let's run a Mix Node on tmux, which allows you to detach your terminal and let your `<NODE>` run on its own on the VPS.
|
||||
No when you installed tmux on your VPS, let's run a mix node on tmux, which allows you to detach your terminal and let your `<NODE>` run on its own on the VPS.
|
||||
|
||||
* Pause your `<NODE>`
|
||||
* Start tmux with the command
|
||||
@@ -321,7 +310,7 @@ tmux attach-session
|
||||
|
||||
Here's a systemd service file to do that:
|
||||
|
||||
##### For Mix Node
|
||||
##### For mix node
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
@@ -365,7 +354,7 @@ WantedBy=multi-user.target
|
||||
|
||||
* Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`.
|
||||
|
||||
##### For Network Requester
|
||||
##### For Network requester
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
@@ -444,20 +433,20 @@ systemctl daemon-reload # to pickup the new unit file
|
||||
```
|
||||
|
||||
```sh
|
||||
# for Mix Node
|
||||
# for mix node
|
||||
systemctl enable nym-mixnode.service
|
||||
|
||||
# for Gateway
|
||||
# for gateway
|
||||
systemctl enable nym-gateway.service
|
||||
```
|
||||
|
||||
Start your node:
|
||||
|
||||
```sh
|
||||
# for Mix Node
|
||||
# for mix node
|
||||
service nym-mixnode start
|
||||
|
||||
# for Gateway
|
||||
# for gateway
|
||||
service nym-gateway start
|
||||
|
||||
```
|
||||
@@ -488,7 +477,7 @@ This lets your operating system know it's ok to reload the service configuration
|
||||
|
||||
Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`.
|
||||
|
||||
`ulimit` is 1024 by default on most systems. It needs to be set higher, because Mix Nodes make and receive a lot of connections to other nodes.
|
||||
`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes.
|
||||
|
||||
If you see errors such as:
|
||||
|
||||
@@ -502,12 +491,12 @@ This means that the operating system is preventing network connections from bein
|
||||
|
||||
> Replace `<NODE>` variable with `nym-mixnode`, `nym-gateway` or `nym-network-requester` according the node you running on your machine.
|
||||
|
||||
The ulimit setup is relevant for maintenance of Nym Mix Node only.
|
||||
The ulimit setup is relevant for maintenance of nym mix node only.
|
||||
|
||||
Query the `ulimit` of your `<NODE>` with:
|
||||
|
||||
```sh
|
||||
# for nym-mixnode, nym-gateway and nym-network-requester:
|
||||
# for nym-mixnode, nym-gateway and nym-network requester:
|
||||
grep -i "open files" /proc/$(ps -A -o pid,cmd|grep <NODE> | grep -v grep |head -n 1 | awk '{print $1}')/limits
|
||||
|
||||
# for nyx validator:
|
||||
@@ -544,7 +533,7 @@ echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf
|
||||
|
||||
Reboot your machine and restart your node. When it comes back, use:
|
||||
```sh
|
||||
# for nym-mixnode, nym-gateway and nym-network-requester:
|
||||
# for nym-mixnode, nym-gateway and nym-network requester:
|
||||
cat /proc/$(pidof <NODE>)/limits | grep "Max open files"
|
||||
|
||||
# for validator
|
||||
@@ -554,7 +543,7 @@ Make sure the limit has changed to 65535.
|
||||
|
||||
#### Set the ulimit on `non-systemd` based distributions
|
||||
|
||||
In case you chose tmux option for Mix Node automation, see your `ulimit` list by running:
|
||||
In case you chose tmux option for mix node automatization, see your `ulimit` list by running:
|
||||
|
||||
```sh
|
||||
ulimit -a
|
||||
@@ -579,13 +568,13 @@ username hard nofile 4096
|
||||
username soft nofile 4096
|
||||
```
|
||||
|
||||
Then reboot your server and restart your Mix Node.
|
||||
Then reboot your server and restart your mix node.
|
||||
|
||||
## Moving a node
|
||||
|
||||
In case of a need to move a node from one machine to another and avoiding to lose the delegation, here are few steps how to do it.
|
||||
|
||||
The following examples transfers a Mix Node (in case of other nodes, change the `mixnodes` in the command for the `<NODE>` of your desire.
|
||||
The following examples transfers a mix node (in case of other nodes, change the `mixnodes` in the command for the `<NODE>` of your desire.
|
||||
|
||||
* Pause your node process.
|
||||
|
||||
@@ -598,7 +587,7 @@ Assuming both machines are remote VPS.
|
||||
# in case none of the nym configs was created previously
|
||||
mkdir ~/.nym
|
||||
|
||||
#in case no nym Mix Node was initialized previously
|
||||
#in case no nym mix node was initialized previously
|
||||
mkdir ~/.nym/mixnodes
|
||||
```
|
||||
* Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running:
|
||||
@@ -625,29 +614,29 @@ ens4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1460
|
||||
|
||||
The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`.
|
||||
|
||||
`./nym-mixnode init --host 10.126.5.7`, initalises the Mix Node, but no packets will be routed because `10.126.5.7` is not on the public internet.
|
||||
`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet.
|
||||
|
||||
Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the Mix Node doesn't know how to bind to a host that's not in the output of `ifconfig`.
|
||||
Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`.
|
||||
|
||||
The right thing to do in this situation is to init with a command:
|
||||
```sh
|
||||
./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18
|
||||
```
|
||||
|
||||
This will bind the Mix Node to the available host `10.126.5.7`, but announce the Mix Node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly.
|
||||
This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly.
|
||||
|
||||
To find the right IP configuration, contact your VPS provider for support.
|
||||
|
||||
## Nym API (previously 'Validator API') endpoints
|
||||
Numerous API endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer.
|
||||
|
||||
### Mix Node Reward Estimation API endpoint
|
||||
### Mix node Reward Estimation API endpoint
|
||||
|
||||
The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.
|
||||
The Reward Estimation API endpoint allows mix node operators to estimate the rewards they could earn for running a Nym mix node with a specific `MIX_ID`.
|
||||
|
||||
> The `<MIX_ID>` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active).
|
||||
|
||||
The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.
|
||||
The endpoint is a particularly common for mix node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mix node, the quality of the mix node's performance, and the overall demand for mixnodes in the network. This information can be useful for mix node operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability.
|
||||
|
||||
Using this API endpoint returns information about the Reward Estimation:
|
||||
|
||||
@@ -668,15 +657,15 @@ Query Response:
|
||||
|
||||
> The unit of value is measured in `uNYM`.
|
||||
|
||||
- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node.
|
||||
- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node.
|
||||
|
||||
- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network.
|
||||
- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network.
|
||||
|
||||
- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network.
|
||||
- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network.
|
||||
|
||||
- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.
|
||||
- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.
|
||||
|
||||
- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node.
|
||||
- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node.
|
||||
|
||||
### Validator: Installing and configuring nginx for HTTPS
|
||||
#### Setup
|
||||
@@ -796,7 +785,7 @@ go_memstats_gc_sys_bytes 1.3884192e+07
|
||||
## Ports
|
||||
All `<NODE>`-specific port configuration can be found in `$HOME/.nym/<NODE>/<YOUR_ID>/config/config.toml`. If you do edit any port configs, remember to restart your client and node processes.
|
||||
|
||||
### Mix Node port reference
|
||||
### Mix node port reference
|
||||
| Default port | Use |
|
||||
| ------------ | ------------------------- |
|
||||
| `1789` | Listen for Mixnet traffic |
|
||||
@@ -811,7 +800,7 @@ All `<NODE>`-specific port configuration can be found in `$HOME/.nym/<NODE>/<YOU
|
||||
| `9000` | Listen for Client traffic |
|
||||
| `9001` | WSS |
|
||||
|
||||
### Network Requester port reference
|
||||
### Network requester port reference
|
||||
|
||||
| Default port | Use |
|
||||
|--------------|---------------------------|
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Mix Nodes
|
||||
|
||||
> The Nym Mix Node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first.
|
||||
> The Nym mix node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first.
|
||||
|
||||
> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
@@ -13,11 +13,11 @@ The `nym-mix node` binary is currently one point version ahead of the rest of th
|
||||
|
||||
## Preliminary steps
|
||||
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Mix Node.
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mix node.
|
||||
|
||||
## Mix node setup
|
||||
|
||||
Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your Mix Node with the instructions below.
|
||||
Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your mix node with the instructions below.
|
||||
|
||||
To begin, move to `/target/release` directory from which you run the node commands:
|
||||
|
||||
@@ -49,7 +49,7 @@ You can also check the various arguments required for individual commands with:
|
||||
|
||||
> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.
|
||||
|
||||
### Initialising your Mix Node
|
||||
### Initialising your mix node
|
||||
|
||||
To check available configuration options for initializing your node use:
|
||||
|
||||
@@ -59,30 +59,125 @@ To check available configuration options for initializing your node use:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --help -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --help -->
|
||||
```
|
||||
~~~
|
||||
|
||||
Initialise your Mix Node with the following command, replacing the value of `--id` with the moniker you wish to give your Mix Node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information.
|
||||
Initalise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information.
|
||||
|
||||
```
|
||||
./nym-mixnode init --id <YOUR_ID> --host $(curl -4 https://ifconfig.me)
|
||||
./nym-mixnode init --id <NODE_NAME> --host $(curl -4 https://ifconfig.me)
|
||||
```
|
||||
If `<YOUR_ID>` was `my-node`, the output shall look like like this:
|
||||
|
||||
<!---serinko: The automatized command did not work, printing the output manually--->
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --id my-node --host $(curl -4 https://ifconfig.me) -->
|
||||
.nym-mixnode init --id <YOUR_ID> --host $(curl -4 https://ifconfig.me) --wallet-address <WALLET_ADDRESS>
|
||||
|
||||
|
||||
Initialising mixnode <YOUR_ID>...
|
||||
Saved mixnet identity and sphinx keypairs
|
||||
2023-06-04T08:20:32.862Z INFO nym_config > Configuration file will be saved to "/home/<USER>/.nym/mixnodes/<YOUR_ID>/config/config.toml"
|
||||
Saved configuration file to "/home/<USER>/.nym/mixnodes/<YOUR_ID>/config/config.toml"
|
||||
Mixnode configuration completed.
|
||||
|
||||
_ __ _ _ _ __ ___
|
||||
| '_ \| | | | '_ \ _ \
|
||||
| | | | |_| | | | | | |
|
||||
|_| |_|\__, |_| |_| |_|
|
||||
|___/
|
||||
|
||||
(nym-mixnode - version v1.1.29)
|
||||
|
||||
|
||||
Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"v1.1.29"},"cost_params
|
||||
Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z
|
||||
Host: 62.240.134.189 (bind address: 62.240.134.189)
|
||||
Version: v1.1.29
|
||||
Mix Port: 1789, Verloc port: 1790, Http Port: 8000
|
||||
```
|
||||
~~~
|
||||
|
||||
> The `init` command will refuse to destroy existing Mix Node keys.
|
||||
> The `init` command will refuse to destroy existing mix node keys.
|
||||
|
||||
During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes/<YOUR_ID>/`.
|
||||
|
||||
### Bonding your mix node
|
||||
|
||||
```admonish caution
|
||||
From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**.
|
||||
```
|
||||
|
||||
#### Bond via the Desktop wallet (recommended)
|
||||
|
||||
You can bond your mix node via the Desktop wallet.
|
||||
|
||||
* Open your wallet, and head to the `Bond` page, then select the node type `Mixnode` and input your node details. Press `Next`.
|
||||
|
||||
* Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`.
|
||||
|
||||
* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it.
|
||||
|
||||
```
|
||||
./nym-mixnode sign --id <YOUR_ID> --contract-msg <PAYLOAD_GENERATED_BY_THE_WALLET>
|
||||
```
|
||||
|
||||
It will look something like this:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
./nym-mixnode sign --id upgrade_test --contract-msg 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4
|
||||
|
||||
_ __ _ _ _ __ ___
|
||||
| '_ \| | | | '_ \ _ \
|
||||
| | | | |_| | | | | | |
|
||||
|_| |_|\__, |_| |_| |_|
|
||||
|___/
|
||||
|
||||
(nym-mixnode - version v1.1.29)
|
||||
|
||||
|
||||
>>> attempting to sign 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4
|
||||
>>> decoding the message...
|
||||
>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"mixnode-bonding","content":{"sender":"n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"mix_node":{"host":"62.240.134.189","mix_port":1789,"verloc_port":1790,"http_api_port":8000,"sphinx_key":"CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z","identity_key":"DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"1.1.14"},"cost_params":{"profit_margin_percent":"0.1","interval_operating_cost":{"denom":"unym","amount":"40000000"}}}}}
|
||||
```
|
||||
~~~
|
||||
|
||||
* Copy the resulting signature:
|
||||
|
||||
```
|
||||
>>> The base58-encoded signature is:
|
||||
2GbKcZVKFdpi3sR9xoJWzwPuGdj3bvd7yDtDYVoKfbTWdpjqAeU8KS5bSftD5giVLJC3gZiCg2kmEjNG5jkdjKUt
|
||||
```
|
||||
|
||||
* And paste it into the wallet nodal, press `Next` and confirm the transaction.
|
||||
|
||||

|
||||
|
||||
* Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour).
|
||||
|
||||
> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks.
|
||||
|
||||
#### Bond via the CLI (power users)
|
||||
If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs.
|
||||
|
||||
### Running your mix node
|
||||
|
||||
Now you've bonded your mix node, run it with:
|
||||
|
||||
```
|
||||
./nym-mixnode run --id <YOUR_ID>
|
||||
```
|
||||
|
||||
If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running.
|
||||
|
||||
Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list.
|
||||
|
||||
Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options.
|
||||
|
||||
## Node Description (optional)
|
||||
|
||||
In order to easily identify your node via human-readable information later on, you can `describe` your Mix Node with the following command:
|
||||
In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mix node with the following command:
|
||||
|
||||
```
|
||||
./nym-mixnode describe --id <YOUR_ID>
|
||||
@@ -98,85 +193,15 @@ link = "https://nymtech.net"
|
||||
location = "Giza, Egypt"
|
||||
```
|
||||
|
||||
> Remember to restart your `nym-mix-node` process in order for the new description to be propagated.
|
||||
|
||||
## Running your Mix Node
|
||||
|
||||
Run your Mix Node with:
|
||||
|
||||
```
|
||||
./nym-mixnode run --id <YOUR_ID>
|
||||
```
|
||||
|
||||
Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options.
|
||||
|
||||
## Bonding your Mix Node
|
||||
|
||||
```admonish caution
|
||||
From `v1.1.3`, if you unbond your Mix Node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**.
|
||||
```
|
||||
|
||||
To initialise, run and bond your Mix Node are the minimum steps to do in order for your Mix Node to work. However we recommend to do a few more steps before bonding. These steps will make it easier for you as a node operator on a long run as well as for others to possibly delegate Nym tokens to your Mix Node. These steps are:
|
||||
|
||||
- [Describe your Mix Node](./mix-node-setup.md#node-description-optional)
|
||||
- [Configure your firewall](./maintenance.md#configure-your-firewall)
|
||||
- [Automate your Mix Node](./maintenance.md#vps-setup-and-automation)
|
||||
- Set the [ulimit](./maintenance.md#set-the-ulimit-via-systemd-service-file), in case you haven't automated with [systemd](./maintenance.md#set-the-ulimit-on-non-systemd-based-distributions)
|
||||
|
||||
### Bond via the Desktop wallet (recommended)
|
||||
|
||||
You can bond your Mix Node via the Desktop wallet.
|
||||
|
||||
* Open your wallet, and head to the `Bond` page, then select the node type `Mixnode` and input your node details. Press `Next`.
|
||||
|
||||
* Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`.
|
||||
|
||||
* You will be asked to run a the `sign` command with your `mixnode` - copy and paste the long signature as the value of `--contract-msg` and run it.
|
||||
|
||||
```
|
||||
./nym-mixnode sign --id <YOUR_ID> --contract-msg <PAYLOAD_GENERATED_BY_THE_WALLET>
|
||||
```
|
||||
|
||||
It will look something like this:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --id my-node --host $(curl -4 https://ifconfig.me) -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode sign --id my-node --contract-msg 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 -->
|
||||
```
|
||||
~~~
|
||||
|
||||
* Copy the resulting signature:
|
||||
|
||||
```sh
|
||||
# >>> The base58-encoded signature is:
|
||||
2bbDJSmSo9r9qdamTNygY297nQTVRyQaxXURuomVcRd7EvG9oEC8uW8fvZZYnDeeC9iWyG9mAbX2K8rWEAxZBro1
|
||||
```
|
||||
|
||||
* And paste it into the wallet nodal, press `Next` and confirm the transaction.
|
||||
|
||||

|
||||
*This image is just an example, copy-paste your own base58-encoded signature*
|
||||
|
||||
* Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour).
|
||||
|
||||
> You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks.
|
||||
|
||||
If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running.
|
||||
|
||||
Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list.
|
||||
|
||||
### Bond via the CLI (power users)
|
||||
If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs.
|
||||
|
||||
> Remember to restart your mix node process in order for the new description to be propagated.
|
||||
|
||||
## Node Families
|
||||
|
||||
Node family involves setting up a group of Mix Nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic.
|
||||
Node family involves setting up a group of mix nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic.
|
||||
|
||||
### Create a Node Family
|
||||
|
||||
To create a Node family, you will need to install and configure multiple Mix Nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication.
|
||||
To create a Node family, you will need to install and configure multiple mix nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication.
|
||||
|
||||
You can use either `nym-cli` which can be downloaded from the [release page](https://github.com/nymtech/nym/releases) or compiling `nyxd`.
|
||||
|
||||
@@ -189,8 +214,7 @@ Change directory by `cd <PATH>/<TO>/<THE>/<RELEASE>` and run the following on th
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --id YOUR_ID --host $(curl -4 https://ifconfig.me) -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode sign --id YOUR_ID --text "TEXT" -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode sign --id YOUR_ID --text "TEXT" -->
|
||||
```
|
||||
~~~
|
||||
|
||||
@@ -224,8 +248,7 @@ Change directory by `cd <PATH>/<TO>/<THE>/<RELEASE>` and run the following on th
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode init --id YOUR_ID --host $(curl -4 https://ifconfig.me) -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode sign --id YOUR_ID --text "TEXT" -->
|
||||
<!-- cmdrun ../../../../target/release/nym-mixnode sign --id YOUR_ID --text "TEXT" -->
|
||||
```
|
||||
~~~
|
||||
|
||||
@@ -251,7 +274,7 @@ To get the node owner signature, use:
|
||||
If wanting to leave, run the same initial command as above, followed by:
|
||||
|
||||
Using `nym-cli`:
|
||||
|
||||
<!---the sting under shall be changed to <NODE_ADDRESS>? --->
|
||||
```
|
||||
./nym-cli cosmwasm execute <WALLET_ADDRESS> '{"leave_family": {"signature": "<base58-encoded-signature>","family_head": "<TEXT>","owner_signautre": "<OWNER_IGNATURE_FROM_NODE_TO_LEAVE>"}}' --mnemonic <MNEMONIC_FROM_NODE_TO_LEAVE>
|
||||
```
|
||||
@@ -264,7 +287,7 @@ Using `nyxd`:
|
||||
|
||||
## Checking that your node is mixing correctly
|
||||
### Network explorers
|
||||
Once you've started your Mix Node and it connects to the validator, your node will automatically show up in the 'Mix Nodes' section of either the Nym Network Explorers:
|
||||
Once you've started your mix node and it connects to the validator, your node will automatically show up in the 'Mix nodes' section of either the Nym Network Explorers:
|
||||
|
||||
- [Mainnet](https://explorer.nymtech.net/overview)
|
||||
- [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
|
||||
@@ -278,7 +301,9 @@ There are also 2 community explorers which have been created by [Nodes Guru](htt
|
||||
|
||||
For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md)
|
||||
|
||||
<!---Enter faq link to the information how to higher chances to become a part of an active set--->
|
||||
|
||||
## Maintenance
|
||||
|
||||
For Mix Node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md)
|
||||
For mix node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Network Requesters
|
||||
|
||||
> Nym Network Requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first.
|
||||
> The Nym network requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first.
|
||||
|
||||
```admonish info
|
||||
As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym Exit Gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries.
|
||||
As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym exit gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries.
|
||||
```
|
||||
|
||||
> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
@@ -15,23 +15,23 @@ As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `n
|
||||
|
||||
## Preliminary steps
|
||||
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Network Requester.
|
||||
Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your network requester.
|
||||
|
||||
## Network Requester Whitelist
|
||||
|
||||
If you have access to a server, you can run the Network Requester, which allows Nym users to send outbound requests from their local machine through the Mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers.
|
||||
If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers.
|
||||
|
||||
By default the Network Requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/`) as a whitelist for outbound requests.
|
||||
By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/`) as a whitelist for outbound requests.
|
||||
|
||||
**Note:** If you run Network Requester as a part of the Exit Gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways/<ID>/data/network-requester-data/allowed.list`.
|
||||
**Note:** If you run network requester as a part of the exit gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways/<ID>/data/network-requester-data/allowed.list`.
|
||||
|
||||
Any request to a URL which is not on this list will be blocked.
|
||||
|
||||
On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically.
|
||||
|
||||
This default whitelist is useful for knowing that the majority of Network Requesters are able to support certain apps 'out of the box'.
|
||||
This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box'.
|
||||
|
||||
**Operators of a Network Requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list.
|
||||
**Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list.
|
||||
|
||||
The domains and IPs on the default whitelist can be broken down by application as follows:
|
||||
|
||||
@@ -109,14 +109,14 @@ alephium.org
|
||||
|
||||
## Network Requester Directory
|
||||
|
||||
You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect.
|
||||
You can find a list of Network requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect.
|
||||
|
||||
> We are currently working on a smart-contract based solution more in line with how Mix Nodes and Gateways announce themselves to the network.
|
||||
> We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network.
|
||||
|
||||
## Viewing command help
|
||||
|
||||
```admonish info
|
||||
If you run your Network Requester as a part of your Exit Gateway according to the suggested setup, please skip this part of the page and read about [Exit Gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead.
|
||||
If you run your network requester as a part of your exit gateway according to the suggested setup, please skip this part of the page and read about [exit gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead.
|
||||
```
|
||||
|
||||
To begin, move to `/target/release` directory from which you run the node commands:
|
||||
@@ -141,9 +141,9 @@ You can check the required parameters for available commands by running:
|
||||
|
||||
> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.
|
||||
|
||||
## Initializing and running your Network Requester
|
||||
## Initializing and running your network requester
|
||||
|
||||
The Network Requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the Mixnet. We want to specify an `<ID>` using the `--id` command and give it a value of your choice. The following command will achieve that:
|
||||
The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `<ID>` using the `--id` command and give it a value of your choice. The following command will achieve that:
|
||||
|
||||
```
|
||||
./nym-network-requester init --id <YOUR_ID>
|
||||
@@ -164,11 +164,11 @@ Now that we have initialized our network-requester, we can start it with the fol
|
||||
./nym-network-requester run --id <YOUR_ID>
|
||||
```
|
||||
|
||||
## Using your Network Requester
|
||||
## Using your network requester
|
||||
|
||||
The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet.
|
||||
|
||||
To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network Requester is ran as a part of [Exit Gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways/<ID>/data/network-requester-data/allowed.list`
|
||||
To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if network requester is ran as a part of [exit gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways/<ID>/data/network-requester-data/allowed.list`
|
||||
|
||||
### Global vs local allow lists
|
||||
Your Network Requester will check for a domain against 2 lists before allowing traffic through for a particular domain or IP.
|
||||
@@ -177,34 +177,34 @@ Your Network Requester will check for a domain against 2 lists before allowing t
|
||||
|
||||
* The second is the local `allowed.list` file.
|
||||
|
||||
### Supporting custom domains with your Network Requester
|
||||
It is easy to add new domains and services to your Network Requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`.
|
||||
### Supporting custom domains with your network requester
|
||||
It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`.
|
||||
|
||||
> In order to keep things more organised, you can now use comments in the `allow.list` like the example at the top of this page.
|
||||
|
||||
How to go about this? Have a look in your `nym-network-requester` config directory:
|
||||
How to go about this? Have a look in your nym-network-requester config directory:
|
||||
|
||||
```
|
||||
# nym-network-requester binary
|
||||
# network requester binary
|
||||
ls -lt $HOME/.nym/service-providers/network-requester/*/data | grep "list"
|
||||
|
||||
# nym-gateway binary
|
||||
# exit gateway binary
|
||||
ls -lt $HOME/.nym/gateways/*/data/network-requester-data | grep "list"
|
||||
|
||||
# returns: allowed.list unknown.list
|
||||
```
|
||||
|
||||
We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your Exit Gateway or standalone Network Requester.
|
||||
We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your exit gateway or standalone network requester.
|
||||
|
||||
> If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com`
|
||||
|
||||
### Running an open proxy
|
||||
If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable Network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk.
|
||||
If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk.
|
||||
|
||||
## Testing your Network Requester
|
||||
1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your Network Requester).
|
||||
## Testing your network requester
|
||||
1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your network requester).
|
||||
|
||||
2. Ensure that your `nym-network-requester` is initialized and running.
|
||||
2. Ensure that your network-requester is initialized and running.
|
||||
|
||||
3. In another terminal window, run the following:
|
||||
|
||||
@@ -220,5 +220,5 @@ This command should return the following:
|
||||
|
||||
## Maintenance
|
||||
|
||||
For Network Requester upgrade (including an upgrade from `<v1.1.9` to `>= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md).
|
||||
For network requester upgrade (including an upgrade from `<v1.1.9` to `>= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md).
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
|
||||
This section contains setup guides for the following node types:
|
||||
* [Mix Node](./mix-node-setup.md)
|
||||
* [Mix node](./mix-node-setup.md)
|
||||
* [Gateway](./gateway-setup.md)
|
||||
* [Network Requester](./network-requester-setup.md)
|
||||
* [Validator](./validator-setup.md)
|
||||
|
||||
@@ -78,7 +78,7 @@ Additional details can be obtained via various methods after you connect to your
|
||||
##### Socket statistics with `ss`
|
||||
|
||||
```
|
||||
sudo ss -s -t | grep 1789 # if you have specified a different port in your Mix Node config, change accordingly
|
||||
sudo ss -s -t | grep 1789 # if you have specified a different port in your mix node config, change accordingly
|
||||
```
|
||||
|
||||
This command should return a lot of data containing `ESTAB`. This command should work on every unix based system.
|
||||
@@ -90,7 +90,7 @@ This command should return a lot of data containing `ESTAB`. This command should
|
||||
lsof -v
|
||||
# install if not installed
|
||||
sudo apt install lsof
|
||||
# run against nym-mix-node node port
|
||||
# run against mix node port
|
||||
sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly
|
||||
```
|
||||
|
||||
@@ -110,7 +110,7 @@ nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3:
|
||||
sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed"
|
||||
```
|
||||
|
||||
If you have created `nym-mixnode.service` file (i.e. you are running your Mix Node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this:
|
||||
If you have created `nym-mixnode.service` file (i.e. you are running your mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this:
|
||||
|
||||
```
|
||||
2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets!
|
||||
@@ -140,7 +140,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu
|
||||
nmap -p 1789 <IP ADDRESS> -Pn
|
||||
```
|
||||
|
||||
If your Mix Node is configured properly it should output something like this:
|
||||
If your mix node is configured properly it should output something like this:
|
||||
|
||||
```
|
||||
bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn
|
||||
@@ -159,12 +159,12 @@ curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/'
|
||||
|
||||
Will return a list all nodes currently online.
|
||||
|
||||
You can query Gateways by replacing `nym-mixnodes` with `nym-gateways` in the above command, and can query for the Mix Nodes and Gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`.
|
||||
You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`.
|
||||
|
||||
|
||||
#### Check with Network API
|
||||
|
||||
We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your Mix Node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints).
|
||||
We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints).
|
||||
|
||||
### Why is my node not mixing any packets?
|
||||
|
||||
@@ -172,24 +172,24 @@ If you are still unable to see your node on the dashboard, or your node is decla
|
||||
|
||||
- The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall).
|
||||
- You provided incorrect information when bonding your node.
|
||||
- You are running your Mix Node from a VPS without IPv6 support.
|
||||
- You did not use the `--announce-host` flag while running the Mix Node from your local machine behind NAT.
|
||||
- You did not configure your router firewall while running the Mix Node from your local machine behind NAT, or you are lacking IPv6 support.
|
||||
- Your Mix Node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd).
|
||||
- You are running your mix node from a VPS without IPv6 support.
|
||||
- You did not use the `--announce-host` flag while running the mix node from your local machine behind NAT.
|
||||
- You did not configure your router firewall while running the mix node from your local machine behind NAT, or you are lacking IPv6 support.
|
||||
- Your mix node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd).
|
||||
|
||||
```admonish caution
|
||||
Your Mix Node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this!
|
||||
Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this!
|
||||
```
|
||||
|
||||
#### Incorrect bonding information
|
||||
|
||||
Check that you have provided the correct information when bonding your Mix Node in the web wallet interface. When in doubt, un-bond and then re-bond your node!
|
||||
Check that you have provided the correct information when bonding your mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node!
|
||||
|
||||
> All delegated stake will be lost when un-bonding! However the Mix Node must be operational in the first place for the delegation to have any effect.
|
||||
> All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect.
|
||||
|
||||
#### Missing `announce-host` flag
|
||||
|
||||
On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your Mix Node host.
|
||||
On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mix node host.
|
||||
|
||||
If the difference between the two is unclear, contact the help desk of your VPS provider.
|
||||
|
||||
@@ -222,15 +222,15 @@ bob@nym:~$ hostname -I
|
||||
|
||||
### Running on a local machine behind NAT with no fixed IP address
|
||||
|
||||
Your ISP has to be IPv6 ready if you want to run a Mix Node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it.
|
||||
Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it.
|
||||
|
||||
Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone!
|
||||
|
||||
If all goes well and you have IPv6 available, then you will need to `init` the Mix Node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity).
|
||||
If all goes well and you have IPv6 available, then you will need to `init` the mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity).
|
||||
|
||||
Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support.
|
||||
|
||||
Here is a sample of the `init` command example to create the Mix Node config.
|
||||
Here is a sample of the `init` command example to create the mix node config.
|
||||
|
||||
```
|
||||
./nym-mixnode init --id <YOUR_ID> --host 0.0.0.0 --announce-host 85.160.12.13
|
||||
@@ -244,7 +244,7 @@ Make sure you check if your node is really mixing. We are aiming to improve the
|
||||
|
||||
### Accidentally killing your node process on exiting session
|
||||
|
||||
When you close your current terminal session, you need to make sure you don't kill the Mix Node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd).
|
||||
When you close your current terminal session, you need to make sure you don't kill the mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd).
|
||||
|
||||
### Common errors and warnings
|
||||
|
||||
@@ -266,14 +266,14 @@ Then you need to `--announce-host <PUBLIC_IP>` and `--host <LOCAL_IP>` on startu
|
||||
|
||||
Yes! Here is what you will need to do:
|
||||
|
||||
Assuming you would like to use port `1337` for your Mix Node, you need to open the new port (and close the old one):
|
||||
Assuming you would like to use port `1337` for your mix node, you need to open the new port (and close the old one):
|
||||
|
||||
```
|
||||
sudo ufw allow 1337
|
||||
sudo ufw deny 1789
|
||||
```
|
||||
|
||||
And then edit the Mix Node's config.
|
||||
And then edit the mix node's config.
|
||||
|
||||
> If you want to change the port for an already running node, you need to stop the process before editing your config file.
|
||||
|
||||
@@ -287,25 +287,25 @@ nano ~/.nym/mixnodes/alice-node/config/config.toml
|
||||
|
||||
You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address.
|
||||
|
||||
Finally, restart your node. You should see if the Mix Node is using the port you have changed in the config.toml file right after you run the node.
|
||||
Finally, restart your node. You should see if the mix node is using the port you have changed in the config.toml file right after you run the node.
|
||||
|
||||
### What is `verloc` and do I have to configure my Mix Node to implement it?
|
||||
### What is `verloc` and do I have to configure my mix node to implement it?
|
||||
|
||||
`verloc` is short for _verifiable location_. Mix Nodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner.
|
||||
`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner.
|
||||
|
||||
You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward.
|
||||
|
||||
## Gateways & Network Requesters
|
||||
## Gateways & Network requesters
|
||||
|
||||
### My Gateway seems to be running but appears offline
|
||||
### My gateway seems to be running but appears offline
|
||||
|
||||
Check your [firewall](./maintenance.md#configure-your-firewall) is active and if the necessary ports are open / allowed.
|
||||
|
||||
### My exit Gateway "is still not online..."
|
||||
### My exit gateway "is still not online..."
|
||||
|
||||
The Nyx chain epoch takes up to 60 min. To prevent the Gateway getting blacklisted, it's important to run it before and during the bonding process. In case it already got blacklisted run it for at several hours. During this time your node is tested by `nym-api` and every positive response picks up your Gateway's routing score.
|
||||
The Nyx chain epoch takes up to 60 min. To prevent the gateway getting blacklisted, it's important to run it right after the bonding process to return positive response our API testing it's routing score.
|
||||
|
||||
You may want to disconnect the Network Requester and let it run as a Gateway alone for some time to regain better routing score and then return to the full [Exit Gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester).
|
||||
You may want to disconnect the network requester and let it run as a gatewy alone for some time to regain better routing score and then areturn to the full [exit gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester).
|
||||
|
||||
|
||||
## Validators
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Validators
|
||||
|
||||
> Nym has two main codebases:
|
||||
> Nym has two main codebases:
|
||||
> - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code except for the validators.
|
||||
> - the [Nym validators](https://github.com/nymtech/nyxd), written in Go & maintained as a no-modification fork of [wasmd](https://github.com/CosmWasm/wasmd)
|
||||
> - the [Nym validators](https://github.com/nymtech/nyxd), written in Go.
|
||||
|
||||
The validator is a Go application which implements it's functionalities using [Cosmos SDK](https://v1.cosmos.network/sdk). The underlying state-replication engine is powered by [CometBFT](https://cometbft.com/), where the consensus mechanism is based on the [Tendermint Consensus Algorithm](https://arxiv.org/abs/1807.04938). Finally, a [CosmWasm](https://cosmwasm.com) smart contract module controls crucial mixnet functionalities like decentralised directory service, node bonding, and delegated mixnet staking.
|
||||
The validator is built using [Cosmos SDK](https://cosmos.network) and [Tendermint](https://tendermint.com), with a [CosmWasm](https://cosmwasm.com) smart contract controlling the directory service, node bonding, and delegated mixnet staking.
|
||||
|
||||
> We are currently running mainnet with a closed set of reputable validators. To ensure decentralisation of Nyx chain, we are working on a mechanism to onboard new validators to the network. To join the waitlist, please drop an email to `validators [at] nymtech.net` with details of your setup, experience and any other relevent information
|
||||
> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation.
|
||||
|
||||
## Building your validator
|
||||
|
||||
@@ -33,9 +33,9 @@ pacman -S git gcc jq
|
||||
`Go` can be installed via the following commands (taken from the [Go Download and install page](https://go.dev/doc/install)):
|
||||
|
||||
```
|
||||
# First remove any existing old Go installation and extract the archive you just downloaded into /usr/local:
|
||||
# First remove any existing old Go installation and extract the archive you just downloaded into /usr/local:
|
||||
# You may need to run the command as root or through sudo
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.10.linux-amd64.tar.gz
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz
|
||||
|
||||
# Add /usr/local/go/bin to the PATH environment variable
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
@@ -47,12 +47,16 @@ Verify `Go` is installed with:
|
||||
```
|
||||
go version
|
||||
# Should return something like:
|
||||
go version go1.20.10 linux/amd64
|
||||
go version go1.20.4 linux/amd64
|
||||
```
|
||||
|
||||
### Download a precompiled validator binary
|
||||
You can find pre-compiled binaries for Ubuntu `22.04` and `20.04` [here](https://github.com/nymtech/nyxd/releases).
|
||||
|
||||
```admonish caution title=""
|
||||
There are seperate releases for Mainnet and the Sandbox testnet - make sure to download the correct binary to avoid `bech32Prefix` mismatches.
|
||||
```
|
||||
|
||||
### Manually compiling your validator binary
|
||||
The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd).
|
||||
|
||||
@@ -60,13 +64,15 @@ The validator binary can be compiled by running the following commands:
|
||||
```
|
||||
git clone https://github.com/nymtech/nyxd.git
|
||||
cd nyxd
|
||||
|
||||
# Make sure to check releases for the latest version information
|
||||
git checkout release/<NYXD_VERSION>
|
||||
|
||||
# Build the binaries
|
||||
# Mainnet
|
||||
make build
|
||||
|
||||
# Sandbox testnet
|
||||
BECH32_PREFIX=nymt make build
|
||||
```
|
||||
|
||||
At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running:
|
||||
|
||||
```
|
||||
@@ -77,49 +83,50 @@ You should see a similar help menu printed to you:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
Nyx Daemon (server)
|
||||
Wasm Daemon (server)
|
||||
|
||||
Usage:
|
||||
nyxd [command]
|
||||
|
||||
Available Commands:
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
config Create or query an application CLI configuration file
|
||||
debug Tool for helping with debugging your application
|
||||
export Export state to JSON
|
||||
genesis Application's genesis-related subcommands
|
||||
help Help about any command
|
||||
init Initialize private validator, p2p, genesis, and application configuration files
|
||||
keys Manage your application's keys
|
||||
prune Prune app history states by keeping the recent heights and deleting old heights
|
||||
query Querying subcommands
|
||||
rollback rollback cosmos-sdk and tendermint state by one height
|
||||
rosetta spin up a rosetta server
|
||||
start Run the full node
|
||||
status Query remote node for status
|
||||
tendermint Tendermint subcommands
|
||||
testnet subcommands for starting or configuring local testnets
|
||||
tx Transactions subcommands
|
||||
version Print the application binary version information
|
||||
add-genesis-account Add a genesis account to genesis.json
|
||||
add-wasm-genesis-message Wasm genesis subcommands
|
||||
collect-gentxs Collect genesis txs and output a genesis.json file
|
||||
config Create or query an application CLI configuration file
|
||||
debug Tool for helping with debugging your application
|
||||
export Export state to JSON
|
||||
gentx Generate a genesis tx carrying a self delegation
|
||||
help Help about any command
|
||||
init Initialize private validator, p2p, genesis, and application configuration files
|
||||
keys Manage your application's keys
|
||||
query Querying subcommands
|
||||
rollback rollback cosmos-sdk and tendermint state by one height
|
||||
start Run the full node
|
||||
status Query remote node for status
|
||||
tendermint Tendermint subcommands
|
||||
tx Transactions subcommands
|
||||
validate-genesis validates the genesis file at the default location or at the location passed as an arg
|
||||
version Print the application binary version information
|
||||
|
||||
Flags:
|
||||
-h, --help help for nyxd
|
||||
--home string directory for config and data
|
||||
--home string directory for config and data (default "/home/willow/.nyxd")
|
||||
--log_format string The logging format (json|plain) (default "plain")
|
||||
--log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info")
|
||||
--trace print out full stack trace on errors
|
||||
|
||||
Use "nyxd [command] --help" for more information about a command.
|
||||
|
||||
```
|
||||
~~~
|
||||
|
||||
### Linking `nyxd` to `libwasmvm.so`
|
||||
|
||||
`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1` and above.
|
||||
`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`.
|
||||
|
||||
If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page.
|
||||
|
||||
If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.x86_64.so` file to correct location.
|
||||
If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location.
|
||||
|
||||
Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`.
|
||||
|
||||
@@ -145,39 +152,40 @@ This should return the regular help menu:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
Nyx Daemon (server)
|
||||
Wasm Daemon (server)
|
||||
|
||||
Usage:
|
||||
nyxd [command]
|
||||
|
||||
Available Commands:
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
config Create or query an application CLI configuration file
|
||||
debug Tool for helping with debugging your application
|
||||
export Export state to JSON
|
||||
genesis Application's genesis-related subcommands
|
||||
help Help about any command
|
||||
init Initialize private validator, p2p, genesis, and application configuration files
|
||||
keys Manage your application's keys
|
||||
prune Prune app history states by keeping the recent heights and deleting old heights
|
||||
query Querying subcommands
|
||||
rollback rollback cosmos-sdk and tendermint state by one height
|
||||
rosetta spin up a rosetta server
|
||||
start Run the full node
|
||||
status Query remote node for status
|
||||
tendermint Tendermint subcommands
|
||||
testnet subcommands for starting or configuring local testnets
|
||||
tx Transactions subcommands
|
||||
version Print the application binary version information
|
||||
add-genesis-account Add a genesis account to genesis.json
|
||||
add-wasm-genesis-message Wasm genesis subcommands
|
||||
collect-gentxs Collect genesis txs and output a genesis.json file
|
||||
config Create or query an application CLI configuration file
|
||||
debug Tool for helping with debugging your application
|
||||
export Export state to JSON
|
||||
gentx Generate a genesis tx carrying a self delegation
|
||||
help Help about any command
|
||||
init Initialize private validator, p2p, genesis, and application configuration files
|
||||
keys Manage your application's keys
|
||||
query Querying subcommands
|
||||
rollback rollback cosmos-sdk and tendermint state by one height
|
||||
start Run the full node
|
||||
status Query remote node for status
|
||||
tendermint Tendermint subcommands
|
||||
tx Transactions subcommands
|
||||
validate-genesis validates the genesis file at the default location or at the location passed as an arg
|
||||
version Print the application binary version information
|
||||
|
||||
Flags:
|
||||
-h, --help help for nyxd
|
||||
--home string directory for config and data
|
||||
--home string directory for config and data (default "/home/willow/.nyxd")
|
||||
--log_format string The logging format (json|plain) (default "plain")
|
||||
--log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info")
|
||||
--trace print out full stack trace on errors
|
||||
|
||||
Use "nyxd [command] --help" for more information about a command.
|
||||
|
||||
```
|
||||
~~~
|
||||
|
||||
@@ -216,7 +224,7 @@ You can use the following command to download them for the correct network:
|
||||
wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json
|
||||
|
||||
# Sandbox testnet
|
||||
wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json | jq '.result.genesis'
|
||||
wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json
|
||||
```
|
||||
|
||||
### `config.toml` configuration
|
||||
@@ -226,18 +234,21 @@ Edit the following config options in `$HOME/.nyxd/config/config.toml` to match t
|
||||
```
|
||||
# Mainnet
|
||||
persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656"
|
||||
create_empty_blocks = false
|
||||
laddr = "tcp://0.0.0.0:26656"
|
||||
```
|
||||
|
||||
```
|
||||
# Sandbox testnet
|
||||
cors_allowed_origins = ["*"]
|
||||
persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@sandbox-validator1.nymtech.net:26666"
|
||||
persistent_peers = "8421c0a3d90d490e27e8061f2abcb1276c8358b6@sandbox-validator1.nymtech.net:26666"
|
||||
create_empty_blocks = false
|
||||
laddr = "tcp://0.0.0.0:26656"
|
||||
```
|
||||
|
||||
These affect the following:
|
||||
These affect the following:
|
||||
* `persistent_peers = "<PEER_ADDRESS>@<DOMAIN>.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`.
|
||||
* `create_empty_blocks = false` will save space
|
||||
* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options
|
||||
|
||||
Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`:
|
||||
@@ -259,11 +270,11 @@ In the file `$HOME/nyxd/config/app.toml`, set the following values:
|
||||
```
|
||||
# Mainnet
|
||||
minimum-gas-prices = "0.025unym,0.025unyx"
|
||||
enable = true in the `[api]` section to get the API server running
|
||||
```
|
||||
|
||||
```
|
||||
# Sandbox Testnet
|
||||
minimum-gas-prices = "0.025unym,0.025unyx"
|
||||
minimum-gas-prices = "0.025unymt,0.025unyxt"
|
||||
enable = true` in the `[api]` section to get the API server running
|
||||
```
|
||||
|
||||
@@ -274,13 +285,9 @@ You'll need an admin account to be in charge of your validator. Set that up with
|
||||
nyxd keys add nyxd-admin
|
||||
```
|
||||
|
||||
```admonish tip title="Key Backends"
|
||||
Cosmos SDK offers multiple backends for securing your keys. Please refer to the Cosmos SDK [docs on available keyring backends](https://docs.cosmos.network/main/user/run-node/keyring#available-backends-for-the-keyring) to learn more
|
||||
```
|
||||
This will add keys for your administrator account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**.
|
||||
|
||||
While using the default settings, this will add keys for your account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**.
|
||||
|
||||
You can get the current account address with:
|
||||
You can get the admin account's address with:
|
||||
|
||||
```
|
||||
nyxd keys show nyxd-admin -a
|
||||
@@ -290,6 +297,10 @@ Type in your keychain **password**, not the mnemonic, when asked.
|
||||
|
||||
## Starting your validator
|
||||
|
||||
```admonish caution title=""
|
||||
If you are running a Sandbox testnet validator, please skip the `validate-genesis` command: it will fail due to the size of the genesis file as this is a fork of an existing chain state.
|
||||
```
|
||||
|
||||
Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup:
|
||||
|
||||
```
|
||||
@@ -302,7 +313,7 @@ If this check passes, you should receive the following output:
|
||||
File at /path/to/genesis.json is a valid genesis file
|
||||
```
|
||||
|
||||
> If this test did not pass, check that you have replaced the contents of `/<PATH-TO>/.nyxd/config/genesis.json` with that of the correct genesis file.
|
||||
> If this test did not pass, check that you have replaced the contents of `/<PATH-TO>/.nymd/config/genesis.json` with that of the correct genesis file.
|
||||
|
||||
### Open firewall ports
|
||||
|
||||
@@ -312,18 +323,14 @@ Before starting the validator, we will need to open the firewall ports:
|
||||
# if ufw is not already installed:
|
||||
sudo apt install ufw
|
||||
sudo ufw enable
|
||||
|
||||
# Customise according to your port bindings. This is only for reference
|
||||
# 26656 : p2p gossip port
|
||||
# 26660: If prometheus is enabled
|
||||
# 22 : Default SSH port
|
||||
sudo ufw allow 26656,26660,22
|
||||
|
||||
sudo ufw allow 1317,26656,26660,22,80,443/tcp
|
||||
# to check everything worked
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
For more information about your validator's port configuration, check the [validator port reference table](./maintenance.md#ports) below. These can be customised in `app.toml` and `config.toml` files.
|
||||
Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/main/core/grpc_rest).
|
||||
|
||||
For more information about your validator's port configuration, check the [validator port reference table](./maintenance.md#ports) below.
|
||||
|
||||
> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well.
|
||||
|
||||
@@ -369,7 +376,8 @@ Once your validator has synced and you have received tokens, you can join consen
|
||||
```
|
||||
# Mainnet
|
||||
nyxd tx staking create-validator
|
||||
--amount=<10000000unyx>
|
||||
--amount=10000000unyx
|
||||
--fees=0unyx
|
||||
--pubkey=$(/home/<USER>/<PATH-TO>/nyxd/binaries/nyxd tendermint show-validator)
|
||||
--moniker="<YOUR_VALIDATOR_NAME>"
|
||||
--chain-id=nyx
|
||||
@@ -379,14 +387,14 @@ nyxd tx staking create-validator
|
||||
--min-self-delegation="1"
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--from=<"KEYRING_NAME">
|
||||
--node=https://rpc.nymtech.net:443
|
||||
--from="KEYRING_NAME"
|
||||
--node https://rpc-1.nyx.nodes.guru:443
|
||||
```
|
||||
```
|
||||
# Sandbox Testnet
|
||||
nyxd tx staking create-validator
|
||||
--amount=<10000000unyx>
|
||||
--amount=10000000unyxt
|
||||
--fees=5000unyxt
|
||||
--pubkey=$(/home/<USER>/<PATH-TO>/nym/binaries/nyxd tendermint show-validator)
|
||||
--moniker="<YOUR_VALIDATOR_NAME>"
|
||||
--chain-id=sandbox
|
||||
@@ -396,13 +404,13 @@ nyxd tx staking create-validator
|
||||
--min-self-delegation="1"
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--from=<"KEYRING_NAME">
|
||||
--from="KEYRING_NAME"
|
||||
--node https://sandbox-validator1.nymtech.net:443
|
||||
```
|
||||
|
||||
You'll need Nyx tokens on mainnet / sandbox to perform the above tasks.
|
||||
You'll need either `unyxt` tokens on Sandbox, or `unyx` tokens on mainnet to perform this command.
|
||||
|
||||
> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation.
|
||||
|
||||
If you want to edit some details for your node you will use a command like this:
|
||||
|
||||
@@ -416,8 +424,8 @@ nyxd tx staking edit-validator
|
||||
--identity="<YOUR_IDENTITY>"
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--from="KEYRING_NAME"
|
||||
--fees 2000unyx
|
||||
```
|
||||
```
|
||||
# Sandbox testnet
|
||||
@@ -429,8 +437,8 @@ nyxd tx staking edit-validator
|
||||
--identity="<YOUR_IDENTITY>"
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--from="KEYRING_NAME"
|
||||
--fees 2000unyxt
|
||||
```
|
||||
|
||||
With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact.
|
||||
@@ -438,6 +446,9 @@ With above command you can specify the `gpg` key last numbers (as used in `keyba
|
||||
### Automating your validator with systemd
|
||||
You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md#systemd) with a quick tutorial.
|
||||
|
||||
### Installing and configuring nginx for HTTPS
|
||||
|
||||
If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](./maintenance.md#setup).
|
||||
|
||||
### Setting the ulimit
|
||||
|
||||
@@ -455,7 +466,7 @@ nyxd tx slashing unjail
|
||||
--chain-id=nyx
|
||||
--gas=auto
|
||||
--gas-adjustment=1.4
|
||||
--gas-prices=0.025unyx
|
||||
--fees=7000unyx
|
||||
```
|
||||
```
|
||||
# Sandbox Testnet
|
||||
@@ -465,7 +476,7 @@ nyxd tx slashing unjail
|
||||
--chain-id=sandbox
|
||||
--gas=auto
|
||||
--gas-adjustment=1.4
|
||||
--gas-prices=0.025unyx
|
||||
--fees=7000unyxt
|
||||
```
|
||||
|
||||
### Upgrading your validator
|
||||
@@ -485,7 +496,7 @@ If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog
|
||||
You can check your current balances with:
|
||||
|
||||
```
|
||||
nyxd query bank balances ${ADDRESS}
|
||||
nymd query bank balances ${ADDRESS}
|
||||
```
|
||||
|
||||
For example, on the Sandbox testnet this would return:
|
||||
@@ -493,7 +504,7 @@ For example, on the Sandbox testnet this would return:
|
||||
```yaml
|
||||
balances:
|
||||
- amount: "919376"
|
||||
denom: unym
|
||||
denom: unymt
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
@@ -505,21 +516,22 @@ You can, of course, stake back the available balance to your validator with the
|
||||
|
||||
```
|
||||
# Mainnet
|
||||
nyxd tx staking delegate VALOPERADDRESS AMOUNTunyx
|
||||
nyxd tx staking delegate VALOPERADDRESS AMOUNTunym
|
||||
--from="KEYRING_NAME"
|
||||
--keyring-backend=os
|
||||
--chain-id=nyx
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
|
||||
--fees 5000unyx
|
||||
```
|
||||
```
|
||||
# Sandbox Testnet
|
||||
nyxd tx staking delegate VALOPERADDRESS AMOUNTunyx
|
||||
nyxd tx staking delegate VALOPERADDRESS AMOUNTunymt
|
||||
--from="KEYRING_NAME"
|
||||
--keyring-backend=os
|
||||
--chain-id=sandbox
|
||||
--gas="auto"
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--fees 5000unyxt
|
||||
```
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import MuiLink from '@mui/material/Link';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Typography } from '@mui/material';
|
||||
import { Socials } from './Socials';
|
||||
import { useIsMobile } from '../hooks/useIsMobile';
|
||||
import { NymVpnIcon } from '../icons/NymVpn';
|
||||
|
||||
export const Footer: FCWithChildren = () => {
|
||||
const isMobile = useIsMobile();
|
||||
@@ -34,9 +31,6 @@ export const Footer: FCWithChildren = () => {
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<MuiLink component={Link} to="http://nymvpn.com" target="_blank" underline="none" marginRight={1}>
|
||||
<NymVpnIcon />
|
||||
</MuiLink>
|
||||
<Socials isFooter />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -22,7 +22,6 @@ import { useMainContext } from '../context/main';
|
||||
import { MobileDrawerClose } from '../icons/MobileDrawerClose';
|
||||
import { Socials } from './Socials';
|
||||
import { Footer } from './Footer';
|
||||
import { NymVpnIcon } from '../icons/NymVpn';
|
||||
import { DarkLightSwitchDesktop } from './Switch';
|
||||
import { NavOptionType } from '../context/nav';
|
||||
|
||||
@@ -342,9 +341,6 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<MuiLink component={Link} to="http://nymvpn.com" target="_blank" underline="none" marginRight={1}>
|
||||
<NymVpnIcon />
|
||||
</MuiLink>
|
||||
<Socials />
|
||||
<DarkLightSwitchDesktop defaultChecked />
|
||||
</Box>
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
interface DiscordIconProps {
|
||||
size?: { width: number; height: number };
|
||||
}
|
||||
|
||||
export const NymVpnIcon: FCWithChildren<DiscordIconProps> = ({ size }) => (
|
||||
<svg width={size?.width} height={size?.height} viewBox="0 0 170 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.6118 0.128906H19.5405V0.187854V20.7961L10.7849 0.164277L10.773 0.128906H10.7255H5.75959H0.187819H0.128418V0.187854V23.8142V23.8732H0.187819H5.75959H5.81899V23.8142V3.17063L14.6103 23.8378L14.6222 23.8732H14.6697H19.6118H25.1717H25.2311V23.8142V0.187854V0.128906H25.1717H19.6118Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M19.4121 0H25.3603V24H14.5297L14.4901 23.8819L5.94824 3.80121V24H0V0H10.8663L10.906 0.118132L19.4121 20.1621V0ZM19.5409 20.7951L10.7853 0.163225L10.7734 0.127854H0.128835V23.8721H5.81941V3.16958L14.6107 23.8368L14.6226 23.8721H25.2315V0.127854H19.5409V20.7951Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M89.8116 0.128906H79.1908H79.1314L79.1195 0.176068L73.6784 20.8904L68.2255 0.176068L68.2136 0.128906H68.1661H57.5215H57.4502V0.187854V23.8142V23.8732H57.5215H63.0814H63.1408V23.8142V3.33568L68.5225 23.826L68.5343 23.8732H68.5937H78.7394H78.7869L78.7988 23.826L84.1804 3.33568V23.8142V23.8732H84.2398H89.8116H89.871V23.8142V0.187854V0.128906H89.8116Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M79.0312 0H90.0003V24H84.052V4.33208L78.9242 23.856L78.9238 23.8572L78.8879 24H68.4342L68.3982 23.8572L68.3979 23.856L63.27 4.33208V24H57.3218V0H68.3146L68.3505 0.142699L68.3509 0.144015L73.6787 20.383L78.9949 0.144015L78.9953 0.142765L79.0312 0ZM73.6788 20.8894L68.2259 0.175015L68.214 0.127854H57.4506V23.8721H63.1412V3.33463L68.5229 23.825L68.5348 23.8721H78.7873L78.7992 23.825L84.1809 3.33463V23.8721H89.8714V0.127854H79.1318L79.1199 0.175015L73.6788 20.8894Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M48.2909 0.128906H48.2553L48.2434 0.152487L41.4836 11.8124L34.6882 0.152487L34.6763 0.128906H34.6407H28.2135H28.0947L28.1541 0.223225L38.6205 18.2142V23.8142V23.8732H38.6799H44.2517H44.3111V23.8142V18.2142L54.7775 0.223225L54.8369 0.128906H54.7181H48.2909Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M48.1757 0H55.0693L54.8879 0.288036L44.4399 18.2474V24H38.4917V18.2474L28.0437 0.288036L27.8623 0H34.756L34.8017 0.0907854L41.4833 11.5555L48.1299 0.0909153L48.1757 0ZM48.2434 0.151434L41.4836 11.8114L34.6882 0.151434L34.6763 0.127854H28.0948L28.1542 0.222173L38.6205 18.2131V23.8721H44.3111V18.2131L54.7775 0.222173L54.8369 0.127854H48.2553L48.2434 0.151434Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M169.238 0V24H166.422C166.006 24 165.654 23.9341 165.366 23.8023C165.088 23.6596 164.811 23.418 164.534 23.0776L153.542 8.76321C153.584 9.19149 153.611 9.60878 153.622 10.0151C153.643 10.4104 153.654 10.7838 153.654 11.1352V24H148.886V0H151.734C151.968 0 152.166 0.0109813 152.326 0.032944C152.486 0.0549066 152.63 0.0988326 152.758 0.164722C152.886 0.219629 153.008 0.30199 153.126 0.411805C153.243 0.521619 153.376 0.669869 153.526 0.856553L164.614 15.2697C164.56 14.8085 164.523 14.3638 164.502 13.9355C164.48 13.4962 164.47 13.0844 164.47 12.7001V0H169.238Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
<path
|
||||
d="M134.206 11.7776C135.614 11.7776 136.627 11.4317 137.246 10.7399C137.865 10.048 138.174 9.08167 138.174 7.84077C138.174 7.29169 138.094 6.79204 137.934 6.3418C137.774 5.89156 137.529 5.50721 137.198 5.18874C136.878 4.8593 136.467 4.60673 135.966 4.43102C135.475 4.25532 134.889 4.16747 134.206 4.16747H131.39V11.7776H134.206ZM134.206 0C135.849 0 137.257 0.203157 138.43 0.609471C139.614 1.0048 140.585 1.55388 141.342 2.25669C142.11 2.95951 142.675 3.78861 143.038 4.74399C143.401 5.69938 143.582 6.73164 143.582 7.84077C143.582 9.03775 143.395 10.1359 143.022 11.1352C142.649 12.1345 142.078 12.9911 141.31 13.7049C140.542 14.4187 139.566 14.9787 138.382 15.385C137.209 15.7804 135.817 15.978 134.206 15.978H131.39V24H125.982V0H134.206Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
<path
|
||||
d="M121.584 0L112.24 24H107.344L98 0H102.352C102.821 0 103.2 0.115305 103.488 0.345915C103.776 0.565545 103.995 0.851064 104.144 1.20247L108.656 14.0508C108.869 14.6108 109.077 15.2258 109.28 15.8957C109.483 16.5546 109.675 17.2464 109.856 17.9712C110.005 17.2464 110.171 16.5546 110.352 15.8957C110.544 15.2258 110.747 14.6108 110.96 14.0508L115.44 1.20247C115.557 0.894989 115.765 0.620452 116.064 0.378861C116.373 0.126287 116.752 0 117.2 0H121.584Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
NymVpnIcon.defaultProps = {
|
||||
size: { width: 80, height: 12 },
|
||||
};
|
||||
@@ -81,8 +81,3 @@ cpucycles = [
|
||||
"opentelemetry",
|
||||
"nym-bin-common/tracing",
|
||||
]
|
||||
|
||||
[package.metadata.deb]
|
||||
name = "nym-mixnode"
|
||||
maintainer-scripts = "debian"
|
||||
systemd-units = { enable = false }
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#DEBHELPER#
|
||||
|
||||
useradd nym
|
||||
mkdir -p /etc/nym
|
||||
chown -R nym /etc/nym
|
||||
su nym -c 'NYM_HOME_DIR=/etc/nym nym-mixnode init --host 0.0.0.0 --id nym-mixnode'
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Nym Mixnode
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/nym-mixnode run --id nym-mixnode
|
||||
User=nym
|
||||
Environment="NYM_HOME_DIR=/etc/nym"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
"axios": "^0.27.2",
|
||||
"eslint": "^8.21.0",
|
||||
"form-data": "4.0.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
@@ -1671,13 +1671,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz",
|
||||
"integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios-mock-adapter": {
|
||||
@@ -4187,11 +4186,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
@@ -6190,13 +6184,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz",
|
||||
"integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"axios-mock-adapter": {
|
||||
@@ -8030,11 +8023,6 @@
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"npm": "8.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
"axios": "^0.27.2",
|
||||
"eslint": "^8.21.0",
|
||||
"form-data": "4.0.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
|
||||
@@ -981,14 +981,13 @@ axios-mock-adapter@^1.20.0:
|
||||
fast-deep-equal "^3.1.3"
|
||||
is-buffer "^2.0.5"
|
||||
|
||||
axios@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
|
||||
integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
|
||||
axios@^0.27.2:
|
||||
version "0.27.2"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz"
|
||||
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
follow-redirects "^1.14.9"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
babel-jest@^28.1.3:
|
||||
version "28.1.3"
|
||||
@@ -1567,10 +1566,10 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz"
|
||||
integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
|
||||
|
||||
follow-redirects@^1.15.0:
|
||||
version "1.15.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
|
||||
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
|
||||
follow-redirects@^1.14.9:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz"
|
||||
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
|
||||
|
||||
form-data@4.0.0, form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -2576,11 +2575,6 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "extension-storage"
|
||||
version = "1.2.4-rc.2"
|
||||
version = "1.2.4-rc.1"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/nymtech/nym"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
build/*
|
||||
data/*
|
||||
dist/*
|
||||
target/*
|
||||
@@ -1,32 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
target
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
node_modules
|
||||
|
||||
data
|
||||
|
||||
build
|
||||
.cargo
|
||||
|
||||
.DS_Store
|
||||
|
||||
# generated Typescript types from Rust
|
||||
bindings
|
||||
|
||||
staging-config
|
||||
|
||||
dist
|
||||
.nymvpn
|
||||
windows/x86_64*
|
||||
*.wixobj
|
||||
*.wixpdb
|
||||
*.msi
|
||||
mkcert*
|
||||
|
||||
nymvpn-oss-licenses.html
|
||||
nymvpn-oss-licenses-rust.html
|
||||
third-party-licenses.txt
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"svg.preview.background": "editor"
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
# Building nymvpn app
|
||||
|
||||
## Install build dependencies
|
||||
|
||||
### Common for all Platforms
|
||||
|
||||
```
|
||||
cargo install cargo-deb
|
||||
cargo install cargo-generate-rpm
|
||||
cargo install --force cargo-make
|
||||
cargo install sd
|
||||
cargo install ripgrep
|
||||
cargo install cargo-about
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
```
|
||||
apt install build-essential \
|
||||
pkg-config \
|
||||
libgtk-3-dev \
|
||||
libssl-dev \
|
||||
libsoup2.4-dev \
|
||||
libjavascriptcoregtk-4.0-dev \
|
||||
libwebkit2gtk-4.0-dev \
|
||||
libmnl-dev \
|
||||
libnftnl-dev \
|
||||
protobuf-compiler \
|
||||
zip \
|
||||
|
||||
```
|
||||
|
||||
Install protoc on x86_64/amd64 machines
|
||||
```
|
||||
# x86_64
|
||||
curl -Lo protoc-3.19.1-linux-x86_64.zip \
|
||||
https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-linux-x86_64.zip && \
|
||||
unzip protoc-3.19.1-linux-x86_64.zip -d /tmp && \
|
||||
mv /tmp/bin/protoc /usr/bin/protoc && \
|
||||
rm protoc-3.19.1-linux-x86_64.zip
|
||||
```
|
||||
|
||||
Install protoc on arm64 machines
|
||||
```
|
||||
# aarch64
|
||||
curl -Lo protoc-3.19.1-linux-aarch_64.zip \
|
||||
https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-linux-aarch_64.zip && \
|
||||
unzip protoc-3.19.1-linux-aarch_64.zip -d /tmp && \
|
||||
sudo mv /tmp/bin/protoc /usr/bin/protoc && \
|
||||
rm protoc-3.19.1-linux-aarch_64.zip
|
||||
|
||||
```
|
||||
|
||||
### macOS
|
||||
TODO
|
||||
|
||||
### Windows
|
||||
TODO
|
||||
|
||||
## Build Debian package
|
||||
|
||||
```
|
||||
cargo make deb
|
||||
```
|
||||
|
||||
## Build RPM package
|
||||
|
||||
```
|
||||
cargo make rpm
|
||||
```
|
||||
|
||||
## Build macOS package
|
||||
|
||||
```
|
||||
cargo make pkg
|
||||
```
|
||||
|
||||
To codesign for distribution provide following environment variables:
|
||||
|
||||
```
|
||||
APPLE_TEAM_ID=...
|
||||
APPLICATION_SIGNING_IDENTITY=...
|
||||
INSTALLER_SIGNING_IDENTITY=...
|
||||
cargo make pkg
|
||||
```
|
||||
|
||||
## Build installer for Windows
|
||||
|
||||
```
|
||||
cargo make msi
|
||||
```
|
||||
|
||||
To codesign for distribution:
|
||||
|
||||
```
|
||||
SIGN=true cargo make msi
|
||||
```
|
||||
|
||||
## Building for Production for Linux
|
||||
|
||||
### Build the Builder
|
||||
|
||||
Build the Docker image to build nymvpn app.
|
||||
```
|
||||
cd nymvpn-packages
|
||||
cargo make builder
|
||||
```
|
||||
|
||||
This will output `tag.txt`, commit it into source code.
|
||||
|
||||
### Build .deb and .rpm
|
||||
|
||||
This step uses builder Docker image with tag in `nymvpn-packages/tag.txt`. The final rpm and deb packages will be stored in `dist` directory.
|
||||
|
||||
```
|
||||
# For host platform
|
||||
cargo make linux
|
||||
|
||||
# For target platform
|
||||
cargo make -e TARGET=aarch64-unknown-linux-gnu linux
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Firstly, thank you for considering to contribute and make nymvpn-app better! Please note that all of your contributions would be under GPL-3.0.
|
||||
|
||||
- Please see issues with `help wanted` or `good first issue` labels.
|
||||
- For bug fixes, Pull Requests or Github Issues are welcome.
|
||||
- For new features its best to create a Github Issue with detailed description.
|
||||
@@ -1,22 +0,0 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"nymvpn-cli",
|
||||
"nymvpn-config",
|
||||
"nymvpn-controller",
|
||||
"nymvpn-daemon",
|
||||
"nymvpn-entity",
|
||||
"nymvpn-migration",
|
||||
"nymvpn-packages",
|
||||
"nymvpn-server",
|
||||
"nymvpn-types",
|
||||
"nymvpn-ui/src-tauri",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
#opt-level = 'z' # Optimize for size.
|
||||
opt-level = 3
|
||||
lto = true # Enable Link Time Optimization
|
||||
#codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||
#panic = 'abort' # Abort on panic
|
||||
strip = true # Strip symbols from binary*
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -1,331 +0,0 @@
|
||||
[env]
|
||||
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||
PWD = {script = ["pwd"]}
|
||||
REPO_ROOT = "${PWD}"
|
||||
BUILDER_TAG = {script = ["cat nymvpn-packages/tag.txt"] }
|
||||
UPSTREAM_REPO = "https://github.com/upvpn/mullvadvpn-app.git"
|
||||
UPSTREAM_REV = "2023.3.upvpn"
|
||||
UPSTREAM_REPO_PATH = "${PWD}/.upvpn/mullvadvpn-app"
|
||||
RUSTUP_HOST = { script = ["rustup show | rg host | awk '{print $3}'"] }
|
||||
APP_VERSION = { script = ["grep version nymvpn-packages/Cargo.toml | cut -d '\"' -f2"]}
|
||||
TARGET = { script = ["echo ${RUSTUP_HOST}"], condition = { env_not_set = ["TARGET"] } }
|
||||
STRIP = {script = ["([ ${TARGET} = \"aarch64-unknown-linux-gnu\" ] && echo \"--no-strip\") || echo \"--strip\""]}
|
||||
|
||||
|
||||
[tasks.release-build]
|
||||
workspace = false
|
||||
command = "cargo"
|
||||
args = ["build", "--release", "--target", "${TARGET}"]
|
||||
|
||||
[tasks.deb]
|
||||
workspace = false
|
||||
command = "cargo"
|
||||
args = ["deb", "-p", "nymvpn-packages", "--target", "${TARGET}", "${STRIP}", "${@}"]
|
||||
dependencies = ["oss", "ui", "wglib"]
|
||||
|
||||
[tasks.rpm]
|
||||
workspace = false
|
||||
command = "cargo"
|
||||
args = ["generate-rpm", "-p", "nymvpn-packages", "--target", "${TARGET}", "${@}"]
|
||||
dependencies = ["oss", "ui", "wglib", "release-build", "strip"]
|
||||
|
||||
[tasks.rpm-no-build]
|
||||
workspace = false
|
||||
command = "cargo"
|
||||
args = ["generate-rpm", "-p", "nymvpn-packages", "--target", "${TARGET}", "${@}"]
|
||||
dependencies = ["ui", "wglib", "strip"]
|
||||
|
||||
[tasks.strip]
|
||||
workspace = false
|
||||
script = '''
|
||||
CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-target}
|
||||
|
||||
if [ "${STRIP:-}" = "--strip" ]; then
|
||||
for file in nymvpn nymvpn-ui nymvpn-daemon
|
||||
do
|
||||
output="${CARGO_TARGET_DIR}/${TARGET}/release/${file}"
|
||||
if [ -f "${output}" ]; then
|
||||
strip "${output}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.pkg]
|
||||
workspace = false
|
||||
script = '''
|
||||
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
|
||||
cp -R nymvpn-packages/macos ${tempdir}
|
||||
cp nymvpn-assets/icons/icon.icns ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/Resources
|
||||
cp nymvpn-packages/nymvpn-oss-licenses.html ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/Resources
|
||||
cp target/${TARGET}/release/nymvpn ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/Resources
|
||||
cp target/${TARGET}/release/nymvpn-daemon ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/Resources
|
||||
cp target/${TARGET}/release/nymvpn-ui ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/MacOS
|
||||
rm ${tempdir}/macos/pkg/root/Applications/upvpn.app/Contents/MacOS/.gitkeep
|
||||
pushd ${tempdir}/macos
|
||||
./build.sh "${APP_VERSION}"
|
||||
popd
|
||||
mkdir -p target/pkg
|
||||
AARCH=$(uname -m)
|
||||
cp ${tempdir}/macos/nymvpn-${APP_VERSION}.pkg target/pkg/nymvpn-${APP_VERSION}-${AARCH}.pkg
|
||||
echo "Output: target/pkg/nymvpn-${APP_VERSION}-${AARCH}.pkg"
|
||||
rm -r ${tempdir}
|
||||
'''
|
||||
dependencies = ["oss", "ui", "wglib", "release-build"]
|
||||
|
||||
[tasks.setupupstream]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
mkdir -p ${UPSTREAM_REPO_PATH}
|
||||
|
||||
if [ ! -d ${UPSTREAM_REPO_PATH}/.git ]; then
|
||||
git clone ${UPSTREAM_REPO} ${UPSTREAM_REPO_PATH}
|
||||
cd ${UPSTREAM_REPO_PATH} && git submodule update --init && cd -
|
||||
fi
|
||||
|
||||
cd ${UPSTREAM_REPO_PATH}
|
||||
git fetch --all --tags
|
||||
git checkout ${UPSTREAM_REV}
|
||||
'''
|
||||
|
||||
[tasks.wglib]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
cd ${UPSTREAM_REPO_PATH}
|
||||
./wireguard/build-wireguard-go.sh "${TARGET}"
|
||||
cp -r ${UPSTREAM_REPO_PATH}/build ${REPO_ROOT}
|
||||
'''
|
||||
dependencies = ["cargo-config", "setupupstream"]
|
||||
|
||||
[tasks.winfw]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
output_dir=${REPO_ROOT}/windows/${TARGET}
|
||||
mkdir -p ${output_dir}
|
||||
cd ${UPSTREAM_REPO_PATH}
|
||||
IS_RELEASE=true CPP_BUILD_MODES=Release ./build-windows-modules.sh
|
||||
cp -r ${UPSTREAM_REPO_PATH}/windows/winfw/bin/x64-Release/ ${output_dir}
|
||||
'''
|
||||
|
||||
[tasks.windows]
|
||||
workspace = false
|
||||
dependencies = ["oss", "cargo-config", "setupupstream", "wglib", "ui", "winfw", "release-build"]
|
||||
|
||||
[tasks.windows-sign]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
./nymvpn-packages/windows/sign.sh \
|
||||
target/${TARGET}/release/nymvpn.exe \
|
||||
target/${TARGET}/release/nymvpn-ui.exe \
|
||||
target/${TARGET}/release/nymvpn-daemon.exe \
|
||||
build/lib/${TARGET}/libwg.dll \
|
||||
windows/${TARGET}/X64-Release/winfw.dll
|
||||
'''
|
||||
|
||||
[tasks.only-msi]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
cd nymvpn-packages/windows
|
||||
candle -ext WixUtilExtension -dAppVersion=${APP_VERSION} -out nymvpn.wixobj -arch x64 nymvpn.wsx
|
||||
light -ext WixUtilExtension -dAppVersion=${APP_VERSION} -out nymvpn-x64-${APP_VERSION}.msi nymvpn.wixobj
|
||||
'''
|
||||
|
||||
[tasks.sign-msi]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
./nymvpn-packages/windows/sign.sh nymvpn-packages/windows/nymvpn-x64-${APP_VERSION}.msi
|
||||
'''
|
||||
|
||||
[tasks.msi]
|
||||
workspace = false
|
||||
dependencies = ["windows", "windows-sign", "only-msi", "sign-msi"]
|
||||
|
||||
[tasks.cargo-config]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
root_dir=$(pwd)
|
||||
mkdir -p ${root_dir}/.cargo
|
||||
cp ${root_dir}/nymvpn-packages/cargo-config.toml ${root_dir}/.cargo/config
|
||||
sd __REPO_ROOT__ "${root_dir}" ${root_dir}/.cargo/config
|
||||
'''
|
||||
|
||||
[tasks.ui]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
cd nymvpn-ui
|
||||
npm install
|
||||
npm run build
|
||||
'''
|
||||
|
||||
[tasks.volumes-for-build]
|
||||
workspace = false
|
||||
script = '''
|
||||
docker volume rm nymvpn-app-builder || true
|
||||
docker volume create nymvpn-app-builder-cargo-git
|
||||
docker volume create nymvpn-app-builder-cargo-registry
|
||||
docker volume create nymvpn-app-builder-cargo-target
|
||||
docker volume create nymvpn-app-builder-go
|
||||
docker volume create nymvpn-app-builder
|
||||
'''
|
||||
|
||||
[tasks.clear-and-copy-source]
|
||||
workspace = false
|
||||
script = '''
|
||||
|
||||
docker run --rm -v ${PWD}:/source \
|
||||
-v nymvpn-app-builder:/build \
|
||||
ghcr.io/nymvpn/nymvpn-app-builder:${BUILDER_TAG} \
|
||||
cp -r \
|
||||
/source/nymvpn-assets \
|
||||
/source/nymvpn-cli \
|
||||
/source/nymvpn-config \
|
||||
/source/nymvpn-controller \
|
||||
/source/nymvpn-daemon \
|
||||
/source/nymvpn-entity \
|
||||
/source/nymvpn-migration \
|
||||
/source/nymvpn-packages \
|
||||
/source/nymvpn-server \
|
||||
/source/nymvpn-types \
|
||||
/source/nymvpn-ui \
|
||||
/source/Cargo.toml \
|
||||
/source/Cargo.lock \
|
||||
/source/about.toml \
|
||||
/source/Makefile.toml \
|
||||
/source/.dockerignore \
|
||||
/build/
|
||||
|
||||
docker run --rm \
|
||||
-v nymvpn-app-builder:/build \
|
||||
ghcr.io/nymvpn/nymvpn-app-builder:${BUILDER_TAG} chown -R root:root .
|
||||
'''
|
||||
|
||||
[tasks.builder-shell]
|
||||
workspace = false
|
||||
command = "docker"
|
||||
args = [
|
||||
"run",
|
||||
"--rm",
|
||||
"-it",
|
||||
"-v", "nymvpn-app-builder-cargo-git:/root/.cargo/git",
|
||||
"-v", "nymvpn-app-builder-cargo-registry:/root/.cargo/registry",
|
||||
"-v", "nymvpn-app-builder-cargo-target:/root/.cargo/target",
|
||||
"-v", "nymvpn-app-builder-go:/root/go",
|
||||
"-v", "nymvpn-app-builder:/build",
|
||||
# To clone github repo using ssh
|
||||
"-v", "${HOME}/.ssh:/root/.ssh",
|
||||
"-e", "CARGO_NET_GIT_FETCH_WITH_CLI=true",
|
||||
"-e", "TARGET=${TARGET}",
|
||||
# tag created by builder task
|
||||
"ghcr.io/nymvpn/nymvpn-app-builder:${BUILDER_TAG}",
|
||||
"bash"
|
||||
]
|
||||
dependencies = ["volumes-for-build", "clear-and-copy-source"]
|
||||
|
||||
[tasks.linux-packages]
|
||||
workspace = false
|
||||
# only need to build once for packaging both
|
||||
dependencies = ["deb", "rpm-no-build"]
|
||||
|
||||
[tasks.build-in-container]
|
||||
workspace = false
|
||||
command = "docker"
|
||||
args = [
|
||||
"run",
|
||||
"--rm",
|
||||
"-it",
|
||||
"-v", "nymvpn-app-builder-cargo-git:/root/.cargo/git",
|
||||
"-v", "nymvpn-app-builder-cargo-registry:/root/.cargo/registry",
|
||||
"-v", "nymvpn-app-builder-cargo-target:/root/.cargo/target",
|
||||
"-v", "nymvpn-app-builder-go:/root/go",
|
||||
"-v", "nymvpn-app-builder:/build",
|
||||
# To clone github repo using ssh
|
||||
"-v", "${HOME}/.ssh:/root/.ssh",
|
||||
"-e", "CARGO_NET_GIT_FETCH_WITH_CLI=true",
|
||||
"-e", "TARGET=${TARGET}",
|
||||
# tag created by builder task
|
||||
"ghcr.io/nymvpn/nymvpn-app-builder:${BUILDER_TAG}",
|
||||
"cargo",
|
||||
"make",
|
||||
"-e", "TARGET=${TARGET}",
|
||||
"linux-packages",
|
||||
]
|
||||
dependencies = ["volumes-for-build", "clear-and-copy-source"]
|
||||
|
||||
[tasks.output-dir]
|
||||
workspace = false
|
||||
script = '''
|
||||
echo "TARGET: ${TARGET}"
|
||||
mkdir -p ${PWD}/dist/${TARGET}
|
||||
'''
|
||||
|
||||
[tasks.linux]
|
||||
workspace = false
|
||||
command = "docker"
|
||||
args = [
|
||||
"run",
|
||||
"--rm",
|
||||
"-it",
|
||||
"-v", "nymvpn-app-builder-cargo-target:/root/.cargo/target",
|
||||
"-v", "${PWD}/dist:/dist",
|
||||
# tag created by builder task
|
||||
"ghcr.io/nymvpn/nymvpn-app-builder:${BUILDER_TAG}",
|
||||
"cp", "-r",
|
||||
"/root/.cargo/target/${TARGET}/debian", "/root/.cargo/target/${TARGET}/generate-rpm",
|
||||
"/dist/${TARGET}",
|
||||
]
|
||||
dependencies = ["output-dir", "build-in-container"]
|
||||
|
||||
[tasks.icon]
|
||||
workspace = false
|
||||
script = '''
|
||||
cd nymvpn-ui
|
||||
cargo tauri icon -o ../nymvpn-assets/icons ../nymvpn-assets/app-icon.png
|
||||
'''
|
||||
|
||||
[tasks.oss]
|
||||
workspace = false
|
||||
script_runner = "sh"
|
||||
script = '''
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
cargo about generate nymvpn-packages/nymvpn-oss-licenses-rust.hbs > nymvpn-packages/nymvpn-oss-licenses-rust.html
|
||||
sd "(talpid-[\w-]+|tunnel-obfuscation) (\d+.\d+.\d+)" '$1 $2 Copyright (C) Mullvad VPN AB, GPL-3.0' nymvpn-packages/nymvpn-oss-licenses-rust.html
|
||||
sd "https://crates.io/crates//(talpid-\w+|tunnel-obfuscation)" 'https://github.com/mullvad/mullvadvpn-app/tree/main/$1' nymvpn-packages/nymvpn-oss-licenses-rust.html
|
||||
|
||||
cd nymvpn-ui && npm i && cd ..
|
||||
npx --yes generate-license-file --overwrite --ci --input nymvpn-ui/package.json --output nymvpn-packages/third-party-licenses.txt
|
||||
|
||||
cat nymvpn-packages/nymvpn-oss-licenses-header.hbs > nymvpn-packages/nymvpn-oss-licenses.html
|
||||
cat nymvpn-packages/nymvpn-oss-licenses-rust.html >> nymvpn-packages/nymvpn-oss-licenses.html
|
||||
cat nymvpn-packages/third-party-licenses.txt >> nymvpn-packages/nymvpn-oss-licenses.html
|
||||
cat nymvpn-packages/nymvpn-oss-licenses-footer.hbs >> nymvpn-packages/nymvpn-oss-licenses.html
|
||||
'''
|
||||
|
||||
|
||||
|
||||
[tasks.android-init]
|
||||
workspace = false
|
||||
script = '''
|
||||
git clone https://github.com:WireGuard/wireguard-tools.git nymvpn-android/app/tunnel/wireguard-tools
|
||||
cd nymvpn-android/app/tunnel/wireguard-tools && git checkout b4f6b4f229d291daf7c35c6f1e7f4841cc6d69bc && cd -
|
||||
git clone https://github.com:termux/termux-elf-cleaner.git nymvpn-android/app/tunnel/elf-cleaner
|
||||
cd nymvpn-android/app/tunnel/elf-cleaner && git checkout 7efc05090675ec6161b7def862728086a26c3b1f && cd -
|
||||
'''
|
||||
@@ -1,12 +0,0 @@
|
||||
# Network Dependency
|
||||
|
||||
nymvpn takes its design inspiration from [mullvadvpn-app](https://github.com/mullvad/mullvadvpn-app).
|
||||
For example Actor pattern is foundational in daemon.
|
||||
|
||||
However, nymvpn uses different design/technologies than mullvadvpn-app in many places: for persisting data in sqlite (sea-orm), desktop app (Tauri), packaging for Windows (Wix), Toml for configuration files, GRPC for backend API.
|
||||
|
||||
nymvpn uses "talpid" crates for all of the client side networking from mullvadvpn-app project, with minimal modification. For example, interface on Linux would be named "nymvpn".
|
||||
|
||||
The modifications to upstream mullvadvpn-app can be found [here](https://github.com/upvpn/mullvadvpn-app)
|
||||
|
||||
We're not affiliated with Mullvad, and we're grateful for their high quality open source projects. If nymvpn doesn't offer what you're looking for please see VPN offering from Mullvad at https://mullvad.net/
|
||||
@@ -1,63 +0,0 @@
|
||||
<div align="center">
|
||||
<a href="https://nymvpn.net">
|
||||
<img src="./nymvpn-assets/icons/Square71x71Logo.png" >
|
||||
</a>
|
||||
<h3 align="center">nymvpn</h3>
|
||||
<h4 align="center">A Modern Serverless VPN</h4>
|
||||
<img src="nymvpn-assets/cli.gif" />
|
||||
</div>
|
||||
|
||||
# nymvpn
|
||||
|
||||
nymvpn (pronounced Up VPN) app is WireGuard VPN client for Linux, macOS, Windows, and Android.
|
||||
For more information please visit https://nymvpn.net
|
||||
|
||||
nymvpn desktop app is made up of UI, CLI and background Daemon.
|
||||
|
||||
# Serverless
|
||||
|
||||
nymvpn uses Serverless computing model, where a Linux based WireGuard server is provisioned on public cloud providers when app requests to connect to VPN. And server is deprovisioned when app requests to disconnect from VPN.
|
||||
|
||||
All of it happens with a single click or tap on the UI, or a single command on terminal.
|
||||
|
||||
# Install
|
||||
App for Linux, macOS, Windows, and Android is available for download on [Github Releases](https://github.com/nymvpn/nymvpn-app/releases) or on website at https://nymvpn.net/download
|
||||
|
||||
|
||||
# Code
|
||||
|
||||
## Organization
|
||||
|
||||
| Crate or Directory | Description |
|
||||
| --- | --- |
|
||||
| nymvpn-android | Standalone app for Android. |
|
||||
| nymvpn-cli | Code for `nymvpn` cli. |
|
||||
| nymvpn-config | Configuration read from env vars, `nymvpn.conf.toml` are merged at runtime in `nymvpn-config` and is source of runtime configuration for `nymvpn-cli`, `nymvpn-daemon`, and `nymvpn-ui`. |
|
||||
| nymvpn-controller | Defines GRPC protobuf for APIs exposed by `nymvpn-daemon` to be consumed by `nymvpn-cli` and `nymvpn-ui`. |
|
||||
| nymvpn-daemon | Daemon is responsible for orchestrating a VPN session. It takes input from nymvpn-cli or nymvpn-ui via GRPC (defined in `nymvpn-controller`) and make calls to backend server via separate GRPC (defined in `nymvpn-server`). When backend informs that a server is ready daemon configures network tunnel, see [NetworkDependency.md](./NetworkDependency.md) for more info. |
|
||||
| nymvpn-entity | Defines data models used by nymvpn-daemon to persist data on disk in sqlite database. |
|
||||
| nymvpn-migration | Defines database migration from which `nymvpn-entity` is generated. |
|
||||
| nymvpn-packages| Contains resources to package binaries for distribution on macOS (pkg), Linux (rpm & deb), and Windows (msi). |
|
||||
|nymvpn-server| Contains GRPC protobuf definitions and code for communication with backend server. |
|
||||
| nymvpn-types | Defines common Rust types for data types used in various crates. These are also used to generate Typescript types for nymvpn-ui for seamless serialization and deserialization across language boundaries. |
|
||||
|nymvpn-ui| A Tauri based desktop app. GPRC communication with daemon is done in Rust. Typescript code interact with Rust code via Tauri commands. |
|
||||
|
||||
|
||||
## Building Desktop Apps
|
||||
|
||||
Please see [Build.md](./Build.md)
|
||||
|
||||
## Building Android App
|
||||
|
||||
Please see [nymvpn-android/README.md](./nymvpn-android/README.md)
|
||||
|
||||
# License
|
||||
|
||||
Android app, and all Rust crates in this repository are [licensed under GPL version 3](./LICENSE).
|
||||
|
||||
Copyright (C) 2023 Nym Technologies S.A.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
@@ -1,3 +0,0 @@
|
||||
# Security
|
||||
|
||||
If you find security issues/vulnerabilities, please report them via security@nymvpn.net with details about the vulnerability/issue. Security issue should not be reported via public Github Issue tracker.
|
||||
@@ -1,30 +0,0 @@
|
||||
accepted = [
|
||||
"Apache-2.0",
|
||||
"MIT",
|
||||
"GPL-3.0",
|
||||
"MPL-2.0",
|
||||
"ISC",
|
||||
"BSD-3-Clause",
|
||||
"BSD-2-Clause",
|
||||
"Unicode-DFS-2016",
|
||||
"WTFPL",
|
||||
"OpenSSL",
|
||||
"NOASSERTION",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
]
|
||||
|
||||
workarounds = [
|
||||
"ring",
|
||||
"rustls",
|
||||
]
|
||||
|
||||
targets = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"aarch64-apple-darwin",
|
||||
"x86_64-pc-windows-msvc",
|
||||
]
|
||||
|
||||
ignore-build-dependencies = true
|
||||
ignore-dev-dependencies = true
|
||||
|
Before Width: | Height: | Size: 545 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 883 B |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 763 B |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 545 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 545 KiB |
@@ -1,659 +0,0 @@
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="100%" viewBox="0 0 2480 2480" enable-background="new 0 0 2480 2480" xml:space="preserve">
|
||||
<path fill="#000000" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M2.000000,1156.000000
|
||||
C2.000000,771.474121 2.000000,386.948273 2.000000,2.000000
|
||||
C386.718231,2.000000 771.436646,2.000000 1157.575928,2.774093
|
||||
C1156.895752,4.252493 1154.836182,5.386602 1152.687378,5.593789
|
||||
C1133.805298,7.414357 1114.907104,9.069780 1095.226807,10.759283
|
||||
C1084.722656,12.009069 1074.967529,13.036946 1065.296387,14.588613
|
||||
C1046.388062,17.622320 1027.440552,20.518517 1008.669189,24.271704
|
||||
C988.973267,28.209772 969.464844,33.085560 949.059448,37.567116
|
||||
C946.606445,37.857994 944.916931,37.960854 943.338196,38.433754
|
||||
C905.230347,49.848984 866.958191,60.757950 829.109192,72.977303
|
||||
C809.630737,79.265816 790.909973,87.901482 771.094727,95.550079
|
||||
C708.056335,120.873268 648.601501,151.681488 591.455200,186.981873
|
||||
C581.890991,192.889832 572.727356,199.446106 562.717407,205.841736
|
||||
C485.335510,255.803986 415.925385,314.480255 351.878967,379.639160
|
||||
C350.056000,381.493774 348.766235,383.872528 346.598083,386.351074
|
||||
C336.670746,396.616455 326.916168,406.152496 318.166016,416.535034
|
||||
C296.527496,442.210358 274.620392,467.712158 254.140381,494.299805
|
||||
C214.260880,546.072327 179.360336,601.135254 148.695190,658.878784
|
||||
C118.683922,715.390991 92.776169,773.679565 71.820473,834.158081
|
||||
C50.995865,894.258301 34.644413,955.509277 23.362127,1018.139221
|
||||
C16.235693,1057.699341 10.648326,1097.425903 7.645359,1137.512329
|
||||
C7.224460,1143.130981 6.797827,1148.756470 6.088929,1154.342651
|
||||
C5.794058,1156.666138 4.936373,1159.359985 2.000000,1156.000000
|
||||
z"/>
|
||||
<path fill="#000000" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1144.000000,2482.000000
|
||||
C763.472534,2482.000000 382.945099,2482.000000 2.000000,2482.000000
|
||||
C2.000000,2092.614990 2.000000,1703.229980 2.840354,1312.796387
|
||||
C4.341088,1313.846558 5.403334,1315.909912 5.592262,1318.050293
|
||||
C6.408852,1327.301758 7.018379,1336.572510 7.615459,1345.841919
|
||||
C10.071630,1383.973022 15.361381,1421.746460 21.943558,1459.353882
|
||||
C31.523199,1514.087402 44.837513,1567.894409 61.760971,1620.828613
|
||||
C86.347641,1697.732544 118.251434,1771.449707 157.290771,1842.110718
|
||||
C196.026291,1912.221802 241.077148,1977.993042 292.739014,2039.196167
|
||||
C304.506073,2053.136963 317.056641,2066.416016 329.501801,2080.542725
|
||||
C338.064240,2090.107910 345.990631,2099.520020 354.754700,2108.074463
|
||||
C375.889771,2128.703857 397.016846,2149.373779 418.914001,2169.179443
|
||||
C435.849579,2184.497559 453.947357,2198.531006 471.971558,2213.595947
|
||||
C480.738647,2220.616211 488.968445,2227.299561 497.402283,2233.714600
|
||||
C538.868896,2265.256348 582.676025,2293.294678 627.428223,2319.866211
|
||||
C637.853210,2326.055908 649.016357,2331.002197 660.245605,2337.048828
|
||||
C661.758423,2338.312500 662.805664,2339.164307 663.980896,2339.765869
|
||||
C705.744995,2361.139404 748.015625,2381.423828 791.896851,2398.136475
|
||||
C807.088379,2403.922363 822.536743,2409.033447 838.378052,2414.957031
|
||||
C882.580322,2430.489990 926.889465,2443.370117 972.065918,2453.111572
|
||||
C987.937622,2456.534180 1003.978516,2459.171875 1020.532410,2462.681152
|
||||
C1053.641235,2467.597900 1086.152588,2472.055908 1118.684082,2476.362061
|
||||
C1125.906372,2477.318115 1133.209839,2477.647217 1140.452515,2478.470947
|
||||
C1142.249756,2478.675537 1145.452026,2478.209473 1144.000000,2482.000000
|
||||
z"/>
|
||||
<path fill="#000000" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1330.000000,2.000000
|
||||
C1713.857544,2.000000 2097.715088,2.000000 2482.000000,2.000000
|
||||
C2482.000000,377.384888 2482.000000,752.769958 2481.270508,1129.683350
|
||||
C2479.812988,1129.458130 2478.641357,1127.757446 2478.425049,1125.942993
|
||||
C2476.303955,1108.153687 2474.590576,1090.313354 2472.288330,1072.548706
|
||||
C2465.317139,1018.756775 2454.290039,965.764282 2439.924805,913.480469
|
||||
C2410.317139,805.719543 2366.872070,703.805603 2309.638672,607.834778
|
||||
C2279.080322,556.593994 2245.477295,507.387878 2207.102783,461.646027
|
||||
C2185.742920,436.185822 2163.918457,411.044861 2141.083740,386.914246
|
||||
C2120.303955,364.955353 2097.875244,344.556519 2075.900391,322.875854
|
||||
C2049.050293,300.195190 2023.122681,277.266205 1995.772095,256.183319
|
||||
C1919.572388,197.446091 1837.257935,148.730927 1749.337158,109.649597
|
||||
C1727.213379,99.815414 1704.468994,91.377357 1681.312744,82.023506
|
||||
C1661.278564,74.856789 1642.080688,67.535522 1622.562744,61.200005
|
||||
C1605.227905,55.573128 1587.538086,51.039959 1569.348145,45.649433
|
||||
C1535.447754,37.638149 1502.300781,29.539127 1468.921631,22.549688
|
||||
C1450.818604,18.759012 1432.319946,16.858213 1413.201904,13.909479
|
||||
C1398.085693,11.913866 1383.790894,9.888351 1369.441406,8.383907
|
||||
C1357.681641,7.150996 1345.856567,6.545444 1334.061523,5.645791
|
||||
C1331.152710,5.423922 1331.154907,5.395327 1330.000000,2.000000
|
||||
z"/>
|
||||
<path fill="#000000" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M2482.000000,1354.000000
|
||||
C2482.000000,1729.859741 2482.000000,2105.719482 2482.000000,2482.000000
|
||||
C2103.281738,2482.000000 1724.563354,2482.000000 1344.315430,2481.265137
|
||||
C1344.194214,2479.820801 1345.551147,2478.641357 1347.019287,2478.481201
|
||||
C1354.873779,2477.624268 1362.792847,2477.302979 1370.622192,2476.279785
|
||||
C1398.529907,2472.632324 1426.410522,2468.776123 1455.144531,2464.862793
|
||||
C1484.524414,2458.810791 1513.163086,2453.338135 1541.560669,2446.816162
|
||||
C1559.249390,2442.753906 1576.573853,2437.106201 1594.844482,2432.142090
|
||||
C1600.700806,2430.654297 1605.865479,2429.451660 1610.832886,2427.692139
|
||||
C1641.329224,2416.889404 1671.780884,2405.960693 1702.995361,2394.897949
|
||||
C1714.292969,2390.337891 1725.003662,2386.301025 1735.360352,2381.500488
|
||||
C1760.088379,2370.039062 1784.854858,2358.629395 1809.236816,2346.459473
|
||||
C1869.238037,2316.510742 1925.746704,2280.830078 1979.677734,2241.039062
|
||||
C2015.833496,2214.363281 2050.923828,2186.328613 2083.269287,2155.113281
|
||||
C2110.550537,2128.784912 2137.848877,2102.374756 2163.551514,2074.534912
|
||||
C2197.400391,2037.871460 2228.250977,1998.649048 2257.070068,1957.831177
|
||||
C2302.509521,1893.473022 2341.425049,1825.434570 2374.022217,1753.742676
|
||||
C2402.992188,1690.027466 2426.233154,1624.269775 2443.892578,1556.565674
|
||||
C2459.084717,1498.321045 2470.223145,1439.301270 2476.330078,1379.378052
|
||||
C2477.070068,1372.116943 2477.632080,1364.836426 2478.475586,1357.588135
|
||||
C2478.686279,1355.777344 2478.205322,1352.590210 2482.000000,1354.000000
|
||||
z"/>
|
||||
<path fill="#FD0059" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M2482.000000,1353.062744
|
||||
C2478.205322,1352.590210 2478.686279,1355.777344 2478.475586,1357.588135
|
||||
C2477.632080,1364.836426 2477.070068,1372.116943 2476.330078,1379.378052
|
||||
C2470.223145,1439.301270 2459.084717,1498.321045 2443.892578,1556.565674
|
||||
C2426.233154,1624.269775 2402.992188,1690.027466 2374.022217,1753.742676
|
||||
C2341.425049,1825.434570 2302.509521,1893.473022 2257.070068,1957.831177
|
||||
C2228.250977,1998.649048 2197.400391,2037.871460 2163.551514,2074.534912
|
||||
C2137.848877,2102.374756 2110.550537,2128.784912 2083.269287,2155.113281
|
||||
C2050.923828,2186.328613 2015.833496,2214.363281 1979.677734,2241.039062
|
||||
C1925.746704,2280.830078 1869.238037,2316.510742 1809.236816,2346.459473
|
||||
C1784.854858,2358.629395 1760.088379,2370.039062 1735.360352,2381.500488
|
||||
C1725.003662,2386.301025 1714.292969,2390.337891 1702.934937,2393.890381
|
||||
C1702.222534,2384.750732 1700.063599,2375.522217 1702.984741,2368.367676
|
||||
C1706.637573,2359.420410 1703.389404,2351.443115 1703.707520,2343.142334
|
||||
C1704.223755,2329.672607 1705.858032,2316.132568 1704.636475,2302.210449
|
||||
C1706.131104,2301.343262 1706.999023,2300.838623 1707.911499,2300.435059
|
||||
C1872.842163,2227.512939 2013.766113,2122.305664 2129.126953,1983.796509
|
||||
C2295.175537,1784.427856 2384.085449,1554.437256 2397.438477,1295.429810
|
||||
C2400.011230,1245.527954 2398.809570,1195.543945 2394.555176,1145.641113
|
||||
C2389.225586,1083.130127 2379.285156,1021.439026 2363.923584,960.643433
|
||||
C2319.840820,786.178650 2239.296875,630.459351 2122.668213,493.482666
|
||||
C2104.113770,471.691101 2084.243408,451.019867 2065.204102,428.914398
|
||||
C2066.549561,423.919678 2068.180664,419.901825 2068.675049,415.748596
|
||||
C2069.418701,409.502869 2074.961914,403.035431 2069.638428,396.963745
|
||||
C2062.773438,389.134186 2062.122070,381.922882 2069.412598,374.247559
|
||||
C2069.738037,373.904999 2069.454346,372.983826 2069.454346,371.716705
|
||||
C2065.993652,368.276642 2060.073975,365.611786 2062.831055,358.350494
|
||||
C2064.850586,353.031799 2069.009521,354.874359 2072.047607,355.040344
|
||||
C2072.672607,349.993500 2073.195801,345.550232 2073.778809,341.114838
|
||||
C2074.552490,335.230011 2075.373047,329.351349 2076.173340,323.470032
|
||||
C2097.875244,344.556519 2120.303955,364.955353 2141.083740,386.914246
|
||||
C2163.918457,411.044861 2185.742920,436.185822 2207.102783,461.646027
|
||||
C2245.477295,507.387878 2279.080322,556.593994 2309.638672,607.834778
|
||||
C2366.872070,703.805603 2410.317139,805.719543 2439.924805,913.480469
|
||||
C2454.290039,965.764282 2465.317139,1018.756775 2472.288330,1072.548706
|
||||
C2474.590576,1090.313354 2476.303955,1108.153687 2478.425049,1125.942993
|
||||
C2478.641357,1127.757446 2479.812988,1129.458130 2481.270508,1130.605713
|
||||
C2482.000000,1204.041748 2482.000000,1278.083618 2482.000000,1353.062744
|
||||
z"/>
|
||||
<path fill="#FD6141" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M329.246643,2079.999756
|
||||
C317.056641,2066.416016 304.506073,2053.136963 292.739014,2039.196167
|
||||
C241.077148,1977.993042 196.026291,1912.221802 157.290771,1842.110718
|
||||
C118.251434,1771.449707 86.347641,1697.732544 61.760971,1620.828613
|
||||
C44.837513,1567.894409 31.523199,1514.087402 21.943558,1459.353882
|
||||
C15.361381,1421.746460 10.071630,1383.973022 7.615459,1345.841919
|
||||
C7.018379,1336.572510 6.408852,1327.301758 5.592262,1318.050293
|
||||
C5.403334,1315.909912 4.341088,1313.846558 2.840354,1311.873901
|
||||
C2.000000,1272.624878 2.000000,1233.249756 2.696669,1192.739746
|
||||
C3.783891,1185.246948 4.191141,1178.889771 4.456792,1172.526733
|
||||
C4.462687,1172.385498 2.854996,1172.177124 2.000000,1172.000000
|
||||
C2.000000,1167.258911 2.000000,1162.517700 2.000000,1156.888306
|
||||
C4.936373,1159.359985 5.794058,1156.666138 6.088929,1154.342651
|
||||
C6.797827,1148.756470 7.224460,1143.130981 7.645359,1137.512329
|
||||
C10.648326,1097.425903 16.235693,1057.699341 23.362127,1018.139221
|
||||
C34.644413,955.509277 50.995865,894.258301 71.820473,834.158081
|
||||
C92.776169,773.679565 118.683922,715.390991 148.695190,658.878784
|
||||
C179.360336,601.135254 214.260880,546.072327 254.140381,494.299805
|
||||
C274.620392,467.712158 296.527496,442.210358 318.166016,416.535034
|
||||
C326.916168,406.152496 336.670746,396.616455 346.819336,387.298340
|
||||
C349.111511,397.039673 350.702759,406.157318 351.959839,415.320801
|
||||
C354.039307,430.478943 347.020142,445.613251 351.698639,460.841003
|
||||
C352.030396,461.920807 351.116547,463.384277 350.778839,464.668579
|
||||
C347.058563,478.817993 346.556641,492.851044 352.077698,507.275665
|
||||
C288.410614,585.358521 235.344467,669.326538 193.521423,760.365295
|
||||
C126.249481,906.800049 91.659683,1060.733765 88.462120,1221.678833
|
||||
C86.775948,1306.550293 94.636253,1390.659058 111.634445,1473.912476
|
||||
C141.932693,1622.306519 199.339981,1759.333130 283.605133,1885.092407
|
||||
C298.609344,1907.485229 314.815765,1929.072510 330.144287,1951.775146
|
||||
C329.368286,1953.753174 328.206390,1955.273804 328.571472,1956.177979
|
||||
C332.204346,1965.176758 325.094452,1975.258179 331.436707,1983.996216
|
||||
C332.000854,1984.773682 331.152161,1986.519043 331.084595,1987.821411
|
||||
C330.446564,2000.127197 326.730957,2012.421387 331.588593,2024.754395
|
||||
C332.597107,2027.314941 331.849121,2030.640747 331.636078,2033.593994
|
||||
C331.187073,2039.818726 330.346924,2046.020508 330.049316,2052.250000
|
||||
C329.607788,2061.491455 329.497742,2070.749023 329.246643,2079.999756
|
||||
z"/>
|
||||
<path fill="#FD2B4F" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1329.062744,2.000000
|
||||
C1331.154907,5.395327 1331.152710,5.423922 1334.061523,5.645791
|
||||
C1345.856567,6.545444 1357.681641,7.150996 1369.441406,8.383907
|
||||
C1383.790894,9.888351 1398.085693,11.913866 1413.202148,14.792110
|
||||
C1414.666626,32.711697 1415.932007,49.558369 1415.786743,66.392868
|
||||
C1415.692139,77.369125 1415.896729,88.638809 1410.759399,99.196487
|
||||
C1365.071655,93.011742 1320.113159,88.816185 1274.882202,87.850662
|
||||
C1265.919922,87.659348 1256.959106,87.391411 1247.998047,86.333542
|
||||
C1248.799072,75.686798 1249.405029,65.844688 1250.443115,56.048374
|
||||
C1252.278687,38.724487 1255.235596,21.364594 1246.212402,4.940386
|
||||
C1245.782349,4.157671 1246.054688,2.988963 1246.000000,2.000000
|
||||
C1273.375122,2.000000 1300.750244,2.000000 1329.062744,2.000000
|
||||
z"/>
|
||||
<path fill="#FE354D" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1245.062744,2.000000
|
||||
C1246.054688,2.988963 1245.782349,4.157671 1246.212402,4.940386
|
||||
C1255.235596,21.364594 1252.278687,38.724487 1250.443115,56.048374
|
||||
C1249.405029,65.844688 1248.799072,75.686798 1247.077271,86.517754
|
||||
C1211.969727,88.932030 1177.771362,90.099472 1143.602539,91.846756
|
||||
C1127.705322,92.659691 1111.865723,94.598114 1095.994629,95.169136
|
||||
C1095.326050,86.458298 1094.384521,78.615601 1094.075439,70.748077
|
||||
C1093.741943,62.257504 1093.748291,53.734406 1094.061401,45.242275
|
||||
C1094.485352,33.744526 1095.342529,22.262749 1096.013794,10.774117
|
||||
C1114.907104,9.069780 1133.805298,7.414357 1152.687378,5.593789
|
||||
C1154.836182,5.386602 1156.895752,4.252493 1158.498291,2.774093
|
||||
C1186.708496,2.000000 1215.416870,2.000000 1245.062744,2.000000
|
||||
z"/>
|
||||
<path fill="#FD394C" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1144.929321,2482.000000
|
||||
C1145.452026,2478.209473 1142.249756,2478.675537 1140.452515,2478.470947
|
||||
C1133.209839,2477.647217 1125.906372,2477.318115 1118.684082,2476.362061
|
||||
C1086.152588,2472.055908 1053.641235,2467.597900 1020.548401,2461.732910
|
||||
C1020.201294,2432.329346 1019.038818,2404.386963 1020.798401,2376.385742
|
||||
C1046.574341,2380.301758 1071.468262,2384.903809 1096.542603,2388.083008
|
||||
C1123.607178,2391.513916 1150.840332,2393.614746 1177.999512,2397.110840
|
||||
C1177.611816,2400.520264 1177.691772,2403.297852 1176.759033,2405.678467
|
||||
C1171.955933,2417.938232 1173.241089,2430.170654 1176.160400,2442.541748
|
||||
C1176.962402,2445.940430 1178.116089,2450.099609 1176.900391,2452.976562
|
||||
C1172.930420,2462.370850 1172.538696,2472.150391 1172.000000,2482.000000
|
||||
C1163.286255,2482.000000 1154.572388,2482.000000 1144.929321,2482.000000
|
||||
z"/>
|
||||
<path fill="#FE304F" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1172.937256,2482.000000
|
||||
C1172.538696,2472.150391 1172.930420,2462.370850 1176.900391,2452.976562
|
||||
C1178.116089,2450.099609 1176.962402,2445.940430 1176.160400,2442.541748
|
||||
C1173.241089,2430.170654 1171.955933,2417.938232 1176.759033,2405.678467
|
||||
C1177.691772,2403.297852 1177.611816,2400.520264 1178.914795,2396.979980
|
||||
C1203.020508,2396.593018 1226.212036,2397.644043 1249.400146,2397.574951
|
||||
C1273.576660,2397.503174 1297.750000,2396.351562 1321.944946,2396.591064
|
||||
C1321.475098,2404.433838 1319.269287,2411.799805 1320.912476,2418.173584
|
||||
C1323.160034,2426.891846 1321.982422,2435.237061 1321.923340,2443.743896
|
||||
C1321.896240,2447.656738 1320.806519,2451.571289 1320.874023,2455.473389
|
||||
C1321.026978,2464.319580 1321.598633,2473.158203 1322.000000,2482.000000
|
||||
C1272.624878,2482.000000 1223.249756,2482.000000 1172.937256,2482.000000
|
||||
z"/>
|
||||
<path fill="#FD2750" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1322.916138,2482.000000
|
||||
C1321.598633,2473.158203 1321.026978,2464.319580 1320.874023,2455.473389
|
||||
C1320.806519,2451.571289 1321.896240,2447.656738 1321.923340,2443.743896
|
||||
C1321.982422,2435.237061 1323.160034,2426.891846 1320.912476,2418.173584
|
||||
C1319.269287,2411.799805 1321.475098,2404.433838 1322.672119,2396.228027
|
||||
C1367.118774,2392.044434 1410.483154,2386.102783 1453.778076,2379.750977
|
||||
C1454.581421,2384.850098 1455.577515,2389.028809 1455.946533,2393.262207
|
||||
C1456.789307,2402.932617 1457.568604,2412.621094 1457.905762,2422.318604
|
||||
C1458.157104,2429.546875 1459.443726,2437.461426 1457.050049,2443.866943
|
||||
C1454.363892,2451.054932 1453.953247,2457.795410 1454.301392,2464.999023
|
||||
C1426.410522,2468.776123 1398.529907,2472.632324 1370.622192,2476.279785
|
||||
C1362.792847,2477.302979 1354.873779,2477.624268 1347.019287,2478.481201
|
||||
C1345.551147,2478.641357 1344.194214,2479.820801 1343.393066,2481.265137
|
||||
C1337.277466,2482.000000 1330.554810,2482.000000 1322.916138,2482.000000
|
||||
z"/>
|
||||
<path fill="#111726" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M2.000000,1172.908203
|
||||
C2.854996,1172.177124 4.462687,1172.385498 4.456792,1172.526733
|
||||
C4.191141,1178.889771 3.783891,1185.246948 2.696669,1191.802368
|
||||
C2.000000,1185.938843 2.000000,1179.877563 2.000000,1172.908203
|
||||
z"/>
|
||||
<path fill="#FD5843" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M352.295471,506.658752
|
||||
C346.556641,492.851044 347.058563,478.817993 350.778839,464.668579
|
||||
C351.116547,463.384277 352.030396,461.920807 351.698639,460.841003
|
||||
C347.020142,445.613251 354.039307,430.478943 351.959839,415.320801
|
||||
C350.702759,406.157318 349.111511,397.039673 347.449158,386.954163
|
||||
C348.766235,383.872528 350.056000,381.493774 351.878967,379.639160
|
||||
C415.925385,314.480255 485.335510,255.803986 563.398560,206.183746
|
||||
C569.218628,209.227905 571.037903,212.937622 568.957886,218.201599
|
||||
C566.186829,225.214447 566.327942,232.258118 568.689331,239.435516
|
||||
C569.473450,241.818924 569.378967,244.587112 569.243042,247.155945
|
||||
C569.017273,251.420425 568.140991,255.659927 568.053833,259.920502
|
||||
C567.772949,273.652466 570.280884,287.473389 566.584961,301.114685
|
||||
C566.366821,301.919708 567.879028,303.193573 568.194397,304.815002
|
||||
C505.921600,350.333984 448.781769,400.660156 396.817505,456.793304
|
||||
C381.682434,473.142609 367.120239,490.022217 352.295471,506.658752
|
||||
z"/>
|
||||
<path fill="#FD4E47" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M568.585999,304.249237
|
||||
C567.879028,303.193573 566.366821,301.919708 566.584961,301.114685
|
||||
C570.280884,287.473389 567.772949,273.652466 568.053833,259.920502
|
||||
C568.140991,255.659927 569.017273,251.420425 569.243042,247.155945
|
||||
C569.378967,244.587112 569.473450,241.818924 568.689331,239.435516
|
||||
C566.327942,232.258118 566.186829,225.214447 568.957886,218.201599
|
||||
C571.037903,212.937622 569.218628,209.227905 564.059692,206.044830
|
||||
C572.727356,199.446106 581.890991,192.889832 591.455200,186.981873
|
||||
C648.601501,151.681488 708.056335,120.873268 771.135132,96.496933
|
||||
C772.619385,105.286263 773.718445,113.192955 773.899719,121.120636
|
||||
C774.125427,130.992645 774.821960,141.104767 773.079834,150.707703
|
||||
C770.877075,162.849945 772.948120,173.603149 777.916504,184.683075
|
||||
C718.252808,211.524277 661.518799,242.315765 607.511963,278.085876
|
||||
C594.478088,286.718567 581.558289,295.523499 568.585999,304.249237
|
||||
z"/>
|
||||
<path fill="#FD4449" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M778.408386,184.169250
|
||||
C772.948120,173.603149 770.877075,162.849945 773.079834,150.707703
|
||||
C774.821960,141.104767 774.125427,130.992645 773.899719,121.120636
|
||||
C773.718445,113.192955 772.619385,105.286263 771.887207,96.423393
|
||||
C790.909973,87.901482 809.630737,79.265816 829.109192,72.977303
|
||||
C866.958191,60.757950 905.230347,49.848984 943.338196,38.433754
|
||||
C944.916931,37.960854 946.606445,37.857994 949.092712,38.511047
|
||||
C950.955872,50.275467 951.446899,61.196079 953.177063,71.916702
|
||||
C954.258545,78.617790 954.122559,84.451302 949.379639,89.509445
|
||||
C947.113892,91.925690 946.649414,94.198669 947.378784,97.554909
|
||||
C949.268311,106.248917 950.501343,115.085594 951.341187,124.241501
|
||||
C909.276917,135.853394 868.375549,148.669510 828.369080,164.223862
|
||||
C811.656860,170.721512 795.058533,177.511948 778.408386,184.169250
|
||||
z"/>
|
||||
<path fill="#FD3D4B" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M951.996399,123.865334
|
||||
C950.501343,115.085594 949.268311,106.248917 947.378784,97.554909
|
||||
C946.649414,94.198669 947.113892,91.925690 949.379639,89.509445
|
||||
C954.122559,84.451302 954.258545,78.617790 953.177063,71.916702
|
||||
C951.446899,61.196079 950.955872,50.275467 949.907776,38.495461
|
||||
C969.464844,33.085560 988.973267,28.209772 1008.669189,24.271704
|
||||
C1027.440552,20.518517 1046.388062,17.622320 1065.296387,14.588613
|
||||
C1074.967529,13.036946 1084.722656,12.009069 1095.226807,10.759282
|
||||
C1095.342529,22.262749 1094.485352,33.744526 1094.061401,45.242275
|
||||
C1093.748291,53.734406 1093.741943,62.257504 1094.075439,70.748077
|
||||
C1094.384521,78.615601 1095.326050,86.458298 1095.269531,95.504791
|
||||
C1064.811768,101.782570 1035.014771,106.551987 1005.357117,112.070274
|
||||
C987.458313,115.400620 969.776001,119.894356 951.996399,123.865334
|
||||
z"/>
|
||||
<path fill="#FE5345" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M659.839844,2336.520508
|
||||
C649.016357,2331.002197 637.853210,2326.055908 627.428223,2319.866211
|
||||
C582.676025,2293.294678 538.868896,2265.256348 497.402283,2233.714600
|
||||
C488.968445,2227.299561 480.738647,2220.616211 472.323059,2212.748535
|
||||
C472.497803,2210.835693 472.882416,2210.254639 473.013123,2209.621338
|
||||
C475.315247,2198.465088 471.920898,2186.470947 477.984131,2175.864990
|
||||
C476.047424,2154.467529 482.650940,2132.597900 474.373993,2111.514648
|
||||
C473.574524,2109.478516 474.074158,2106.932129 474.551453,2104.885742
|
||||
C512.278076,2137.957031 550.918823,2168.899414 592.145081,2196.422852
|
||||
C614.526550,2211.364990 635.941956,2227.859131 659.997437,2241.080811
|
||||
C660.670776,2249.479492 661.500549,2257.026611 661.963074,2264.596191
|
||||
C662.749268,2277.463135 663.659729,2290.340088 663.812256,2303.220947
|
||||
C663.893433,2310.079834 662.561646,2316.964355 661.739685,2323.821777
|
||||
C661.230530,2328.069580 660.481384,2332.288574 659.839844,2336.520508
|
||||
z"/>
|
||||
<path fill="#FE5B43" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M473.970764,2104.622559
|
||||
C474.074158,2106.932129 473.574524,2109.478516 474.373993,2111.514648
|
||||
C482.650940,2132.597900 476.047424,2154.467529 477.984131,2175.864990
|
||||
C471.920898,2186.470947 475.315247,2198.465088 473.013123,2209.621338
|
||||
C472.882416,2210.254639 472.497803,2210.835693 471.879852,2212.288086
|
||||
C453.947357,2198.531006 435.849579,2184.497559 418.914001,2169.179443
|
||||
C397.016846,2149.373779 375.889771,2128.703857 354.754700,2108.074463
|
||||
C345.990631,2099.520020 338.064240,2090.107910 329.501770,2080.542725
|
||||
C329.497742,2070.749023 329.607788,2061.491455 330.049316,2052.250000
|
||||
C330.346924,2046.020508 331.187073,2039.818726 331.636078,2033.593994
|
||||
C331.849121,2030.640747 332.597107,2027.314941 331.588593,2024.754395
|
||||
C326.730957,2012.421387 330.446564,2000.127197 331.084595,1987.821411
|
||||
C331.152161,1986.519043 332.000854,1984.773682 331.436707,1983.996216
|
||||
C325.094452,1975.258179 332.204346,1965.176758 328.571472,1956.177979
|
||||
C328.206390,1955.273804 329.368286,1953.753174 330.713379,1952.173584
|
||||
C360.199677,1988.093140 390.371094,2022.983643 423.096802,2055.587646
|
||||
C439.779816,2072.208496 456.995758,2088.294678 473.970764,2104.622559
|
||||
z"/>
|
||||
<path fill="#FD4A48" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M660.245667,2337.048828
|
||||
C660.481384,2332.288574 661.230530,2328.069580 661.739685,2323.821777
|
||||
C662.561646,2316.964355 663.893433,2310.079834 663.812256,2303.220947
|
||||
C663.659729,2290.340088 662.749268,2277.463135 661.963074,2264.596191
|
||||
C661.500549,2257.026611 660.670776,2249.479492 660.676819,2241.211914
|
||||
C707.186646,2267.078613 754.482605,2290.716064 803.502991,2310.861328
|
||||
C817.633301,2316.668701 831.822876,2322.331299 845.989258,2328.935303
|
||||
C845.614258,2345.645020 845.523987,2361.480225 840.857300,2376.891602
|
||||
C839.839905,2380.251709 839.015564,2385.068359 840.636963,2387.574463
|
||||
C846.152283,2396.099609 843.788452,2403.249268 838.863953,2410.620605
|
||||
C838.171448,2411.657227 838.182434,2413.163818 837.867798,2414.452881
|
||||
C822.536743,2409.033447 807.088379,2403.922363 791.896851,2398.136475
|
||||
C748.015625,2381.423828 705.744995,2361.139404 663.980896,2339.765869
|
||||
C662.805664,2339.164307 661.758423,2338.312500 660.245667,2337.048828
|
||||
z"/>
|
||||
<path fill="#FD414A" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M838.378052,2414.957031
|
||||
C838.182434,2413.163818 838.171448,2411.657227 838.863953,2410.620605
|
||||
C843.788452,2403.249268 846.152283,2396.099609 840.636963,2387.574463
|
||||
C839.015564,2385.068359 839.839905,2380.251709 840.857300,2376.891602
|
||||
C845.523987,2361.480225 845.614258,2345.645020 846.744873,2328.954102
|
||||
C880.444214,2338.418213 913.206848,2349.388428 946.401489,2358.842041
|
||||
C970.638367,2365.744385 995.443848,2370.649658 1019.995911,2376.445068
|
||||
C1019.038818,2404.386963 1020.201294,2432.329346 1019.958191,2461.219727
|
||||
C1003.978516,2459.171875 987.937622,2456.534180 972.065918,2453.111572
|
||||
C926.889465,2443.370117 882.580322,2430.489990 838.378052,2414.957031
|
||||
z"/>
|
||||
<path fill="#FD0155" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M2075.900391,322.875854
|
||||
C2075.373047,329.351349 2074.552490,335.230011 2073.778809,341.114838
|
||||
C2073.195801,345.550232 2072.672607,349.993500 2072.047607,355.040344
|
||||
C2069.009521,354.874359 2064.850586,353.031799 2062.831055,358.350494
|
||||
C2060.073975,365.611786 2065.993652,368.276642 2069.454346,371.716705
|
||||
C2069.454346,372.983826 2069.738037,373.904999 2069.412598,374.247559
|
||||
C2062.122070,381.922882 2062.773438,389.134186 2069.638428,396.963745
|
||||
C2074.961914,403.035431 2069.418701,409.502869 2068.675049,415.748596
|
||||
C2068.180664,419.901825 2066.549561,423.919678 2064.628418,428.515320
|
||||
C2060.484619,425.789642 2057.117188,422.569153 2053.797119,419.300537
|
||||
C1977.195312,343.888367 1891.729736,280.400085 1797.524536,228.641983
|
||||
C1759.367310,207.677673 1719.990845,189.289185 1679.997559,171.621979
|
||||
C1681.336304,152.104416 1682.968262,133.457199 1683.564331,114.776932
|
||||
C1683.908936,103.978073 1682.583618,93.125916 1682.009888,82.297729
|
||||
C1704.468994,91.377357 1727.213379,99.815414 1749.337158,109.649597
|
||||
C1837.257935,148.730927 1919.572388,197.446091 1995.772095,256.183319
|
||||
C2023.122681,277.266205 2049.050293,300.195190 2075.900391,322.875854
|
||||
z"/>
|
||||
<path fill="#FD1E51" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1411.654297,99.205811
|
||||
C1415.896729,88.638809 1415.692139,77.369125 1415.786743,66.392868
|
||||
C1415.932007,49.558369 1414.666626,32.711697 1413.999878,14.987562
|
||||
C1432.319946,16.858213 1450.818604,18.759012 1468.921631,22.549688
|
||||
C1502.300781,29.539127 1535.447754,37.638149 1569.348145,46.577469
|
||||
C1570.998779,62.309551 1567.693237,76.806503 1571.695679,91.289131
|
||||
C1573.305176,97.112778 1572.783813,103.855881 1569.305542,109.689880
|
||||
C1568.507080,111.029327 1568.292358,112.849648 1568.221680,114.466690
|
||||
C1567.949707,120.681519 1567.845459,126.903702 1566.871338,132.991791
|
||||
C1555.177734,129.928696 1544.303467,126.951164 1533.402710,124.073380
|
||||
C1493.290771,113.483772 1452.558472,105.921730 1411.654297,99.205811
|
||||
z"/>
|
||||
<path fill="#FD0D53" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1567.678589,133.123138
|
||||
C1567.845459,126.903702 1567.949707,120.681519 1568.221680,114.466690
|
||||
C1568.292358,112.849648 1568.507080,111.029327 1569.305542,109.689880
|
||||
C1572.783813,103.855881 1573.305176,97.112778 1571.695679,91.289131
|
||||
C1567.693237,76.806503 1570.998779,62.309551 1570.004883,46.952065
|
||||
C1587.538086,51.039959 1605.227905,55.573128 1622.562744,61.200005
|
||||
C1642.080688,67.535522 1661.278564,74.856789 1681.312744,82.023514
|
||||
C1682.583618,93.125916 1683.908936,103.978073 1683.564331,114.776932
|
||||
C1682.968262,133.457199 1681.336304,152.104416 1679.263672,171.466797
|
||||
C1673.169434,170.057678 1668.030029,167.717163 1662.718018,165.874619
|
||||
C1631.060303,154.893616 1599.362793,144.027695 1567.678589,133.123138
|
||||
z"/>
|
||||
<path fill="#FD1C52" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1455.144531,2464.862793
|
||||
C1453.953247,2457.795410 1454.363892,2451.054932 1457.050049,2443.866943
|
||||
C1459.443726,2437.461426 1458.157104,2429.546875 1457.905762,2422.318604
|
||||
C1457.568604,2412.621094 1456.789307,2402.932617 1455.946533,2393.262207
|
||||
C1455.577515,2389.028809 1454.581421,2384.850098 1454.471191,2379.482422
|
||||
C1483.844116,2371.806641 1512.689697,2365.602051 1541.359741,2358.670654
|
||||
C1559.048218,2354.394287 1576.468872,2349.010742 1594.001831,2344.965820
|
||||
C1593.330078,2350.676758 1591.985107,2355.567627 1592.139038,2360.410889
|
||||
C1592.497925,2371.700684 1597.676025,2382.670166 1594.467163,2394.243652
|
||||
C1594.392456,2394.513428 1594.699585,2394.866699 1594.714233,2395.186523
|
||||
C1594.955322,2400.392334 1595.461060,2405.606201 1595.335571,2410.804199
|
||||
C1595.163330,2417.932129 1594.509277,2425.048340 1594.061768,2432.169678
|
||||
C1576.573853,2437.106201 1559.249390,2442.753906 1541.560669,2446.816162
|
||||
C1513.163086,2453.338135 1484.524414,2458.810791 1455.144531,2464.862793
|
||||
z"/>
|
||||
<path fill="#FD0D53" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1594.844482,2432.142090
|
||||
C1594.509277,2425.048340 1595.163330,2417.932129 1595.335571,2410.804199
|
||||
C1595.461060,2405.606201 1594.955322,2400.392334 1594.714233,2395.186523
|
||||
C1594.699585,2394.866699 1594.392456,2394.513428 1594.467163,2394.243652
|
||||
C1597.676025,2382.670166 1592.497925,2371.700684 1592.139038,2360.410889
|
||||
C1591.985107,2355.567627 1593.330078,2350.676758 1594.686768,2344.658936
|
||||
C1631.596558,2329.880371 1667.813477,2316.250244 1704.030518,2302.620117
|
||||
C1705.858032,2316.132568 1704.223755,2329.672607 1703.707520,2343.142334
|
||||
C1703.389404,2351.443115 1706.637573,2359.420410 1702.984741,2368.367676
|
||||
C1700.063599,2375.522217 1702.222534,2384.750732 1702.187012,2394.066406
|
||||
C1671.780884,2405.960693 1641.329224,2416.889404 1610.832886,2427.692139
|
||||
C1605.865479,2429.451660 1600.700806,2430.654297 1594.844482,2432.142090
|
||||
z"/>
|
||||
<path fill="#111726" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1704.636475,2302.210449
|
||||
C1667.813477,2316.250244 1631.596558,2329.880371 1594.694580,2343.817383
|
||||
C1576.468872,2349.010742 1559.048218,2354.394287 1541.359741,2358.670654
|
||||
C1512.689697,2365.602051 1483.844116,2371.806641 1454.379395,2378.586670
|
||||
C1410.483154,2386.102783 1367.118774,2392.044434 1322.651855,2395.309082
|
||||
C1297.750000,2396.351562 1273.576660,2397.503174 1249.400146,2397.574951
|
||||
C1226.212036,2397.644043 1203.020508,2396.593018 1178.915283,2396.165039
|
||||
C1150.840332,2393.614746 1123.607178,2391.513916 1096.542603,2388.083008
|
||||
C1071.468262,2384.903809 1046.574341,2380.301758 1020.798401,2376.385742
|
||||
C995.443848,2370.649658 970.638367,2365.744385 946.401489,2358.842041
|
||||
C913.206848,2349.388428 880.444214,2338.418213 846.740845,2328.078857
|
||||
C831.822876,2322.331299 817.633301,2316.668701 803.502991,2310.861328
|
||||
C754.482605,2290.716064 707.186646,2267.078613 660.668091,2240.370605
|
||||
C635.941956,2227.859131 614.526550,2211.364990 592.145081,2196.422852
|
||||
C550.918823,2168.899414 512.278076,2137.957031 474.551453,2104.885742
|
||||
C456.995758,2088.294678 439.779816,2072.208496 423.096802,2055.587646
|
||||
C390.371094,2022.983643 360.199677,1988.093140 331.036163,1951.430176
|
||||
C314.815765,1929.072510 298.609344,1907.485229 283.605133,1885.092407
|
||||
C199.339981,1759.333130 141.932693,1622.306519 111.634445,1473.912476
|
||||
C94.636253,1390.659058 86.775948,1306.550293 88.462120,1221.678833
|
||||
C91.659683,1060.733765 126.249481,906.800049 193.521423,760.365295
|
||||
C235.344467,669.326538 288.410614,585.358521 352.077698,507.275696
|
||||
C367.120239,490.022217 381.682434,473.142609 396.817505,456.793304
|
||||
C448.781769,400.660156 505.921600,350.333984 568.194397,304.815002
|
||||
C581.558289,295.523499 594.478088,286.718567 607.511963,278.085876
|
||||
C661.518799,242.315765 718.252808,211.524277 777.916504,184.683075
|
||||
C795.058533,177.511948 811.656860,170.721512 828.369080,164.223862
|
||||
C868.375549,148.669510 909.276917,135.853394 951.341187,124.241501
|
||||
C969.776001,119.894356 987.458313,115.400620 1005.357117,112.070274
|
||||
C1035.014771,106.551987 1064.811768,101.782570 1095.275024,96.362015
|
||||
C1111.865723,94.598114 1127.705322,92.659691 1143.602539,91.846756
|
||||
C1177.771362,90.099472 1211.969727,88.932030 1247.076904,87.343018
|
||||
C1256.959106,87.391411 1265.919922,87.659348 1274.882202,87.850662
|
||||
C1320.113159,88.816185 1365.071655,93.011742 1410.759399,99.196487
|
||||
C1452.558472,105.921730 1493.290771,113.483772 1533.402710,124.073380
|
||||
C1544.303467,126.951164 1555.177734,129.928696 1566.871338,132.991791
|
||||
C1599.362793,144.027695 1631.060303,154.893616 1662.718018,165.874619
|
||||
C1668.030029,167.717163 1673.169434,170.057678 1679.122314,172.323257
|
||||
C1719.990845,189.289185 1759.367310,207.677673 1797.524536,228.641983
|
||||
C1891.729736,280.400085 1977.195312,343.888367 2053.797119,419.300537
|
||||
C2057.117188,422.569153 2060.484619,425.789642 2064.405762,429.431580
|
||||
C2084.243408,451.019867 2104.113770,471.691101 2122.668213,493.482666
|
||||
C2239.296875,630.459351 2319.840820,786.178650 2363.923584,960.643433
|
||||
C2379.285156,1021.439026 2389.225586,1083.130127 2394.555176,1145.641113
|
||||
C2398.809570,1195.543945 2400.011230,1245.527954 2397.438477,1295.429810
|
||||
C2384.085449,1554.437256 2295.175537,1784.427856 2129.126953,1983.796509
|
||||
C2013.766113,2122.305664 1872.842163,2227.512939 1707.911499,2300.435059
|
||||
C1706.999023,2300.838623 1706.131104,2301.343262 1704.636475,2302.210449
|
||||
M1543.000000,1475.916992
|
||||
C1560.885010,1475.916992 1578.770142,1475.916992 1597.815063,1475.916992
|
||||
C1597.815063,1343.276855 1597.815063,1211.767822 1597.815063,1080.258789
|
||||
C1598.370850,1080.218994 1598.926636,1080.179199 1599.482544,1080.139404
|
||||
C1633.850098,1211.957520 1668.217651,1343.775513 1702.546143,1475.443481
|
||||
C1769.731934,1475.443481 1835.939819,1475.443481 1902.799194,1475.443481
|
||||
C1911.464722,1442.042969 1920.041992,1408.918823 1928.654541,1375.803833
|
||||
C1937.197021,1342.959106 1945.775513,1310.123657 1954.337402,1277.283936
|
||||
C1962.983276,1244.122070 1971.464111,1210.916138 1980.320435,1177.810669
|
||||
C1989.040771,1145.213989 1996.857056,1112.357666 2006.236450,1079.943237
|
||||
C2006.922363,1080.078369 2007.608154,1080.213501 2008.293945,1080.348511
|
||||
C2008.293945,1211.892090 2008.293945,1343.435669 2008.293945,1475.259277
|
||||
C2045.304443,1475.259277 2081.697754,1475.259277 2118.277832,1475.259277
|
||||
C2118.277832,1319.766602 2118.277832,1164.932129 2118.277832,1009.858276
|
||||
C2048.318604,1009.858276 1978.869995,1009.858276 1909.208252,1009.858276
|
||||
C1874.011719,1144.833252 1838.957642,1279.261963 1803.903564,1413.690552
|
||||
C1803.296875,1413.673828 1802.690063,1413.657227 1802.083374,1413.640625
|
||||
C1766.868286,1278.899902 1731.653076,1144.159302 1696.539429,1009.806763
|
||||
C1625.816528,1009.806763 1556.285645,1009.806763 1486.763916,1009.806763
|
||||
C1486.763916,1165.253540 1486.763916,1320.110352 1486.763916,1475.916992
|
||||
C1505.179443,1475.916992 1523.089722,1475.916992 1543.000000,1475.916992
|
||||
M652.718262,1192.136841
|
||||
C627.059082,1131.158569 601.399841,1070.180298 575.927673,1009.646484
|
||||
C540.850159,1007.638428 376.362366,1008.593018 368.720612,1010.721680
|
||||
C368.720612,1165.601807 368.720612,1320.420776 368.720612,1475.558838
|
||||
C405.586884,1475.558838 441.804169,1475.558838 479.239441,1475.558838
|
||||
C479.239441,1471.639893 479.239471,1468.072998 479.239471,1464.505981
|
||||
C479.239471,1428.844482 479.239441,1393.183105 479.239471,1357.521606
|
||||
C479.239532,1266.534912 479.228546,1175.548096 479.284668,1084.561401
|
||||
C479.286682,1081.310669 478.380066,1077.736694 481.084198,1073.635864
|
||||
C537.977600,1208.396118 594.365112,1341.958008 650.639954,1475.253052
|
||||
C671.545288,1477.250610 850.587708,1476.370483 857.275146,1474.384888
|
||||
C857.275146,1319.501709 857.275146,1164.707520 857.275146,1009.877747
|
||||
C820.111389,1009.877747 783.604797,1009.877747 747.287354,1009.877747
|
||||
C747.018433,1010.861938 746.855103,1011.180908 746.854858,1011.499939
|
||||
C746.746033,1143.139038 746.648804,1274.778076 746.538818,1406.417236
|
||||
C746.538269,1407.072876 746.388184,1407.734131 746.252258,1408.381104
|
||||
C746.194031,1408.657959 746.053467,1409.030518 745.840820,1409.133423
|
||||
C745.570862,1409.264160 745.189697,1409.165039 744.160767,1409.165039
|
||||
C713.989868,1337.451416 683.707458,1265.472534 652.718262,1192.136841
|
||||
M959.001221,1009.216125
|
||||
C944.459412,1009.216125 929.917542,1009.216125 913.991943,1009.216125
|
||||
C917.005737,1014.547791 919.083618,1018.292542 921.224487,1022.000916
|
||||
C985.469849,1133.285889 1049.688477,1244.586670 1114.062378,1355.797241
|
||||
C1117.536865,1361.799561 1119.156494,1367.707397 1119.095215,1374.644775
|
||||
C1118.830933,1404.632812 1118.982300,1434.624390 1118.982300,1464.614746
|
||||
C1118.982300,1468.191528 1118.982178,1471.768188 1118.982178,1475.875977
|
||||
C1156.657959,1475.942383 1193.117554,1475.921387 1230.004639,1475.903931
|
||||
C1230.004639,1471.100220 1230.004517,1467.789429 1230.004517,1464.478516
|
||||
C1230.004517,1434.821411 1230.214233,1405.161865 1229.861328,1375.508911
|
||||
C1229.770020,1367.838135 1231.788940,1361.477295 1235.588745,1354.913086
|
||||
C1300.632080,1242.552002 1365.488647,1130.082764 1430.359375,1017.621826
|
||||
C1431.736206,1015.235107 1432.792358,1012.663391 1434.319092,1009.516113
|
||||
C1391.183350,1009.516113 1349.285889,1009.516113 1306.819458,1009.516113
|
||||
C1263.059082,1085.544434 1219.280884,1161.603882 1175.042847,1238.462158
|
||||
C1172.418457,1234.160156 1170.285034,1230.816528 1168.299927,1227.386841
|
||||
C1127.610229,1157.086060 1086.880249,1086.808472 1046.377808,1016.399963
|
||||
C1043.363647,1011.160278 1040.141357,1008.979919 1033.975464,1009.070435
|
||||
C1009.655273,1009.427551 985.326599,1009.216614 959.001221,1009.216125
|
||||
z"/>
|
||||
<path fill="#FEFEFE" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M1542.000000,1475.916992
|
||||
C1523.089722,1475.916992 1505.179443,1475.916992 1486.763916,1475.916992
|
||||
C1486.763916,1320.110352 1486.763916,1165.253540 1486.763916,1009.806763
|
||||
C1556.285645,1009.806763 1625.816528,1009.806763 1696.539429,1009.806763
|
||||
C1731.653076,1144.159302 1766.868286,1278.899902 1802.083374,1413.640625
|
||||
C1802.690063,1413.657227 1803.296875,1413.673828 1803.903564,1413.690552
|
||||
C1838.957642,1279.261963 1874.011719,1144.833252 1909.208252,1009.858276
|
||||
C1978.869995,1009.858276 2048.318604,1009.858276 2118.277832,1009.858276
|
||||
C2118.277832,1164.932129 2118.277832,1319.766602 2118.277832,1475.259277
|
||||
C2081.697754,1475.259277 2045.304443,1475.259277 2008.293945,1475.259277
|
||||
C2008.293945,1343.435669 2008.293945,1211.892090 2008.293945,1080.348511
|
||||
C2007.608154,1080.213501 2006.922363,1080.078369 2006.236450,1079.943237
|
||||
C1996.857056,1112.357666 1989.040771,1145.213989 1980.320435,1177.810669
|
||||
C1971.464111,1210.916138 1962.983276,1244.122070 1954.337402,1277.283936
|
||||
C1945.775513,1310.123657 1937.197021,1342.959106 1928.654541,1375.803833
|
||||
C1920.041992,1408.918823 1911.464722,1442.042969 1902.799194,1475.443481
|
||||
C1835.939819,1475.443481 1769.731934,1475.443481 1702.546143,1475.443481
|
||||
C1668.217651,1343.775513 1633.850098,1211.957520 1599.482544,1080.139404
|
||||
C1598.926636,1080.179199 1598.370850,1080.218994 1597.815063,1080.258789
|
||||
C1597.815063,1211.767822 1597.815063,1343.276855 1597.815063,1475.916992
|
||||
C1578.770142,1475.916992 1560.885010,1475.916992 1542.000000,1475.916992
|
||||
z"/>
|
||||
<path fill="#FDFDFD" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M653.071655,1192.815308
|
||||
C683.707458,1265.472534 713.989868,1337.451416 744.160767,1409.165039
|
||||
C745.189697,1409.165039 745.570862,1409.264160 745.840820,1409.133423
|
||||
C746.053467,1409.030518 746.194031,1408.657959 746.252258,1408.381104
|
||||
C746.388184,1407.734131 746.538269,1407.072876 746.538818,1406.417236
|
||||
C746.648804,1274.778076 746.746033,1143.139038 746.854858,1011.499939
|
||||
C746.855103,1011.180908 747.018433,1010.861938 747.287354,1009.877747
|
||||
C783.604797,1009.877747 820.111389,1009.877747 857.275146,1009.877747
|
||||
C857.275146,1164.707520 857.275146,1319.501709 857.275146,1474.384888
|
||||
C850.587708,1476.370483 671.545288,1477.250610 650.639954,1475.253052
|
||||
C594.365112,1341.958008 537.977600,1208.396118 481.084198,1073.635864
|
||||
C478.380066,1077.736694 479.286682,1081.310669 479.284668,1084.561401
|
||||
C479.228546,1175.548096 479.239532,1266.534912 479.239471,1357.521606
|
||||
C479.239441,1393.183105 479.239471,1428.844482 479.239471,1464.505981
|
||||
C479.239471,1468.072998 479.239441,1471.639893 479.239441,1475.558838
|
||||
C441.804169,1475.558838 405.586884,1475.558838 368.720612,1475.558838
|
||||
C368.720612,1320.420776 368.720612,1165.601807 368.720612,1010.721680
|
||||
C376.362366,1008.593018 540.850159,1007.638428 575.927673,1009.646484
|
||||
C601.399841,1070.180298 627.059082,1131.158569 653.071655,1192.815308
|
||||
z"/>
|
||||
<path fill="#FEFEFE" opacity="1.000000" stroke="none"
|
||||
d="
|
||||
M960.001160,1009.216187
|
||||
C985.326599,1009.216614 1009.655273,1009.427551 1033.975464,1009.070435
|
||||
C1040.141357,1008.979919 1043.363647,1011.160278 1046.377808,1016.399963
|
||||
C1086.880249,1086.808472 1127.610229,1157.086060 1168.299927,1227.386841
|
||||
C1170.285034,1230.816528 1172.418457,1234.160156 1175.042847,1238.462158
|
||||
C1219.280884,1161.603882 1263.059082,1085.544434 1306.819458,1009.516113
|
||||
C1349.285889,1009.516113 1391.183350,1009.516113 1434.319092,1009.516113
|
||||
C1432.792358,1012.663391 1431.736206,1015.235107 1430.359375,1017.621826
|
||||
C1365.488647,1130.082764 1300.632080,1242.552002 1235.588745,1354.913086
|
||||
C1231.788940,1361.477295 1229.770020,1367.838135 1229.861328,1375.508911
|
||||
C1230.214233,1405.161865 1230.004517,1434.821411 1230.004517,1464.478516
|
||||
C1230.004517,1467.789429 1230.004639,1471.100220 1230.004639,1475.903931
|
||||
C1193.117554,1475.921387 1156.657959,1475.942383 1118.982178,1475.875977
|
||||
C1118.982178,1471.768188 1118.982300,1468.191528 1118.982300,1464.614746
|
||||
C1118.982300,1434.624390 1118.830933,1404.632812 1119.095215,1374.644775
|
||||
C1119.156494,1367.707397 1117.536865,1361.799561 1114.062378,1355.797241
|
||||
C1049.688477,1244.586670 985.469849,1133.285889 921.224487,1022.000916
|
||||
C919.083618,1018.292542 917.005737,1014.547791 913.991943,1009.216125
|
||||
C929.917542,1009.216125 944.459412,1009.216125 960.001160,1009.216187
|
||||
z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 40 KiB |
@@ -1,28 +0,0 @@
|
||||
[package]
|
||||
name = "nymvpn-cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0"
|
||||
authors = ["Nym Technologies S.A."]
|
||||
description = "Cli to manage VPN session via nymvpn daemon"
|
||||
homepage = "https://nymvpn.net"
|
||||
repository = "https://github.com/nymvpn/nymvpn-app"
|
||||
|
||||
[[bin]]
|
||||
name = "nymvpn"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.68"
|
||||
clap = { version = "4.2.3", features = ["derive"] }
|
||||
tokio = { version = "1.27.0", features = ["rt-multi-thread", "macros", "signal"] }
|
||||
validator = { version = "0.16.0", features = ["derive"] }
|
||||
nymvpn-controller = {path = "../nymvpn-controller"}
|
||||
nymvpn-types = {path = "../nymvpn-types"}
|
||||
thiserror = "1.0.40"
|
||||
tonic = "0.9.2"
|
||||
dialoguer = { version = "0.10.4", features = ["fuzzy-select"] }
|
||||
indicatif = "0.17.3"
|
||||
tokio-stream = { version = "0.1.12", features = ["sync"] }
|
||||
console = "0.15.5"
|
||||
@@ -1 +0,0 @@
|
||||
../nymvpn.conf.toml
|
||||
@@ -1,59 +0,0 @@
|
||||
use std::process::ExitCode;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use clap::{Parser, Subcommand};
|
||||
use console::style;
|
||||
|
||||
use crate::commands::{
|
||||
connect::Connect, disconnect::Disconnect, error::CliError, locations::ListLocations,
|
||||
sign_in::SignIn, sign_out::SignOut, status::Status,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait RunCommand {
|
||||
async fn run(self) -> Result<(), CliError>;
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about)]
|
||||
pub struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Commands {
|
||||
/// Sign in to your https://nymvpn.net account
|
||||
SignIn(SignIn),
|
||||
/// Sign out current device
|
||||
SignOut(SignOut),
|
||||
/// Current VPN status
|
||||
Status(Status),
|
||||
/// Available locations for VPN
|
||||
Locations(ListLocations),
|
||||
/// Connect VPN
|
||||
Connect(Connect),
|
||||
/// Disconnect VPN
|
||||
Disconnect(Disconnect),
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub async fn run(self) -> ExitCode {
|
||||
let output = match self.command {
|
||||
Commands::SignIn(sign_in) => sign_in.run().await,
|
||||
Commands::SignOut(sign_out) => sign_out.run().await,
|
||||
Commands::Locations(list_locations) => list_locations.run().await,
|
||||
Commands::Connect(connect) => connect.run().await,
|
||||
Commands::Disconnect(disconnect) => disconnect.run().await,
|
||||
Commands::Status(status) => status.run().await,
|
||||
};
|
||||
|
||||
match output {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(e) => {
|
||||
eprintln!("{}", style(e).for_stderr().red());
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, FuzzySelect};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use tokio_stream::StreamExt;
|
||||
use tonic::Request;
|
||||
use nymvpn_types::{notification::Notification, vpn_session::VpnStatus};
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::{error::CliError, locations::list_locations};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct Connect {}
|
||||
|
||||
pub async fn start_signal_watch(message: String) {
|
||||
tokio::spawn(async move {
|
||||
let ctrl_c = async {
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install TERM signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
|
||||
println!("{}", style(message).cyan());
|
||||
|
||||
std::process::exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RunCommand for Connect {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
// get locations
|
||||
let locations = list_locations().await?;
|
||||
|
||||
let selection = FuzzySelect::with_theme(&ColorfulTheme::default())
|
||||
.items(&locations)
|
||||
.with_prompt("Location:")
|
||||
.interact_opt()?;
|
||||
|
||||
if let Some(index) = selection {
|
||||
// start signal watcher for user interrupts
|
||||
start_signal_watch(
|
||||
"You can continue to watch status using 'nymvpn status' cli or on the app.\nTo end current session use 'nymvpn disconnect' cli or the app".into(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let location = locations.get(index).unwrap();
|
||||
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
let mut stream = client.watch_events(()).await?.into_inner();
|
||||
|
||||
let vpn_status = client
|
||||
.connect_vpn(Request::new(location.clone().into()))
|
||||
.await
|
||||
.map(|res| res.into_inner())
|
||||
.map(VpnStatus::from)?;
|
||||
|
||||
// wait while vpn becomes active
|
||||
let pb = ProgressBar::new(100);
|
||||
let mut progress = 0;
|
||||
let mut done = false;
|
||||
pb.set_style(
|
||||
ProgressStyle::with_template(
|
||||
"{spinner:.blue} [{elapsed_precise}] [{bar:.cyan/blue}] {wide_msg}",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
pb.set_position(progress);
|
||||
pb.set_message(format!("{}", style(vpn_status.to_string()).yellow()));
|
||||
pb.enable_steady_tick(Duration::from_secs(1));
|
||||
while let Some(event) = stream.next().await {
|
||||
match event {
|
||||
Ok(event) => {
|
||||
if let Some(event) = event.event {
|
||||
match event {
|
||||
nymvpn_controller::proto::daemon_event::Event::VpnStatus(
|
||||
vpn_status,
|
||||
) => {
|
||||
let vpn_status: VpnStatus = vpn_status.into();
|
||||
progress = match vpn_status {
|
||||
VpnStatus::Accepted(_) => 25,
|
||||
VpnStatus::Connected(_, _) => {
|
||||
done = true;
|
||||
100
|
||||
}
|
||||
VpnStatus::Connecting(_) => 95,
|
||||
VpnStatus::Disconnected => {
|
||||
done = true;
|
||||
0
|
||||
}
|
||||
VpnStatus::Disconnecting(_) => progress,
|
||||
VpnStatus::ServerCreated(_) => 50,
|
||||
VpnStatus::ServerRunning(_) => 75,
|
||||
VpnStatus::ServerReady(_) => 80,
|
||||
};
|
||||
pb.set_position(progress);
|
||||
pb.set_message(format!(
|
||||
"{}",
|
||||
style(vpn_status.to_string()).yellow()
|
||||
));
|
||||
}
|
||||
nymvpn_controller::proto::daemon_event::Event::Notification(
|
||||
notification,
|
||||
) => {
|
||||
let id = notification.id.clone();
|
||||
if let Ok(notification) = Notification::try_from(notification) {
|
||||
pb.set_position(0);
|
||||
pb.set_message(format!(
|
||||
"{}",
|
||||
style(notification.message).red(),
|
||||
));
|
||||
}
|
||||
|
||||
client.ack_notification(id).await?;
|
||||
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err)?,
|
||||
}
|
||||
|
||||
if done {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pb.finish();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::error::CliError;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct Disconnect {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RunCommand for Disconnect {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
let vpn_status = client
|
||||
.disconnect_vpn(())
|
||||
.await
|
||||
.map(|res| res.into_inner())
|
||||
.map(nymvpn_types::vpn_session::VpnStatus::from)?;
|
||||
|
||||
println!("{}", style(vpn_status).yellow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use tonic::Status;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CliError {
|
||||
#[error("daemon is offline")]
|
||||
DaemonUnavailable,
|
||||
#[error("{}", .0.message())]
|
||||
Grpc(#[from] Status),
|
||||
#[error("{0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("{0}")]
|
||||
InvalidArgument(String),
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::error::CliError;
|
||||
|
||||
#[derive(Args, Debug, Validate)]
|
||||
pub struct ListLocations {}
|
||||
|
||||
pub async fn list_locations() -> Result<Vec<nymvpn_types::location::Location>, CliError> {
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
let locations = client.get_locations(()).await?;
|
||||
|
||||
Ok(locations.into_inner().into())
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RunCommand for ListLocations {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
let locations = list_locations().await?;
|
||||
|
||||
for location in locations {
|
||||
if location.state.is_some() {
|
||||
println!(
|
||||
"{}, {}, {}",
|
||||
style(location.city).white(),
|
||||
style(location.state.unwrap()).white().dim(),
|
||||
style(location.country).white().dim()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"{}, {}",
|
||||
style(location.city).white(),
|
||||
style(location.country).white().dim()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
pub mod connect;
|
||||
pub mod disconnect;
|
||||
pub mod error;
|
||||
pub mod locations;
|
||||
pub mod sign_in;
|
||||
pub mod sign_out;
|
||||
pub mod status;
|
||||
@@ -1,49 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Input, Password};
|
||||
use nymvpn_controller::proto::SignInRequest;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::error::CliError;
|
||||
|
||||
#[derive(Args, Debug, Validate)]
|
||||
pub struct SignIn {
|
||||
email: Option<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RunCommand for SignIn {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
let email = match self.email {
|
||||
Some(email) => email,
|
||||
None => Input::<String>::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Email:")
|
||||
.interact_text()?,
|
||||
};
|
||||
|
||||
if !validator::validate_email(&email) {
|
||||
return Err(CliError::InvalidArgument(format!(
|
||||
"\"{email}\" is not a valid email"
|
||||
)));
|
||||
}
|
||||
|
||||
let password = Password::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Password:")
|
||||
.interact()?;
|
||||
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
client
|
||||
.account_sign_in(SignInRequest { email, password })
|
||||
.await?;
|
||||
|
||||
println!("{}", style("Successfully signed in").yellow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::error::CliError;
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct SignOut;
|
||||
|
||||
#[async_trait]
|
||||
impl RunCommand for SignOut {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
client.account_sign_out(()).await?;
|
||||
|
||||
println!("{}", style("Successfully signed out").yellow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
use clap::Args;
|
||||
use console::style;
|
||||
|
||||
use crate::cli::RunCommand;
|
||||
|
||||
use super::error::CliError;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct Status {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RunCommand for Status {
|
||||
async fn run(self) -> Result<(), CliError> {
|
||||
let mut client = nymvpn_controller::new_grpc_client()
|
||||
.await
|
||||
.map_err(|_| CliError::DaemonUnavailable)?;
|
||||
|
||||
let vpn_status = client
|
||||
.get_vpn_status(())
|
||||
.await
|
||||
.map(|res| res.into_inner())
|
||||
.map(nymvpn_types::vpn_session::VpnStatus::from)?;
|
||||
|
||||
println!("{}", style(vpn_status).yellow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
pub mod cli;
|
||||
pub mod commands;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> ExitCode {
|
||||
cli::Cli::parse().run().await
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
[package]
|
||||
name = "nymvpn-config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0"
|
||||
authors = ["Nym Technologies S.A."]
|
||||
homepage = "https://nymvpn.net"
|
||||
repository = "https://github.com/nymvpn/nymvpn-app"
|
||||
|
||||
[dependencies]
|
||||
figment = { version = "0.10.8", features = ["env", "toml"] }
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
thiserror = "1.0.40"
|
||||
tokio = { version = "1.27.0", features = ["fs"] }
|
||||
|
||||
[build-dependencies]
|
||||
toml = "0.7.3"
|
||||
serde = "1.0.160"
|
||||
@@ -1,25 +0,0 @@
|
||||
use std::error::Error;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Package {
|
||||
version: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CargoToml {
|
||||
package: Package,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let path = "../nymvpn-packages/Cargo.toml";
|
||||
println!("cargo:rerun-if-changed={path}");
|
||||
let cargo_toml: CargoToml = toml::from_str(&std::fs::read_to_string(path)?)?;
|
||||
println!(
|
||||
"cargo:rustc-env=NYMVPN_VERSION={}",
|
||||
cargo_toml.package.version
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
#[cfg(unix)]
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use figment::{
|
||||
providers::{Env, Format, Serialized, Toml},
|
||||
Figment,
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConfigError {
|
||||
#[error("failed to create dir {0}: {1}")]
|
||||
CreateDirError(PathBuf, std::io::Error),
|
||||
#[error("failed to set permissions ({0:?}) on ({1}): {2:?}")]
|
||||
DirPermissionError(std::fs::Permissions, PathBuf, std::io::Error),
|
||||
}
|
||||
|
||||
static CONFIG: OnceCell<Config> = OnceCell::new();
|
||||
static CONFIG_DIR: OnceCell<PathBuf> = OnceCell::new();
|
||||
static LOG_DIR: OnceCell<PathBuf> = OnceCell::new();
|
||||
static SOCKET_PATH: OnceCell<PathBuf> = OnceCell::new();
|
||||
const CONFIG_FILENAME: &str = "nymvpn.conf.toml";
|
||||
|
||||
pub fn config() -> &'static Config {
|
||||
#[cfg(windows)]
|
||||
let program_data_path = PathBuf::from(std::env::var("ProgramData").unwrap_or(
|
||||
std::env::var("PROGRAMDATA").expect("missing ProgramData and PROGRAMDATA env var"),
|
||||
));
|
||||
|
||||
let config_dir = CONFIG_DIR.get_or_init(|| {
|
||||
#[cfg(unix)]
|
||||
return PathBuf::from("/etc/nymvpn");
|
||||
#[cfg(windows)]
|
||||
{
|
||||
return program_data_path.join("nymvpn");
|
||||
}
|
||||
});
|
||||
|
||||
let _ = LOG_DIR.get_or_init(|| {
|
||||
#[cfg(unix)]
|
||||
return PathBuf::from("/var/log/nymvpn");
|
||||
#[cfg(windows)]
|
||||
return program_data_path.join("nymvpn").join("log");
|
||||
});
|
||||
|
||||
let _ = SOCKET_PATH.get_or_init(|| {
|
||||
#[cfg(unix)]
|
||||
return PathBuf::from("/var/run/nymvpn.sock");
|
||||
#[cfg(windows)]
|
||||
return PathBuf::from("//./pipe/nymvpn");
|
||||
});
|
||||
|
||||
CONFIG.get_or_init(|| {
|
||||
Figment::from(Serialized::defaults(Config::default()))
|
||||
.merge(Toml::file(PathBuf::from(config_dir).join(CONFIG_FILENAME)))
|
||||
.merge(Toml::file(CONFIG_FILENAME))
|
||||
.merge(Env::prefixed("NYMVPN_"))
|
||||
.extract()
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
config_dir: PathBuf,
|
||||
log_dir: PathBuf,
|
||||
// todo: non string types for grpc and rest api?
|
||||
grpc_api_host_port: String,
|
||||
socket_path: PathBuf,
|
||||
daemon_log_filename: String,
|
||||
allowed_endpoint_ipv4: IpAddr,
|
||||
license_file_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config_dir: CONFIG_DIR.get().unwrap().into(),
|
||||
log_dir: LOG_DIR.get().unwrap().into(),
|
||||
grpc_api_host_port: "grpcs://api.nymvpn.net:44444".into(),
|
||||
socket_path: SOCKET_PATH.get().unwrap().into(),
|
||||
daemon_log_filename: "nymvpn-daemon.log".into(),
|
||||
// IP of api.nymvpn.net
|
||||
allowed_endpoint_ipv4: IpAddr::V4(Ipv4Addr::new(168, 220, 80, 137)),
|
||||
license_file_path: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn db_dir(&self) -> PathBuf {
|
||||
self.config_dir.join("db")
|
||||
}
|
||||
|
||||
pub fn db_url(&self) -> String {
|
||||
format!("sqlite://{}/nymvpn.db?mode=rwc", self.db_dir().display())
|
||||
}
|
||||
|
||||
pub fn grpc_api_host_port(&self) -> &str {
|
||||
&self.grpc_api_host_port
|
||||
}
|
||||
|
||||
pub fn allowed_endpoint_ipv4(&self) -> &IpAddr {
|
||||
&self.allowed_endpoint_ipv4
|
||||
}
|
||||
|
||||
pub fn log_dir(&self) -> &Path {
|
||||
self.log_dir.as_path()
|
||||
}
|
||||
|
||||
pub fn daemon_log_filename(&self) -> &str {
|
||||
&self.daemon_log_filename
|
||||
}
|
||||
|
||||
pub fn daemon_log_file_full_path(&self) -> PathBuf {
|
||||
self.log_dir().join(self.daemon_log_filename())
|
||||
}
|
||||
|
||||
pub fn socket_path(&self) -> &Path {
|
||||
return &self.socket_path;
|
||||
}
|
||||
|
||||
pub fn version(&self) -> &'static str {
|
||||
env!("NYMVPN_VERSION")
|
||||
}
|
||||
|
||||
pub fn license_file_path(&self) -> PathBuf {
|
||||
if self.license_file_path.is_some() {
|
||||
return self.license_file_path.clone().unwrap();
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
return PathBuf::from_str("/opt/nymvpn/nymvpn-oss-licenses.html").unwrap();
|
||||
#[cfg(target_os = "macos")]
|
||||
return PathBuf::from_str(
|
||||
"/Applications/nymvpn.net/Contents/Resources/nymvpn-oss-licenses.html",
|
||||
)
|
||||
.unwrap();
|
||||
#[cfg(target_os = "windows")]
|
||||
return PathBuf::from(std::env::var("PROGRAMFILES").unwrap_or(
|
||||
std::env::var("ProgramFiles").expect("missing PROGRAMFILES and ProgramFiles env var"),
|
||||
))
|
||||
.join("nymvpn")
|
||||
.join("nymvpn-oss-licenses.html");
|
||||
}
|
||||
|
||||
pub fn icon_path(&self) -> &'static str {
|
||||
#[cfg(target_os = "linux")]
|
||||
return "/usr/share/icons/hicolor/32x32/apps/nymvpn.png";
|
||||
#[cfg(target_os = "macos")]
|
||||
return "/Applications/nymvpn.net/Contents/Resources/icon.icns";
|
||||
#[cfg(target_os = "windows")]
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "nymvpn-controller"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0"
|
||||
authors = ["Nym Technologies S.A."]
|
||||
homepage = "https://nymvpn.net"
|
||||
repository = "https://github.com/nymvpn/nymvpn-app"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.28"
|
||||
hyper = "0.14.26"
|
||||
parity-tokio-ipc = "0.9.0"
|
||||
prost = "0.11.9"
|
||||
prost-types = "0.11.9"
|
||||
thiserror = "1.0.40"
|
||||
tokio = "1.27.0"
|
||||
tonic = "0.9.2"
|
||||
tower = "0.4.13"
|
||||
nymvpn-config = { path = "../nymvpn-config" }
|
||||
nymvpn-types = {path = "../nymvpn-types"} # grpc types to nymvpn-types conversions
|
||||
chrono = { version = "0.4.24", features = ["serde"] }
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.9.2"
|
||||
@@ -1,7 +0,0 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
const PROTO_PATH: &str = "proto/nymvpn-controller.proto";
|
||||
tonic_build::configure().protoc_arg("--experimental_allow_proto3_optional")
|
||||
.compile(&[PROTO_PATH], &["proto"])?;
|
||||
println!("cargo:rerun-if-changed=proto");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package nymvpn.controller;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
service ControllerService {
|
||||
// Locations served
|
||||
rpc GetLocations(google.protobuf.Empty) returns (Locations);
|
||||
rpc RecentLocations(google.protobuf.Empty) returns (Locations);
|
||||
|
||||
// Account
|
||||
rpc IsAuthenticated(google.protobuf.Empty) returns (google.protobuf.BoolValue);
|
||||
rpc AccountSignIn(SignInRequest) returns (google.protobuf.Empty);
|
||||
rpc AccountSignOut(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
rpc GetAccountInfo(google.protobuf.Empty) returns (AccountInfo);
|
||||
|
||||
// Control VPN
|
||||
rpc ConnectVpn(Location) returns (VpnStatus);
|
||||
rpc DisconnectVpn(google.protobuf.Empty) returns (VpnStatus);
|
||||
rpc GetVpnStatus(google.protobuf.Empty) returns (VpnStatus);
|
||||
|
||||
// Notifications
|
||||
rpc GetNotifications(google.protobuf.Empty) returns (Notifications);
|
||||
rpc AckNotification(google.protobuf.StringValue) returns (google.protobuf.Empty);
|
||||
|
||||
// Versions and Updates
|
||||
rpc LatestAppVersion(google.protobuf.Empty) returns (google.protobuf.StringValue);
|
||||
|
||||
// Events
|
||||
rpc WatchEvents(google.protobuf.Empty) returns (stream DaemonEvent);
|
||||
}
|
||||
|
||||
message SignInRequest {
|
||||
string email = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message AccountInfo {
|
||||
string email = 1;
|
||||
uint32 balance = 2;
|
||||
}
|
||||
|
||||
message Notifications {
|
||||
repeated Notification notification = 1;
|
||||
}
|
||||
|
||||
enum NotificationType {
|
||||
SERVER_FAILED = 0;
|
||||
CLIENT_FAILED = 1;
|
||||
}
|
||||
|
||||
message Notification {
|
||||
string id = 1;
|
||||
NotificationType notification_type = 2;
|
||||
string message = 3;
|
||||
google.protobuf.Timestamp timestamp = 4;
|
||||
}
|
||||
|
||||
message VpnStatus {
|
||||
|
||||
message Accepted {
|
||||
Location location = 1;
|
||||
};
|
||||
|
||||
message ServerCreated {
|
||||
Location location = 1;
|
||||
}
|
||||
|
||||
message ServerRunning {
|
||||
Location location = 1;
|
||||
}
|
||||
|
||||
message ServerReady {
|
||||
Location location = 1;
|
||||
}
|
||||
|
||||
message Connecting {
|
||||
Location location = 1;
|
||||
}
|
||||
|
||||
message Connected {
|
||||
Location location = 1;
|
||||
google.protobuf.Timestamp timestamp = 2;
|
||||
}
|
||||
|
||||
message Disconnecting {
|
||||
Location location = 1;
|
||||
}
|
||||
|
||||
message Disconnected {}
|
||||
|
||||
oneof vpn_status {
|
||||
Accepted accepted = 1;
|
||||
Connecting connecting = 2;
|
||||
ServerCreated server_created = 3;
|
||||
ServerRunning server_running = 4;
|
||||
ServerReady server_ready = 5;
|
||||
Connected connected = 6;
|
||||
Disconnecting disconnecting = 7;
|
||||
Disconnected disconnected = 8;
|
||||
}
|
||||
}
|
||||
|
||||
message Locations {
|
||||
repeated Location location = 1;
|
||||
}
|
||||
|
||||
message Location {
|
||||
string code = 1;
|
||||
string country = 2;
|
||||
string country_code = 3;
|
||||
string city = 4;
|
||||
string city_code = 5;
|
||||
optional string state = 6;
|
||||
optional string state_code = 7;
|
||||
}
|
||||
|
||||
message DaemonEvent {
|
||||
oneof event {
|
||||
VpnStatus vpn_status = 1;
|
||||
Notification notification = 2;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use hyper::Body;
|
||||
use tonic::body::BoxBody;
|
||||
use tower::{Layer, Service};
|
||||
|
||||
#[tonic::async_trait]
|
||||
pub trait Auth: Clone + Send + Sync {
|
||||
async fn is_authenticated(&self) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ControllerAuthLayer<P: Auth> {
|
||||
auth: P,
|
||||
}
|
||||
|
||||
impl<P: Auth> ControllerAuthLayer<P> {
|
||||
pub fn new(auth: P) -> Self {
|
||||
Self { auth }
|
||||
}
|
||||
}
|
||||
|
||||
const ALLOWED_UNAUTHORIZED_PATHS: [&str; 2] = [
|
||||
"/nymvpn.controller.ControllerService/AccountSignIn",
|
||||
"/nymvpn.controller.ControllerService/IsAuthenticated",
|
||||
];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ControllerAuthMiddleware<S, P: Auth> {
|
||||
auth: P,
|
||||
inner: S,
|
||||
}
|
||||
|
||||
impl<S, P: Auth> Layer<S> for ControllerAuthLayer<P> {
|
||||
type Service = ControllerAuthMiddleware<S, P>;
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
ControllerAuthMiddleware {
|
||||
auth: self.auth.clone(),
|
||||
inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, P> Service<hyper::Request<Body>> for ControllerAuthMiddleware<S, P>
|
||||
where
|
||||
S: Service<hyper::Request<Body>, Response = hyper::Response<BoxBody>> + Clone + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
P: Auth + 'static,
|
||||
{
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: hyper::Request<Body>) -> Self::Future {
|
||||
// This is necessary because tonic internally uses `tower::buffer::Buffer`.
|
||||
// See https://github.com/tower-rs/tower/issues/547#issuecomment-767629149
|
||||
// for details on why this is necessary
|
||||
let clone = self.inner.clone();
|
||||
let mut inner = std::mem::replace(&mut self.inner, clone);
|
||||
|
||||
let auth = self.auth.clone();
|
||||
Box::pin(async move {
|
||||
if ALLOWED_UNAUTHORIZED_PATHS.contains(&req.uri().path())
|
||||
|| auth.is_authenticated().await
|
||||
{
|
||||
return inner.call(req).await;
|
||||
}
|
||||
|
||||
Ok(tonic::Status::unauthenticated("please sign in first").to_http())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
impl From<crate::proto::SignInRequest> for nymvpn_types::nymvpn_server::UserCredentials {
|
||||
fn from(value: crate::proto::SignInRequest) -> Self {
|
||||
Self {
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
impl From<nymvpn_types::location::Location> for crate::proto::Location {
|
||||
fn from(value: nymvpn_types::location::Location) -> Self {
|
||||
Self {
|
||||
code: value.code,
|
||||
country: value.country,
|
||||
country_code: value.country_code,
|
||||
city: value.city,
|
||||
city_code: value.city_code,
|
||||
state: value.state,
|
||||
state_code: value.state_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::proto::Location> for nymvpn_types::location::Location {
|
||||
fn from(value: crate::proto::Location) -> Self {
|
||||
Self {
|
||||
code: value.code,
|
||||
country: value.country,
|
||||
country_code: value.country_code,
|
||||
city: value.city,
|
||||
city_code: value.city_code,
|
||||
state: value.state,
|
||||
state_code: value.state_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<nymvpn_types::location::Location>> for crate::proto::Locations {
|
||||
fn from(value: Vec<nymvpn_types::location::Location>) -> Self {
|
||||
Self {
|
||||
location: value
|
||||
.into_iter()
|
||||
.map(crate::proto::Location::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::proto::Locations> for Vec<nymvpn_types::location::Location> {
|
||||
fn from(value: crate::proto::Locations) -> Self {
|
||||
value
|
||||
.location
|
||||
.into_iter()
|
||||
.map(nymvpn_types::location::Location::from)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
pub mod account;
|
||||
pub mod location;
|
||||
pub mod notification;
|
||||
pub mod vpn_status;
|
||||
@@ -1,77 +0,0 @@
|
||||
use crate::timestamp_to_datetime_utc;
|
||||
|
||||
impl From<crate::proto::NotificationType> for nymvpn_types::notification::NotificationType {
|
||||
fn from(value: crate::proto::NotificationType) -> Self {
|
||||
match value {
|
||||
crate::proto::NotificationType::ServerFailed => {
|
||||
nymvpn_types::notification::NotificationType::ServerFailed
|
||||
}
|
||||
crate::proto::NotificationType::ClientFailed => {
|
||||
nymvpn_types::notification::NotificationType::ClientFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nymvpn_types::notification::NotificationType> for crate::proto::NotificationType {
|
||||
fn from(value: nymvpn_types::notification::NotificationType) -> Self {
|
||||
match value {
|
||||
nymvpn_types::notification::NotificationType::ServerFailed => {
|
||||
crate::proto::NotificationType::ServerFailed
|
||||
}
|
||||
nymvpn_types::notification::NotificationType::ClientFailed => {
|
||||
crate::proto::NotificationType::ClientFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::proto::Notification> for nymvpn_types::notification::Notification {
|
||||
type Error = String;
|
||||
fn try_from(value: crate::proto::Notification) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
id: value.id,
|
||||
message: value.message,
|
||||
notification_type: value.notification_type.try_into()?,
|
||||
timestamp: timestamp_to_datetime_utc(value.timestamp)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nymvpn_types::notification::Notification> for crate::proto::Notification {
|
||||
fn from(value: nymvpn_types::notification::Notification) -> Self {
|
||||
let seconds = value.timestamp.timestamp();
|
||||
let nanos = value.timestamp.timestamp_subsec_nanos();
|
||||
Self {
|
||||
id: value.id,
|
||||
notification_type: value.notification_type.into(),
|
||||
message: value.message,
|
||||
timestamp: Some(prost_types::Timestamp {
|
||||
seconds,
|
||||
nanos: nanos as i32,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<nymvpn_types::notification::Notification>> for crate::proto::Notifications {
|
||||
fn from(value: Vec<nymvpn_types::notification::Notification>) -> Self {
|
||||
Self {
|
||||
notification: value
|
||||
.into_iter()
|
||||
.map(crate::proto::Notification::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::proto::Notifications> for Vec<nymvpn_types::notification::Notification> {
|
||||
type Error = String;
|
||||
fn try_from(value: crate::proto::Notifications) -> Result<Self, Self::Error> {
|
||||
let mut notifications = vec![];
|
||||
for notification in value.notification {
|
||||
notifications.push(notification.try_into()?)
|
||||
}
|
||||
Ok(notifications)
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
use crate::{datetime_utc_to_timestamp, timestamp_to_datetime_utc};
|
||||
|
||||
impl From<nymvpn_types::vpn_session::VpnStatus> for crate::proto::VpnStatus {
|
||||
fn from(value: nymvpn_types::vpn_session::VpnStatus) -> Self {
|
||||
match value {
|
||||
nymvpn_types::vpn_session::VpnStatus::Accepted(location) => crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::Accepted(
|
||||
crate::proto::vpn_status::Accepted {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
},
|
||||
nymvpn_types::vpn_session::VpnStatus::Connecting(location) => crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::Connecting(
|
||||
crate::proto::vpn_status::Connecting {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
},
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerRunning(location) => {
|
||||
crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::ServerRunning(
|
||||
crate::proto::vpn_status::ServerRunning {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerReady(location) => crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::ServerReady(
|
||||
crate::proto::vpn_status::ServerReady {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
},
|
||||
nymvpn_types::vpn_session::VpnStatus::Connected(location, connected_time) => {
|
||||
crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::Connected(
|
||||
crate::proto::vpn_status::Connected {
|
||||
location: Some(location.into()),
|
||||
timestamp: Some(datetime_utc_to_timestamp(connected_time)),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
nymvpn_types::vpn_session::VpnStatus::Disconnecting(location) => {
|
||||
crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::Disconnecting(
|
||||
crate::proto::vpn_status::Disconnecting {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
nymvpn_types::vpn_session::VpnStatus::Disconnected => crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::Disconnected(
|
||||
crate::proto::vpn_status::Disconnected {},
|
||||
)),
|
||||
},
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerCreated(location) => {
|
||||
crate::proto::VpnStatus {
|
||||
vpn_status: Some(crate::proto::vpn_status::VpnStatus::ServerCreated(
|
||||
crate::proto::vpn_status::ServerCreated {
|
||||
location: Some(location.into()),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::proto::VpnStatus> for nymvpn_types::vpn_session::VpnStatus {
|
||||
fn from(value: crate::proto::VpnStatus) -> Self {
|
||||
let vpn_status = value.vpn_status.unwrap();
|
||||
match vpn_status {
|
||||
crate::proto::vpn_status::VpnStatus::Accepted(accepted) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::Accepted(accepted.location.unwrap().into())
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::Connecting(connecting) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::Connecting(connecting.location.unwrap().into())
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::ServerRunning(srun) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerRunning(srun.location.unwrap().into())
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::ServerReady(sr) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerReady(sr.location.unwrap().into())
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::Connected(connected) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::Connected(
|
||||
connected.location.unwrap().into(),
|
||||
timestamp_to_datetime_utc(connected.timestamp).unwrap(),
|
||||
)
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::Disconnecting(disconnecting) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::Disconnecting(
|
||||
disconnecting.location.unwrap().into(),
|
||||
)
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::Disconnected(_) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::Disconnected
|
||||
}
|
||||
crate::proto::vpn_status::VpnStatus::ServerCreated(server_created) => {
|
||||
nymvpn_types::vpn_session::VpnStatus::ServerCreated(
|
||||
server_created.location.unwrap().into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
use auth::Auth;
|
||||
use parity_tokio_ipc::Endpoint as IpcEndpoint;
|
||||
use prost_types::Timestamp;
|
||||
use thiserror::Error;
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio::io::AsyncWrite;
|
||||
use tokio::io::ReadBuf;
|
||||
use tonic::transport::server::Connected;
|
||||
use tonic::transport::Channel;
|
||||
use tonic::transport::Endpoint as TonicEndpoint;
|
||||
use tonic::transport::Server;
|
||||
use tonic::transport::Uri;
|
||||
use tower::service_fn;
|
||||
|
||||
pub mod proto {
|
||||
tonic::include_proto!("nymvpn.controller");
|
||||
}
|
||||
|
||||
pub mod auth;
|
||||
pub mod conversions;
|
||||
|
||||
use chrono::{TimeZone, Utc};
|
||||
pub use proto::controller_service_server::{ControllerService, ControllerServiceServer};
|
||||
use nymvpn_types::DateTimeUtc;
|
||||
|
||||
use crate::auth::ControllerAuthLayer;
|
||||
|
||||
pub type ControllerServiceClient =
|
||||
proto::controller_service_client::ControllerServiceClient<Channel>;
|
||||
|
||||
pub type GrpcServerJoinHandle = tokio::task::JoinHandle<Result<(), ControllerError>>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ControllerError {
|
||||
#[error("{0}")]
|
||||
TonicTransportError(tonic::transport::Error),
|
||||
#[error("security attributes error {0:#?}")]
|
||||
SecurityAttributesError(std::io::Error),
|
||||
#[error("incoming connection error {0:#?}")]
|
||||
IncomingConnectionError(std::io::Error),
|
||||
}
|
||||
|
||||
pub async fn new_grpc_client() -> Result<ControllerServiceClient, ControllerError> {
|
||||
let ipc_path = nymvpn_config::config().socket_path();
|
||||
|
||||
// URI is unused
|
||||
let channel = TonicEndpoint::from_static("http://[::]:50051")
|
||||
.connect_with_connector(service_fn(move |_: Uri| {
|
||||
IpcEndpoint::connect(ipc_path.clone())
|
||||
}))
|
||||
.await
|
||||
.map_err(ControllerError::TonicTransportError)?;
|
||||
|
||||
Ok(ControllerServiceClient::new(channel))
|
||||
}
|
||||
|
||||
pub async fn spawn_grpc_server<S, P, F>(
|
||||
service: S,
|
||||
auth: P,
|
||||
shutdown: F,
|
||||
) -> std::result::Result<GrpcServerJoinHandle, ControllerError>
|
||||
where
|
||||
S: proto::controller_service_server::ControllerService,
|
||||
F: Future<Output = ()> + Send + 'static,
|
||||
P: Auth + 'static,
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
use parity_tokio_ipc::SecurityAttributes;
|
||||
|
||||
let socket_path = nymvpn_config::config().socket_path();
|
||||
|
||||
let mut endpoint = IpcEndpoint::new(socket_path.to_string_lossy().to_string());
|
||||
endpoint.set_security_attributes(
|
||||
SecurityAttributes::allow_everyone_create()
|
||||
.map_err(ControllerError::SecurityAttributesError)?
|
||||
.set_mode(0o766)
|
||||
.map_err(ControllerError::SecurityAttributesError)?,
|
||||
);
|
||||
|
||||
let incoming = endpoint
|
||||
.incoming()
|
||||
.map_err(ControllerError::IncomingConnectionError)?;
|
||||
|
||||
Ok(tokio::spawn(async move {
|
||||
Server::builder()
|
||||
.layer(ControllerAuthLayer::new(auth))
|
||||
.add_service(ControllerServiceServer::new(service))
|
||||
.serve_with_incoming_shutdown(incoming.map_ok(StreamBox), shutdown)
|
||||
.await
|
||||
.map_err(ControllerError::TonicTransportError)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StreamBox<T: AsyncRead + AsyncWrite>(pub T);
|
||||
|
||||
impl<T: AsyncRead + AsyncWrite> Connected for StreamBox<T> {
|
||||
type ConnectInfo = Option<()>;
|
||||
|
||||
fn connect_info(&self) -> Self::ConnectInfo {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for StreamBox<T> {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<std::io::Result<()>> {
|
||||
Pin::new(&mut self.0).poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for StreamBox<T> {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<std::io::Result<usize>> {
|
||||
Pin::new(&mut self.0).poll_write(cx, buf)
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
|
||||
Pin::new(&mut self.0).poll_flush(cx)
|
||||
}
|
||||
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
|
||||
Pin::new(&mut self.0).poll_shutdown(cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timestamp_to_datetime_utc(timestamp: Option<Timestamp>) -> Result<DateTimeUtc, String> {
|
||||
let timestamp = timestamp.ok_or(format!("no timestamp"))?;
|
||||
let date_time_utc = match Utc.timestamp_opt(timestamp.seconds, timestamp.nanos as u32) {
|
||||
chrono::LocalResult::Single(dtu) => dtu,
|
||||
chrono::LocalResult::None => Err("invalid utc time none")?,
|
||||
chrono::LocalResult::Ambiguous(a, _b) => {
|
||||
//Err(format!("ambiguous utc time {a} {b}"))?
|
||||
a
|
||||
}
|
||||
};
|
||||
Ok(date_time_utc)
|
||||
}
|
||||
|
||||
pub fn datetime_utc_to_timestamp(datetime_utc: DateTimeUtc) -> Timestamp {
|
||||
let seconds = datetime_utc.timestamp();
|
||||
let nanos = std::cmp::max(datetime_utc.timestamp_subsec_nanos() as i32, 0);
|
||||
prost_types::Timestamp { seconds, nanos }
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
[package]
|
||||
name = "nymvpn-daemon"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0"
|
||||
authors = ["Nym Technologies S.A."]
|
||||
homepage = "https://nymvpn.net"
|
||||
repository = "https://github.com/nymvpn/nymvpn-app"
|
||||
|
||||
[dependencies]
|
||||
clap = "4.2.7"
|
||||
async-trait = "0.1.68"
|
||||
futures = "0.3.28"
|
||||
hyper = "0.14.26"
|
||||
thiserror = "1.0.40"
|
||||
tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal", "macros", "sync", "fs"] }
|
||||
tokio-stream = { version = "0.1.12", features = ["sync"] }
|
||||
tonic = "0.9.2"
|
||||
tower = "0.4.13"
|
||||
tracing = "0.1.37"
|
||||
tracing-appender = "0.2.2"
|
||||
tracing-subscriber = { version = "0.3.16", features = ["default", "env-filter", "tracing-log"] }
|
||||
nymvpn-config = {path = "../nymvpn-config"}
|
||||
nymvpn-controller = {path = "../nymvpn-controller"}
|
||||
nymvpn-server = {path = "../nymvpn-server"}
|
||||
nymvpn-types = {path = "../nymvpn-types"}
|
||||
nymvpn-entity = {path = "../nymvpn-entity"}
|
||||
nymvpn-migration = {path = "../nymvpn-migration"}
|
||||
sea-orm = { version = "0.11.2", features = ["sqlx-sqlite", "runtime-tokio-rustls"] }
|
||||
chrono = "0.4.24"
|
||||
talpid-core = {git = "https://github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
|
||||
talpid-types = {git = "https://github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
|
||||
talpid-platform-metadata = {git = "https://github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
|
||||
futures-channel = "0.3.28"
|
||||
uuid = { version = "1.3.1", features = ["v4", "serde"] }
|
||||
libc = "0.2"
|
||||
lazy_static = "1.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = "0.26.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-service = "0.6.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows-sys]
|
||||
version = "0.45.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
"Win32_Security_Authorization",
|
||||
"Win32_Security_Authentication_Identity",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_Kernel",
|
||||
"Win32_System_Memory",
|
||||
"Win32_System_Threading",
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
../nymvpn.conf.toml
|
||||
@@ -1,10 +0,0 @@
|
||||
pub async fn remove_old_socket_file() {
|
||||
if let Err(e) = tokio::fs::remove_file(nymvpn_config::config().socket_path()).await {
|
||||
if e.kind() != std::io::ErrorKind::NotFound {
|
||||
tracing::error!(
|
||||
"Failed to remove old socket file {}",
|
||||
nymvpn_config::config().socket_path().display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::{sync::oneshot, task::JoinHandle};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use tonic::{Request, Response, Status};
|
||||
use nymvpn_controller::{
|
||||
proto::{AccountInfo, Locations, Notifications, SignInRequest, VpnStatus},
|
||||
spawn_grpc_server, ControllerError, ControllerService,
|
||||
};
|
||||
use nymvpn_migration::DbErr;
|
||||
use nymvpn_types::notification::Notification;
|
||||
|
||||
use crate::{
|
||||
daemon::{DaemonCommand, DaemonCommandSender, DaemonError, EventListener},
|
||||
device::handler::DeviceHandler,
|
||||
shutdown::ShutdownManager,
|
||||
};
|
||||
|
||||
pub struct ControllerServer;
|
||||
|
||||
impl ControllerServer {
|
||||
pub async fn start(
|
||||
daemon_command_sender: DaemonCommandSender,
|
||||
shutdown_manager: &ShutdownManager,
|
||||
device_handler: DeviceHandler,
|
||||
) -> Result<ControllerServerAndEventBroadcaster, ControllerError> {
|
||||
let events_subscribers =
|
||||
Arc::<tokio::sync::RwLock<Vec<DaemonEventsListenerSender>>>::default();
|
||||
|
||||
let controller_service = ControllerServiceImpl {
|
||||
daemon_command_sender,
|
||||
events_subscribers: events_subscribers.clone(),
|
||||
};
|
||||
|
||||
let handle = spawn_grpc_server(
|
||||
controller_service,
|
||||
device_handler,
|
||||
shutdown_manager.shutdown_received_future(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let controller_server_handle = tokio::spawn(async move {
|
||||
if let Err(e) = handle.await {
|
||||
tracing::error!("Controller GRPC server error: {e}")
|
||||
}
|
||||
tracing::info!("Controller server shut down")
|
||||
});
|
||||
|
||||
Ok(ControllerServerAndEventBroadcaster {
|
||||
events_subscribers,
|
||||
controller_server_handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ControllerServerAndEventBroadcaster {
|
||||
pub events_subscribers: Arc<tokio::sync::RwLock<Vec<DaemonEventsListenerSender>>>,
|
||||
pub controller_server_handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl ControllerServerAndEventBroadcaster {
|
||||
async fn notify(&self, event: nymvpn_controller::proto::DaemonEvent) {
|
||||
let mut subscribers = self.events_subscribers.write().await;
|
||||
|
||||
subscribers.retain(|tx| tx.send(Ok(event.clone())).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl EventListener for ControllerServerAndEventBroadcaster {
|
||||
async fn send_vpn_status(&self, status: nymvpn_types::vpn_session::VpnStatus) {
|
||||
tracing::debug!("notifying new vpn status");
|
||||
self.notify(nymvpn_controller::proto::DaemonEvent {
|
||||
event: Some(nymvpn_controller::proto::daemon_event::Event::VpnStatus(
|
||||
nymvpn_controller::proto::VpnStatus::from(status),
|
||||
)),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn send_notification(&self, notification: Notification) {
|
||||
tracing::debug!("sending new notification");
|
||||
self.notify(nymvpn_controller::proto::DaemonEvent {
|
||||
event: Some(nymvpn_controller::proto::daemon_event::Event::Notification(
|
||||
nymvpn_controller::proto::Notification::from(notification),
|
||||
)),
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ControllerServiceImpl {
|
||||
daemon_command_sender: DaemonCommandSender,
|
||||
events_subscribers: Arc<tokio::sync::RwLock<Vec<DaemonEventsListenerSender>>>,
|
||||
}
|
||||
|
||||
pub type ServiceResult<T> = std::result::Result<Response<T>, Status>;
|
||||
pub type VpnStatusListenerSender =
|
||||
tokio::sync::mpsc::UnboundedSender<Result<nymvpn_controller::proto::VpnStatus, Status>>;
|
||||
pub type VpnStatusListenerReceiver =
|
||||
UnboundedReceiverStream<Result<nymvpn_controller::proto::VpnStatus, Status>>;
|
||||
|
||||
pub type DaemonEventsListenerSender =
|
||||
tokio::sync::mpsc::UnboundedSender<Result<nymvpn_controller::proto::DaemonEvent, Status>>;
|
||||
|
||||
pub type DaemonEventsListenerReceiver =
|
||||
UnboundedReceiverStream<Result<nymvpn_controller::proto::DaemonEvent, Status>>;
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl ControllerService for ControllerServiceImpl {
|
||||
type WatchEventsStream = DaemonEventsListenerReceiver;
|
||||
|
||||
/// Locations served
|
||||
async fn get_locations(&self, _: Request<()>) -> ServiceResult<Locations> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::ListLocations(tx))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(|locations| Response::new(locations.into()))
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn recent_locations(&self, _: Request<()>) -> ServiceResult<Locations> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::RecentLocations(tx))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(|locations| Response::new(locations.into()))
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
/// Account
|
||||
async fn is_authenticated(&self, _req: Request<()>) -> ServiceResult<bool> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::IsAuthenticated(tx))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn account_sign_in(&self, req: Request<SignInRequest>) -> ServiceResult<()> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::AccountSignIn(tx, req.into_inner().into()))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn account_sign_out(&self, _: Request<()>) -> ServiceResult<()> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::AccountSignOut(tx))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn get_account_info(&self, _: Request<()>) -> ServiceResult<AccountInfo> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Control VPN
|
||||
async fn connect_vpn(
|
||||
&self,
|
||||
req: Request<nymvpn_controller::proto::Location>,
|
||||
) -> ServiceResult<VpnStatus> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::Connect(tx, req.into_inner().into()))?;
|
||||
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(nymvpn_controller::proto::VpnStatus::from)
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn disconnect_vpn(&self, _: Request<()>) -> ServiceResult<VpnStatus> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::Disconnect(tx))?;
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(nymvpn_controller::proto::VpnStatus::from)
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn get_vpn_status(&self, _: Request<()>) -> ServiceResult<VpnStatus> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::GetVpnStatus(tx))?;
|
||||
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(nymvpn_controller::proto::VpnStatus::from)
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
/// Notifications
|
||||
async fn get_notifications(&self, _: Request<()>) -> ServiceResult<Notifications> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::GetNotifications(tx))?;
|
||||
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(nymvpn_controller::proto::Notifications::from)
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
async fn ack_notification(&self, id: Request<String>) -> ServiceResult<()> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::AckNotification(tx, id.into_inner()))?;
|
||||
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
// Versions and Updates
|
||||
async fn latest_app_version(&self, _: Request<()>) -> ServiceResult<String> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.send_command_to_daemon(DaemonCommand::LatestAppVersion(tx))?;
|
||||
|
||||
self.wait_for_result(rx)
|
||||
.await?
|
||||
.map(Response::new)
|
||||
.map_err(map_daemon_error)
|
||||
}
|
||||
|
||||
/// Event stream
|
||||
async fn watch_events(&self, _: Request<()>) -> ServiceResult<Self::WatchEventsStream> {
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let mut subscribers = self.events_subscribers.write().await;
|
||||
subscribers.push(tx);
|
||||
Ok(Response::new(UnboundedReceiverStream::new(rx)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllerServiceImpl {
|
||||
fn send_command_to_daemon(&self, command: DaemonCommand) -> Result<(), Status> {
|
||||
self.daemon_command_sender
|
||||
.send(command)
|
||||
.map_err(|_| Status::internal("the daemon channel receiver has been dropped"))
|
||||
}
|
||||
|
||||
async fn wait_for_result<T>(&self, rx: tokio::sync::oneshot::Receiver<T>) -> Result<T, Status> {
|
||||
rx.await.map_err(|_| Status::internal("sender was dropped"))
|
||||
}
|
||||
}
|
||||
|
||||
fn map_db_error(_db_err: DbErr) -> Status {
|
||||
Status::internal("daemon is unable to manage its database")
|
||||
}
|
||||
|
||||
pub const SERVER_UNAVAILABLE_PLEASE_TRY_AGAIN_LATER: &str =
|
||||
"server is unavailable, please try again later";
|
||||
pub const VPN_SESSION_SERVICE_UNAVAILABLE: &str =
|
||||
"daemon is partially up: vpn session service unavailable";
|
||||
|
||||
fn map_daemon_error(error: DaemonError) -> Status {
|
||||
tracing::error!("{:?}", error);
|
||||
match error {
|
||||
DaemonError::DaemonUnavailable => Status::internal("daemon is unavailable"),
|
||||
DaemonError::AnotherVpnSessionInProgress(location) => Status::failed_precondition(format!(
|
||||
"cannot start a new vpn session when another is in progress (to city {})",
|
||||
location.city
|
||||
)),
|
||||
DaemonError::InvalidOpVpnSessionInProgress(message) => Status::failed_precondition(message),
|
||||
DaemonError::DbErr(db_err) => map_db_error(db_err),
|
||||
DaemonError::DeviceError(device_error) => match device_error {
|
||||
crate::device::DeviceError::DeviceServiceUnavailable => {
|
||||
Status::internal("daemon is partially up: device service unavailable")
|
||||
}
|
||||
crate::device::DeviceError::Server(status) => status,
|
||||
crate::device::DeviceError::Connection(_) => {
|
||||
Status::unavailable(SERVER_UNAVAILABLE_PLEASE_TRY_AGAIN_LATER)
|
||||
}
|
||||
crate::device::DeviceError::DbErr(db_err) => map_db_error(db_err),
|
||||
crate::device::DeviceError::InitError(_) => {
|
||||
Status::internal("failed to initialize device")
|
||||
}
|
||||
},
|
||||
DaemonError::VpnSessionError(vpn_session_error) => match vpn_session_error {
|
||||
crate::vpn_session::handler::VpnSessionError::VpnSessionServiceDown => {
|
||||
Status::internal(VPN_SESSION_SERVICE_UNAVAILABLE)
|
||||
}
|
||||
crate::vpn_session::handler::VpnSessionError::Connection(_) => {
|
||||
Status::unavailable(SERVER_UNAVAILABLE_PLEASE_TRY_AGAIN_LATER)
|
||||
}
|
||||
crate::vpn_session::handler::VpnSessionError::Server(status) => status,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,732 +0,0 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use talpid_core::tunnel_state_machine::{TunnelCommand, TunnelStateMachineHandle};
|
||||
use talpid_types::tunnel::TunnelStateTransition;
|
||||
use tokio::sync::oneshot;
|
||||
use nymvpn_controller::auth::Auth;
|
||||
use nymvpn_migration::DbErr;
|
||||
use nymvpn_types::{
|
||||
location::Location,
|
||||
notification::Notification,
|
||||
nymvpn_server::{ClientConnected, EndSession, NewSession, UserCredentials, VpnSessionStatus},
|
||||
vpn_session::VpnStatus,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
controller::ControllerServerAndEventBroadcaster,
|
||||
device::{handler::DeviceHandler, storage::DeviceStorage, DeviceError},
|
||||
location_storage::LocationStorage,
|
||||
shutdown::Shutdown,
|
||||
state::DaemonState,
|
||||
vpn_session::{
|
||||
handler::{VpnSessionError, VpnSessionHandler},
|
||||
storage::{SessionInfo, VpnSessionStorage},
|
||||
},
|
||||
ResponseTx,
|
||||
};
|
||||
|
||||
pub struct Daemon {
|
||||
// in memory current state of the server + client side state
|
||||
state: DaemonState,
|
||||
controller_server_and_event_broadcaster: ControllerServerAndEventBroadcaster,
|
||||
daemon_command_sender: DaemonCommandSender,
|
||||
daemon_receiver: DaemonReceiver,
|
||||
device_handler: DeviceHandler,
|
||||
vpn_session_storage: VpnSessionStorage,
|
||||
device_storage: DeviceStorage,
|
||||
vpn_session_handler: VpnSessionHandler,
|
||||
tunnel_state_machine_handle: TunnelStateMachineHandle,
|
||||
location_storage: LocationStorage,
|
||||
shutdown: Option<Shutdown>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DaemonError {
|
||||
#[error("daemon is offline")]
|
||||
DaemonUnavailable,
|
||||
#[error("another vpn session in progress: {0}")]
|
||||
AnotherVpnSessionInProgress(Location),
|
||||
#[error("invalid op when vpn session in progress: {0}")]
|
||||
InvalidOpVpnSessionInProgress(String),
|
||||
#[error("")]
|
||||
DbErr(#[from] DbErr),
|
||||
#[error("device error: {0}")]
|
||||
DeviceError(#[from] DeviceError),
|
||||
#[error("vpn session error: {0}")]
|
||||
VpnSessionError(#[from] VpnSessionError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DaemonCommand {
|
||||
IsAuthenticated(ResponseTx<bool, DaemonError>),
|
||||
AccountSignIn(ResponseTx<(), DaemonError>, UserCredentials),
|
||||
AccountSignOut(ResponseTx<(), DaemonError>),
|
||||
ListLocations(ResponseTx<Vec<Location>, DaemonError>),
|
||||
RecentLocations(ResponseTx<Vec<Location>, DaemonError>),
|
||||
Connect(ResponseTx<VpnStatus, DaemonError>, Location),
|
||||
Disconnect(ResponseTx<VpnStatus, DaemonError>),
|
||||
GetVpnStatus(ResponseTx<VpnStatus, DaemonError>),
|
||||
GetNotifications(ResponseTx<Vec<Notification>, DaemonError>),
|
||||
AckNotification(ResponseTx<(), DaemonError>, String),
|
||||
LatestAppVersion(ResponseTx<String, DaemonError>),
|
||||
}
|
||||
|
||||
pub type DaemonReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonEvent>;
|
||||
pub type DaemonSender = tokio::sync::mpsc::UnboundedSender<DaemonEvent>;
|
||||
|
||||
pub struct DaemonCommandChannel {
|
||||
sender: DaemonCommandSender,
|
||||
receiver: DaemonReceiver,
|
||||
}
|
||||
|
||||
impl DaemonCommandChannel {
|
||||
pub fn new() -> Self {
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
Self {
|
||||
sender: DaemonCommandSender(tx),
|
||||
receiver: rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sender(&self) -> DaemonCommandSender {
|
||||
self.sender.clone()
|
||||
}
|
||||
|
||||
pub fn destructure(self) -> (DaemonCommandSender, DaemonReceiver) {
|
||||
(self.sender, self.receiver)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DaemonCommandSender(DaemonSender);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DaemonEventSender(DaemonSender);
|
||||
|
||||
impl DaemonCommandSender {
|
||||
pub fn send(&self, command: DaemonCommand) -> Result<(), DaemonError> {
|
||||
self.0
|
||||
.send(DaemonEvent::Command(command))
|
||||
.map_err(|_| DaemonError::DaemonUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
impl DaemonEventSender {
|
||||
pub fn send(&self, event: DaemonEvent) -> Result<(), DaemonError> {
|
||||
self.0
|
||||
.send(event)
|
||||
.map_err(|_| DaemonError::DaemonUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> talpid_core::mpsc::Sender<E> for DaemonEventSender
|
||||
where
|
||||
DaemonEvent: From<E>,
|
||||
{
|
||||
fn send(&self, event: E) -> Result<(), talpid_core::mpsc::Error> {
|
||||
self.0
|
||||
.send(DaemonEvent::from(event))
|
||||
.map_err(|_| talpid_core::mpsc::Error::ChannelClosed)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DaemonCommandSender> for DaemonEventSender {
|
||||
fn from(dcs: DaemonCommandSender) -> Self {
|
||||
Self(dcs.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// All possible events that can happen during the lifetime of a Daemon
|
||||
#[derive(Debug)]
|
||||
pub enum DaemonEvent {
|
||||
/// Command for the Daemon
|
||||
Command(DaemonCommand),
|
||||
/// Initiated by signals like ctrl-c, SIGINT or SIGTERM
|
||||
Shutdown,
|
||||
/// Vpn Session Status received from Server
|
||||
VpnSessionStatus(VpnSessionStatus),
|
||||
/// Tunnel has changed state.
|
||||
TunnelStateTransition(TunnelStateTransition),
|
||||
}
|
||||
|
||||
impl From<TunnelStateTransition> for DaemonEvent {
|
||||
fn from(tst: TunnelStateTransition) -> Self {
|
||||
DaemonEvent::TunnelStateTransition(tst)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DaemonEvent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let event = match self {
|
||||
DaemonEvent::Command(command) => match command {
|
||||
DaemonCommand::IsAuthenticated(_) => "IsAuthenticated".into(),
|
||||
DaemonCommand::AccountSignIn(_, user_creds) => {
|
||||
format!("AccountSignIn: {}", user_creds.email)
|
||||
}
|
||||
DaemonCommand::AccountSignOut(_) => "AccountSignOut".into(),
|
||||
DaemonCommand::ListLocations(_) => "ListLocations".into(),
|
||||
DaemonCommand::RecentLocations(_) => "RecentLocations".into(),
|
||||
DaemonCommand::Connect(_, location) => format!("Connect: {}", location.code),
|
||||
DaemonCommand::Disconnect(_) => "Disconnect".into(),
|
||||
DaemonCommand::GetVpnStatus(_) => "GetVpnStatus".into(),
|
||||
DaemonCommand::GetNotifications(_) => "GetNotifications".into(),
|
||||
DaemonCommand::AckNotification(_, id) => format!("AckNotification: {id}"),
|
||||
DaemonCommand::LatestAppVersion(_) => "LatestAppVersion".into(),
|
||||
},
|
||||
DaemonEvent::Shutdown => "Shutdown".into(),
|
||||
DaemonEvent::VpnSessionStatus(status) => format!("VpnSessionStatus: {status}"),
|
||||
DaemonEvent::TunnelStateTransition(transition) => match transition {
|
||||
TunnelStateTransition::Disconnected => "TunnelStateTransition: Disconnected".into(),
|
||||
TunnelStateTransition::Connecting(endpoint) => {
|
||||
format!("TunnelStateTransition: {endpoint}")
|
||||
}
|
||||
TunnelStateTransition::Connected(endpoint) => {
|
||||
format!("TunnelStateTransition: {endpoint}")
|
||||
}
|
||||
TunnelStateTransition::Disconnecting(action) => {
|
||||
format!("TunnelStateTransition: {action:?}")
|
||||
}
|
||||
TunnelStateTransition::Error(e) => format!("TunnelStateTransition: {e:?}"),
|
||||
},
|
||||
};
|
||||
|
||||
write!(f, "{event}")
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait EventListener {
|
||||
async fn send_vpn_status(&self, status: VpnStatus);
|
||||
|
||||
async fn send_notification(&self, notification: Notification);
|
||||
|
||||
//todo: add other events
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new(
|
||||
dc: DaemonCommandChannel,
|
||||
device_handler: DeviceHandler,
|
||||
vpn_session_storage: VpnSessionStorage,
|
||||
device_storage: DeviceStorage,
|
||||
vpn_session_handler: VpnSessionHandler,
|
||||
controller_server_and_event_broadcaster: ControllerServerAndEventBroadcaster,
|
||||
tunnel_state_machine_handle: TunnelStateMachineHandle,
|
||||
location_storage: LocationStorage,
|
||||
shutdown: Option<Shutdown>,
|
||||
) -> Self {
|
||||
let (daemon_command_sender, daemon_receiver) = dc.destructure();
|
||||
|
||||
Daemon {
|
||||
state: DaemonState::new(),
|
||||
daemon_command_sender,
|
||||
daemon_receiver,
|
||||
device_handler,
|
||||
device_storage,
|
||||
vpn_session_storage,
|
||||
vpn_session_handler,
|
||||
controller_server_and_event_broadcaster,
|
||||
tunnel_state_machine_handle,
|
||||
location_storage,
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
|
||||
fn register_shutdown(&mut self) {
|
||||
let mut shutdown = self.shutdown.take().unwrap();
|
||||
let sender = DaemonEventSender::from(self.daemon_command_sender.clone());
|
||||
tokio::spawn(async move {
|
||||
shutdown.recv().await;
|
||||
if let Err(e) = sender.send(DaemonEvent::Shutdown) {
|
||||
//todo: Display trait
|
||||
tracing::error!("failed to send shutdown event to Daemon: {e:#?}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn run(mut self) {
|
||||
self.register_shutdown();
|
||||
while let Some(event) = self.daemon_receiver.recv().await {
|
||||
if let DaemonEvent::Shutdown = event {
|
||||
break;
|
||||
}
|
||||
self.handle_event(event).await;
|
||||
}
|
||||
self.handle_shutdown().await;
|
||||
}
|
||||
|
||||
async fn handle_shutdown(mut self) {
|
||||
tracing::info!("handling shutdown ...");
|
||||
|
||||
// if any, disconnect and end existing session
|
||||
if let Err(err) = self.on_disconnect_inner("daemon shutdown".into()).await {
|
||||
tracing::error!("when ending session during shutdown: {err}");
|
||||
};
|
||||
|
||||
// wait for tunnel state machine to stop
|
||||
self.tunnel_state_machine_handle.try_join().await;
|
||||
|
||||
if let Err(err) = self.vpn_session_handler.shutdown().await {
|
||||
tracing::error!("error when vpn session handler was shutting down: {err}");
|
||||
};
|
||||
|
||||
let ControllerServerAndEventBroadcaster {
|
||||
events_subscribers,
|
||||
controller_server_handle,
|
||||
} = self.controller_server_and_event_broadcaster;
|
||||
|
||||
let mut guard = events_subscribers.write().await;
|
||||
guard.clear();
|
||||
|
||||
drop(guard);
|
||||
drop(events_subscribers);
|
||||
|
||||
let _ = tokio::join!(controller_server_handle);
|
||||
// device handler last as controller depends on it for auth
|
||||
if let Err(err) = self.device_handler.shutdown().await {
|
||||
tracing::error!("error when device handler was shutting down: {err}");
|
||||
};
|
||||
}
|
||||
|
||||
async fn handle_event(&mut self, event: DaemonEvent) {
|
||||
tracing::debug!("daemon event: {event}");
|
||||
match event {
|
||||
DaemonEvent::Command(command) => self.handle_command(command).await,
|
||||
DaemonEvent::VpnSessionStatus(vpn_session_status) => {
|
||||
self.handle_vpn_session_status(vpn_session_status).await
|
||||
}
|
||||
DaemonEvent::TunnelStateTransition(transition) => {
|
||||
self.handle_tunnel_state_transition(transition).await
|
||||
}
|
||||
DaemonEvent::Shutdown => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_tunnel_state_transition(&mut self, transition: TunnelStateTransition) {
|
||||
tracing::info!("tunnel transition: {transition:?}");
|
||||
let processed = self
|
||||
.vpn_session_storage
|
||||
.tunnel_state_transition(transition.clone(), self.state.vpn_status())
|
||||
.await
|
||||
.expect("failed to process tunnel state transition");
|
||||
|
||||
if let Some(reason) = processed.end_session {
|
||||
tracing::info!("ending session after tunnel transition {reason}");
|
||||
if let Err(err) = self.end_session(reason).await {
|
||||
tracing::error!(
|
||||
"failed to end session on state transition: {transition:?}: {err:?}"
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(session_info) = processed.client_connected {
|
||||
tracing::info!("client connected {}", session_info.request_id);
|
||||
self.client_connected(session_info).await;
|
||||
}
|
||||
|
||||
if let Some(tunnel_command) = processed.tunnel_command {
|
||||
tracing::info!("sending tunnel command after tunnel state transition");
|
||||
self.send_tunnel_command(tunnel_command);
|
||||
}
|
||||
|
||||
if let Some(notification) = processed.notification {
|
||||
tracing::info!("sending notification after tunnel state transition {notification:?}");
|
||||
self.add_notification(notification).await;
|
||||
}
|
||||
|
||||
// update vpn status and send device event
|
||||
self.set_vpn_status(processed.vpn_status).await;
|
||||
}
|
||||
|
||||
async fn handle_vpn_session_status(&mut self, vpn_session_status: VpnSessionStatus) {
|
||||
// Update DB and get next set of actions
|
||||
let processed = self
|
||||
.vpn_session_storage
|
||||
.updated_server_status(vpn_session_status.clone())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!(
|
||||
"failed to process updated vpn session status {vpn_session_status}: {e}"
|
||||
)
|
||||
})
|
||||
.expect("unrecoverable db error in handle_vpn_session_status");
|
||||
|
||||
if let Some(notification) = processed.notification {
|
||||
self.add_notification(notification).await;
|
||||
}
|
||||
|
||||
if let Some(new_vpn_status) = processed.vpn_status {
|
||||
// Update in memory status and notify clients of new status
|
||||
self.set_vpn_status(new_vpn_status.clone()).await;
|
||||
|
||||
// Start next state machine if this is ServerReady
|
||||
self.update_tunnel_on_new_status(new_vpn_status).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_tunnel_on_new_status(&self, new_vpn_status: VpnStatus) {
|
||||
if let VpnStatus::ServerReady(_) = new_vpn_status {
|
||||
self.send_tunnel_command(TunnelCommand::Connect);
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_command(&mut self, command: DaemonCommand) {
|
||||
match command {
|
||||
DaemonCommand::IsAuthenticated(tx) => self.is_authenticated(tx).await,
|
||||
DaemonCommand::AccountSignIn(tx, auth_input) => {
|
||||
self.on_account_sign_in(tx, auth_input).await
|
||||
}
|
||||
DaemonCommand::AccountSignOut(tx) => self.on_account_sign_out(tx).await,
|
||||
DaemonCommand::ListLocations(tx) => self.on_list_locations(tx).await,
|
||||
DaemonCommand::RecentLocations(tx) => self.on_recent_locations(tx).await,
|
||||
DaemonCommand::Connect(tx, location) => self.on_connect(tx, location).await,
|
||||
DaemonCommand::Disconnect(tx) => self.on_disconnect(tx).await,
|
||||
DaemonCommand::GetVpnStatus(tx) => self.on_get_vpn_status(tx).await,
|
||||
DaemonCommand::GetNotifications(tx) => self.on_get_notifications(tx).await,
|
||||
DaemonCommand::AckNotification(tx, id) => self.on_ack_notification(tx, id).await,
|
||||
DaemonCommand::LatestAppVersion(tx) => self.on_latest_app_version(tx).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_latest_app_version(&self, tx: ResponseTx<String, DaemonError>) {
|
||||
let device_handler = self.device_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
device_handler
|
||||
.latest_app_version()
|
||||
.await
|
||||
.map_err(DaemonError::DeviceError),
|
||||
"on_latest_app_version",
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async fn on_get_notifications(&self, tx: ResponseTx<Vec<Notification>, DaemonError>) {
|
||||
let notifications = self.state.notifications();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(tx, Ok(notifications), "on_get_notifications");
|
||||
});
|
||||
}
|
||||
|
||||
async fn on_ack_notification(&mut self, tx: ResponseTx<(), DaemonError>, id: String) {
|
||||
self.state.remove_notification(id);
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(tx, Ok(()), "on_ack_notification");
|
||||
});
|
||||
}
|
||||
|
||||
async fn add_notification(&mut self, notification: Notification) {
|
||||
// save in current state
|
||||
self.state.add_notification(notification.clone());
|
||||
// notify event listeners
|
||||
self.controller_server_and_event_broadcaster
|
||||
.send_notification(notification)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn set_vpn_status(&mut self, vpn_status: nymvpn_types::vpn_session::VpnStatus) {
|
||||
// save current state
|
||||
self.state.set_vpn_status(vpn_status.clone());
|
||||
// and notify event listeners,
|
||||
{
|
||||
// todo: make broadcaster clone-able and send event on spawned task
|
||||
self.controller_server_and_event_broadcaster
|
||||
.send_vpn_status(vpn_status.into())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_connect_inner(&mut self, location: Location) -> Result<VpnStatus, DaemonError> {
|
||||
if let Some(location) = self.state.vpn_session_in_progress() {
|
||||
tracing::warn!("another vpn session in progress: {location}");
|
||||
return Err(DaemonError::AnotherVpnSessionInProgress(location));
|
||||
}
|
||||
|
||||
let request_id = self
|
||||
.vpn_session_storage
|
||||
.new_session(location.clone())
|
||||
.await?;
|
||||
|
||||
let device_unique_id = self.device_storage.get_device_unique_id().await?;
|
||||
|
||||
let new_session = NewSession {
|
||||
request_id,
|
||||
device_unique_id,
|
||||
location_code: location.code.clone(),
|
||||
};
|
||||
|
||||
match self
|
||||
.vpn_session_handler
|
||||
.new_session(new_session.clone())
|
||||
.await
|
||||
{
|
||||
Ok(accepted) => {
|
||||
// update local record
|
||||
self.vpn_session_storage
|
||||
.update_on_accepted(accepted)
|
||||
.await?;
|
||||
// update state
|
||||
self.state.accepted(location.clone());
|
||||
|
||||
Ok(VpnStatus::Accepted(location))
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("cannot connect: {err}");
|
||||
// remove local record
|
||||
self.vpn_session_storage
|
||||
.delete(new_session.request_id)
|
||||
.await?;
|
||||
// add notification about it
|
||||
let notification = self
|
||||
.state
|
||||
.add_notification_for_failed_new_session(request_id, location, err);
|
||||
self.add_notification(notification).await;
|
||||
Ok(VpnStatus::Disconnected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_connect(
|
||||
&mut self,
|
||||
tx: ResponseTx<VpnStatus, DaemonError>,
|
||||
location: nymvpn_types::location::Location,
|
||||
) {
|
||||
tracing::info!("Connection requested to {location}");
|
||||
let location_storage = self.location_storage.clone();
|
||||
let location_to_add = location.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = location_storage.add_recent(location_to_add).await {
|
||||
tracing::error!("failed to save recent location: {e}");
|
||||
}
|
||||
});
|
||||
Self::oneshot_send(tx, self.on_connect_inner(location).await, "on_connect");
|
||||
}
|
||||
|
||||
async fn tunnel_command_on_disconnect(&self) {
|
||||
let current_state = self.state.vpn_status();
|
||||
match ¤t_state {
|
||||
VpnStatus::ServerReady(_) | VpnStatus::Connecting(_) | VpnStatus::Connected(_, _) => {
|
||||
self.send_tunnel_command(TunnelCommand::Disconnect)
|
||||
}
|
||||
VpnStatus::Accepted(_)
|
||||
| VpnStatus::ServerCreated(_)
|
||||
| VpnStatus::ServerRunning(_)
|
||||
| VpnStatus::Disconnecting(_)
|
||||
| VpnStatus::Disconnected => {
|
||||
tracing::info!("Not sending tunnel command to disconnect. State: {current_state}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn end_session(&mut self, end_reason: String) -> Result<(), DaemonError> {
|
||||
// Get session info and mark for deletion in DB
|
||||
let session_info = self.vpn_session_storage.end_session().await?;
|
||||
|
||||
match session_info {
|
||||
Some(session_info) => {
|
||||
let device_unique_id = self.device_storage.get_device_unique_id().await?;
|
||||
|
||||
let end_session = EndSession {
|
||||
request_id: session_info.request_id,
|
||||
device_unique_id,
|
||||
vpn_session_uuid: session_info.vpn_session_id,
|
||||
reason: end_reason,
|
||||
};
|
||||
|
||||
// make api call to server to end session,
|
||||
// ignore errors as reclaimer should eventually cleanup
|
||||
match self
|
||||
.vpn_session_handler
|
||||
.end_session(end_session.clone())
|
||||
.await
|
||||
{
|
||||
Ok(ended) => {
|
||||
tracing::info!("vpn session successfully ended on server: {ended}");
|
||||
// on success delete record from DB
|
||||
self.vpn_session_storage
|
||||
.delete(session_info.request_id)
|
||||
.await?;
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("couldn't end session on server {end_session}: {err}");
|
||||
}
|
||||
};
|
||||
}
|
||||
None => {
|
||||
tracing::warn!("No existing vpn session found in DB in end_session");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn client_connected(&self, session_info: SessionInfo) {
|
||||
let device_storage = self.device_storage.clone();
|
||||
let vpn_session_handler = self.vpn_session_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
async fn call_client_connected(
|
||||
session_info: SessionInfo,
|
||||
device_storage: DeviceStorage,
|
||||
vpn_session_handler: VpnSessionHandler,
|
||||
) -> Result<(), DaemonError> {
|
||||
let device_unique_id = device_storage.get_device_unique_id().await?;
|
||||
|
||||
let client_connected = ClientConnected {
|
||||
request_id: session_info.request_id,
|
||||
device_unique_id,
|
||||
vpn_session_uuid: session_info.vpn_session_id,
|
||||
};
|
||||
|
||||
let _ = vpn_session_handler
|
||||
.client_connected(client_connected.clone())
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if let Err(e) =
|
||||
call_client_connected(session_info.clone(), device_storage, vpn_session_handler)
|
||||
.await
|
||||
{
|
||||
tracing::error!(
|
||||
"couldn't make client connected call on server: {session_info}: {e}"
|
||||
);
|
||||
}
|
||||
|
||||
Ok::<(), DaemonError>(())
|
||||
});
|
||||
}
|
||||
|
||||
async fn on_disconnect_inner(&mut self, end_reason: String) -> Result<VpnStatus, DaemonError> {
|
||||
self.tunnel_command_on_disconnect().await;
|
||||
self.end_session(end_reason).await?;
|
||||
let status = self.state.update_state_on_disconnect();
|
||||
self.controller_server_and_event_broadcaster
|
||||
.send_vpn_status(status.clone())
|
||||
.await;
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
async fn on_disconnect(&mut self, tx: ResponseTx<VpnStatus, DaemonError>) {
|
||||
tracing::info!("Disconnect requested");
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
self.on_disconnect_inner("client requested".into()).await,
|
||||
"on_disconnect",
|
||||
);
|
||||
}
|
||||
|
||||
async fn on_get_vpn_status(&self, tx: ResponseTx<VpnStatus, DaemonError>) {
|
||||
let vpn_status = self.state.vpn_status();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(tx, Ok(vpn_status), "on_get_vpn_status_response")
|
||||
});
|
||||
}
|
||||
|
||||
async fn is_authenticated(&self, tx: ResponseTx<bool, DaemonError>) {
|
||||
let device_handler = self.device_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
Ok(device_handler.is_authenticated().await),
|
||||
"is_authenticated_response",
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
async fn on_account_sign_in(
|
||||
&self,
|
||||
tx: ResponseTx<(), DaemonError>,
|
||||
user_creds: UserCredentials,
|
||||
) {
|
||||
// if vpn session in progress do not sign in
|
||||
if let Some(location) = self.state.vpn_session_in_progress() {
|
||||
tracing::warn!("sign in attempt when vpn session in progress: {location}");
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
Err(DaemonError::InvalidOpVpnSessionInProgress(format!(
|
||||
"cannot sign in when a vpn session is in progress (to city {})",
|
||||
location.city
|
||||
))),
|
||||
"on_account_sign_in error",
|
||||
);
|
||||
} else {
|
||||
let device_handler = self.device_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
device_handler
|
||||
.sign_in(user_creds)
|
||||
.await
|
||||
.map_err(DaemonError::DeviceError),
|
||||
"on_account_login response",
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_account_sign_out(&self, tx: ResponseTx<(), DaemonError>) {
|
||||
// if vpn session in progress do not sign out
|
||||
if let Some(location) = self.state.vpn_session_in_progress() {
|
||||
tracing::warn!("sign out attempt when vpn session in progress: {location}");
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
Err(DaemonError::InvalidOpVpnSessionInProgress(format!(
|
||||
"cannot sign out when a vpn session is in progress (to city {})",
|
||||
location.city
|
||||
))),
|
||||
"on_account_sign_out error",
|
||||
);
|
||||
} else {
|
||||
let device_handler = self.device_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
device_handler
|
||||
.sign_out()
|
||||
.await
|
||||
.map_err(DaemonError::DeviceError),
|
||||
"on_account_sign_out response",
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_list_locations(&self, tx: ResponseTx<Vec<Location>, DaemonError>) {
|
||||
let vpn_session_handler = self.vpn_session_handler.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
vpn_session_handler
|
||||
.list_locations()
|
||||
.await
|
||||
.map_err(DaemonError::VpnSessionError),
|
||||
"on_list_locations response",
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
async fn on_recent_locations(&self, tx: ResponseTx<Vec<Location>, DaemonError>) {
|
||||
let location_storage = self.location_storage.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::oneshot_send(
|
||||
tx,
|
||||
location_storage.recent().await.map_err(DaemonError::DbErr),
|
||||
"on_recent_locations response",
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn send_tunnel_command(&self, command: TunnelCommand) {
|
||||
self.tunnel_state_machine_handle
|
||||
.command_tx()
|
||||
.unbounded_send(command)
|
||||
.expect("Tunnel state machine has stopped");
|
||||
}
|
||||
|
||||
fn oneshot_send<T>(tx: oneshot::Sender<T>, t: T, msg: &'static str) {
|
||||
if tx.send(t).is_err() {
|
||||
tracing::warn!("Unable to send {} to the daemon command sender", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||