Compare commits

...

4 Commits

Author SHA1 Message Date
benedetta davico 2026639fd2 Merge pull request #6344 from nymtech/jmwample/nym-api-cfg-niolo
Jmwample/nym api cfg niolo
2026-01-22 09:20:43 +01:00
jmwample 9098981318 env feature locking to protect contracts 2026-01-20 11:17:20 -07:00
jmwample ef39111f82 minor fixes 2026-01-20 11:17:20 -07:00
jmwample c92d3029fa apply configured api urls via env 2026-01-20 11:17:20 -07:00
5 changed files with 70 additions and 14 deletions
Generated
+2
View File
@@ -6326,6 +6326,8 @@ dependencies = [
"regex",
"schemars 0.8.22",
"serde",
"serde_json",
"tracing",
"url",
"utoipa",
]
+3 -1
View File
@@ -12,6 +12,8 @@ dotenvy = { workspace = true, optional = true }
log = { workspace = true, optional = true }
schemars = { workspace = true, features = ["preserve_order"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }
serde_json = {workspace = true, optional = true }
tracing = {workspace = true, optional = true }
url = { workspace = true, optional = true }
utoipa = { workspace = true, optional = true }
@@ -20,7 +22,7 @@ utoipa = { workspace = true, optional = true }
[features]
default = ["env", "network"]
env = ["dotenvy", "log"]
env = ["dotenvy", "log", "serde_json", "tracing"]
network = ["schemars", "serde", "url"]
utoipa = [ "dep:utoipa" ]
+12
View File
@@ -72,6 +72,13 @@ pub const NYM_VPN_APIS: &[ApiUrlConst] = &[
},
];
#[cfg(feature = "env")]
fn serialize_api_urls(urls: &[ApiUrlConst]) -> String {
serde_json::to_string(urls)
.inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}"))
.unwrap_or_default()
}
// I'm making clippy mad on purpose, because that url HAS TO be updated and deployed before merging
pub const EXIT_POLICY_URL: &str =
"https://nymtech.net/.wellknown/network-requester/exit-policy.txt";
@@ -162,9 +169,11 @@ pub fn export_to_env() {
);
set_var_to_default(var_names::NYXD, NYXD_URL);
set_var_to_default(var_names::NYM_API, NYM_API);
set_var_to_default(var_names::NYM_APIS, &serialize_api_urls(NYM_APIS));
set_var_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS);
set_var_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL);
set_var_to_default(var_names::NYM_VPN_API, NYM_VPN_API);
set_var_to_default(var_names::NYM_VPN_APIS, &serialize_api_urls(NYM_VPN_APIS));
set_var_to_default(
var_names::UPGRADE_MODE_ATTESTATION_URL,
UPGRADE_MODE_ATTESTATION_URL,
@@ -211,6 +220,9 @@ pub fn export_to_env_if_not_set() {
);
set_var_conditionally_to_default(var_names::NYXD, NYXD_URL);
set_var_conditionally_to_default(var_names::NYM_API, NYM_API);
set_var_conditionally_to_default(var_names::NYM_APIS, &serialize_api_urls(NYM_APIS));
set_var_conditionally_to_default(var_names::NYM_VPN_API, NYM_VPN_API);
set_var_conditionally_to_default(var_names::NYM_VPN_APIS, &serialize_api_urls(NYM_VPN_APIS));
set_var_conditionally_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS);
set_var_conditionally_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL);
set_var_conditionally_to_default(
+51 -13
View File
@@ -7,6 +7,13 @@ use serde::{Deserialize, Serialize};
use std::ops::Not;
use url::Url;
#[cfg(feature = "env")]
use crate::var_names;
#[cfg(feature = "env")]
use std::env::{VarError, var};
#[cfg(feature = "env")]
use std::ffi::OsStr;
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ChainDetails {
@@ -55,7 +62,7 @@ pub struct ApiUrl {
pub front_hosts: Option<Vec<String>>,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug, Serialize)]
pub struct ApiUrlConst<'a> {
pub url: &'a str,
pub front_hosts: Option<&'a [&'a str]>,
@@ -106,10 +113,6 @@ impl NymNetworkDetails {
#[cfg(feature = "env")]
pub fn new_from_env() -> Self {
use crate::var_names;
use std::env::{VarError, var};
use std::ffi::OsStr;
fn get_optional_env<K: AsRef<OsStr>>(env: K) -> Option<String> {
match var(env) {
Ok(var) => {
@@ -125,6 +128,11 @@ impl NymNetworkDetails {
}
let nym_api = var(var_names::NYM_API).expect("nym api not set");
let nym_api_urls = try_parse_api_urls(var_names::NYM_APIS).unwrap_or(vec![ApiUrl {
url: nym_api.clone(),
front_hosts: None,
}]);
let nym_vpn_api_urls = try_parse_api_urls(var_names::NYM_VPN_APIS);
NymNetworkDetails::new_empty()
.with_network_name(var(var_names::NETWORK_NAME).expect("network name not set"))
@@ -161,10 +169,8 @@ impl NymNetworkDetails {
.with_multisig_contract(get_optional_env(var_names::MULTISIG_CONTRACT_ADDRESS))
.with_coconut_dkg_contract(get_optional_env(var_names::COCONUT_DKG_CONTRACT_ADDRESS))
.with_nym_vpn_api_url(get_optional_env(var_names::NYM_VPN_API))
.with_nym_api_urls(Some(vec![ApiUrl {
url: nym_api,
front_hosts: None,
}]))
.with_nym_vpn_api_urls(nym_vpn_api_urls)
.with_nym_api_urls(nym_api_urls)
}
pub fn new_mainnet() -> Self {
@@ -218,6 +224,9 @@ impl NymNetworkDetails {
}
}
unsafe {
let nym_api_urls = self.nym_api_urls();
let nym_vpn_api_urls = self.nym_vpn_api_urls();
set_var(var_names::NETWORK_NAME, self.network_name);
set_var(var_names::BECH32_PREFIX, self.chain_details.bech32_account_prefix);
@@ -243,9 +252,10 @@ impl NymNetworkDetails {
set_optional_var(var_names::COCONUT_DKG_CONTRACT_ADDRESS, self.contracts.coconut_dkg_contract_address);
set_optional_var(var_names::NYM_VPN_API, self.nym_vpn_api_url);
set_optional_var(var_names::NYM_VPN_APIS, nym_vpn_api_urls);
set_optional_var(var_names::NYM_APIS, nym_api_urls);
}
}
pub fn default_gas_price_amount(&self) -> f64 {
@@ -355,8 +365,14 @@ impl NymNetworkDetails {
}
#[must_use]
pub fn with_nym_api_urls(mut self, urls: Option<Vec<ApiUrl>>) -> Self {
self.nym_api_urls = urls;
pub fn with_nym_api_urls(mut self, urls: Vec<ApiUrl>) -> Self {
self.nym_api_urls = Some(urls);
self
}
#[must_use]
pub fn with_nym_vpn_api_urls(mut self, urls: Option<Vec<ApiUrl>>) -> Self {
self.nym_vpn_api_urls = urls;
self
}
@@ -366,6 +382,28 @@ impl NymNetworkDetails {
.expect("the provided nym-vpn api url is invalid!")
})
}
#[cfg(feature = "env")]
fn nym_api_urls(&self) -> Option<String> {
serde_json::to_string(self.nym_api_urls.as_deref()?)
.inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}"))
.ok()
}
#[cfg(feature = "env")]
fn nym_vpn_api_urls(&self) -> Option<String> {
serde_json::to_string(self.nym_vpn_api_urls.as_deref()?)
.inspect_err(|e| tracing::warn!("failed to serialize nym_vpn_api_urls for env: {e}"))
.ok()
}
}
#[cfg(feature = "env")]
fn try_parse_api_urls(k: impl AsRef<OsStr>) -> Option<Vec<ApiUrl>> {
let raw = var(k).ok()?;
serde_json::from_str(&raw)
.inspect_err(|e| tracing::warn!("failed to parse api urls from env \"{raw:?}\": {e}"))
.ok()
}
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
+2
View File
@@ -21,9 +21,11 @@ pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "COCONUT_DKG_CONTRACT_ADDRESS";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
pub const NYXD: &str = "NYXD";
pub const NYM_API: &str = "NYM_API";
pub const NYM_APIS: &str = "NYM_APIS";
pub const NYXD_WEBSOCKET: &str = "NYXD_WS";
pub const EXIT_POLICY_URL: &str = "EXIT_POLICY";
pub const NYM_VPN_API: &str = "NYM_VPN_API";
pub const NYM_VPN_APIS: &str = "NYM_VPN_APIS";
pub const CLIENT_STATS_COLLECTION_PROVIDER: &str = "CLIENT_STATS_COLLECTION_PROVIDER";
pub const UPGRADE_MODE_ATTESTATION_URL: &str = "UPGRADE_MODE_ATTESTATION_URL";
pub const UPGRADE_MODE_ATTESTER_ED25519_BS58_PUBKEY: &str = "UPGRADE_MODE_ATTESTER_ED25519_PUBKEY";