Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make API requests through nym-http-api-client #1951

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions nym-vpn-core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion nym-vpn-core/crates/nym-harbour-master-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ license.workspace = true
[dependencies]
chrono.workspace = true
nym-http-api-client.workspace = true
reqwest = { workspace = true, features = ["rustls-tls"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
Expand Down
1 change: 0 additions & 1 deletion nym-vpn-core/crates/nym-vpn-account-controller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ nym-vpn-api-client = { path = "../nym-vpn-api-client" }
nym-vpn-network-config = { path = "../nym-vpn-network-config" }
nym-vpn-store = { path = "../nym-vpn-store" }
nym-wg-gateway-client = { path = "../nym-wg-gateway-client" }
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
si-scale.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion nym-vpn-core/crates/nym-vpn-api-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ nym-crypto = { workspace = true, features = ["asymmetric", "stream_cipher"] }
nym-ecash-time.workspace = true
nym-http-api-client.workspace = true
nym-validator-client.workspace = true
reqwest = { workspace = true, features = ["rustls-tls", "json"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
sha2.workspace = true
strum.workspace = true
strum_macros.workspace = true
thiserror.workspace = true
tracing.workspace = true
url.workspace = true
zeroize.workspace = true

[dev-dependencies]
Expand Down
82 changes: 80 additions & 2 deletions nym-vpn-core/crates/nym-vpn-api-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ use std::{fmt, time::Duration};
use backon::Retryable;
use nym_credential_proxy_requests::api::v1::ticketbook::models::PartialVerificationKeysResponse;
use nym_http_api_client::{HttpClientError, Params, PathSegments, UserAgent, NO_PARAMS};
use reqwest::Url;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;

use crate::request::{UpdateDeviceRequestBody, UpdateDeviceRequestStatus};
use crate::response::{NymVpnHealthResponse, NymVpnUsagesResponse};
use crate::response::{
DiscoveryResponse, NymNetworkDetailsResponse, NymVpnHealthResponse, NymVpnUsagesResponse,
NymWellknownDiscoveryItem, RegisteredNetworksResponse,
};
use crate::types::DeviceStatus;
use crate::{
error::{Result, VpnApiClientError},
Expand Down Expand Up @@ -867,6 +870,81 @@ impl VpnApiClient {
}
}

// Bootstrapping Environments and Network Discovery
impl VpnApiClient {
/// Hard coded well known URL for bootstrapping environment and discovery config
/// allowing more refined URL usage.
// hard coded for now.
const WELLKNOWN_URL: &str = "https://nymvpn.com/api";

/// Returns a VpnApiClient Based on locally set well known url and empty user agent.
///
/// THIS SHOULD ONLY BE USED FOR BOOTSTRAPPING.
pub fn well_known() -> Result<Self> {
let user_agent = UserAgent {
application: String::new(),
version: String::new(),
platform: String::new(),
git_commit: String::new(),
};
Self::new(Self::WELLKNOWN_URL.parse().unwrap(), user_agent)
}

pub async fn get_network_envs(&self) -> Result<RegisteredNetworksResponse> {
self.inner
.get_json(
&[
routes::PUBLIC,
routes::V1,
routes::WELLKNOWN,
routes::ENVS_FILE,
],
NO_PARAMS,
)
.await
.map_err(VpnApiClientError::FailedToGetNetworkEnvs)
}

pub async fn get_discovery_init(&self, network_name: &str) -> Result<DiscoveryResponse> {
self.inner
.get_json(
&[
routes::PUBLIC,
routes::V1,
routes::WELLKNOWN,
network_name,
routes::DISCOVERY_FILE,
],
NO_PARAMS,
)
.await
.map_err(VpnApiClientError::FailedToGetDiscoveryInfo)
}

pub async fn get_nym_network_details(&self) -> Result<NymNetworkDetailsResponse> {
self.inner
.get_json(&[routes::V1, routes::NETWORK, routes::DETAILS], NO_PARAMS)
.await
.map_err(VpnApiClientError::FailedToGetNetworkDetails)
}

pub async fn get_nym_vpn_network_details(&self) -> Result<NymWellknownDiscoveryItem> {
tracing::debug!("Fetching nym vpn network details");
self.inner
.get_json(
&[
routes::PUBLIC,
routes::V1,
routes::WELLKNOWN,
routes::CURRENT_ENV,
],
NO_PARAMS,
)
.await
.map_err(VpnApiClientError::FailedToGetVPNNetworkDetails)
}
}

#[cfg(test)]
mod tests {
use nym_crypto::asymmetric::ed25519;
Expand Down
12 changes: 12 additions & 0 deletions nym-vpn-core/crates/nym-vpn-api-client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ pub enum VpnApiClientError {

#[error("failed to get usage")]
FailedToGetUsage(#[source] HttpClientError<UnexpectedError>),

#[error("failed to get registered network environments")]
FailedToGetNetworkEnvs(#[source] HttpClientError<UnexpectedError>),

#[error("failed to get discovery info")]
FailedToGetDiscoveryInfo(#[source] HttpClientError<UnexpectedError>),

#[error("failed to get network Details")]
FailedToGetNetworkDetails(#[source] HttpClientError<UnexpectedError>),

#[error("failed to get vpn network Details")]
FailedToGetVPNNetworkDetails(#[source] HttpClientError<UnexpectedError>),
}

pub type Result<T> = std::result::Result<T, VpnApiClientError>;
51 changes: 51 additions & 0 deletions nym-vpn-core/crates/nym-vpn-api-client/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use itertools::Itertools;
use nym_contracts_common::Percent;
use nym_credential_proxy_requests::api::v1::ticketbook::models::TicketbookWalletSharesResponse;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt;
use std::net::IpAddr;

Expand Down Expand Up @@ -552,3 +553,53 @@ fn extract_error_response_inner(
_ => None,
}
}

// The response type we fetch from the discovery endpoint
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct DiscoveryResponse {
pub network_name: String,
pub nym_api_url: String,
pub nym_vpn_api_url: String,
pub account_management: Option<AccountManagementResponse>,
pub feature_flags: Option<serde_json::Value>,
pub system_messages: Option<Vec<SystemMessageResponse>>,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
pub struct AccountManagementResponse {
pub url: String,
pub paths: AccountManagementPathsResponse,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
pub struct AccountManagementPathsResponse {
pub sign_up: String,
pub sign_in: String,
pub account: String,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct SystemMessageResponse {
pub name: String,
pub display_from: String,
pub display_until: String,
pub message: String,
pub properties: serde_json::Value,
}

// The response type we fetch from the network details endpoint. This will be added to and exported
// from nym-api-requests.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct NymNetworkDetailsResponse {
pub network: nym_config::defaults::NymNetworkDetails,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct NymWellknownDiscoveryItem {
pub network_name: String,
pub nym_api_url: String,
pub nym_vpn_api_url: String,
}

pub type RegisteredNetworksResponse = HashSet<String>;
7 changes: 7 additions & 0 deletions nym-vpn-core/crates/nym-vpn-api-client/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub(crate) const ACCOUNT: &str = "account";
pub(crate) const HEALTH: &str = "health";
pub(crate) const SUMMARY: &str = "summary";
pub(crate) const DEVICE: &str = "device";
pub(crate) const NETWORK: &str = "network";
pub(crate) const DETAILS: &str = "details";
pub(crate) const ACTIVE: &str = "active";
pub(crate) const ZKNYM: &str = "zknym";
pub(crate) const AVAILABLE: &str = "available";
Expand All @@ -25,3 +27,8 @@ pub(crate) const PARTIAL_VERIFICATION_KEYS: &str = "partial-verification-keys";
pub(crate) const SHOW_VPN_ONLY: &str = "show_vpn_only";
pub(crate) const VPN_MIN_PERFORMANCE: &str = "vpn_min_performance";
pub(crate) const MIXNET_MIN_PERFORMANCE: &str = "mixnet_min_performance";

pub(crate) const WELLKNOWN: &str = ".wellknown";
pub(crate) const ENVS_FILE: &str = "envs.json";
pub(crate) const DISCOVERY_FILE: &str = "discovery.json";
pub(crate) const CURRENT_ENV: &str = "current-env.json";
7 changes: 2 additions & 5 deletions nym-vpn-core/crates/nym-vpn-network-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ futures-util.workspace = true
itertools.workspace = true
nym-config.workspace = true
nym-sdk.workspace = true
reqwest = { workspace = true, default-features = false, features = [
"blocking",
"rustls-tls",
"json",
] }
serde.workspace = true
serde_json.workspace = true
tempfile.workspace = true
Expand All @@ -28,5 +23,7 @@ tokio-util.workspace = true
tracing.workspace = true
url = { workspace = true, features = ["serde"] }

nym-vpn-api-client = { path = "../nym-vpn-api-client" }

[build-dependencies]
serde_json.workspace = true
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt;

use url::Url;

use crate::response::{AccountManagementPathsResponse, AccountManagementResponse};
use nym_vpn_api_client::response::{AccountManagementPathsResponse, AccountManagementResponse};

#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct AccountManagement {
Expand Down
Loading
Loading