PeerAllowPush: consent to exchange pushes, for a while, and nothing else

PeerTrust syncs a peer's pins and serves it everything - too much to
grant a stranger. An app that wants two peers sharing something (two
phones at the same place) to hand each other new content allows pushes
for ttl_secs (at most a day): both sides may push, the receiver pins,
and the allowance lapses on its own. Asking again extends it;
PeerUntrust ends it. varde-ctl peer allow-push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-10-03 13:21:50 +02:00
co-authored by Claude Opus 5.5
parent 0006a188e3
commit 2063d11890
6 changed files with 167 additions and 11 deletions
+46
View File
@@ -422,3 +422,49 @@ fn push_rejected_without_receiver_trust() {
// And the receiver holds none of it.
assert!(!is_complete(&b.socket, &hash));
}
/// A push allowance is enough on both sides: two daemons that only
/// allowed pushes with each other (strangers sharing a place, in redoal)
/// exchange content without trusting each other - and the allowance
/// grants nothing else, so neither lists the other as a trusted peer.
#[test]
fn push_allowance_is_enough_and_is_not_trust() {
let _serial = MDNS_SERIAL.lock().unwrap_or_else(|e| e.into_inner());
let dir_a = tempfile::tempdir().unwrap();
let dir_b = tempfile::tempdir().unwrap();
let a = support::spawn_daemon_with_env(dir_a.path(), &[("VARDE_DISCOVERY", "true")]);
let b = support::spawn_daemon_with_env(dir_b.path(), &[("VARDE_DISCOVERY", "true")]);
let mut client_a = support::Client::connect(&a.socket);
let mut client_b = support::Client::connect(&b.socket);
let id_a = node_id(&mut client_a);
let id_b = node_id(&mut client_b);
let dir = tempfile::tempdir().unwrap();
let src = dir.path().join("voice.bin");
let payload = vec![7u8; 120_000];
std::fs::write(&src, &payload).unwrap();
let hash = add_file(&mut client_a, &src);
pin(&mut client_a, &hash, false);
assert!(client_a.request(&Request::PeerAllowPush { node_id: id_b.clone(), ttl_secs: 600 }).ok);
assert!(client_b.request(&Request::PeerAllowPush { node_id: id_a, ttl_secs: 600 }).ok);
match client_a.request(&Request::PeerList {}).data {
Some(ResponseData::Peers { peers }) => assert!(peers.is_empty(), "an allowance is not trust: {peers:?}"),
other => panic!("unexpected peer list: {other:?}"),
}
// The peer's address arrives by mdns; retry until it does.
let deadline = Instant::now() + Duration::from_secs(30);
let reply = loop {
let reply = client_a.request(&Request::Push { hash: hash.clone(), node_id: id_b.clone() });
if reply.ok || Instant::now() > deadline {
break reply;
}
std::thread::sleep(Duration::from_millis(500));
};
if !reply.ok {
eprintln!("SKIP: push never reached the peer (multicast unavailable?): {:?}", reply.error);
return;
}
assert!(wait_complete(&b.socket, &hash, Duration::from_secs(60)), "pushed content not complete on receiver");
}