11use std:: {
22 any:: Any ,
33 collections:: HashMap ,
4+ future:: Future ,
45 net:: SocketAddr ,
6+ path:: PathBuf ,
57 sync:: {
68 atomic:: { AtomicBool , AtomicU64 , Ordering } ,
79 Arc , Mutex , RwLock ,
@@ -14,7 +16,7 @@ use defguard_version::{
1416 server:: { grpc:: DefguardVersionInterceptor , DefguardVersionLayer } ,
1517 ComponentInfo , DefguardComponent , Version ,
1618} ;
17- use tokio:: sync:: { mpsc, oneshot} ;
19+ use tokio:: sync:: { broadcast , mpsc, oneshot} ;
1820use tokio_stream:: wrappers:: UnboundedReceiverStream ;
1921use tonic:: {
2022 transport:: { Identity , Server , ServerTlsConfig } ,
@@ -25,6 +27,7 @@ use tracing::Instrument;
2527
2628use crate :: {
2729 error:: ApiError ,
30+ http:: { GRPC_CERT_NAME , GRPC_KEY_NAME } ,
2831 proto:: { core_request, core_response, proxy_server, CoreRequest , CoreResponse , DeviceInfo } ,
2932 MIN_CORE_VERSION , VERSION ,
3033} ;
@@ -46,12 +49,18 @@ pub(crate) struct ProxyServer {
4649 pub ( crate ) core_version : Arc < Mutex < Option < Version > > > ,
4750 config : Arc < Mutex < Option < Configuration > > > ,
4851 cookie_key : Arc < RwLock < Option < Key > > > ,
52+ cert_dir : PathBuf ,
53+ reset_tx : broadcast:: Sender < ( ) > ,
4954}
5055
5156impl ProxyServer {
5257 #[ must_use]
5358 /// Create new `ProxyServer`.
54- pub ( crate ) fn new ( cookie_key : Arc < RwLock < Option < Key > > > ) -> Self {
59+ pub ( crate ) fn new (
60+ cookie_key : Arc < RwLock < Option < Key > > > ,
61+ cert_dir : PathBuf ,
62+ reset_tx : broadcast:: Sender < ( ) > ,
63+ ) -> Self {
5564 Self {
5665 cookie_key,
5766 current_id : Arc :: new ( AtomicU64 :: new ( 1 ) ) ,
@@ -60,6 +69,8 @@ impl ProxyServer {
6069 connected : Arc :: new ( AtomicBool :: new ( false ) ) ,
6170 core_version : Arc :: new ( Mutex :: new ( None ) ) ,
6271 config : Arc :: new ( Mutex :: new ( None ) ) ,
72+ cert_dir,
73+ reset_tx,
6374 }
6475 }
6576
@@ -79,7 +90,10 @@ impl ProxyServer {
7990 lock. clone ( )
8091 }
8192
82- pub ( crate ) async fn run ( self , addr : SocketAddr ) -> Result < ( ) , anyhow:: Error > {
93+ pub ( crate ) async fn run < F > ( self , addr : SocketAddr , shutdown : F ) -> Result < ( ) , anyhow:: Error >
94+ where
95+ F : Future < Output = ( ) > + Send + ' static ,
96+ {
8397 info ! ( "Starting gRPC server on {addr}" ) ;
8498 let config = self . get_configuration ( ) ;
8599 let ( grpc_cert, grpc_key) = if let Some ( cfg) = config {
@@ -107,7 +121,7 @@ impl ProxyServer {
107121
108122 builder
109123 . add_service ( versioned_service)
110- . serve ( addr)
124+ . serve_with_shutdown ( addr, shutdown )
111125 . await
112126 . map_err ( |err| {
113127 error ! ( "gRPC server error: {err}" ) ;
@@ -176,6 +190,8 @@ impl Clone for ProxyServer {
176190 core_version : Arc :: clone ( & self . core_version ) ,
177191 cookie_key : Arc :: clone ( & self . cookie_key ) ,
178192 config : Arc :: clone ( & self . config ) ,
193+ cert_dir : self . cert_dir . clone ( ) ,
194+ reset_tx : self . reset_tx . clone ( ) ,
179195 }
180196 }
181197}
@@ -272,4 +288,50 @@ impl proxy_server::Proxy for ProxyServer {
272288
273289 Ok ( Response :: new ( UnboundedReceiverStream :: new ( rx) ) )
274290 }
291+
292+ #[ instrument( skip( self , _request) ) ]
293+ async fn purge ( & self , _request : Request < ( ) > ) -> Result < Response < ( ) > , Status > {
294+ debug ! ( "Received purge request, removing gRPC certificate files" ) ;
295+ let cert_path = self . cert_dir . join ( GRPC_CERT_NAME ) ;
296+ let key_path = self . cert_dir . join ( GRPC_KEY_NAME ) ;
297+
298+ if let Err ( err) = tokio:: fs:: remove_file ( & cert_path) . await {
299+ if err. kind ( ) != std:: io:: ErrorKind :: NotFound {
300+ error ! (
301+ "Failed to remove gRPC certificate at {:?}: {err}" ,
302+ cert_path
303+ ) ;
304+ return Err ( Status :: internal ( "Failed to remove gRPC certificate" ) ) ;
305+ }
306+ }
307+
308+ if let Err ( err) = tokio:: fs:: remove_file ( & key_path) . await {
309+ if err. kind ( ) != std:: io:: ErrorKind :: NotFound {
310+ error ! ( "Failed to remove gRPC key at {:?}: {err}" , key_path) ;
311+ return Err ( Status :: internal ( "Failed to remove gRPC key" ) ) ;
312+ }
313+ }
314+
315+ * self
316+ . config
317+ . lock ( )
318+ . expect ( "Failed to lock config mutex during purge" ) = None ;
319+ * self
320+ . core_version
321+ . lock ( )
322+ . expect ( "Failed to lock core_version mutex during purge" ) = None ;
323+ * self
324+ . cookie_key
325+ . write ( )
326+ . expect ( "Failed to lock cookie key during purge" ) = None ;
327+ self . connected . store ( false , Ordering :: Relaxed ) ;
328+
329+ if self . reset_tx . send ( ( ) ) . is_err ( ) {
330+ error ! ( "Failed to notify reset handler" ) ;
331+ return Err ( Status :: internal ( "Failed to restart setup process" ) ) ;
332+ }
333+
334+ info ! ( "Removed gRPC certificate files; entering setup mode" ) ;
335+ Ok ( Response :: new ( ( ) ) )
336+ }
275337}
0 commit comments