feat(rpc): auth handshake, server-push broker, audit logging

- auth_handshake.rs: connection-init protocol (magic 0x01, token, ack)
- push.rs: PushBroker manages per-identity push connections with gc
- server.rs: ConnectionState, auth handshake on first bi-stream, pass
  identity_key/session_token to RequestContext per stream
- client.rs: session_token in RpcClientConfig, auto auth handshake on connect
- middleware.rs: log_rpc_call with SHA-256 redaction, hex_prefix helper
- lib.rs: export auth_handshake and push modules
This commit is contained in:
2026-03-04 12:08:20 +01:00
parent ff93275dc1
commit f09dbe10ce
7 changed files with 387 additions and 8 deletions

View File

@@ -8,6 +8,7 @@ use quinn::{Connection, Endpoint};
use tokio::sync::mpsc;
use tracing::{debug, warn};
use crate::auth_handshake;
use crate::error::{RpcError, RpcStatus};
use crate::framing::{PushFrame, RequestFrame, ResponseFrame};
@@ -21,6 +22,8 @@ pub struct RpcClientConfig {
pub tls_config: Arc<rustls::ClientConfig>,
/// ALPN protocol.
pub alpn: Vec<u8>,
/// Session token to send during auth handshake.
pub session_token: Option<Vec<u8>>,
}
/// A QUIC RPC client connection.
@@ -49,6 +52,20 @@ impl RpcClient {
debug!(remote = %connection.remote_address(), "connected to RPC server");
// Perform auth handshake if a session token was provided.
if let Some(ref token) = config.session_token {
let (mut send, mut recv) = connection
.open_bi()
.await
.map_err(|e| RpcError::Connection(format!("open auth stream: {e}")))?;
auth_handshake::send_auth_init(&mut send, token).await?;
send.finish()
.map_err(|e| RpcError::Connection(format!("finish auth send: {e}")))?;
auth_handshake::recv_auth_ack(&mut recv).await?;
debug!("auth handshake complete");
}
Ok(Self {
connection,
next_request_id: AtomicU32::new(1),