Compare commits

...

5 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 5007d867b8 getting started with routes 2024-05-26 15:10:43 +01:00
Jędrzej Stuczyński fa0ec3453d AppState 2024-05-26 13:55:47 +01:00
Jędrzej Stuczyński a2b1917d06 explicitly import all macros 2024-05-26 13:30:30 +01:00
Jędrzej Stuczyński 77b4fd2aa5 use auth middleware for prometheus metrics 2024-05-26 13:07:16 +01:00
Jędrzej Stuczyński 61e08d6e43 moved common axum middleware to common crate 2024-05-26 12:39:41 +01:00
79 changed files with 596 additions and 143 deletions
Generated
+12 -49
View File
@@ -447,29 +447,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "axum-extra"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733"
dependencies = [
"axum 0.7.5",
"axum-core 0.4.3",
"bytes",
"futures-util",
"headers",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite",
"serde",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "backtrace"
version = "0.3.71"
@@ -2738,30 +2715,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "headers"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
dependencies = [
"base64 0.21.7",
"bytes",
"headers-core",
"http 1.1.0",
"httpdate",
"mime",
"sha1",
]
[[package]]
name = "headers-core"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
"http 1.1.0",
]
[[package]]
name = "heck"
version = "0.3.3"
@@ -3933,6 +3886,7 @@ version = "1.1.38"
dependencies = [
"anyhow",
"async-trait",
"axum 0.7.5",
"bip39",
"bs58 0.5.1",
"cfg-if",
@@ -3946,6 +3900,7 @@ dependencies = [
"dirs 4.0.0",
"futures",
"getset",
"http 1.1.0",
"humantime-serde",
"itertools 0.12.1",
"k256",
@@ -3963,6 +3918,7 @@ dependencies = [
"nym-crypto",
"nym-dkg",
"nym-gateway-client",
"nym-http-api-common",
"nym-inclusion-probability",
"nym-mixnet-contract-common",
"nym-multisig-contract-common",
@@ -3997,8 +3953,11 @@ dependencies = [
"time",
"tokio",
"tokio-stream",
"tower-http",
"ts-rs",
"url",
"utoipa",
"utoipa-swagger-ui",
"zeroize",
]
@@ -4732,11 +4691,17 @@ version = "0.1.0"
dependencies = [
"axum 0.7.5",
"bytes",
"colored",
"futures",
"mime",
"serde",
"serde_json",
"serde_yaml",
"tokio",
"tower",
"tracing",
"utoipa",
"zeroize",
]
[[package]]
@@ -5120,11 +5085,9 @@ name = "nym-node-http-api"
version = "0.1.0"
dependencies = [
"axum 0.7.5",
"axum-extra",
"colored",
"dashmap",
"fastrand 2.1.0",
"headers",
"hmac 0.12.1",
"hyper 1.3.1",
"ipnetwork 0.16.0",
+10 -4
View File
@@ -12,9 +12,15 @@ license.workspace = true
[dependencies]
axum.workspace = true
bytes = { workspace = true }
mime = { workspace = true }
bytes.workspace = true
colored.workspace = true
futures.workspace = true
mime.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
serde_yaml = { workspace = true }
utoipa = { workspace = true }
serde_yaml.workspace = true
tokio.workspace = true
tower.workspace = true
tracing.workspace = true
utoipa.workspace = true
zeroize.workspace = true
+2
View File
@@ -8,6 +8,8 @@ use bytes::{BufMut, BytesMut};
use serde::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
pub mod middleware;
#[derive(Debug, Clone, ToSchema)]
pub enum FormattedResponse<T> {
Json(Json<T>),
@@ -0,0 +1,147 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use axum::http::{header, HeaderValue, StatusCode};
use axum::response::IntoResponse;
use axum::{extract::Request, response::Response};
use futures::future::BoxFuture;
use std::sync::Arc;
use std::task::{Context, Poll};
use tower::{Layer, Service};
use tracing::{debug, instrument, trace};
use zeroize::Zeroizing;
#[derive(Debug, Clone)]
pub struct BearerAuthLayer {
bearer_token: Arc<Zeroizing<String>>,
allow_empty: bool,
}
impl BearerAuthLayer {
pub fn new(bearer_token: Arc<Zeroizing<String>>) -> Self {
BearerAuthLayer {
bearer_token,
allow_empty: false,
}
}
pub fn new_raw(bearer_token: impl Into<String>) -> Self {
BearerAuthLayer::new(Arc::new(Zeroizing::new(bearer_token.into())))
}
#[must_use]
pub fn with_allow_empty(mut self, allow_empty: bool) -> Self {
self.allow_empty = allow_empty;
self
}
}
impl<S> Layer<S> for BearerAuthLayer {
type Service = RequireBearerAuth<S>;
fn layer(&self, inner: S) -> Self::Service {
RequireBearerAuth::new(inner, self.bearer_token.clone()).with_allow_empty(self.allow_empty)
}
}
#[derive(Debug, Clone)]
pub struct RequireBearerAuth<S> {
inner: S,
bearer_token: Arc<Zeroizing<String>>,
allow_empty: bool,
}
impl<S> RequireBearerAuth<S> {
pub fn new(inner: S, bearer_token: Arc<Zeroizing<String>>) -> Self {
RequireBearerAuth {
inner,
bearer_token,
allow_empty: false,
}
}
#[must_use]
pub fn with_allow_empty(mut self, allow_empty: bool) -> Self {
self.allow_empty = allow_empty;
self
}
fn check_auth_header(&self, header: Option<&HeaderValue>) -> Result<(), &'static str> {
let Some(token) = header else {
trace!("missing header");
return Err("`Authorization` header is missing");
};
let Ok(authorization) = token.to_str() else {
trace!("invalid header");
return Err("`Authorization` header contains invalid characters");
};
debug!("header value: '{authorization}'");
let split = authorization.split_once(' ');
let bearer_token = match split {
// Found proper bearer
Some(("Bearer", contents)) => contents,
// Found empty bearer;
_ if authorization == "Bearer" => "",
// Found nothing
_ => return Err("`Authorization` header must be a bearer token"),
};
debug!("parsed token: '{bearer_token}'");
if self.bearer_token.is_empty() && bearer_token.is_empty() {
return Ok(());
}
if bearer_token.is_empty() {
return Err("`Authorization` header must contain non-empty `Bearer` token");
}
if self.bearer_token.as_str() != bearer_token {
return Err("`Authorization` header does not contain the correct `Bearer` token");
}
Ok(())
}
}
impl<S> Service<Request> for RequireBearerAuth<S>
where
S: Service<Request, Response = Response> + Send + 'static,
S: Send + Sync + 'static,
S::Future: Send + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
#[inline]
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
#[instrument(skip_all, fields(uri = %req.uri()))]
fn call(&mut self, req: Request) -> Self::Future {
debug!("checking the auth");
if self.bearer_token.is_empty() && !self.allow_empty {
return Box::pin(async move {
Ok((
StatusCode::INTERNAL_SERVER_ERROR,
"no valid access token has been specified on the server",
)
.into_response())
});
}
let auth_header = req.headers().get(header::AUTHORIZATION);
match self.check_auth_header(auth_header) {
Ok(_authorised) => Box::pin(self.inner.call(req)),
Err(err) => {
Box::pin(async move { Ok((StatusCode::UNAUTHORIZED, err).into_response()) })
}
}
}
}
@@ -0,0 +1,4 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod bearer;
@@ -1,4 +1,4 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use axum::{
@@ -12,6 +12,7 @@ use axum::{
};
use colored::*;
use std::net::SocketAddr;
use tokio::time::Instant;
use tracing::info;
/// Simple logger for requests
@@ -29,7 +30,9 @@ pub async fn logger(
let host = header_map(req.headers().get(HOST), "Unknown Host".to_string());
let start = Instant::now();
let res = next.run(req).await;
let time_taken = start.elapsed();
let status = res.status();
let print_status = if status.is_client_error() || status.is_server_error() {
status.to_string().red()
@@ -39,7 +42,17 @@ pub async fn logger(
status.to_string().yellow()
};
info!(target: "incoming request", "[{addr} -> {host}] {method} '{uri}': {print_status} / agent: {agent}");
let taken = "time taken".bold();
let time_taken = match time_taken.as_millis() {
ms if ms > 500 => format!("{taken}: {}", format!("{ms}ms").red()),
ms if ms > 200 => format!("{taken}: {}", format!("{ms}ms").yellow()),
ms if ms > 50 => format!("{taken}: {}", format!("{ms}ms").bright_yellow()),
ms => format!("{taken}: {ms}ms"),
};
let agent_str = "agent".bold();
info!("[{addr} -> {host}] {method} '{uri}': {print_status} {time_taken} {agent_str}: {agent}");
res
}
@@ -0,0 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod auth;
pub mod logging;
pub use auth::bearer::{BearerAuthLayer, RequireBearerAuth};
pub use logging::logger;
+12 -7
View File
@@ -32,8 +32,6 @@ pin-project = { workspace = true }
rand = "0.8.5"
rand-07 = { package = "rand", version = "0.7.3" } # required for compatibility
reqwest = { workspace = true, features = ["json"] }
rocket = { workspace = true, features = ["json"] }
rocket_cors = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tap = { workspace = true }
@@ -55,11 +53,21 @@ sqlx = { workspace = true, features = [
"migrate",
] }
okapi = { workspace = true, features = ["impl_json_schema"] }
rocket_okapi = { workspace = true, features = ["swagger"] }
schemars = { workspace = true, features = ["preserve_order"] }
zeroize = { workspace = true }
rocket = { workspace = true, features = ["json"] }
rocket_cors = { workspace = true }
rocket_okapi = { workspace = true, features = ["swagger"] }
okapi = { workspace = true, features = ["impl_json_schema"] }
axum.workspace = true
http.workspace = true
tower-http = { workspace = true, features = ["cors"] }
utoipa = { workspace = true, features = ["axum_extras", "time"] }
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
nym-http-api-common = { path = "../common/http-api-common" }
## ephemera-specific
#actix-web = "4"
#array-bytes = "6.0.0"
@@ -68,12 +76,9 @@ zeroize = { workspace = true }
#serde_derive = "1.0.149"
#uuid = { version = "1.3.0", features = ["serde", "v4"] }
## internal
#ephemera = { path = "../ephemera" }
nym-bandwidth-controller = { path = "../common/bandwidth-controller" }
nym-coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
nym-coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg" }
#nym-ephemera-common = { path = "../common/cosmwasm-smart-contracts/ephemera" }
nym-config = { path = "../common/config" }
cosmwasm-std = { workspace = true }
nym-credential-storage = { path = "../common/credential-storage" }
+138
View File
@@ -34,3 +34,141 @@ impl<T> From<T> for Deprecated<T> {
}
}
}
macro_rules! absolute_route {
( $name:ident, $parent:expr, $suffix:expr ) => {
pub fn $name() -> String {
format!("{}{}", $parent, $suffix)
}
};
}
pub mod routes {
pub const V1: &str = "/v1";
pub mod v1 {
use super::*;
pub const CIRCULATING_SUPPLY: &str = "/circulating-supply";
pub const MIXNODES: &str = "/mixnodes";
pub const GATEWAYS: &str = "/gateways";
pub const STATUS: &str = "/status";
pub const EPOCH: &str = "/epoch";
pub const NETWORK: &str = "/network";
pub const API_STATUS: &str = "/api-status";
pub mod circulating_supply {
use super::*;
pub const TOTAL_SUPPLY_VALUE: &str = "/total-supply-value";
pub const CIRCULATING_SUPPLY_VALUE: &str = "/circulating-supply-value";
}
pub mod mixnodes {
use super::*;
pub const DETAILED: &str = "/detailed";
pub const ACTIVE: &str = "/active";
pub const REWARDED: &str = "/rewarded";
pub const BLACKLISTED: &str = "/blacklisted";
pub mod active {
pub const DETAILED: &str = "/detailed";
}
pub mod rewarded {
pub const DETAILED: &str = "/detailed";
}
}
pub mod gateways {
use super::*;
pub const DETAILED: &str = "/detailed";
pub const BLACKLISTED: &str = "/blacklisted";
pub const DESCRIBED: &str = "/described";
}
pub mod epoch {
use super::*;
pub const REWARD_PARAMS: &str = "reward_params";
pub const CURRENT: &str = "current";
}
pub mod status {
use super::*;
pub const GATEWAY: &str = "/gateway";
pub const MIXNODE: &str = "/mixnode";
pub const MIXNODES: &str = "/mixnode";
pub const GATEWAYS: &str = "/gateways";
pub const UNSTABLE: &str = "/unstable";
pub mod gateway {
pub const REPORT: &str = "/report";
pub const HISTORY: &str = "/history";
pub const CORE_STATUS_COUNT: &str = "/core-status-count";
pub const AVG_UPTIME: &str = "/avg_uptime";
}
pub mod mixnode {
pub const REPORT: &str = "/report";
pub const HISTORY: &str = "/history";
pub const CORE_STATUS_COUNT: &str = "/core-status-count";
pub const STATUS: &str = "/status";
pub const REWARD_ESTIMATION: &str = "/reward-estimation";
pub const COMPUTE_REWARD_ESTIMATION: &str = "/compute-reward-estimation";
pub const STAKE_SATURATION: &str = "/stake-saturation";
pub const INCLUSION_PROBABILITY: &str = "/inclusion-probability";
pub const AVG_UPTIME: &str = "/avg_uptime";
}
pub mod mixnodes {
pub const INCLUSION_PROBABILITY: &str = "/inclusion-probability";
pub const DETAILED: &str = "/detailed";
pub const DETAILED_UNFILTERED: &str = "/detailed-unfiltered";
pub const ACTIVE: &str = "/active";
pub const REWARDED: &str = "/rewarded";
pub mod rewarded {
pub const DETAILED: &str = "/detailed";
}
pub mod active {
pub const DETAILED: &str = "/detailed";
}
}
pub mod gateways {
pub const DETAILED: &str = "/detailed";
pub const DETAILED_UNFILTERED: &str = "/detailed-unfiltered";
}
pub mod unstable {
pub mod by_mix_id {
pub const TEST_RESULTS: &str = "/test-results";
}
pub mod by_gateway_identity {
pub const TEST_RESULTS: &str = "/test-results";
}
}
}
pub mod network {
use super::*;
pub const DETAILS: &str = "/details";
pub const NYM_CONTRACTS: &str = "/nym-contracts";
pub const NYM_CONTRACTS_DETAILED: &str = "/nym-contracts-detailed";
}
pub mod api_status {
use super::*;
pub const HEALTH: &str = "/health";
pub const BUILD_INFORMATION: &str = "/build-information";
pub const SIGNER_INFORMATION: &str = "/signer-information";
}
}
}
+1
View File
@@ -3,6 +3,7 @@
use self::data::CirculatingSupplyCacheData;
use cosmwasm_std::Addr;
use log::error;
use nym_api_requests::models::CirculatingSupplyResponse;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::nyxd::Coin;
+1
View File
@@ -4,6 +4,7 @@
use super::CirculatingSupplyCache;
use crate::circulating_supply_api::cache::CirculatingSupplyCacheError;
use crate::support::nyxd::Client;
use log::{error, trace};
use nym_contracts_common::truncate_decimal;
use nym_task::TaskClient;
use nym_validator_client::nyxd::Coin;
+1 -1
View File
@@ -7,7 +7,7 @@ use nym_api_requests::models::CirculatingSupplyResponse;
use nym_validator_client::nyxd::Coin;
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, State};
use rocket_okapi::openapi;
// TODO: this is not the best place to put it, it should be more centralised,
+7 -8
View File
@@ -1,15 +1,8 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::ops::Deref;
use k256::ecdsa::signature::Verifier;
use rand::rngs::OsRng;
use rand::RngCore;
use rocket::serde::json::Json;
use rocket::State as RocketState;
use time::OffsetDateTime;
use log::{debug, error, trace};
use nym_api_requests::coconut::models::{
CredentialsRequestBody, EpochCredentialsResponse, FreePassNonceResponse, FreePassRequest,
IssuedCredentialResponse, IssuedCredentialsResponse,
@@ -26,6 +19,12 @@ use nym_credentials::coconut::bandwidth::{
bandwidth_credential_params, CredentialType, IssuanceBandwidthCredential,
};
use nym_validator_client::nyxd::Coin;
use rand::rngs::OsRng;
use rand::RngCore;
use rocket::serde::json::Json;
use rocket::{get, post, State as RocketState};
use std::ops::Deref;
use time::OffsetDateTime;
use crate::coconut::api_routes::helpers::build_credentials_response;
use crate::coconut::error::{CoconutError, Result};
+1
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::coconut::error::Result;
use async_trait::async_trait;
use cw3::{ProposalResponse, VoteResponse};
use cw4::MemberResponse;
use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
+1
View File
@@ -4,6 +4,7 @@
use crate::coconut::error::Result;
use crate::nyxd;
use crate::support::nyxd::ClientInner;
use async_trait::async_trait;
use nym_coconut::VerificationKey;
use nym_coconut_dkg_common::types::{Epoch, EpochId};
use nym_credentials::coconut::utils::obtain_aggregate_verification_key;
@@ -5,6 +5,7 @@ use crate::coconut::client::Client;
use crate::coconut::keys::KeyPairWithEpoch;
use crate::support::{config, nyxd};
use anyhow::{anyhow, bail, Context};
use log::warn;
use nym_coconut_dkg_common::types::{EpochId, EpochState};
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
use rand::{CryptoRng, RngCore};
@@ -8,6 +8,7 @@ use crate::coconut::keys::KeyPair as CoconutKeyPair;
use crate::nyxd;
use crate::support::config;
use anyhow::{bail, Result};
use log::{debug, error, info, trace, warn};
use nym_coconut_dkg_common::types::{Epoch, EpochId, EpochState};
use nym_crypto::asymmetric::identity;
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::coconut::dkg::controller::keys::archive_coconut_keypair;
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::error::CoconutError;
use crate::coconut::keys::KeyPairWithEpoch;
use log::debug;
use log::{debug, error, info, warn};
use nym_coconut_dkg_common::dealing::{chunk_dealing, DealingChunkInfo, MAX_DEALING_CHUNK_SIZE};
use nym_coconut_dkg_common::types::{DealingIndex, EpochId};
use nym_dkg::{Dealing, Scalar};
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::coconut::error::CoconutError;
use crate::coconut::keys::KeyPairWithEpoch;
use crate::coconut::state::bandwidth_credential_params;
use cosmwasm_std::Addr;
use log::debug;
use log::{debug, error, info, warn};
use nym_coconut::KeyPair as CoconutKeyPair;
use nym_coconut::{check_vk_pairing, Base58, SecretKey, VerificationKey};
use nym_coconut_dkg_common::event_attributes::DKG_PROPOSAL_ID;
@@ -4,6 +4,7 @@
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::error::CoconutError;
use cw3::Status;
use log::{debug, error, info, warn};
use nym_coconut_dkg_common::types::EpochId;
use rand::{CryptoRng, RngCore};
use thiserror::Error;
@@ -6,6 +6,7 @@ use crate::coconut::error::CoconutError;
use crate::coconut::state::bandwidth_credential_params;
use cosmwasm_std::Addr;
use cw3::Vote;
use log::{debug, error, info, warn};
use nym_coconut::{check_vk_pairing, Base58, VerificationKey};
use nym_coconut_dkg_common::types::EpochId;
use nym_coconut_dkg_common::verification_key::ContractVKShare;
+1 -1
View File
@@ -3,7 +3,7 @@
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::error::CoconutError;
use log::debug;
use log::{debug, info};
use nym_coconut_dkg_common::types::EpochId;
use rand::{CryptoRng, RngCore};
use thiserror::Error;
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::coconut::dkg::state::registration::{
use crate::coconut::error::CoconutError;
use crate::coconut::keys::{KeyPair as CoconutKeyPair, KeyPairWithEpoch};
use cosmwasm_std::Addr;
use log::debug;
use log::{debug, warn};
use nym_coconut_dkg_common::dealer::DealerDetails;
use nym_coconut_dkg_common::types::EpochId;
use nym_crypto::asymmetric::identity;
+1
View File
@@ -10,6 +10,7 @@ use nym_config::defaults::NYM_API_VERSION;
use nym_crypto::asymmetric::identity;
use nym_validator_client::nym_api::routes::{BANDWIDTH, COCONUT_ROUTES};
use rocket::fairing::AdHoc;
use rocket::routes;
pub(crate) mod api_routes;
pub(crate) mod client;
+1
View File
@@ -8,6 +8,7 @@ use crate::coconut::error::{CoconutError, Result};
use crate::coconut::keys::KeyPair;
use crate::coconut::storage::CoconutStorageExt;
use crate::support::storage::NymApiStorage;
use log::{debug, warn};
use nym_api_requests::coconut::helpers::issued_credential_plaintext;
use nym_api_requests::coconut::BlindSignRequestBody;
use nym_coconut::{BlindedSignature, VerificationKey};
+1
View File
@@ -3,6 +3,7 @@
use crate::coconut::storage::models::{EpochCredentials, IssuedCredential};
use crate::support::storage::manager::StorageManager;
use async_trait::async_trait;
use nym_coconut_dkg_common::types::EpochId;
use thiserror::Error;
+1
View File
@@ -5,6 +5,7 @@ use crate::coconut::storage::manager::CoconutStorageManagerExt;
use crate::coconut::storage::models::{join_attributes, EpochCredentials, IssuedCredential};
use crate::node_status_api::models::NymApiStorageError;
use crate::support::storage::NymApiStorage;
use async_trait::async_trait;
use nym_api_requests::coconut::models::Pagination;
use nym_coconut::{Base58, BlindedSignature};
use nym_coconut_dkg_common::types::EpochId;
@@ -3,6 +3,7 @@
use crate::epoch_operations::error::RewardingError;
use crate::RewardedSetUpdater;
use log::{error, warn};
use nym_mixnet_contract_common::EpochState;
use std::cmp::max;
+1
View File
@@ -18,6 +18,7 @@ use crate::support::nyxd::Client;
use crate::support::storage::NymApiStorage;
use error::RewardingError;
pub(crate) use helpers::MixnodeWithPerformance;
use log::{error, info, trace, warn};
use nym_mixnet_contract_common::{CurrentIntervalResponse, Interval};
use nym_task::{TaskClient, TaskManager};
use std::collections::HashSet;
@@ -5,6 +5,7 @@ use crate::epoch_operations::error::RewardingError;
use crate::epoch_operations::helpers::stake_to_f64;
use crate::RewardedSetUpdater;
use cosmwasm_std::Decimal;
use log::{debug, error, warn};
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::reward_params::Performance;
use nym_mixnet_contract_common::{
@@ -4,6 +4,7 @@
use crate::epoch_operations::error::RewardingError;
use crate::epoch_operations::helpers::MixnodeWithPerformance;
use crate::RewardedSetUpdater;
use log::{error, warn};
use nym_mixnet_contract_common::{EpochState, Interval, MixId};
impl RewardedSetUpdater {
@@ -3,6 +3,7 @@
use crate::epoch_operations::error::RewardingError;
use crate::epoch_operations::RewardedSetUpdater;
use log::{error, info};
impl RewardedSetUpdater {
// returns boolean indicating whether we should bother continuing
+2 -4
View File
@@ -1,9 +1,6 @@
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
#[macro_use]
extern crate rocket;
use crate::coconut::dkg::controller::keys::{
can_validate_coconut_keys, load_bte_keypair, load_coconut_keypair_if_exists,
};
@@ -20,6 +17,7 @@ use ::nym_config::defaults::setup_env;
use circulating_supply_api::cache::CirculatingSupplyCache;
use clap::Parser;
use coconut::dkg::controller::DkgController;
use log::{info, trace};
use node_status_api::NodeStatusCache;
use nym_bin_common::logging::setup_logging;
use nym_config::defaults::NymNetworkDetails;
@@ -86,7 +84,7 @@ async fn start_nym_api_tasks(config: Config) -> anyhow::Result<ShutdownHandles>
let identity_public_key = *identity_keypair.public_key();
// let's build our rocket!
let rocket = http::setup_rocket(
let rocket = http::old_setup_rest_api(
&config,
network_details,
nyxd_client.clone(),
+1 -1
View File
@@ -5,7 +5,7 @@ use crate::network::models::{ContractInformation, NetworkDetails};
use crate::nym_contract_cache::cache::NymContractCache;
use nym_contracts_common::ContractBuildInformation;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, State};
use rocket_okapi::openapi;
use std::collections::HashMap;
use std::ops::Deref;
+1
View File
@@ -15,6 +15,7 @@ use crate::nym_contract_cache::cache::NymContractCache;
use crate::storage::NymApiStorage;
use crate::support::{config, nyxd};
use futures::channel::mpsc;
use log::info;
use nym_bandwidth_controller::BandwidthController;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_crypto::asymmetric::{encryption, identity};
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::network_monitor::test_packet::NodeTestMessage;
use crate::network_monitor::test_route::TestRoute;
use crate::storage::NymApiStorage;
use crate::support::config;
use log::{debug, error, info};
use log::{debug, error, info, trace};
use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::MessageReceiver;
use nym_task::TaskClient;
@@ -4,7 +4,7 @@
use crate::network_monitor::monitor::sender::GatewayPackets;
use crate::network_monitor::test_route::TestRoute;
use crate::nym_contract_cache::cache::NymContractCache;
use log::info;
use log::{error, info, trace};
use nym_crypto::asymmetric::{encryption, identity};
use nym_mixnet_contract_common::{GatewayBond, Layer, MixNodeBond};
use nym_node_tester_utils::node::TestableNode;
@@ -7,7 +7,7 @@ use crate::network_monitor::ROUTE_TESTING_TEST_NONCE;
use futures::channel::mpsc;
use futures::lock::{Mutex, MutexGuard};
use futures::{SinkExt, StreamExt};
use log::warn;
use log::{debug, error, trace, warn};
use nym_crypto::asymmetric::encryption;
use nym_node_tester_utils::error::NetworkTestingError;
use nym_node_tester_utils::processor::TestPacketProcessor;
@@ -5,6 +5,7 @@ use crate::network_monitor::gateways_reader::{GatewayMessages, GatewaysReader};
use crate::network_monitor::monitor::processor::ReceivedProcessorSender;
use futures::channel::mpsc;
use futures::StreamExt;
use log::trace;
use nym_crypto::asymmetric::identity;
use nym_gateway_client::{AcknowledgementReceiver, MixnetMessageReceiver};
use nym_task::TaskClient;
+2
View File
@@ -6,7 +6,9 @@ use crate::support::caching::cache::{SharedCache, UninitialisedCache};
use crate::support::caching::refresher::{CacheItemProvider, CacheRefresher};
use crate::support::config;
use crate::support::config::DEFAULT_NODE_DESCRIBE_BATCH_SIZE;
use async_trait::async_trait;
use futures::{stream, StreamExt};
use log::debug;
use nym_api_requests::models::{
IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription,
};
@@ -1,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use log::error;
use nym_api_requests::models::InclusionProbability;
use nym_contracts_common::truncate_decimal;
use nym_mixnet_contract_common::{MixId, MixNodeDetails, RewardingParams};
+1
View File
@@ -4,6 +4,7 @@
use self::data::NodeStatusCacheData;
use self::inclusion_probabilities::InclusionProbabilities;
use crate::support::caching::Cache;
use log::error;
use nym_api_requests::models::{GatewayBondAnnotated, MixNodeBondAnnotated, MixnodeStatus};
use nym_contracts_common::{IdentityKey, IdentityKeyRef};
use nym_mixnet_contract_common::MixId;
+1
View File
@@ -15,6 +15,7 @@ use crate::{
storage::NymApiStorage,
support::caching::CacheNotification,
};
use log::error;
use nym_task::TaskClient;
use std::time::Duration;
use tokio::sync::watch;
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use log::warn;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
use rocket::Request;
+1
View File
@@ -3,6 +3,7 @@
use crate::node_status_api::utils::NodeUptimes;
use crate::storage::models::NodeStatus;
use log::error;
use nym_api_requests::models::{
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, HistoricalUptimeResponse,
MixnodeStatusReportResponse, MixnodeUptimeHistoryResponse, NodePerformance, RequestError,
+3 -2
View File
@@ -11,7 +11,7 @@ use nym_api_requests::models::{
};
use nym_mixnet_contract_common::MixId;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, post, State};
use rocket_okapi::openapi;
use super::helpers::_get_gateways_detailed;
@@ -233,6 +233,7 @@ pub mod unstable {
use crate::node_status_api::models::ErrorResponse;
use crate::support::http::helpers::PaginationRequest;
use crate::support::storage::NymApiStorage;
use log::{error, trace};
use nym_api_requests::models::{
GatewayTestResultResponse, MixnodeTestResultResponse, PartialTestResult, TestNode,
TestRoute,
@@ -241,7 +242,7 @@ pub mod unstable {
use nym_mixnet_contract_common::MixId;
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, State};
use rocket_okapi::openapi;
use std::cmp::min;
use std::collections::HashMap;
@@ -6,7 +6,7 @@ use crate::node_status_api::models::{
};
use crate::node_status_api::ONE_DAY;
use crate::storage::NymApiStorage;
use log::error;
use log::{error, info, trace, warn};
use nym_task::{TaskClient, TaskManager};
use std::time::Duration;
use time::{OffsetDateTime, PrimitiveDateTime, Time};
+1
View File
@@ -4,6 +4,7 @@
use crate::nym_contract_cache::cache::data::CachedContractsInfo;
use crate::support::caching::Cache;
use data::ValidatorCacheData;
use log::{debug, error};
use nym_api_requests::models::MixnodeStatus;
use nym_mixnet_contract_common::{
families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeBond, MixNodeDetails,
+1
View File
@@ -7,6 +7,7 @@ use crate::nyxd::Client;
use crate::support::caching::CacheNotification;
use anyhow::Result;
use futures::future::join_all;
use log::{error, info, trace, warn};
use nym_mixnet_contract_common::{MixId, MixNodeDetails, RewardedSetNodeStatus};
use nym_task::TaskClient;
use nym_validator_client::nyxd::contract_traits::{
+1 -1
View File
@@ -15,7 +15,7 @@ use nym_mixnet_contract_common::{
use nym_name_service_common::response::NamesListResponse;
use nym_service_provider_directory_common::response::ServicesListResponse;
use rocket::{serde::json::Json, State};
use rocket::{get, serde::json::Json, State};
use rocket_okapi::openapi;
use std::collections::HashSet;
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::nym_contract_cache::cache::NymContractCache;
use crate::support::caching::cache::SharedCache;
use nym_api_requests::models::DescribedGateway;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, State};
use rocket_okapi::openapi;
use std::ops::Deref;
+1 -1
View File
@@ -8,7 +8,7 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned;
use nym_coconut::Base58;
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use rocket::{get, State};
use rocket_okapi::openapi;
#[openapi(tag = "Api Status")]
+2
View File
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::support::caching::cache::SharedCache;
use async_trait::async_trait;
use log::error;
use nym_task::TaskClient;
use std::time::Duration;
use tokio::time::interval;
+20
View File
@@ -7,6 +7,7 @@ use crate::support::config::persistence::{
use crate::support::config::r#override::OverrideConfig;
use crate::support::config::template::CONFIG_TEMPLATE;
use anyhow::bail;
use log::debug;
use nym_config::defaults::mainnet::read_parsed_var_if_not_default;
use nym_config::defaults::var_names::{CONFIGURED, NYXD};
use nym_config::serde_helpers::de_maybe_stringified;
@@ -16,6 +17,7 @@ use nym_config::{
};
use serde::{Deserialize, Serialize};
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::{Path, PathBuf};
use std::time::Duration;
use url::Url;
@@ -225,6 +227,17 @@ impl Config {
}
}
fn default_http_socket_addr() -> SocketAddr {
// replicate rocket behaviour
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080)
} else {
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)
}
}
}
// we only really care about the mnemonic being zeroized
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Zeroize, ZeroizeOnDrop)]
pub struct Base {
@@ -234,6 +247,12 @@ pub struct Base {
#[zeroize(skip)]
pub local_validator: Url,
/// Socket address this api will use for binding its http API.
/// default: `0.0.0.0:8080`
#[zeroize(skip)]
#[serde(default = "default_http_socket_addr")]
pub bind_address: SocketAddr,
/// Mnemonic used for rewarding and/or multisig operations
// TODO: similarly to the note in gateway, this should get moved to a separate file
#[serde(deserialize_with = "de_maybe_stringified")]
@@ -256,6 +275,7 @@ impl Base {
storage_paths: NymApiPaths::new_default(&id),
id,
local_validator: default_validator,
bind_address: default_http_socket_addr(),
mnemonic: None,
}
}
+4
View File
@@ -15,6 +15,10 @@ id = '{{ base.id }}'
# Validator server to which the API will be getting information about the network.
local_validator = '{{ base.local_validator }}'
# Socket address this api will use for binding its http API.
# default: `0.0.0.0:8080`
bind_address = '{{ base.bind_address }}'
# Mnemonic used for rewarding and validator interaction
mnemonic = '{{ base.mnemonic }}'
+1
View File
@@ -1,6 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use rocket::FromForm;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+41 -6
View File
@@ -13,21 +13,48 @@ use crate::nym_contract_cache::cache::NymContractCache;
use crate::status::{api_status_routes, ApiStatusState, SignerState};
use crate::support::caching::cache::SharedCache;
use crate::support::config::Config;
use crate::support::http::router::NymApiRouter;
use crate::support::{nyxd, storage};
use crate::{circulating_supply_api, nym_contract_cache, nym_nodes::nym_node_routes};
use anyhow::{bail, Result};
use anyhow::{bail, Context, Result};
use axum::Router;
use http::{header, Method, Request, Response};
use nym_crypto::asymmetric::identity;
use nym_validator_client::nyxd::Coin;
use rocket::http::Method;
use rocket::{Ignite, Rocket};
use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors};
use rocket_okapi::mount_endpoints_and_merged_docs;
use rocket_okapi::swagger_ui::make_swagger_ui;
use std::net::SocketAddr;
use tower_http::cors::{Any, CorsLayer};
pub(crate) mod helpers;
pub(crate) mod openapi;
pub(crate) mod router;
pub(crate) mod state;
pub(crate) async fn setup_rocket(
pub(crate) async fn setup_rest_api(
config: &Config,
network_details: NetworkDetails,
nyxd_client: nyxd::Client,
identity_keypair: identity::KeyPair,
coconut_keypair: coconut::keys::KeyPair,
) -> anyhow::Result<()> {
let bind_address = config.base.bind_address;
// TODO: we might want to bind on both ipv4 and ipv6:
// https://github.com/tokio-rs/axum/blob/main/examples/listen-multiple-addrs/src/main.rs
let listener = tokio::net::TcpListener::bind(&bind_address)
.await
.context(format!("failed to bind http api to {bind_address}"))?;
let serve_future = axum::serve(
listener,
NymApiRouter::new().into_make_service_with_connect_info(),
);
unimplemented!()
}
pub(crate) async fn old_setup_rest_api(
config: &Config,
network_details: NetworkDetails,
nyxd_client: nyxd::Client,
@@ -56,7 +83,7 @@ pub(crate) async fn setup_rocket(
.manage(network_details)
.manage(SharedCache::<DescribedNodes>::new())
.mount("/swagger", make_swagger_ui(&openapi::get_docs()))
.attach(setup_cors()?)
.attach(old_setup_cors()?)
.attach(NymContractCache::stage())
.attach(NodeStatusCache::stage())
.attach(CirculatingSupplyCache::stage(mix_denom.clone()))
@@ -121,13 +148,13 @@ pub(crate) async fn setup_rocket(
Ok(rocket.manage(status_state).ignite().await?)
}
fn setup_cors() -> Result<Cors> {
fn old_setup_cors() -> Result<Cors> {
let allowed_origins = AllowedOrigins::all();
// You can also deserialize this
let cors = rocket_cors::CorsOptions {
allowed_origins,
allowed_methods: vec![Method::Post, Method::Get]
allowed_methods: vec![rocket::http::Method::Post, rocket::http::Method::Get]
.into_iter()
.map(From::from)
.collect(),
@@ -139,3 +166,11 @@ fn setup_cors() -> Result<Cors> {
Ok(cors)
}
fn setup_cors() -> CorsLayer {
CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST])
.allow_headers(Any)
.allow_credentials(true)
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
use axum::Router;
use nym_http_api_common::middleware::logger;
use std::net::SocketAddr;
pub mod v1;
pub struct NymApiRouter {
inner: Router,
}
impl NymApiRouter {
pub fn new() -> NymApiRouter {
// TODO: perhaps metrics:
// https://github.com/tokio-rs/axum/blob/main/examples/prometheus-metrics/src/main.rs
NymApiRouter {
inner: Router::new().layer(axum::middleware::from_fn(logger)),
}
}
pub fn into_make_service_with_connect_info(
self,
) -> IntoMakeServiceWithConnectInfo<Router, SocketAddr> {
self.inner.into_make_service_with_connect_info()
}
}
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub(crate) mod api_status;
pub(crate) mod circulating_supply;
pub(crate) mod epoch;
pub(crate) mod gateways;
pub(crate) mod mixnodes;
pub(crate) mod network;
pub(crate) mod status;
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
use crate::node_describe_cache::DescribedNodes;
use crate::node_status_api::NodeStatusCache;
use crate::nym_contract_cache::cache::NymContractCache;
use crate::support::caching::cache::SharedCache;
use crate::support::storage::NymApiStorage;
use axum::extract::FromRef;
#[derive(Clone)]
pub struct AppState {
pub contract_cache: NymContractCache,
pub status_cache: NodeStatusCache,
pub circulating_supply_cache: CirculatingSupplyCache,
pub storage: NymApiStorage,
pub describes_nodes_state: SharedCache<DescribedNodes>,
}
impl FromRef<AppState> for NymContractCache {
fn from_ref(app_state: &AppState) -> Self {
app_state.contract_cache.clone()
}
}
impl FromRef<AppState> for NodeStatusCache {
fn from_ref(app_state: &AppState) -> Self {
app_state.status_cache.clone()
}
}
impl FromRef<AppState> for CirculatingSupplyCache {
fn from_ref(app_state: &AppState) -> Self {
app_state.circulating_supply_cache.clone()
}
}
impl FromRef<AppState> for NymApiStorage {
fn from_ref(app_state: &AppState) -> Self {
app_state.storage.clone()
}
}
impl FromRef<AppState> for SharedCache<DescribedNodes> {
fn from_ref(app_state: &AppState) -> Self {
app_state.describes_nodes_state.clone()
}
}
+1
View File
@@ -13,6 +13,7 @@ use crate::storage::models::{NodeStatus, TestingRoute};
use crate::support::storage::models::{
GatewayDetails, MixnodeDetails, TestedGatewayStatus, TestedMixnodeStatus,
};
use log::{error, info, warn};
use nym_mixnet_contract_common::MixId;
use rocket::fairing::AdHoc;
use sqlx::ConnectOptions;
-2
View File
@@ -8,8 +8,6 @@ license.workspace = true
[dependencies]
axum.workspace = true
axum-extra = { workspace = true, features = ["typed-header"] }
headers.workspace = true
# useful for `#[axum_macros::debug_handler]`
#axum-macros = "0.3.8"
-1
View File
@@ -11,7 +11,6 @@ use std::net::SocketAddr;
use tracing::{debug, error};
pub mod error;
pub mod middleware;
pub mod router;
pub mod state;
@@ -1,4 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub mod logging;
-1
View File
@@ -9,7 +9,6 @@ use nym_task::TaskClient;
use std::net::SocketAddr;
use tracing::{debug, error, info};
pub mod middleware;
pub mod router;
pub mod state;
@@ -8,24 +8,30 @@ use crate::state::metrics::MetricsAppState;
use axum::extract::FromRef;
use axum::routing::get;
use axum::Router;
use nym_http_api_common::middleware::BearerAuthLayer;
use nym_node_requests::routes::api::v1::metrics;
pub mod mixing;
pub mod prometheus;
pub mod verloc;
#[derive(Debug, Clone, Default)]
#[derive(Debug, Default, Clone)]
pub struct Config {
//
pub prometheus_token: String,
}
pub(super) fn routes<S>(_config: Config) -> Router<S>
pub(super) fn routes<S>(config: Config) -> Router<S>
where
S: Send + Sync + 'static + Clone,
MetricsAppState: FromRef<S>,
{
let auth_middleware = BearerAuthLayer::new_raw(config.prometheus_token);
Router::new()
.route(metrics::MIXING, get(mixing_stats))
.route(metrics::VERLOC, get(verloc_stats))
.route(metrics::PROMETHEUS, get(prometheus_metrics))
.route(
metrics::PROMETHEUS,
get(prometheus_metrics).layer(auth_middleware),
)
}
@@ -1,12 +1,6 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::state::metrics::MetricsAppState;
use axum::extract::State;
use axum::http::StatusCode;
use axum_extra::TypedHeader;
use headers::authorization::Bearer;
use headers::Authorization;
use nym_metrics::metrics;
/// Returns `prometheus` compatible metrics
@@ -25,21 +19,6 @@ use nym_metrics::metrics;
("prometheus_token" = [])
)
)]
pub(crate) async fn prometheus_metrics<'a>(
TypedHeader(authorization): TypedHeader<Authorization<Bearer>>,
State(state): State<MetricsAppState>,
) -> Result<String, StatusCode> {
if authorization.token().is_empty() {
return Err(StatusCode::UNAUTHORIZED);
}
// TODO: is 500 the correct error code here?
let Some(metrics_key) = state.prometheus_access_token else {
return Err(StatusCode::INTERNAL_SERVER_ERROR);
};
if metrics_key != authorization.token() {
return Err(StatusCode::UNAUTHORIZED);
}
Ok(metrics!())
pub(crate) async fn prometheus_metrics() -> String {
metrics!()
}
+8 -2
View File
@@ -3,12 +3,12 @@
pub use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use crate::error::NymNodeHttpError;
use crate::middleware::logging;
use crate::state::AppState;
use crate::NymNodeHTTPServer;
use axum::response::Redirect;
use axum::routing::get;
use axum::Router;
use nym_http_api_common::middleware::logger;
use nym_node_requests::api::v1::gateway::models::{Gateway, Wireguard};
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
use nym_node_requests::api::v1::mixnode::models::Mixnode;
@@ -148,6 +148,12 @@ impl Config {
self.api.v1_config.ip_packet_router.details = Some(ip_packet_router);
self
}
#[must_use]
pub fn with_metrics_token(mut self, bearer_token: impl Into<Option<String>>) -> Self {
self.api.v1_config.metrics.prometheus_token = bearer_token.into().unwrap_or_default();
self
}
}
pub struct NymNodeRouter {
@@ -193,7 +199,7 @@ impl NymNodeRouter {
routes::API,
api::routes(config.api, initial_wg_state.unwrap_or_default()),
)
.layer(axum::middleware::from_fn(logging::logger))
.layer(axum::middleware::from_fn(logger))
.with_state(state),
}
}
@@ -134,8 +134,6 @@ impl VerlocStatsState {
#[derive(Debug, Clone, Default)]
pub struct MetricsAppState {
pub(crate) prometheus_access_token: Option<String>,
pub(crate) mixing_stats: SharedMixingStats,
pub(crate) verloc: SharedVerlocStats,
@@ -37,10 +37,4 @@ impl AppState {
self.metrics.verloc = verloc_stats;
self
}
#[must_use]
pub fn with_metrics_key(mut self, bearer_token: impl Into<Option<String>>) -> Self {
self.metrics.prometheus_access_token = bearer_token.into();
self
}
}
+1
View File
@@ -369,6 +369,7 @@ pub struct Http {
/// An optional bearer token for accessing certain http endpoints.
/// Currently only used for obtaining mixnode's stats.
#[serde(default)]
#[serde(deserialize_with = "de_maybe_stringified")]
pub access_token: Option<String>,
/// Specify whether basic system information should be exposed.
+3 -3
View File
@@ -540,7 +540,8 @@ impl NymNode {
.with_ip_packet_router_details(ipr_details)
.with_used_exit_policy(exit_policy_details)
.with_description(self.description.clone())
.with_auxiliary_details(auxiliary_details);
.with_auxiliary_details(auxiliary_details)
.with_metrics_token(self.config.http.access_token.clone());
if self.config.http.expose_system_info {
config = config.with_system_info(get_system_info(
@@ -560,8 +561,7 @@ impl NymNode {
let app_state = AppState::new()
.with_mixing_stats(self.mixnode.mixing_stats.clone())
.with_verloc_stats(self.verloc_stats.clone())
.with_metrics_key(self.config.http.access_token.clone());
.with_verloc_stats(self.verloc_stats.clone());
Ok(NymNodeRouter::new(config, Some(app_state), Some(wg_state))
.build_server(&self.config.http.bind_address)