207 lines
6.3 KiB
Rust
207 lines
6.3 KiB
Rust
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
use crate::config::NodeModes;
|
|
use crate::error::{KeyIOFailure, NymNodeError};
|
|
use crate::node::key_rotation::key::{SphinxPrivateKey, SphinxPublicKey};
|
|
use crate::node::nym_apis_client::NymApisClient;
|
|
use nym_crypto::asymmetric::{ed25519, x25519};
|
|
use nym_node_requests::api::v1::node::models::NodeDescription;
|
|
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
|
use nym_pemstore::KeyPairPath;
|
|
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
|
use nym_validator_client::QueryHttpRpcNyxdClient;
|
|
use serde::Serialize;
|
|
use std::fmt::{Display, Formatter};
|
|
use std::path::Path;
|
|
use tracing::warn;
|
|
use url::Url;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub(crate) struct DisplaySphinxKey {
|
|
public_key: String,
|
|
rotation_id: u32,
|
|
}
|
|
|
|
impl From<&SphinxPrivateKey> for DisplaySphinxKey {
|
|
fn from(value: &SphinxPrivateKey) -> Self {
|
|
let pubkey: SphinxPublicKey = value.into();
|
|
DisplaySphinxKey {
|
|
public_key: pubkey.inner.to_base58_string(),
|
|
rotation_id: pubkey.rotation_id,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for DisplaySphinxKey {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{} (rotation: {})", self.public_key, self.rotation_id)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub(crate) struct DisplayDetails {
|
|
pub(crate) current_modes: NodeModes,
|
|
|
|
pub(crate) description: NodeDescription,
|
|
|
|
pub(crate) ed25519_identity_key: String,
|
|
pub(crate) x25519_primary_sphinx_key: DisplaySphinxKey,
|
|
pub(crate) x25519_secondary_sphinx_key: Option<DisplaySphinxKey>,
|
|
pub(crate) x25519_noise_key: String,
|
|
pub(crate) x25519_wireguard_key: String,
|
|
|
|
pub(crate) exit_network_requester_address: String,
|
|
pub(crate) exit_ip_packet_router_address: String,
|
|
pub(crate) exit_authenticator_address: String,
|
|
}
|
|
|
|
impl Display for DisplayDetails {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
writeln!(f, "current mode: {:#?}", self.current_modes)?;
|
|
writeln!(f, "moniker: '{}'", self.description.moniker)?;
|
|
writeln!(f, "website: '{}'", self.description.website)?;
|
|
writeln!(
|
|
f,
|
|
"security contact: '{}'",
|
|
self.description.security_contact
|
|
)?;
|
|
writeln!(f, "details: '{}'", self.description.details)?;
|
|
writeln!(f, "ed25519 identity: {}", self.ed25519_identity_key)?;
|
|
writeln!(
|
|
f,
|
|
"x25519 primary sphinx: {}",
|
|
self.x25519_primary_sphinx_key
|
|
)?;
|
|
if let Some(secondary) = &self.x25519_secondary_sphinx_key {
|
|
writeln!(f, "x25519 primary sphinx: {secondary}")?;
|
|
}
|
|
writeln!(f, "x25519 noise: {}", self.x25519_noise_key)?;
|
|
writeln!(
|
|
f,
|
|
"exit network requester address: {}",
|
|
self.exit_network_requester_address
|
|
)?;
|
|
writeln!(
|
|
f,
|
|
"exit ip packet router address: {}",
|
|
self.exit_ip_packet_router_address
|
|
)?;
|
|
writeln!(
|
|
f,
|
|
"exit authenticator address: {}",
|
|
self.exit_authenticator_address
|
|
)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub(crate) fn load_keypair<T: PemStorableKeyPair>(
|
|
paths: &KeyPairPath,
|
|
name: impl Into<String>,
|
|
) -> Result<T, KeyIOFailure> {
|
|
nym_pemstore::load_keypair(paths).map_err(|err| KeyIOFailure::KeyPairLoadFailure {
|
|
keys: name.into(),
|
|
paths: paths.clone(),
|
|
err,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn store_keypair<T: PemStorableKeyPair>(
|
|
keys: &T,
|
|
paths: &KeyPairPath,
|
|
name: impl Into<String>,
|
|
) -> Result<(), KeyIOFailure> {
|
|
nym_pemstore::store_keypair(keys, paths).map_err(|err| KeyIOFailure::KeyPairStoreFailure {
|
|
keys: name.into(),
|
|
paths: paths.clone(),
|
|
err,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn load_key<T, P>(path: P, name: impl Into<String>) -> Result<T, KeyIOFailure>
|
|
where
|
|
T: PemStorableKey,
|
|
P: AsRef<Path>,
|
|
{
|
|
nym_pemstore::load_key(path.as_ref()).map_err(|err| KeyIOFailure::KeyLoadFailure {
|
|
key: name.into(),
|
|
path: path.as_ref().to_path_buf(),
|
|
err,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn store_key<T, P>(key: &T, path: P, name: impl Into<String>) -> Result<(), KeyIOFailure>
|
|
where
|
|
T: PemStorableKey,
|
|
P: AsRef<Path>,
|
|
{
|
|
nym_pemstore::store_key(key, path.as_ref()).map_err(|err| KeyIOFailure::KeyStoreFailure {
|
|
key: name.into(),
|
|
path: path.as_ref().to_path_buf(),
|
|
err,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn load_ed25519_identity_keypair(
|
|
paths: &KeyPairPath,
|
|
) -> Result<ed25519::KeyPair, NymNodeError> {
|
|
Ok(load_keypair(paths, "ed25519-identity")?)
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn load_ed25519_identity_public_key<P: AsRef<Path>>(
|
|
path: P,
|
|
) -> Result<ed25519::PublicKey, NymNodeError> {
|
|
Ok(load_key(path, "ed25519-identity-public-key")?)
|
|
}
|
|
|
|
pub(crate) fn load_x25519_noise_keypair(
|
|
paths: &KeyPairPath,
|
|
) -> Result<x25519::KeyPair, NymNodeError> {
|
|
Ok(load_keypair(paths, "x25519-noise")?)
|
|
}
|
|
|
|
pub(crate) fn load_x25519_wireguard_keypair(
|
|
paths: &KeyPairPath,
|
|
) -> Result<x25519::KeyPair, NymNodeError> {
|
|
Ok(load_keypair(paths, "x25519-wireguard")?)
|
|
}
|
|
|
|
pub(crate) fn store_ed25519_identity_keypair(
|
|
keys: &ed25519::KeyPair,
|
|
paths: &KeyPairPath,
|
|
) -> Result<(), NymNodeError> {
|
|
Ok(store_keypair(keys, paths, "ed25519-identity")?)
|
|
}
|
|
|
|
pub(crate) fn store_x25519_noise_keypair(
|
|
keys: &x25519::KeyPair,
|
|
paths: &KeyPairPath,
|
|
) -> Result<(), NymNodeError> {
|
|
Ok(store_keypair(keys, paths, "x25519-noise")?)
|
|
}
|
|
|
|
pub(crate) async fn get_current_rotation_id(
|
|
nym_apis: &[Url],
|
|
fallback_nyxd: &[Url],
|
|
) -> Result<u32, NymNodeError> {
|
|
let apis_client = NymApisClient::new(nym_apis)?;
|
|
if let Ok(rotation_info) = apis_client.get_key_rotation_info().await {
|
|
let current_epoch = rotation_info.current_epoch_id;
|
|
return Ok(rotation_info
|
|
.key_rotation_state
|
|
.key_rotation_id(current_epoch));
|
|
}
|
|
warn!("failed to retrieve key rotation id from nym apis. falling back to contract query");
|
|
|
|
for nyxd_url in fallback_nyxd {
|
|
let client = QueryHttpRpcNyxdClient::connect_to_default_env(nyxd_url.as_str())?;
|
|
if let Ok(res) = client.get_key_rotation_id().await {
|
|
return Ok(res.rotation_id);
|
|
}
|
|
}
|
|
|
|
Err(NymNodeError::NymApisExhausted)
|
|
}
|