From aa58c80db9ff0efae0163bf2af871ac6fa92237a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Fri, 16 May 2025 15:38:23 +0300 Subject: [PATCH] Add a cache for the credentials seen before on top-up --- service-providers/authenticator/src/lib.rs | 1 + .../authenticator/src/mixnet_listener.rs | 5 +- .../src/seen_credential_cache.rs | 58 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 service-providers/authenticator/src/seen_credential_cache.rs diff --git a/service-providers/authenticator/src/lib.rs b/service-providers/authenticator/src/lib.rs index ec7ca579f9..048f91f4f2 100644 --- a/service-providers/authenticator/src/lib.rs +++ b/service-providers/authenticator/src/lib.rs @@ -10,3 +10,4 @@ pub mod error; pub mod mixnet_client; pub mod mixnet_listener; mod peer_manager; +mod seen_credential_cache; diff --git a/service-providers/authenticator/src/mixnet_listener.rs b/service-providers/authenticator/src/mixnet_listener.rs index d88a1185c5..080b5e95ee 100644 --- a/service-providers/authenticator/src/mixnet_listener.rs +++ b/service-providers/authenticator/src/mixnet_listener.rs @@ -7,7 +7,7 @@ use std::{ time::{Duration, SystemTime}, }; -use crate::{config::Config, error::*}; +use crate::{config::Config, error::*, seen_credential_cache::SeenCredentialCache}; use crate::{error::AuthenticatorError, peer_manager::PeerManager}; use defguard_wireguard_rs::net::IpAddrMask; use defguard_wireguard_rs::{host::Peer, key::Key}; @@ -77,6 +77,8 @@ pub(crate) struct MixnetListener { pub(crate) ecash_verifier: Option>, pub(crate) timeout_check_interval: IntervalStream, + + pub(crate) seen_credential_cache: SeenCredentialCache, } impl MixnetListener { @@ -98,6 +100,7 @@ impl MixnetListener { peer_manager: PeerManager::new(wireguard_gateway_data), ecash_verifier, timeout_check_interval, + seen_credential_cache: SeenCredentialCache::new(), } } diff --git a/service-providers/authenticator/src/seen_credential_cache.rs b/service-providers/authenticator/src/seen_credential_cache.rs new file mode 100644 index 0000000000..f169942508 --- /dev/null +++ b/service-providers/authenticator/src/seen_credential_cache.rs @@ -0,0 +1,58 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + time::{Duration, SystemTime}, +}; + +use nym_credentials_interface::CredentialSpendingData; +use nym_wireguard_types::PeerPublicKey; + +const SEEN_CREDENTIAL_CACHE_TIME: Duration = Duration::from_secs(60 * 60); // 1 hour + +#[derive(Eq, Hash, PartialEq)] +struct TimestampedPeerPubKey { + peer_pub_key: PeerPublicKey, + timestamp: SystemTime, +} + +pub(crate) struct SeenCredentialCache { + cached_credentials: HashMap, +} + +impl SeenCredentialCache { + pub(crate) fn new() -> Self { + SeenCredentialCache { + cached_credentials: HashMap::new(), + } + } + + pub(crate) fn insert_credential( + &mut self, + credential: CredentialSpendingData, + peer_pub_key: PeerPublicKey, + ) { + let value = TimestampedPeerPubKey { + peer_pub_key, + timestamp: SystemTime::now(), + }; + self.cached_credentials + .insert(credential.serial_number_b58(), value); + } + + pub(crate) fn contains(&self, credential: &CredentialSpendingData) -> bool { + self.cached_credentials + .contains_key(&credential.serial_number_b58()) + } + + pub(crate) fn remove_stale(&mut self) { + let now = SystemTime::now(); + self.cached_credentials.retain(|_, value| { + let Ok(cache_time) = now.duration_since(value.timestamp) else { + return false; + }; + cache_time < SEEN_CREDENTIAL_CACHE_TIME + }); + } +}