97 lines
3.8 KiB
Rust
97 lines
3.8 KiB
Rust
use std::{net::UdpSocket, thread, time::Duration};
|
|
|
|
use irtt_client::{Authentication, Client, ClientConfig, ClientEvent, HmacKey, SocketConfig};
|
|
use irtt_proto::{decode_request, verify_packet_hmac};
|
|
use irtt_server::{ServerConfig, ServerCore};
|
|
|
|
// Exercise the runtime-free API against the production server core, including
|
|
// the wire HMAC flag on Open, Echo and Close for an explicitly empty key.
|
|
#[test]
|
|
fn concrete_authentication_preserves_session_and_empty_key_behavior() {
|
|
for key in [None, Some(b"session-test-key".as_slice()), Some(&[])] {
|
|
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
|
|
socket
|
|
.set_read_timeout(Some(Duration::from_secs(2)))
|
|
.unwrap();
|
|
let addr = socket.local_addr().unwrap();
|
|
let server = thread::spawn(move || {
|
|
let config = key.map_or_else(ServerConfig::default, |key| {
|
|
ServerConfig::default().with_hmac_key(key)
|
|
});
|
|
let mut core = ServerCore::new(config);
|
|
let mut buffer = [0; 2048];
|
|
for _ in 0..3 {
|
|
let (len, peer) = socket.recv_from(&mut buffer).unwrap();
|
|
let packet = &buffer[..len];
|
|
assert_eq!(decode_request(packet).unwrap().hmac_present, key.is_some());
|
|
if let Some(key) = key {
|
|
verify_packet_hmac(key, packet).unwrap();
|
|
}
|
|
if let Some(reply) = core.handle_datagram(peer, packet).unwrap() {
|
|
socket.send_to(reply.bytes(), peer).unwrap();
|
|
}
|
|
}
|
|
assert_eq!(core.session_count(), 0, "Close must release the session");
|
|
});
|
|
let mut client = Client::connect(ClientConfig {
|
|
server_addr: addr.to_string(),
|
|
auth: key.map_or(Authentication::Unauthenticated, |key| {
|
|
Authentication::Hmac(HmacKey::new(key))
|
|
}),
|
|
open_timeouts: vec![Duration::from_millis(200)],
|
|
socket_config: SocketConfig {
|
|
recv_timeout: Some(Duration::from_secs(1)),
|
|
..SocketConfig::default()
|
|
},
|
|
..ClientConfig::default()
|
|
})
|
|
.unwrap();
|
|
client.open().unwrap();
|
|
client.send_probe().unwrap();
|
|
assert!(client
|
|
.recv_once()
|
|
.unwrap()
|
|
.iter()
|
|
.any(|event| { matches!(event, ClientEvent::EchoReply { .. }) }));
|
|
client.close().unwrap();
|
|
server.join().unwrap();
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn authentication_debug_redacts_keys_in_enclosing_configurations() {
|
|
let sentinel = b"CONSPICUOUS_HMAC_SECRET_DO_NOT_PRINT";
|
|
let key = HmacKey::new(sentinel.as_slice());
|
|
let auth = Authentication::Hmac(key.clone());
|
|
let config = ClientConfig {
|
|
auth: auth.clone(),
|
|
..ClientConfig::default()
|
|
};
|
|
let mut outputs = vec![
|
|
format!("{key:?}"),
|
|
format!("{auth:?}"),
|
|
format!("{config:?}"),
|
|
];
|
|
#[cfg(feature = "tokio")]
|
|
{
|
|
use irtt_client::managed::{ManagedClientConfig, ManagedTargetConfig, TargetAuth};
|
|
let mut target = ManagedTargetConfig::new("one", "127.0.0.1:2112");
|
|
target.auth = TargetAuth::Override(auth);
|
|
outputs.push(format!("{target:?}"));
|
|
outputs.push(format!(
|
|
"{:?}",
|
|
ManagedClientConfig {
|
|
client: config,
|
|
..ManagedClientConfig::default()
|
|
}
|
|
));
|
|
}
|
|
// Check both textual and ordinary byte-slice Debug encodings so replacing
|
|
// the opaque formatter with a derived formatter cannot slip through.
|
|
for output in outputs.drain(..) {
|
|
assert!(!output.contains(std::str::from_utf8(sentinel).unwrap()));
|
|
assert!(!output.contains(&format!("{sentinel:?}")));
|
|
assert!(output.contains("[REDACTED]"));
|
|
}
|
|
}
|