Audit fixes: key permissions, lock contention, Docker IP filter, doc updates

Security: identity.key written with 0600 permissions (Unix). Docker bridge
IPs (172.17-31.x) filtered from is_shareable_addr to prevent topology
disclosure in relay introductions.

Lock contention: ManifestPush relay and DeleteRecord CDN notify now gather
connections under lock, then send outside lock.

UI: syncBtn null guard prevents crash on hidden element.

Documentation: design.html version badge updated to v0.4.4. Self Last
Encounter threshold corrected from 3h to 4h. Multi-Device Identity section
rewritten for multi-identity-per-device (complete) + multi-device (planned)
+ post merge (planned). MEMORY.md updated to v0.4.4+ status.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scott Reimers 2026-03-31 19:37:17 -04:00
parent 18a40756d8
commit fb1e92985c
5 changed files with 85 additions and 58 deletions

View file

@ -4935,41 +4935,31 @@ impl ConnectionManager {
}
}
// Send CDN delete notices (async, best-effort)
// Gather connections for CDN delete notices under lock, then send outside
let mut delete_notices: Vec<(iroh::endpoint::Connection, crate::protocol::BlobDeleteNoticePayload)> = Vec::new();
for (cid, downstream, upstream) in &blob_cleanup {
// Notify downstream (with our upstream info for tree healing)
let upstream_info = upstream.as_ref().map(|(nid, addrs)| {
PeerWithAddress {
n: hex::encode(nid),
a: addrs.clone(),
}
});
let ds_payload = crate::protocol::BlobDeleteNoticePayload {
cid: *cid,
upstream_node: upstream_info,
};
let upstream_info = upstream.as_ref().map(|(nid, addrs)| PeerWithAddress { n: hex::encode(nid), a: addrs.clone() });
let ds_payload = crate::protocol::BlobDeleteNoticePayload { cid: *cid, upstream_node: upstream_info };
for (ds_nid, _) in downstream {
if let Some(pc) = cm.connections_ref().get(ds_nid) {
if let Ok(mut send) = pc.connection.open_uni().await {
let _ = write_typed_message(&mut send, MessageType::BlobDeleteNotice, &ds_payload).await;
let _ = send.finish();
}
delete_notices.push((pc.connection.clone(), ds_payload.clone()));
}
}
// Notify upstream (no upstream info — just "remove me")
if let Some((up_nid, _)) = upstream {
let up_payload = crate::protocol::BlobDeleteNoticePayload {
cid: *cid,
upstream_node: None,
};
let up_payload = crate::protocol::BlobDeleteNoticePayload { cid: *cid, upstream_node: None };
if let Some(pc) = cm.connections_ref().get(up_nid) {
if let Ok(mut send) = pc.connection.open_uni().await {
let _ = write_typed_message(&mut send, MessageType::BlobDeleteNotice, &up_payload).await;
let _ = send.finish();
}
delete_notices.push((pc.connection.clone(), up_payload));
}
}
}
drop(cm);
// Send outside lock
for (conn, payload) in &delete_notices {
if let Ok(mut send) = conn.open_uni().await {
let _ = write_typed_message(&mut send, MessageType::BlobDeleteNotice, payload).await;
let _ = send.finish();
}
}
}
MessageType::VisibilityUpdate => {
let payload: crate::protocol::VisibilityUpdatePayload =
@ -5167,13 +5157,18 @@ impl ConnectionManager {
}
drop(storage);
// Relay to downstream (best-effort via mesh connections)
for (ds_nid, relay_payload) in &relay_targets {
if let Some(pc) = cm.connections_ref().get(ds_nid) {
if let Ok(mut send) = pc.connection.open_uni().await {
let _ = write_typed_message(&mut send, MessageType::ManifestPush, relay_payload).await;
let _ = send.finish();
}
// Gather relay connections under lock, then relay outside
let relay_conns: Vec<(iroh::endpoint::Connection, crate::protocol::ManifestPushPayload)> = relay_targets.iter()
.filter_map(|(ds_nid, payload)| {
cm.connections_ref().get(ds_nid).map(|pc| (pc.connection.clone(), payload.clone()))
})
.collect();
drop(cm);
// Relay outside lock
for (conn, relay_payload) in &relay_conns {
if let Ok(mut send) = conn.open_uni().await {
let _ = write_typed_message(&mut send, MessageType::ManifestPush, relay_payload).await;
let _ = send.finish();
}
}
@ -5291,8 +5286,7 @@ impl ConnectionManager {
});
}
drop(cm);
debug!(peer = hex::encode(remote_node_id), stored, relayed = relay_targets.len(), "Received manifest push");
debug!(peer = hex::encode(remote_node_id), stored, relayed = relay_conns.len(), "Received manifest push");
}
MessageType::SocialDisconnectNotice => {
let payload: SocialDisconnectNoticePayload = read_payload(recv, MAX_PAYLOAD).await?;