Add authorized pipe messages over Iroh

This commit is contained in:
Eric Wendland 2026-05-20 13:57:14 +02:00
commit 78dbbf240b
11 changed files with 712 additions and 31 deletions

View file

@ -5,7 +5,7 @@ use geth_discovery::{DiscoveredPeer, PeerCard};
use geth_document::{DocumentResource, DocumentState};
use geth_keychain::{KeychainOp, KeychainOpSignature};
use geth_kv::{KvEntry, KvResource, KvSyncEntry};
use geth_pipe::{PipeConnection, PipeListener};
use geth_pipe::{PipeConnection, PipeListener, PipeMessage};
use geth_pubsub::PubsubMessage;
use geth_resource::ResourceDescriptor;
use geth_secrets::{BearerAccess, BearerChallenge, BearerProof, ResourceMasterSecret};
@ -298,6 +298,16 @@ pub enum ControlRequest {
node: Option<String>,
bearer_secret: Option<String>,
},
PipeSend {
target: String,
data_base64: String,
node: Option<String>,
bearer_secret: Option<String>,
},
PipeRecv {
name: String,
peek: bool,
},
ModuleStub {
module: String,
command: String,
@ -632,6 +642,27 @@ pub enum ControlResponse {
reason: String,
note: String,
},
PipeSent {
message: Option<PipeMessage>,
listener_found: bool,
note: String,
},
PipeRemoteSent {
peer_node_id: String,
peer_agent_id: String,
endpoint_id: String,
message: Option<PipeMessage>,
listener_found: bool,
allowed: bool,
reason: String,
note: String,
},
PipeMessages {
name: String,
messages: Vec<PipeMessage>,
drained: bool,
note: String,
},
SshProxyConnected {
peer_node_id: String,
peer_agent_id: String,
@ -988,6 +1019,39 @@ pub enum PeerControlResponse {
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum PipeWireRequest {
Send {
peer_card: PeerCard,
target: String,
data_base64: String,
nonce: String,
bearer_proof: Option<BearerProof>,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum PipeWireResponse {
Sent {
node_id: String,
agent_id: String,
endpoint_id: String,
remote_endpoint_id: String,
message: Box<Option<PipeMessage>>,
listener_found: bool,
allowed: bool,
reason: String,
evaluated_ops: usize,
nonce: String,
note: String,
},
Error {
message: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SyncWatermark {
pub stream: String,
@ -1040,6 +1104,26 @@ pub fn decode_peer_response(line: &str) -> Result<PeerControlResponse, ControlEr
serde_json::from_str(line).map_err(ControlError::from)
}
pub fn encode_pipe_wire_request(request: &PipeWireRequest) -> Result<String, ControlError> {
let mut line = serde_json::to_string(request)?;
line.push('\n');
Ok(line)
}
pub fn decode_pipe_wire_request(line: &str) -> Result<PipeWireRequest, ControlError> {
serde_json::from_str(line).map_err(ControlError::from)
}
pub fn encode_pipe_wire_response(response: &PipeWireResponse) -> Result<String, ControlError> {
let mut line = serde_json::to_string(response)?;
line.push('\n');
Ok(line)
}
pub fn decode_pipe_wire_response(line: &str) -> Result<PipeWireResponse, ControlError> {
serde_json::from_str(line).map_err(ControlError::from)
}
#[cfg(test)]
mod tests {
use super::*;
@ -1260,6 +1344,43 @@ mod tests {
request
);
let request = ControlRequest::PipeSend {
target: "inbox".to_owned(),
data_base64: "aGVsbG8=".to_owned(),
node: Some("node:peer".to_owned()),
bearer_secret: None,
};
assert_eq!(
decode_request(&encode_request(&request).expect("encode")).expect("decode"),
request
);
let request = ControlRequest::PipeRecv {
name: "inbox".to_owned(),
peek: true,
};
assert_eq!(
decode_request(&encode_request(&request).expect("encode")).expect("decode"),
request
);
let response = ControlResponse::PipeMessages {
name: "inbox".to_owned(),
messages: vec![PipeMessage {
pipe: "inbox".to_owned(),
data_base64: "aGVsbG8=".to_owned(),
received_at: geth_types::UnixMillis(1),
source_node: Some("node:peer".to_owned()),
note: "pipe".to_owned(),
}],
drained: false,
note: "pipe messages".to_owned(),
};
assert_eq!(
decode_response(&encode_response(&response).expect("encode")).expect("decode"),
response
);
let request = ControlRequest::PubsubPub {
topic: "presence/test".to_owned(),
message: "online".to_owned(),
@ -1854,6 +1975,55 @@ mod tests {
request
);
let request = PipeWireRequest::Send {
peer_card: PeerCard {
node_id: "node:caller".into(),
agent_id: "agent:caller".into(),
endpoints: Vec::new(),
issued_at: geth_types::UnixMillis(1),
signature: geth_discovery::SignatureMetadata {
namespace: "geth.peer-card.v1@geth.local".to_owned(),
signer: "agent:caller".to_owned(),
public_key: "key".to_owned(),
signature: "sig".to_owned(),
},
},
target: "inbox".to_owned(),
data_base64: "aGVsbG8=".to_owned(),
nonce: "nonce".to_owned(),
bearer_proof: None,
};
assert_eq!(
decode_pipe_wire_request(&encode_pipe_wire_request(&request).expect("encode"))
.expect("decode"),
request
);
let response = PipeWireResponse::Sent {
node_id: "node:peer".to_owned(),
agent_id: "agent:peer".to_owned(),
endpoint_id: "endpoint:peer".to_owned(),
remote_endpoint_id: "endpoint:caller".to_owned(),
message: Box::new(Some(PipeMessage {
pipe: "inbox".to_owned(),
data_base64: "aGVsbG8=".to_owned(),
received_at: geth_types::UnixMillis(1),
source_node: Some("node:caller".to_owned()),
note: "pipe".to_owned(),
})),
listener_found: true,
allowed: true,
reason: "direct grant".to_owned(),
evaluated_ops: 1,
nonce: "nonce".to_owned(),
note: "pipe wire".to_owned(),
};
assert_eq!(
decode_pipe_wire_response(&encode_pipe_wire_response(&response).expect("encode"))
.expect("decode"),
response
);
let response = PeerControlResponse::SshProxyConnected {
node_id: "node:peer".to_owned(),
agent_id: "agent:peer".to_owned(),