initial host information endpoint
This commit is contained in:
@@ -145,8 +145,12 @@ impl PublicKey {
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
|
||||
self.0.verify(message, &signature.0)
|
||||
pub fn verify<M: AsRef<[u8]>>(
|
||||
&self,
|
||||
message: M,
|
||||
signature: &Signature,
|
||||
) -> Result<(), SignatureError> {
|
||||
self.0.verify(message.as_ref(), &signature.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,16 +243,16 @@ impl PrivateKey {
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn sign(&self, message: &[u8]) -> Signature {
|
||||
pub fn sign<M: AsRef<[u8]>>(&self, message: M) -> Signature {
|
||||
let expanded_secret_key = ed25519_dalek::ExpandedSecretKey::from(&self.0);
|
||||
let public_key: PublicKey = self.into();
|
||||
let sig = expanded_secret_key.sign(message, &public_key.0);
|
||||
let sig = expanded_secret_key.sign(message.as_ref(), &public_key.0);
|
||||
Signature(sig)
|
||||
}
|
||||
|
||||
/// Signs text with the provided Ed25519 private key, returning a base58 signature
|
||||
pub fn sign_text(&self, text: &str) -> String {
|
||||
let signature_bytes = self.sign(text.as_ref()).to_bytes();
|
||||
let signature_bytes = self.sign(text).to_bytes();
|
||||
bs58::encode(signature_bytes).into_string()
|
||||
}
|
||||
}
|
||||
|
||||
+18
-6
@@ -11,8 +11,14 @@ use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_task::TaskClient;
|
||||
|
||||
fn load_gateway_details(
|
||||
config: &Config,
|
||||
_config: &Config,
|
||||
) -> Result<http::api::v1::gateway::types::Gateway, GatewayError> {
|
||||
Ok(http::api::v1::gateway::types::Gateway {})
|
||||
}
|
||||
|
||||
fn load_host_details(
|
||||
config: &Config,
|
||||
) -> Result<http::api::v1::node::types::HostInformation, GatewayError> {
|
||||
let identity_public_key: identity::PublicKey = load_public_key(
|
||||
&config.storage_paths.keys.public_identity_key_file,
|
||||
"gateway identity",
|
||||
@@ -23,9 +29,14 @@ fn load_gateway_details(
|
||||
"gateway sphinx",
|
||||
)?;
|
||||
|
||||
Ok(http::api::v1::gateway::types::Gateway {
|
||||
encoded_identity_key: identity_public_key.to_base58_string(),
|
||||
encoded_sphinx_key: sphinx_public_key.to_base58_string(),
|
||||
Ok(http::api::v1::node::types::HostInformation {
|
||||
// TODO: this should be extracted differently, i.e. it's the issue of the public/private address
|
||||
ip_address: vec![config.gateway.listening_address],
|
||||
hostname: None,
|
||||
keys: http::api::v1::node::types::HostKeys {
|
||||
ed25519: identity_public_key.to_base58_string(),
|
||||
x25519: sphinx_public_key.to_base58_string(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -80,8 +91,9 @@ pub(crate) fn start_http_api(
|
||||
// and makes the code a bit nicer to manage. on top of it, all of it will refactored anyway at some point
|
||||
// (famous last words, eh? - 22.09.23)
|
||||
|
||||
let mut config = nym_node::http::Config::new(bin_info_owned!())
|
||||
.with_gateway(load_gateway_details(gateway_config)?);
|
||||
let mut config =
|
||||
nym_node::http::Config::new(bin_info_owned!(), load_host_details(gateway_config)?)
|
||||
.with_gateway(load_gateway_details(gateway_config)?);
|
||||
|
||||
if let Some(nr_config) = network_requester_config {
|
||||
config = config
|
||||
|
||||
@@ -38,4 +38,5 @@ utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
|
||||
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["openapi"] }
|
||||
nym-crypto = { path = "../common/crypto", features = ["asymmetric"] }
|
||||
nym-task = { path = "../common/task" }
|
||||
|
||||
@@ -6,7 +6,9 @@ use axum::http::{header, HeaderValue, StatusCode};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::{Json, Router};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Deref;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
pub mod v1;
|
||||
@@ -32,6 +34,48 @@ pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
// data: T,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, ToSchema)]
|
||||
pub struct SignedResponse<T> {
|
||||
pub response: T,
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
impl<T> SignedResponse<T> {
|
||||
pub fn new(response: T, key: &identity::PrivateKey) -> serde_json::Result<Self>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let plaintext = serde_json::to_string(&response)?;
|
||||
let signature = key.sign(plaintext).to_base58_string();
|
||||
Ok(SignedResponse {
|
||||
response,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn verify(&self, key: &identity::PublicKey) -> bool
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let Ok(plaintext) = serde_json::to_string(&self.response) else {
|
||||
return false;
|
||||
};
|
||||
let Ok(signature) = identity::Signature::from_base58_string(&self.signature) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
key.verify(plaintext, &signature).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for SignedResponse<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.response
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ToSchema)]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
|
||||
@@ -6,10 +6,10 @@ use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, ToSchema)]
|
||||
pub struct Gateway {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the gateway used for deriving shared keys with clients
|
||||
/// and for signing any messages
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
pub encoded_sphinx_key: String,
|
||||
// /// Base58 encoded ed25519 EdDSA public key of the gateway used for deriving shared keys with clients
|
||||
// /// and for signing any messages
|
||||
// pub encoded_identity_key: String,
|
||||
//
|
||||
// /// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
// pub encoded_sphinx_key: String,
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, ToSchema)]
|
||||
pub struct Mixnode {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the mixnode.
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
pub encoded_sphinx_key: String,
|
||||
// /// Base58 encoded ed25519 EdDSA public key of the mixnode.
|
||||
// pub encoded_identity_key: String,
|
||||
//
|
||||
// /// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
// pub encoded_sphinx_key: String,
|
||||
}
|
||||
|
||||
@@ -1,2 +1,30 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::api::v1::node::types::HostInformation;
|
||||
use crate::http::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
|
||||
/// Returns host information of this node.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/host-information",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
("application/json" = HostInformation),
|
||||
("application/yaml" = HostInformation)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn host_information(
|
||||
host_information: HostInformation,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> HostInformationResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
output.to_response(host_information)
|
||||
}
|
||||
|
||||
pub type HostInformationResponse = FormattedResponse<HostInformation>;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::api::v1::node::build_information::build_information;
|
||||
use crate::http::api::v1::node::host_information::host_information;
|
||||
use crate::http::api::v1::node::roles::roles;
|
||||
use crate::http::api::v1::node::types::NodeRoles;
|
||||
use crate::http::api::v1::node::types::{HostInformation, NodeRoles};
|
||||
use crate::http::state::AppState;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
@@ -17,12 +18,13 @@ pub mod types;
|
||||
pub(crate) mod routes {
|
||||
pub(crate) const ROLES: &str = "/roles";
|
||||
pub(crate) const BUILD_INFO: &str = "/build-information";
|
||||
// pub(crate) const HOST_INFO: &str = "/host-information";
|
||||
pub(crate) const HOST_INFO: &str = "/host-information";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub build_information: BinaryBuildInformationOwned,
|
||||
pub host_information: HostInformation,
|
||||
pub roles: NodeRoles,
|
||||
}
|
||||
|
||||
@@ -42,4 +44,11 @@ pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
move |query| roles(node_roles, query)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
routes::HOST_INFO,
|
||||
get({
|
||||
let host_info = config.host_information;
|
||||
move |query| host_information(host_info, query)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
pub(crate) use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use serde::Serialize;
|
||||
use std::net::IpAddr;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Default, Debug, Copy, ToSchema, Serialize)]
|
||||
@@ -11,3 +12,25 @@ pub struct NodeRoles {
|
||||
pub gateway_enabled: bool,
|
||||
pub network_requester_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, ToSchema, Serialize)]
|
||||
pub struct HostInformation {
|
||||
/// Ip address(es) of this host, such as `1.1.1.1`.
|
||||
pub ip_address: Vec<IpAddr>,
|
||||
|
||||
/// Optional hostname of this node, for example `nymtech.net`.
|
||||
pub hostname: Option<String>,
|
||||
|
||||
/// Public keys associated with this node.
|
||||
pub keys: HostKeys,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, ToSchema, Serialize)]
|
||||
pub struct HostKeys {
|
||||
/// Base58-encoded ed25519 public key of this node. Currently it corresponds to either mixnode's or gateway's identity.
|
||||
pub ed25519: String,
|
||||
|
||||
/// Base58-encoded x25519 public key of this node used for sphinx/outfox packet creation.
|
||||
/// Currently it corresponds to either mixnode's or gateway's key.
|
||||
pub x25519: String,
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
info(title = "NymNode API"),
|
||||
paths(
|
||||
api::v1::node::build_information::build_information,
|
||||
api::v1::node::host_information::host_information,
|
||||
api::v1::node::roles::roles,
|
||||
api::v1::gateway::root::root_gateway,
|
||||
api::v1::mixnode::root::root_mixnode,
|
||||
@@ -21,13 +22,14 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api::Output,
|
||||
api::OutputParams,
|
||||
api::v1::node::types::BinaryBuildInformationOwned,
|
||||
api::v1::node::types::HostInformation,
|
||||
api::v1::node::types::HostKeys,
|
||||
api::v1::node::types::NodeRoles,
|
||||
api::v1::gateway::types::Gateway,
|
||||
api::v1::mixnode::types::Mixnode,
|
||||
api::v1::network_requester::types::NetworkRequester,
|
||||
))
|
||||
)]
|
||||
|
||||
pub(crate) struct ApiDoc;
|
||||
|
||||
pub(crate) fn route() -> Router<AppState> {
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::error::NymNodeError;
|
||||
use crate::http::api::v1::gateway::types::Gateway;
|
||||
use crate::http::api::v1::mixnode::types::Mixnode;
|
||||
use crate::http::api::v1::network_requester::types::NetworkRequester;
|
||||
use crate::http::api::v1::node::types::HostInformation;
|
||||
use crate::http::middleware::logging;
|
||||
use crate::http::state::AppState;
|
||||
use crate::http::NymNodeHTTPServer;
|
||||
@@ -31,14 +32,18 @@ pub struct Config {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(binary_info: BinaryBuildInformationOwned) -> Self {
|
||||
pub fn new(
|
||||
build_information: BinaryBuildInformationOwned,
|
||||
host_information: HostInformation,
|
||||
) -> Self {
|
||||
Config {
|
||||
landing: Default::default(),
|
||||
policy: Default::default(),
|
||||
api: api::Config {
|
||||
v1_config: api::v1::Config {
|
||||
node: api::v1::node::Config {
|
||||
build_information: binary_info,
|
||||
build_information,
|
||||
host_information,
|
||||
roles: Default::default(),
|
||||
},
|
||||
gateway: Default::default(),
|
||||
|
||||
Reference in New Issue
Block a user