[Clean] safer unwrap & except handling
Some checks failed
CI / checks (push) Failing after 1m51s

This commit is contained in:
Alex Emmet 2026-07-15 19:11:01 +02:00
commit 5f11d476b6
17 changed files with 475 additions and 348 deletions

View file

@ -26,8 +26,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"Missing TLS certificate at {cert_path}: enter the Nix shell first or run the server to generate it: {e}"
)
});
let host_public_key = load_public_key_bundle("host.mpkb")
.expect("Missing host.mpkb: run the server first to export it");
let host_public_key = match load_public_key_bundle("host.mpkb") {
Ok(bundle) => bundle,
Err(e) => {
return Err(format!(
"Missing host.mpkb: run the server first to export it ({e})"
)
.into());
}
};
println!("Connecting to 127.0.0.1:8080 ...");

View file

@ -7,11 +7,10 @@ pub fn build_demo_message(
client_id: u64,
keyring: &Keyring,
server_bundle: &PublicKeyBundle,
) -> CommunicationValue {
) -> Result<CommunicationValue, Box<dyn std::error::Error>> {
// Encrypt to the server's KEM public key; the server decrypts with its keyring.
let enc_type = EncryptionType::MlKemChaCha20Poly1305;
let signer =
Ed25519Signer::new(&keyring.sig_cl_secret_key).expect("Ed25519 signer from keyring");
let signer = Ed25519Signer::new(&keyring.sig_cl_secret_key)?;
let tm = TypeMap::latest();
@ -52,8 +51,7 @@ pub fn build_demo_message(
);
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs();
let msg = CommunicationValue::new(CommunicationType::Ping)
@ -84,7 +82,7 @@ pub fn build_demo_message(
.add_typed_default(DataType::SignedPayload, dv_sig)
.add_typed_default(DataType::SecurePayload, dv_sec)
.with_sender(client_id);
msg
Ok(msg)
}
pub async fn send_and_receive(
@ -92,7 +90,7 @@ pub async fn send_and_receive(
keyring: &Keyring,
server_bundle: &PublicKeyBundle,
) -> Result<(), Box<dyn std::error::Error>> {
let msg = build_demo_message(conn.client_id, keyring, server_bundle);
let msg = build_demo_message(conn.client_id, keyring, server_bundle)?;
println!("Sending: {msg}");
conn.sender.send(&msg).await?;

View file

@ -19,7 +19,12 @@ pub fn load_client_db(
Err(_) => HashMap::new(),
};
let clients: Arc<Mutex<HashMap<u64, PublicKeyBundle>>> = Arc::new(Mutex::new(clients_map));
let next_value = clients.lock().unwrap().keys().max().unwrap_or(&999) + 1;
let next_value = {
let guard = clients
.lock()
.map_err(|_| std::io::Error::other("client database mutex poisoned"))?;
guard.keys().max().copied().unwrap_or(999) + 1
};
let next_id = Arc::new(Mutex::new(next_value));
Ok((clients, next_id))
}

View file

@ -17,17 +17,47 @@ pub fn process_and_respond(
tm: &TypeMap,
client_pk: Option<&mtp::crypto::PublicKeyBundle>,
host_keyring: &Keyring,
) -> CommunicationValue {
let desc_id = DataTypeId(tm.data_id_enum(DataType::Description).unwrap());
let ts_id = DataTypeId(tm.data_id_enum(DataType::Timestamp).unwrap());
let data_id = DataTypeId(tm.data_id_enum(DataType::Data).unwrap());
let flags_id = DataTypeId(tm.data_id_enum(DataType::Flags).unwrap());
let value_id = DataTypeId(tm.data_id_enum(DataType::Value).unwrap());
let bin_id = DataTypeId(tm.data_id_enum(DataType::BinaryData).unwrap());
let items_id = DataTypeId(tm.data_id_enum(DataType::Items).unwrap());
let _enc_id = DataTypeId(tm.data_id_enum(DataType::EncryptedPayload).unwrap());
let _sig_id = DataTypeId(tm.data_id_enum(DataType::SignedPayload).unwrap());
let _secure_id = DataTypeId(tm.data_id_enum(DataType::SecurePayload).unwrap());
) -> Result<CommunicationValue, String> {
let desc_id = DataTypeId(
tm.data_id_enum(DataType::Description)
.ok_or("missing Description type mapping")?,
);
let ts_id = DataTypeId(
tm.data_id_enum(DataType::Timestamp)
.ok_or("missing Timestamp type mapping")?,
);
let data_id = DataTypeId(
tm.data_id_enum(DataType::Data)
.ok_or("missing Data type mapping")?,
);
let flags_id = DataTypeId(
tm.data_id_enum(DataType::Flags)
.ok_or("missing Flags type mapping")?,
);
let value_id = DataTypeId(
tm.data_id_enum(DataType::Value)
.ok_or("missing Value type mapping")?,
);
let bin_id = DataTypeId(
tm.data_id_enum(DataType::BinaryData)
.ok_or("missing BinaryData type mapping")?,
);
let items_id = DataTypeId(
tm.data_id_enum(DataType::Items)
.ok_or("missing Items type mapping")?,
);
let _enc_id = DataTypeId(
tm.data_id_enum(DataType::EncryptedPayload)
.ok_or("missing EncryptedPayload type mapping")?,
);
let _sig_id = DataTypeId(
tm.data_id_enum(DataType::SignedPayload)
.ok_or("missing SignedPayload type mapping")?,
);
let _secure_id = DataTypeId(
tm.data_id_enum(DataType::SecurePayload)
.ok_or("missing SecurePayload type mapping")?,
);
let description = msg.get_data(DataType::Description);
let timestamp = msg.get_data(DataType::Timestamp);
@ -118,10 +148,10 @@ pub fn process_and_respond(
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.map_err(|e| e.to_string())?
.as_secs();
CommunicationValue::from_comm(CommunicationType::Pong, tm)
Ok(CommunicationValue::from_comm(CommunicationType::Pong, tm)
.add_data(desc_id, description.clone())
.add_data(ts_id, DataValue::UnsignedNumber(now as u128))
.add_data(
@ -134,5 +164,5 @@ pub fn process_and_respond(
.add_data(flags_id, flags.clone())
.add_data(value_id, value.clone())
.add_data(bin_id, binary.clone())
.add_data(items_id, items.clone())
.add_data(items_id, items.clone()))
}

View file

@ -62,7 +62,10 @@ async fn handle_pipe_loopback(
tokio::io::AsyncWriteExt::write_all(&mut writer, &buf[..n]).await?;
}
writer.finish().await?;
println!(" [loopback] Pipe {pipe_id} loopback complete ({} bytes)", total);
println!(
" [loopback] Pipe {pipe_id} loopback complete ({} bytes)",
total
);
}
None => {
eprintln!(" [loopback] Return pipe denied by client for pipe {pipe_id}");
@ -83,10 +86,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (_host_id, host_keyring) = keys::load_or_generate_host_keys("host.mk")?;
keys::export_host_public_keys(&host_keyring)?;
let decrypt_keyring = Arc::new(
mtp::crypto::Keyring::from_bytes(&host_keyring.to_bytes())
.expect("re-load host keyring for decryption"),
);
let decrypt_keyring = Arc::new(match mtp::crypto::Keyring::from_bytes(&host_keyring.to_bytes())
{
Ok(keyring) => keyring,
Err(e) => {
return Err(format!("failed to re-load host keyring for decryption: {e}").into());
}
});
let (clients, next_id) = clients::load_client_db("clients.json")?;
@ -94,7 +100,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let get_existing_user = move |id: u64, _description: Option<String>| {
let clients = clients_for_get.clone();
Box::pin(async move {
let result = clients.lock().unwrap().get(&id).cloned();
let result = clients.lock()?.get(&id).cloned();
if result.is_some() {
println!("Auth lookup: client ID {id} found");
} else {
@ -113,8 +119,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let nid_arc = next_id_for_register.clone();
let path = clients_path.clone();
Box::pin(async move {
let mut db = db_arc.lock().unwrap();
let mut nid = nid_arc.lock().unwrap();
let mut db = db_arc.lock()?;
let mut nid = nid_arc.lock()?;
let id = *nid;
*nid += 1;
db.insert(id, bundle);
@ -160,7 +166,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
);
println!("Client ID: {}", conn.client_id);
let tm: &TypeMap = conn.codec.registry().get(&conn.version).unwrap();
let tm: &TypeMap = conn.codec.registry().get(&conn.version)?;
println!("Waiting for messages / pipe requests ...");
loop {
@ -185,12 +191,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match msg {
Ok(msg) => {
println!("Received: {msg}");
let response = handlers::process_and_respond(
let response = match handlers::process_and_respond(
&msg,
tm,
conn.client_public_key.as_ref(),
&decrypt_keyring,
);
) {
Ok(response) => response,
Err(e) => {
eprintln!("Failed to build response: {e}");
continue;
}
};
println!("Sending: {response}");
if let Err(e) = conn.sender.send(&response).await {
eprintln!("Send error: {e}");