refactor: centralize peer control caller auth
This commit is contained in:
parent
f88bc851a4
commit
1a6d9db913
3 changed files with 153 additions and 384 deletions
|
|
@ -222,6 +222,12 @@ struct PipeUnixConnectWire {
|
||||||
bearer_proof: Option<BearerProof>,
|
bearer_proof: Option<BearerProof>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PeerControlCaller {
|
||||||
|
peer_card: PeerCard,
|
||||||
|
remote_endpoint_id: String,
|
||||||
|
store: Store,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InitOwnerOptions {
|
pub struct InitOwnerOptions {
|
||||||
pub admin_key_path: Option<PathBuf>,
|
pub admin_key_path: Option<PathBuf>,
|
||||||
|
|
@ -4114,49 +4120,26 @@ async fn handle_iroh_control_connection(
|
||||||
tracing::debug!(remote_endpoint_id = %log_remote_endpoint_id, alpn = %log_alpn, request_bytes, "read iroh peer-control request line");
|
tracing::debug!(remote_endpoint_id = %log_remote_endpoint_id, alpn = %log_alpn, request_bytes, "read iroh peer-control request line");
|
||||||
let response = match geth_control::decode_peer_request(&request_line)? {
|
let response = match geth_control::decode_peer_request(&request_line)? {
|
||||||
PeerControlRequest::Ping { peer_card, nonce } => {
|
PeerControlRequest::Ping { peer_card, nonce } => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
PeerControlResponse::Pong {
|
PeerControlResponse::Pong {
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
alpn,
|
alpn,
|
||||||
nonce,
|
nonce,
|
||||||
note: "peer endpoint authenticated by Iroh and peer-card signature; candidate status does not grant resource capabilities".to_owned(),
|
note: "peer endpoint authenticated by Iroh and peer-card signature; candidate status does not grant resource capabilities".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PeerControlRequest::SyncStatus { peer_card, nonce } => {
|
PeerControlRequest::SyncStatus { peer_card, nonce } => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
let watermarks =
|
||||||
let discovered = DiscoveredPeer::candidate(
|
sync_watermarks_for_peer(&caller.store, caller.peer_card.node_id.as_str())?;
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let watermarks = sync_watermarks_for_peer(&store, peer_card.node_id.as_str())?;
|
|
||||||
PeerControlResponse::SyncStatus {
|
PeerControlResponse::SyncStatus {
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
watermarks,
|
watermarks,
|
||||||
nonce,
|
nonce,
|
||||||
note: "sync status authenticated endpoint/card binding and returns only streams for capabilities already granted to the caller".to_owned(),
|
note: "sync status authenticated endpoint/card binding and returns only streams for capabilities already granted to the caller".to_owned(),
|
||||||
|
|
@ -4167,21 +4150,9 @@ async fn handle_iroh_control_connection(
|
||||||
since_ms,
|
since_ms,
|
||||||
nonce,
|
nonce,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
let ops = load_keychain_ops(&caller.store)?;
|
||||||
let discovered = DiscoveredPeer::candidate(
|
let signatures = load_keychain_signatures(&caller.store)?;
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let ops = load_keychain_ops(&store)?;
|
|
||||||
let signatures = load_keychain_signatures(&store)?;
|
|
||||||
let returned_op_ids = ops
|
let returned_op_ids = ops
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| op.created_at.0 >= since_ms)
|
.filter(|op| op.created_at.0 >= since_ms)
|
||||||
|
|
@ -4197,7 +4168,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
ops: ops
|
ops: ops
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|op| op.created_at.0 >= since_ms)
|
.filter(|op| op.created_at.0 >= since_ms)
|
||||||
|
|
@ -4219,21 +4190,9 @@ async fn handle_iroh_control_connection(
|
||||||
since_ms,
|
since_ms,
|
||||||
nonce,
|
nonce,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
let ops = load_auth_ops(&caller.store)?;
|
||||||
let discovered = DiscoveredPeer::candidate(
|
let signatures = load_auth_signatures(&caller.store)?;
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let ops = load_auth_ops(&store)?;
|
|
||||||
let signatures = load_auth_signatures(&store)?;
|
|
||||||
let returned_op_ids = ops
|
let returned_op_ids = ops
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| op.created_at.0 >= since_ms)
|
.filter(|op| op.created_at.0 >= since_ms)
|
||||||
|
|
@ -4249,7 +4208,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
ops: ops
|
ops: ops
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|op| op.created_at.0 >= since_ms)
|
.filter(|op| op.created_at.0 >= since_ms)
|
||||||
|
|
@ -4271,25 +4230,14 @@ async fn handle_iroh_control_connection(
|
||||||
request,
|
request,
|
||||||
nonce,
|
nonce,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
let accepted =
|
||||||
let discovered = DiscoveredPeer::candidate(
|
insert_node_enrollment_request_if_not_conflicting(&caller.store, &request)?;
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let accepted = insert_node_enrollment_request_if_not_conflicting(&store, &request)?;
|
|
||||||
PeerControlResponse::NodeEnrollmentSubmitted {
|
PeerControlResponse::NodeEnrollmentSubmitted {
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
request_id: request.id.to_string(),
|
request_id: request.id.to_string(),
|
||||||
accepted,
|
accepted,
|
||||||
nonce,
|
nonce,
|
||||||
|
|
@ -4302,22 +4250,10 @@ async fn handle_iroh_control_connection(
|
||||||
capability,
|
capability,
|
||||||
nonce,
|
nonce,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let explanation = geth_auth::explain_auth_ops(
|
let explanation = geth_auth::explain_auth_ops(
|
||||||
&load_auth_ops_for_resource(&store, &resource)?,
|
&load_auth_ops_for_resource(&caller.store, &resource)?,
|
||||||
PrincipalId::new(peer_card.node_id.to_string()),
|
PrincipalId::new(caller.peer_card.node_id.to_string()),
|
||||||
ResourceId::new(resource.clone()),
|
ResourceId::new(resource.clone()),
|
||||||
Capability::new(capability.clone()),
|
Capability::new(capability.clone()),
|
||||||
);
|
);
|
||||||
|
|
@ -4325,7 +4261,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
resource,
|
resource,
|
||||||
capability,
|
capability,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
|
|
@ -4341,24 +4277,12 @@ async fn handle_iroh_control_connection(
|
||||||
nonce,
|
nonce,
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:cas:local".to_owned();
|
let resource = "resource:cas:local".to_owned();
|
||||||
let capability = "cas.fetch".to_owned();
|
let capability = "cas.fetch".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4372,7 +4296,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
hash,
|
hash,
|
||||||
size_bytes,
|
size_bytes,
|
||||||
content_base64: Some(
|
content_base64: Some(
|
||||||
|
|
@ -4394,7 +4318,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
hash,
|
hash,
|
||||||
size_bytes: 0,
|
size_bytes: 0,
|
||||||
content_base64: None,
|
content_base64: None,
|
||||||
|
|
@ -4413,31 +4337,19 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_cas::validate_file_root_name(&name)?;
|
geth_cas::validate_file_root_name(&name)?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:cas-tree:{name}");
|
let resource = format!("resource:cas-tree:{name}");
|
||||||
let capability = "cas.fetch".to_owned();
|
let capability = "cas.fetch".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
bearer_proof.as_ref(),
|
bearer_proof.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
let (root, tree_content_base64) = if explanation.allowed {
|
let (root, tree_content_base64) = if explanation.allowed {
|
||||||
if let Some(root) = store.get_file_root_by_name(&name)? {
|
if let Some(root) = caller.store.get_file_root_by_name(&name)? {
|
||||||
let root_view = file_root_from_stored(&root);
|
let root_view = file_root_from_stored(&root);
|
||||||
let tree_content_base64 = root
|
let tree_content_base64 = root
|
||||||
.latest_tree_hash
|
.latest_tree_hash
|
||||||
|
|
@ -4462,7 +4374,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
name,
|
name,
|
||||||
root,
|
root,
|
||||||
tree_content_base64,
|
tree_content_base64,
|
||||||
|
|
@ -4479,25 +4391,13 @@ async fn handle_iroh_control_connection(
|
||||||
nonce,
|
nonce,
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:ssh:certs".to_owned();
|
let resource = "resource:ssh:certs".to_owned();
|
||||||
let capability = "ssh_cert.sync".to_owned();
|
let capability = "ssh_cert.sync".to_owned();
|
||||||
let high_water_ms = geth_store::now_ms();
|
let high_water_ms = geth_store::now_ms();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4505,12 +4405,14 @@ async fn handle_iroh_control_connection(
|
||||||
)?;
|
)?;
|
||||||
let (requests, certificates, log_entries) = if explanation.allowed {
|
let (requests, certificates, log_entries) = if explanation.allowed {
|
||||||
(
|
(
|
||||||
store
|
caller
|
||||||
|
.store
|
||||||
.list_ssh_cert_requests_since(since_ms)?
|
.list_ssh_cert_requests_since(since_ms)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ssh_cert_request_from_stored)
|
.map(ssh_cert_request_from_stored)
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
store
|
caller
|
||||||
|
.store
|
||||||
.list_ssh_certificates_since(since_ms)?
|
.list_ssh_certificates_since(since_ms)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ssh_certificate_from_stored)
|
.map(ssh_certificate_from_stored)
|
||||||
|
|
@ -4529,7 +4431,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
requests,
|
requests,
|
||||||
certificates,
|
certificates,
|
||||||
log_entries,
|
log_entries,
|
||||||
|
|
@ -4547,32 +4449,21 @@ async fn handle_iroh_control_connection(
|
||||||
nonce,
|
nonce,
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:ssh:revocations".to_owned();
|
let resource = "resource:ssh:revocations".to_owned();
|
||||||
let capability = "ssh_revocation.sync".to_owned();
|
let capability = "ssh_revocation.sync".to_owned();
|
||||||
let high_water_ms = geth_store::now_ms();
|
let high_water_ms = geth_store::now_ms();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
bearer_proof.as_ref(),
|
bearer_proof.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
let (revocations, log_entries) = if explanation.allowed {
|
let (revocations, log_entries) = if explanation.allowed {
|
||||||
store
|
caller
|
||||||
|
.store
|
||||||
.list_ssh_revocations_since(since_ms)?
|
.list_ssh_revocations_since(since_ms)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ssh_revocation_from_stored)
|
.map(ssh_revocation_from_stored)
|
||||||
|
|
@ -4589,7 +4480,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
revocations,
|
revocations,
|
||||||
log_entries,
|
log_entries,
|
||||||
high_water_ms,
|
high_water_ms,
|
||||||
|
|
@ -4608,19 +4499,11 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_kv::validate_kv_name(&name).map_err(|_| NodeError::InvalidKvName(name.clone()))?;
|
geth_kv::validate_kv_name(&name).map_err(|_| NodeError::InvalidKvName(name.clone()))?;
|
||||||
peer_card.validate_candidate()?;
|
let PeerControlCaller {
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
peer_card,
|
||||||
let discovered = DiscoveredPeer::candidate(
|
remote_endpoint_id,
|
||||||
peer_card.clone(),
|
store,
|
||||||
UnixMillis(geth_store::now_ms()),
|
} = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
if let Some(kv) = store.get_kv_store_by_name(&name)? {
|
if let Some(kv) = store.get_kv_store_by_name(&name)? {
|
||||||
let capability = "kv.read".to_owned();
|
let capability = "kv.read".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
|
|
@ -4686,19 +4569,11 @@ async fn handle_iroh_control_connection(
|
||||||
} => {
|
} => {
|
||||||
geth_pubsub::validate_topic(&topic)?;
|
geth_pubsub::validate_topic(&topic)?;
|
||||||
geth_pubsub::validate_message(&message)?;
|
geth_pubsub::validate_message(&message)?;
|
||||||
peer_card.validate_candidate()?;
|
let PeerControlCaller {
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
peer_card,
|
||||||
let discovered = DiscoveredPeer::candidate(
|
remote_endpoint_id,
|
||||||
peer_card.clone(),
|
store,
|
||||||
UnixMillis(geth_store::now_ms()),
|
} = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pubsub:{topic}");
|
let resource = format!("resource:pubsub:{topic}");
|
||||||
let capability = "pubsub.publish".to_owned();
|
let capability = "pubsub.publish".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
|
|
@ -4746,19 +4621,11 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_pubsub::validate_topic(&topic)?;
|
geth_pubsub::validate_topic(&topic)?;
|
||||||
peer_card.validate_candidate()?;
|
let PeerControlCaller {
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
peer_card,
|
||||||
let discovered = DiscoveredPeer::candidate(
|
remote_endpoint_id,
|
||||||
peer_card.clone(),
|
store,
|
||||||
UnixMillis(geth_store::now_ms()),
|
} = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pubsub:{topic}");
|
let resource = format!("resource:pubsub:{topic}");
|
||||||
let capability = "pubsub.subscribe".to_owned();
|
let capability = "pubsub.subscribe".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
|
|
@ -4800,24 +4667,12 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_pipe::validate_pipe_name(&target)?;
|
geth_pipe::validate_pipe_name(&target)?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pipe:{target}");
|
let resource = format!("resource:pipe:{target}");
|
||||||
let capability = "pipe.connect".to_owned();
|
let capability = "pipe.connect".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4836,7 +4691,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection,
|
connection,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -4852,24 +4707,12 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_pipe::validate_pipe_name(&name)?;
|
geth_pipe::validate_pipe_name(&name)?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pipe:{name}");
|
let resource = format!("resource:pipe:{name}");
|
||||||
let capability = "pipe.listen".to_owned();
|
let capability = "pipe.listen".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4884,7 +4727,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
listener,
|
listener,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -4898,24 +4741,12 @@ async fn handle_iroh_control_connection(
|
||||||
nonce,
|
nonce,
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:ssh-proxy:local".to_owned();
|
let resource = "resource:ssh-proxy:local".to_owned();
|
||||||
let capability = "ssh_proxy.connect".to_owned();
|
let capability = "ssh_proxy.connect".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4936,7 +4767,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection,
|
connection,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -4951,24 +4782,12 @@ async fn handle_iroh_control_connection(
|
||||||
nonce,
|
nonce,
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:ssh-proxy:local".to_owned();
|
let resource = "resource:ssh-proxy:local".to_owned();
|
||||||
let capability = "ssh_proxy.admin_shell".to_owned();
|
let capability = "ssh_proxy.admin_shell".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -4983,7 +4802,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
command,
|
command,
|
||||||
output,
|
output,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
|
|
@ -5002,25 +4821,13 @@ async fn handle_iroh_control_connection(
|
||||||
} => {
|
} => {
|
||||||
geth_document::validate_document_name(&name)
|
geth_document::validate_document_name(&name)
|
||||||
.map_err(|_| NodeError::InvalidDocumentName(name.clone()))?;
|
.map_err(|_| NodeError::InvalidDocumentName(name.clone()))?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
if let Some(document) = caller.store.get_document_resource_by_name(&name)? {
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
if let Some(document) = store.get_document_resource_by_name(&name)? {
|
|
||||||
let capability = "document.read".to_owned();
|
let capability = "document.read".to_owned();
|
||||||
let high_water_ms = document.updated_at_ms;
|
let high_water_ms = document.updated_at_ms;
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&document.resource_id,
|
&document.resource_id,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5035,7 +4842,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
name,
|
name,
|
||||||
state,
|
state,
|
||||||
high_water_ms,
|
high_water_ms,
|
||||||
|
|
@ -5060,24 +4867,12 @@ async fn handle_iroh_control_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} => {
|
} => {
|
||||||
geth_db::validate_db_name(&name).map_err(|_| NodeError::InvalidDbName(name.clone()))?;
|
geth_db::validate_db_name(&name).map_err(|_| NodeError::InvalidDbName(name.clone()))?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
if let Some(db) = caller.store.get_db_resource_by_name(&name)? {
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
if let Some(db) = store.get_db_resource_by_name(&name)? {
|
|
||||||
let capability = "db.sync".to_owned();
|
let capability = "db.sync".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&db.resource_id,
|
&db.resource_id,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5108,7 +4903,7 @@ async fn handle_iroh_control_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id,
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
name,
|
name,
|
||||||
batch,
|
batch,
|
||||||
high_water_db_version,
|
high_water_db_version,
|
||||||
|
|
@ -5164,19 +4959,11 @@ async fn handle_ssh_proxy_wire_connection(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
peer_card.validate_candidate()?;
|
let PeerControlCaller {
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, &remote_endpoint_id)?;
|
peer_card,
|
||||||
let discovered = DiscoveredPeer::candidate(
|
remote_endpoint_id,
|
||||||
peer_card.clone(),
|
store,
|
||||||
UnixMillis(geth_store::now_ms()),
|
} = authenticate_peer_control_caller(&node, peer_card, &remote_endpoint_id)?;
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = "resource:ssh-proxy:local".to_owned();
|
let resource = "resource:ssh-proxy:local".to_owned();
|
||||||
let capability = "ssh_proxy.connect".to_owned();
|
let capability = "ssh_proxy.connect".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
|
|
@ -5389,24 +5176,12 @@ async fn handle_overlay_packet_wire_request(
|
||||||
.decode(&packet_base64)
|
.decode(&packet_base64)
|
||||||
.map_err(|error| NodeError::IrohPeer(format!("invalid overlay packet base64: {error}")))?;
|
.map_err(|error| NodeError::IrohPeer(format!("invalid overlay packet base64: {error}")))?;
|
||||||
geth_overlay::validate_ipv4_packet(&packet)?;
|
geth_overlay::validate_ipv4_packet(&packet)?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(node, peer_card, remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = geth_overlay::overlay_resource_id(&network).to_string();
|
let resource = geth_overlay::overlay_resource_id(&network).to_string();
|
||||||
let capability = "overlay.route".to_owned();
|
let capability = "overlay.route".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5415,9 +5190,9 @@ async fn handle_overlay_packet_wire_request(
|
||||||
let packet = if explanation.allowed {
|
let packet = if explanation.allowed {
|
||||||
let injected = overlay_runtime_inject(node, &network, packet.clone())?;
|
let injected = overlay_runtime_inject(node, &network, packet.clone())?;
|
||||||
let mut packet = record_overlay_packet(
|
let mut packet = record_overlay_packet(
|
||||||
&store,
|
&caller.store,
|
||||||
&network,
|
&network,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&node.node_id,
|
&node.node_id,
|
||||||
packet_base64,
|
packet_base64,
|
||||||
packet.len(),
|
packet.len(),
|
||||||
|
|
@ -5434,7 +5209,7 @@ async fn handle_overlay_packet_wire_request(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
packet,
|
packet,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -5457,24 +5232,12 @@ fn handle_pipe_send_wire_request(
|
||||||
base64::engine::general_purpose::STANDARD
|
base64::engine::general_purpose::STANDARD
|
||||||
.decode(&data_base64)
|
.decode(&data_base64)
|
||||||
.map_err(|error| NodeError::IrohPeer(format!("invalid pipe payload: {error}")))?;
|
.map_err(|error| NodeError::IrohPeer(format!("invalid pipe payload: {error}")))?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(node, peer_card, remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pipe:{target}");
|
let resource = format!("resource:pipe:{target}");
|
||||||
let capability = "pipe.connect".to_owned();
|
let capability = "pipe.connect".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5485,7 +5248,7 @@ fn handle_pipe_send_wire_request(
|
||||||
node,
|
node,
|
||||||
target,
|
target,
|
||||||
data_base64,
|
data_base64,
|
||||||
Some(peer_card.node_id.to_string()),
|
Some(caller.peer_card.node_id.to_string()),
|
||||||
"remote pipe byte message over dedicated Iroh pipe ALPN".to_owned(),
|
"remote pipe byte message over dedicated Iroh pipe ALPN".to_owned(),
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -5495,7 +5258,7 @@ fn handle_pipe_send_wire_request(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
message: Box::new(message),
|
message: Box::new(message),
|
||||||
listener_found,
|
listener_found,
|
||||||
allowed: explanation.allowed,
|
allowed: explanation.allowed,
|
||||||
|
|
@ -5520,24 +5283,12 @@ async fn handle_pipe_tcp_wire_connection(
|
||||||
bearer_proof,
|
bearer_proof,
|
||||||
} = request;
|
} = request;
|
||||||
let target = geth_pipe::validate_tcp_forward_target_addr(&target_addr)?;
|
let target = geth_pipe::validate_tcp_forward_target_addr(&target_addr)?;
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pipe-tcp:{target_addr}");
|
let resource = format!("resource:pipe-tcp:{target_addr}");
|
||||||
let capability = "pipe.forward".to_owned();
|
let capability = "pipe.forward".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5548,7 +5299,7 @@ async fn handle_pipe_tcp_wire_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection: None,
|
connection: None,
|
||||||
allowed: false,
|
allowed: false,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -5583,7 +5334,7 @@ async fn handle_pipe_tcp_wire_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection: Some(PipeConnection {
|
connection: Some(PipeConnection {
|
||||||
target: target_addr.clone(),
|
target: target_addr.clone(),
|
||||||
connected_at: UnixMillis(geth_store::now_ms()),
|
connected_at: UnixMillis(geth_store::now_ms()),
|
||||||
|
|
@ -5632,24 +5383,12 @@ async fn handle_pipe_unix_wire_connection(
|
||||||
} = request;
|
} = request;
|
||||||
let target_path = geth_pipe::validate_unix_forward_path(&target_path)?;
|
let target_path = geth_pipe::validate_unix_forward_path(&target_path)?;
|
||||||
let target_display = target_path.display().to_string();
|
let target_display = target_path.display().to_string();
|
||||||
peer_card.validate_candidate()?;
|
let caller = authenticate_peer_control_caller(&node, peer_card, remote_endpoint_id)?;
|
||||||
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
|
||||||
let discovered = DiscoveredPeer::candidate(
|
|
||||||
peer_card.clone(),
|
|
||||||
UnixMillis(geth_store::now_ms()),
|
|
||||||
DiscoverySource::PeerExchange,
|
|
||||||
)?;
|
|
||||||
let store = Store::open(&node.paths.metadata_db())?;
|
|
||||||
store.upsert_peer_card(&StoredPeerCard {
|
|
||||||
peer_id: peer_card.node_id.to_string(),
|
|
||||||
card_json: serde_json::to_string(&peer_card)?,
|
|
||||||
updated_at_ms: discovered.discovered_at.0,
|
|
||||||
})?;
|
|
||||||
let resource = format!("resource:pipe-unix:{target_display}");
|
let resource = format!("resource:pipe-unix:{target_display}");
|
||||||
let capability = "pipe.forward".to_owned();
|
let capability = "pipe.forward".to_owned();
|
||||||
let explanation = explain_peer_or_bearer(
|
let explanation = explain_peer_or_bearer(
|
||||||
&store,
|
&caller.store,
|
||||||
peer_card.node_id.as_str(),
|
caller.peer_card.node_id.as_str(),
|
||||||
&resource,
|
&resource,
|
||||||
&capability,
|
&capability,
|
||||||
&nonce,
|
&nonce,
|
||||||
|
|
@ -5660,7 +5399,7 @@ async fn handle_pipe_unix_wire_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection: None,
|
connection: None,
|
||||||
allowed: false,
|
allowed: false,
|
||||||
reason: explanation.reason,
|
reason: explanation.reason,
|
||||||
|
|
@ -5696,7 +5435,7 @@ async fn handle_pipe_unix_wire_connection(
|
||||||
node_id: node.node_id.clone(),
|
node_id: node.node_id.clone(),
|
||||||
agent_id: node.agent_id.clone(),
|
agent_id: node.agent_id.clone(),
|
||||||
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
endpoint_id: node.iroh_status.endpoint_id.clone().unwrap_or_default(),
|
||||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
remote_endpoint_id: caller.remote_endpoint_id,
|
||||||
connection: Some(PipeConnection {
|
connection: Some(PipeConnection {
|
||||||
target: target_display.clone(),
|
target: target_display.clone(),
|
||||||
connected_at: UnixMillis(geth_store::now_ms()),
|
connected_at: UnixMillis(geth_store::now_ms()),
|
||||||
|
|
@ -5774,6 +5513,31 @@ fn ensure_peer_card_matches_endpoint(card: &PeerCard, endpoint_id: &str) -> Resu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn authenticate_peer_control_caller(
|
||||||
|
node: &LocalNode,
|
||||||
|
peer_card: PeerCard,
|
||||||
|
remote_endpoint_id: &str,
|
||||||
|
) -> Result<PeerControlCaller, NodeError> {
|
||||||
|
peer_card.validate_candidate()?;
|
||||||
|
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
||||||
|
let discovered = DiscoveredPeer::candidate(
|
||||||
|
peer_card.clone(),
|
||||||
|
UnixMillis(geth_store::now_ms()),
|
||||||
|
DiscoverySource::PeerExchange,
|
||||||
|
)?;
|
||||||
|
let store = Store::open(&node.paths.metadata_db())?;
|
||||||
|
store.upsert_peer_card(&StoredPeerCard {
|
||||||
|
peer_id: peer_card.node_id.to_string(),
|
||||||
|
card_json: serde_json::to_string(&peer_card)?,
|
||||||
|
updated_at_ms: discovered.discovered_at.0,
|
||||||
|
})?;
|
||||||
|
Ok(PeerControlCaller {
|
||||||
|
peer_card,
|
||||||
|
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
||||||
|
store,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn peer_gossip_endpoint_id(
|
fn peer_gossip_endpoint_id(
|
||||||
node: &LocalNode,
|
node: &LocalNode,
|
||||||
peer_node: &str,
|
peer_node: &str,
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,11 @@ authenticates the Iroh endpoint and peer-card signature, but it does not
|
||||||
authorize any resource module. Protected peer control requests must also prove
|
authorize any resource module. Protected peer control requests must also prove
|
||||||
that the signed peer card binds the observed Iroh EndpointID, then reduce
|
that the signed peer card binds the observed Iroh EndpointID, then reduce
|
||||||
resource auth ops; an EndpointID alone is not accepted as a resource principal.
|
resource auth ops; an EndpointID alone is not accepted as a resource principal.
|
||||||
|
Inbound protected control, pipe-wire, SSH-proxy, and overlay-wire handlers use a
|
||||||
|
shared authenticated caller context that validates the peer card, checks the
|
||||||
|
observed endpoint binding, records the peer card as untrusted candidate
|
||||||
|
metadata, and then passes the verified caller identity plus store handle to the
|
||||||
|
resource-specific authorization step.
|
||||||
Remote geth JSONL messages over Iroh are bounded before decoding:
|
Remote geth JSONL messages over Iroh are bounded before decoding:
|
||||||
peer-control and module wire requests/responses are limited to 16 MiB,
|
peer-control and module wire requests/responses are limited to 16 MiB,
|
||||||
streaming handshakes for SSH proxy and TCP/Unix pipe forwarding are limited to
|
streaming handshakes for SSH proxy and TCP/Unix pipe forwarding are limited to
|
||||||
|
|
|
||||||
|
|
@ -52,17 +52,17 @@ behavior.
|
||||||
- `[ ]` Each command family has a small handler module or function group.
|
- `[ ]` Each command family has a small handler module or function group.
|
||||||
- `[x]` Local-only behavior remains covered by existing integration tests.
|
- `[x]` Local-only behavior remains covered by existing integration tests.
|
||||||
|
|
||||||
- `[ ]` Extract protected peer-control routing.
|
- `[~]` Extract protected peer-control routing.
|
||||||
Acceptance criteria:
|
Acceptance criteria:
|
||||||
- `[x]` Shared bounded Iroh line-read and send-finish helpers live outside
|
- `[x]` Shared bounded Iroh line-read and send-finish helpers live outside
|
||||||
the main feature handler module.
|
the main feature handler module.
|
||||||
- `[x]` Outbound peer-control, pipe-wire, and overlay-wire request helpers
|
- `[x]` Outbound peer-control, pipe-wire, and overlay-wire request helpers
|
||||||
live outside the main feature handler module.
|
live outside the main feature handler module.
|
||||||
- `[ ]` Iroh control ALPN handling, nonce checks, peer-card validation, and
|
- `[~]` Iroh control ALPN handling, nonce checks, peer-card validation, and
|
||||||
endpoint-binding validation are centralized.
|
endpoint-binding validation are centralized.
|
||||||
- `[ ]` Feature handlers receive authenticated caller context rather than
|
- `[x]` Feature handlers receive authenticated caller context rather than
|
||||||
repeating peer-card boilerplate.
|
repeating peer-card boilerplate.
|
||||||
- `[ ]` Remote request tests still prove discovery alone grants no access.
|
- `[x]` Remote request tests still prove discovery alone grants no access.
|
||||||
|
|
||||||
- `[ ]` Extract resource module handlers.
|
- `[ ]` Extract resource module handlers.
|
||||||
Acceptance criteria:
|
Acceptance criteria:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue