10 Commits
Author SHA1 Message Date
Bendik Aagaard LynghaugandClaude Fable 5.1 7916e59acb release v0.1.9
ci / quality (push) Failing after 3s
release / build (aarch64-unknown-linux-gnu) (push) Successful in 2m23s
release / build (x86_64-unknown-linux-gnu) (push) Successful in 2m1s
release / publish (push) Successful in 47s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:58:27 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 458c2a2266 The socket unit owns /run/varde; the service names no runtime directory
RuntimeDirectoryPreserve=yes (0.1.7) made systemd privatise the
directory under DynamicUser: /run/varde became a symlink into
/run/private, 0700, and no unprivileged client - the redoal relay, a
desktop app - could connect. Without RuntimeDirectory= on the service
the socket unit creates the directory (DirectoryMode=0755), nothing
removes it on a service stop, and nothing privatises it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:56:47 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 a1776dbbed release v0.1.8
ci / quality (push) Failing after 9s
release / build (aarch64-unknown-linux-gnu) (push) Successful in 2m31s
release / build (x86_64-unknown-linux-gnu) (push) Successful in 2m2s
release / publish (push) Successful in 47s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:55:18 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 ddfb983108 iroh 1.3.0 in the lock, this time
0.1.7's bump never reached Cargo.lock: the update ran through a pipe
that closed early and cargo died before writing it. Verified in the
lock now; the suite passes on 1.3.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:53:41 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 0f2b0504d5 release v0.1.7
ci / quality (push) Failing after 5s
release / build (aarch64-unknown-linux-gnu) (push) Successful in 2m30s
release / build (x86_64-unknown-linux-gnu) (push) Successful in 2m16s
release / publish (push) Successful in 46s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:45:20 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 08fcba749a iroh 1.3, and a socket that survives a service restart
iroh 1.0.2 -> 1.3.0 (relay reconnects that keep answering, rate-limit
notices from relays, the n0 DNS resolver with configurable fallbacks,
relay connection metrics), iroh-mdns-address-lookup 0.4 -> 0.6,
n0-future 0.1 -> 0.3. No code changes were needed; the suite passes.

varde.service now keeps /run/varde across restarts
(RuntimeDirectoryPreserve=yes): stopping the service removed the
directory and with it the socket unit's file, leaving varde.socket
"active" on an unlinked path after any service restart. The install
notes say to restart the socket, which cycles both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 13:43:43 +02:00
Bendik Aagaard LynghaugandClaude Opus 5.5 6ca859c691 release v0.1.6
ci / quality (push) Failing after 5s
release / build (aarch64-unknown-linux-gnu) (push) Successful in 2m25s
release / build (x86_64-unknown-linux-gnu) (push) Successful in 2m0s
release / publish (push) Successful in 48s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:30:44 +02:00
Bendik Aagaard LynghaugandClaude Opus 5.5 c2b9167e1e Pushes name the peer by ticket, and an allowance can confirm its push
PeerAllowPush and Push take a blob ticket the peer issued as well as a
NodeId; the ticket's addresses are remembered, so the push dials
directly. A peer allowed to push may observe too: the sender confirms a
push by observing it, and without that every allowance-only push
reported failure though it had landed. The allowance test now fails
instead of skipping on anything but an unreachable peer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:29:03 +02:00
Bendik Aagaard LynghaugandClaude Opus 5.5 4d9985c9cb release v0.1.5
ci / quality (push) Failing after 5s
release / build (aarch64-unknown-linux-gnu) (push) Successful in 2m26s
release / build (x86_64-unknown-linux-gnu) (push) Successful in 2m18s
release / publish (push) Successful in 47s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:24:51 +02:00
Bendik Aagaard LynghaugandClaude Opus 5.5 2063d11890 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>
2026-10-03 13:21:50 +02:00
13 changed files with 378 additions and 394 deletions
Generated
+148 -371
View File
@@ -431,9 +431,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "chacha20"
@@ -581,16 +581,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
@@ -631,24 +621,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "crossbeam-channel"
version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.22"
@@ -722,41 +694,6 @@ dependencies = [
"syn 2.0.118",
]
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.118",
]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn 2.0.118",
]
[[package]]
name = "data-encoding"
version = "2.11.0"
@@ -814,65 +751,13 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
[[package]]
name = "derive_builder"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.118",
]
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl 1.0.0",
]
[[package]]
name = "derive_more"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
dependencies = [
"derive_more-impl 2.1.1",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.118",
"unicode-xid",
"derive_more-impl",
]
[[package]]
@@ -966,12 +851,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "either"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
[[package]]
name = "embedded-io"
version = "0.4.0"
@@ -1406,35 +1285,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hickory-net"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183"
dependencies = [
"async-trait",
"bytes",
"cfg-if",
"data-encoding",
"futures-channel",
"futures-io",
"futures-util",
"h2",
"hickory-proto",
"http",
"idna",
"ipnet",
"jni 0.22.4",
"rand 0.10.2",
"rustls",
"thiserror 2.0.18",
"tinyvec",
"tokio",
"tokio-rustls",
"tracing",
"url",
]
[[package]]
name = "hickory-proto"
version = "0.26.1"
@@ -1446,43 +1296,13 @@ dependencies = [
"ipnet",
"jni 0.22.4",
"once_cell",
"prefix-trie",
"rand 0.10.2",
"ring",
"thiserror 2.0.18",
"tinyvec",
"tracing",
"url",
]
[[package]]
name = "hickory-resolver"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c"
dependencies = [
"cfg-if",
"futures-util",
"hickory-net",
"hickory-proto",
"ipconfig",
"ipnet",
"jni 0.22.4",
"moka",
"ndk-context",
"once_cell",
"parking_lot",
"rand 0.10.2",
"resolv-conf",
"rustls",
"smallvec",
"system-configuration",
"thiserror 2.0.18",
"tokio",
"tokio-rustls",
"tracing",
]
[[package]]
name = "http"
version = "1.4.2"
@@ -1703,12 +1523,6 @@ dependencies = [
"zerovec",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "identity-hash"
version = "0.1.0"
@@ -1802,15 +1616,12 @@ name = "ipnet"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
dependencies = [
"serde",
]
[[package]]
name = "iroh"
version = "1.0.2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fca9b4b462c343ff88fc0af4096c186f939b602a0bc08723536ef2c31c93971"
checksum = "885787b892b5e2507c701f132ecbd45d2bad4bbb75157a19427087c16dadb833"
dependencies = [
"backon",
"blake3",
@@ -1818,11 +1629,10 @@ dependencies = [
"cfg_aliases",
"ctutils",
"data-encoding",
"derive_more 2.1.1",
"derive_more",
"ed25519-dalek",
"futures-util",
"getrandom 0.4.3",
"hickory-resolver",
"http",
"ipnet",
"iroh-base",
@@ -1830,7 +1640,7 @@ dependencies = [
"iroh-metrics",
"iroh-relay",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"n0-watcher",
"netwatch",
"noq",
@@ -1859,14 +1669,14 @@ dependencies = [
[[package]]
name = "iroh-base"
version = "1.0.3"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6be73e16ee21c923aca9b3121aaa0db936f7c7ecc156ff47b8dac944c68d59a8"
checksum = "6ae9092be76c9f5429776ab3394f5a5a78dc19dc2524267e884a5b9781546c3f"
dependencies = [
"curve25519-dalek",
"data-encoding",
"data-encoding-macro",
"derive_more 2.1.1",
"derive_more",
"ed25519-dalek",
"getrandom 0.4.3",
"n0-error",
@@ -1889,7 +1699,7 @@ dependencies = [
"chrono",
"constant_time_eq",
"data-encoding",
"derive_more 2.1.1",
"derive_more",
"genawaiter",
"getrandom 0.4.3",
"hex",
@@ -1901,7 +1711,7 @@ dependencies = [
"iroh-util",
"irpc",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"nested_enum_utils",
"noq",
"postcard",
@@ -1919,18 +1729,17 @@ dependencies = [
[[package]]
name = "iroh-dns"
version = "1.0.2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "516e4eedc38e33ab69a6bd325520332dc3d67b25454e2d590ebb84a25240dd9a"
checksum = "80276761b56e904e26ea71d0863beef0bb8d5ab6b639cbd1338e4b615209e3a1"
dependencies = [
"arc-swap",
"cfg_aliases",
"derive_more 2.1.1",
"hickory-resolver",
"derive_more",
"iroh-base",
"n0-dns-resolver",
"n0-error",
"n0-future 0.3.2",
"ndk-context",
"n0-future",
"portable-atomic",
"rand 0.10.2",
"rustls",
@@ -1956,17 +1765,17 @@ dependencies = [
[[package]]
name = "iroh-mdns-address-lookup"
version = "0.4.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c1f941695731bc3999d8c13d7e94d50e229427da81ac957eec3818264f17559"
checksum = "7afb03c296022fcb724a7bb76dbb8dcca6aac4f4eb65df161e084b7276c93d8c"
dependencies = [
"data-encoding",
"derive_more 2.1.1",
"derive_more",
"futures-util",
"iroh",
"iroh-base",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"n0-watcher",
"swarm-discovery",
"tokio",
@@ -1976,9 +1785,9 @@ dependencies = [
[[package]]
name = "iroh-metrics"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291065721ad7c477b972e581bbc528df031dc8eb5e39fe1ff3300ae5dfb157ef"
checksum = "8ede55536349842337f7cdc63012ec33dc637945f3259c98a0763aac364cdf09"
dependencies = [
"iroh-metrics-derive",
"itoa",
@@ -2003,17 +1812,16 @@ dependencies = [
[[package]]
name = "iroh-relay"
version = "1.0.2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8149bb6a57126225a07d6928846d82dcedfd24ea0f863ef7b2eb475e1d726354"
checksum = "ee116a8233f84980574bb8d11e4517503080cd2c3605bafca04ee9c35d708bd9"
dependencies = [
"blake3",
"bytes",
"cfg_aliases",
"data-encoding",
"derive_more 2.1.1",
"derive_more",
"getrandom 0.4.3",
"hickory-resolver",
"http",
"http-body-util",
"hyper",
@@ -2023,7 +1831,7 @@ dependencies = [
"iroh-metrics",
"lru",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"noq",
"noq-proto",
"num_enum",
@@ -2042,7 +1850,6 @@ dependencies = [
"tokio-websockets",
"tracing",
"url",
"vergen-gitcl",
"webpki-roots",
"ws_stream_wasm",
]
@@ -2054,7 +1861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da53233419ca36bf521ed45683b7748366f9b233032891eefc2d70567a84ac54"
dependencies = [
"data-encoding",
"derive_more 2.1.1",
"derive_more",
"iroh-base",
"n0-error",
"postcard",
@@ -2067,10 +1874,10 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20e41eb982f15230c55f0a70a74a514360e1f565b07861924fd0e8db172b3d00"
dependencies = [
"derive_more 2.1.1",
"derive_more",
"iroh",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"tokio",
"tracing",
]
@@ -2085,7 +1892,7 @@ dependencies = [
"futures-util",
"irpc-derive",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"noq",
"postcard",
"rcgen",
@@ -2326,20 +2133,28 @@ dependencies = [
]
[[package]]
name = "moka"
version = "0.12.15"
name = "n0-dns-resolver"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
checksum = "535c99c9a786bee714155d2ee4fc2477405c2c43536e1bc6a51de09a0d1448f7"
dependencies = [
"crossbeam-channel",
"crossbeam-epoch",
"crossbeam-utils",
"equivalent",
"parking_lot",
"portable-atomic",
"smallvec",
"tagptr",
"uuid",
"derive_more",
"ipconfig",
"jni 0.22.4",
"lru",
"n0-error",
"n0-future",
"ndk-context",
"rand 0.10.2",
"reqwest",
"rustc-hash",
"rustls",
"simple-dns",
"system-configuration",
"tokio",
"tokio-rustls",
"tracing",
"webpki-roots",
]
[[package]]
@@ -2363,27 +2178,6 @@ dependencies = [
"syn 2.0.118",
]
[[package]]
name = "n0-future"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794"
dependencies = [
"cfg_aliases",
"derive_more 1.0.0",
"futures-buffered",
"futures-lite",
"futures-util",
"js-sys",
"pin-project",
"send_wrapper",
"tokio",
"tokio-util",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-time",
]
[[package]]
name = "n0-future"
version = "0.3.2"
@@ -2391,7 +2185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe"
dependencies = [
"cfg_aliases",
"derive_more 2.1.1",
"derive_more",
"futures-buffered",
"futures-lite",
"futures-util",
@@ -2411,9 +2205,9 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
dependencies = [
"derive_more 2.1.1",
"derive_more",
"n0-error",
"n0-future 0.3.2",
"n0-future",
]
[[package]]
@@ -2448,9 +2242,9 @@ dependencies = [
"libc",
"mac-addr",
"ndk-context",
"netlink-packet-core",
"netlink-packet-route",
"netlink-sys",
"netlink-packet-core 0.8.2",
"netlink-packet-route 0.31.0",
"netlink-sys 0.8.8",
"objc2",
"objc2-core-foundation",
"objc2-core-wlan",
@@ -2461,6 +2255,30 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "netdev"
version = "0.46.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c52c2584961c68f5a6e3356797344061f818c93b8acc9cd6d7e284795e563e"
dependencies = [
"block2",
"dispatch2",
"dlopen2",
"ipnet",
"jni 0.21.1",
"libc",
"mac-addr",
"ndk-context",
"netlink-packet-core 0.9.0",
"netlink-packet-route 0.33.0",
"netlink-sys 0.9.0",
"objc2-core-foundation",
"objc2-system-configuration",
"once_cell",
"plist",
"windows-sys 0.61.2",
]
[[package]]
name = "netlink-packet-core"
version = "0.8.2"
@@ -2470,6 +2288,12 @@ dependencies = [
"paste",
]
[[package]]
name = "netlink-packet-core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d6e2daf9a8c2e21302714706860a0e6be02e03d17294ecc66b354ea7d4059dd"
[[package]]
name = "netlink-packet-route"
version = "0.31.0"
@@ -2479,7 +2303,20 @@ dependencies = [
"bitflags",
"libc",
"log",
"netlink-packet-core",
"netlink-packet-core 0.8.2",
]
[[package]]
name = "netlink-packet-route"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d48ffc8b73a506e1ff0878528c72668f2bfbc3d875b6be890a96be5d0d5576"
dependencies = [
"bitflags",
"libc",
"log",
"netlink-packet-core 0.9.0",
"zerocopy",
]
[[package]]
@@ -2492,8 +2329,8 @@ dependencies = [
"futures-channel",
"futures-util",
"log",
"netlink-packet-core",
"netlink-sys",
"netlink-packet-core 0.8.2",
"netlink-sys 0.8.8",
"thiserror 2.0.18",
]
@@ -2511,26 +2348,38 @@ dependencies = [
]
[[package]]
name = "netwatch"
version = "0.19.1"
name = "netlink-sys"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d9cbe01741347ef750d743d6690603f5eed8341e679fb51c8e629337aa11976"
checksum = "c99d38e00b420df49e940fe0826e667c3dad82ac68eb4c2bbf754c1c14a83a10"
dependencies = [
"bytes",
"libc",
"log",
]
[[package]]
name = "netwatch"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39da9cad5f23aa43401f09497d3b280e51b5feba115d9ffbf38ca35d6ff95e96"
dependencies = [
"atomic-waker",
"bytes",
"cfg_aliases",
"derive_more 2.1.1",
"derive_more",
"ipnet",
"js-sys",
"libc",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"n0-watcher",
"netdev",
"netlink-packet-core",
"netlink-packet-route",
"netdev 0.45.0",
"netdev 0.46.3",
"netlink-packet-core 0.8.2",
"netlink-packet-route 0.31.0",
"netlink-proto",
"netlink-sys",
"netlink-sys 0.8.8",
"noq-udp",
"objc2-core-foundation",
"objc2-system-configuration",
@@ -2559,13 +2408,13 @@ dependencies = [
[[package]]
name = "noq"
version = "1.0.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf95190af1bd4a00a10e8255ca0c8ddd9e9a9f5e79151d7a7eb6d56aff5dc89"
checksum = "b78be567e796cfa74bb9bdc4117790af2d505eb887019cf8803244353eb09d89"
dependencies = [
"bytes",
"cfg_aliases",
"derive_more 2.1.1",
"derive_more",
"noq-proto",
"noq-udp",
"pin-project-lite",
@@ -2581,13 +2430,13 @@ dependencies = [
[[package]]
name = "noq-proto"
version = "1.1.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baa7b5ccd819a9c68a0d955e67a881032d09b1a17219b1f90b0997a0888e1a15"
checksum = "7c1e5b6fe668491eca022f745a0a9402585626c73a7b839b3424ace15d6a9c8f"
dependencies = [
"aes-gcm",
"bytes",
"derive_more 2.1.1",
"derive_more",
"enum-assoc",
"fastbloom",
"getrandom 0.4.3",
@@ -2610,9 +2459,9 @@ dependencies = [
[[package]]
name = "noq-udp"
version = "1.0.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3137a52df66c20090a889828d1c655f21f52294cba64e5c4fbb04fc83eee7c8e"
checksum = "4dc50afea61aff926e150a36c31f06094608848e114a3fe667d76ec233163b1c"
dependencies = [
"cfg_aliases",
"libc",
@@ -2686,15 +2535,6 @@ dependencies = [
"syn 2.0.118",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "objc2"
version = "0.6.4"
@@ -2984,19 +2824,19 @@ dependencies = [
[[package]]
name = "portmapper"
version = "0.19.1"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3713e4977408279158444a18c1a01ac9bf2e7eaf1fbfd1a19ac9cd18d90721"
checksum = "ca97242f016e090a25330613bc2382aab65eb22f9149dbe84d8f8e711d49a530"
dependencies = [
"base64",
"bytes",
"derive_more 2.1.1",
"derive_more",
"hyper-util",
"igd-next",
"iroh-metrics",
"libc",
"n0-error",
"n0-future 0.3.2",
"n0-future",
"netwatch",
"num_enum",
"rand 0.10.2",
@@ -3070,17 +2910,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "prefix-trie"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7"
dependencies = [
"either",
"ipnet",
"num-traits",
]
[[package]]
name = "proc-macro-crate"
version = "3.5.0"
@@ -3381,12 +3210,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "resolv-conf"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
[[package]]
name = "ring"
version = "0.17.14"
@@ -3481,7 +3304,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
dependencies = [
"core-foundation 0.10.1",
"core-foundation",
"core-foundation-sys",
"jni 0.22.4",
"log",
@@ -3574,7 +3397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
dependencies = [
"bitflags",
"core-foundation 0.10.1",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
@@ -3767,9 +3590,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "simple-dns"
version = "0.11.3"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4"
checksum = "2b6f884fa9a8d48101774bfbd3aeb81e968dd22cffd19a372da69f183db22c1a"
dependencies = [
"bitflags",
]
@@ -3973,12 +3796,12 @@ dependencies = [
[[package]]
name = "system-configuration"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
checksum = "501336eb7ba9e417300a6a0fa985721065467aa83a6dcf0422a8e43e4c0328fa"
dependencies = [
"bitflags",
"core-foundation 0.9.4",
"core-foundation",
"system-configuration-sys",
]
@@ -3992,12 +3815,6 @@ dependencies = [
"libc",
]
[[package]]
name = "tagptr"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
[[package]]
name = "tempfile"
version = "3.27.0"
@@ -4005,7 +3822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom 0.4.3",
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.2",
@@ -4068,9 +3885,7 @@ checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
dependencies = [
"deranged",
"js-sys",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde_core",
"time-core",
@@ -4477,7 +4292,6 @@ version = "1.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a"
dependencies = [
"getrandom 0.4.3",
"js-sys",
"serde_core",
"wasm-bindgen",
@@ -4491,7 +4305,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "varde-ctl"
version = "0.1.4"
version = "0.1.9"
dependencies = [
"anyhow",
"clap",
@@ -4504,7 +4318,7 @@ dependencies = [
[[package]]
name = "varde-daemon"
version = "0.1.4"
version = "0.1.9"
dependencies = [
"anyhow",
"base64",
@@ -4512,7 +4326,7 @@ dependencies = [
"iroh-blobs",
"iroh-mdns-address-lookup",
"irpc",
"n0-future 0.1.3",
"n0-future",
"postcard",
"proptest",
"reflink-copy",
@@ -4530,49 +4344,12 @@ dependencies = [
[[package]]
name = "varde-proto"
version = "0.1.4"
version = "0.1.9"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "vergen"
version = "9.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75"
dependencies = [
"anyhow",
"derive_builder",
"rustversion",
"vergen-lib",
]
[[package]]
name = "vergen-gitcl"
version = "9.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9"
dependencies = [
"anyhow",
"derive_builder",
"rustversion",
"time",
"vergen",
"vergen-lib",
]
[[package]]
name = "vergen-lib"
version = "9.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569"
dependencies = [
"anyhow",
"derive_builder",
"rustversion",
]
[[package]]
name = "version_check"
version = "0.9.5"
+1 -1
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["varde-proto", "varde-daemon", "varde-ctl"]
[workspace.package]
version = "0.1.4"
version = "0.1.9"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://project.uhhm.no/uhhm/varde"
+2 -2
View File
@@ -5,6 +5,6 @@ post_install() {
}
post_upgrade() {
echo ":: Restart a running daemon to pick up the new version:"
echo " systemctl --user try-restart varde.service (and/or: systemctl try-restart varde.service)"
echo ":: Restart a running daemon to pick up the new version - the socket, not the service:"
echo " systemctl try-restart varde.socket; systemctl --user try-restart varde.socket"
}
+7 -1
View File
@@ -15,7 +15,13 @@ Restart=on-failure
# Hardening
DynamicUser=yes
StateDirectory=varde
RuntimeDirectory=varde
# No RuntimeDirectory= here: varde.socket creates /run/varde for its
# socket file, and the service only uses the activation socket. With
# RuntimeDirectory= on the service, stopping it removed the socket file
# from under the socket unit (0.1.6 and earlier), and preserving it
# (0.1.7/0.1.8) made systemd privatise the directory under DynamicUser -
# /run/varde -> /run/private/varde, 0700 - so no unprivileged client
# could connect at all.
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
+3
View File
@@ -5,6 +5,9 @@ Description=varde API socket
[Socket]
ListenStream=/run/varde/varde.sock
SocketMode=0666
# The directory is this unit's, world-readable, so clients of any user
# reach the socket (see varde.service for why the service must not own it).
DirectoryMode=0755
[Install]
WantedBy=sockets.target
+13 -1
View File
@@ -73,7 +73,8 @@ enum Command {
/// Peer trust operations
#[command(subcommand)]
Peer(PeerCommand),
/// Push fully-present content to a trusted peer
/// Push fully-present content to a trusted peer, or one allowed to
/// exchange pushes
Push {
/// BLAKE3 hash (hex)
hash: String,
@@ -116,6 +117,14 @@ enum PeerCommand {
/// iroh NodeId (z-base-32)
node_id: String,
},
/// Allow pushes with a peer for a while, without trusting it
AllowPush {
/// iroh NodeId (z-base-32)
node_id: String,
/// How long, in seconds (at most a day)
#[arg(long, default_value_t = 1800)]
ttl: u64,
},
/// List trusted peers
List,
}
@@ -187,6 +196,9 @@ fn to_request(command: Command) -> Result<Request> {
},
Command::Peer(PeerCommand::Trust { node_id }) => Request::PeerTrust { node_id },
Command::Peer(PeerCommand::Untrust { node_id }) => Request::PeerUntrust { node_id },
Command::Peer(PeerCommand::AllowPush { node_id, ttl }) => {
Request::PeerAllowPush { node_id, ttl_secs: ttl }
}
Command::Peer(PeerCommand::List) => Request::PeerList {},
Command::Push { hash, node_id } => Request::Push { hash, node_id },
Command::Gc => Request::Gc {},
+2 -2
View File
@@ -19,10 +19,10 @@ iroh-blobs = { workspace = true }
# Request::Put / Read carry content inline, base64.
base64 = "0.22"
# mDNS/local-network address lookup left iroh core in 1.0.
iroh-mdns-address-lookup = "0.4"
iroh-mdns-address-lookup = "0.6"
# Interop with iroh-blobs streams and channels; both are already in the
# dependency tree via iroh-blobs.
n0-future = "0.1"
n0-future = "0.3"
irpc = "0.17"
# Feature-gated D-Bus client for NetworkManager metered status.
zbus = { version = "5", optional = true, default-features = false, features = ["tokio"] }
+37 -8
View File
@@ -335,6 +335,26 @@ impl Daemon {
}
}
/// The peer a request names: a NodeId, or a blob ticket from it (whose
/// addresses are remembered, so dialing it needs no discovery). An app
/// that knows peers by the tickets they hand out - redoal does - can
/// allow and push without unpacking them.
fn peer_of(&self, peer: &str) -> Result<iroh::EndpointId, OpError> {
if let Ok(id) = peer.parse::<iroh::EndpointId>() {
return Ok(id);
}
match crate::transfer::parse_ticket(peer) {
Ok((_, _, addr)) => {
let id = addr.id;
self.transfer.remember(addr);
Ok(id)
}
Err(_) => Err(OpError::InvalidArgument(format!(
"{peer:?} is neither a node id nor a ticket"
))),
}
}
/// Trusted peers seen on the LAN recently.
fn present_trusted_peers(&self) -> Vec<PeerInfo> {
let peers = self.lan_peers.lock().expect("lan peers lock");
@@ -566,24 +586,33 @@ impl Daemon {
let parsed: iroh::EndpointId = node_id
.parse()
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
if !self.meta.untrust_peer(&parsed.to_string())? {
let was_trusted = self.meta.untrust_peer(&parsed.to_string())?;
let was_allowed = self.meta.disallow_push(&parsed.to_string())?;
if !was_trusted && !was_allowed {
return Err(OpError::NotFound(format!("{parsed} was not trusted")));
}
Ok(ResponseData::Done {})
}
Request::PeerAllowPush { node_id, ttl_secs } => {
let parsed = self.peer_of(&node_id)?;
let ttl = ttl_secs.min(varde_proto::MAX_PUSH_TTL_SECS);
self.meta
.allow_push(&parsed.to_string(), crate::meta::unix_now() + ttl)?;
debug!(peer = %parsed, ttl, "pushes allowed");
Ok(ResponseData::Done {})
}
Request::PeerList {} => Ok(ResponseData::Peers {
peers: self.present_trusted_peers(),
}),
Request::Push { hash, node_id } => {
let parsed = parse_hash(&hash)?;
let peer: iroh::EndpointId = node_id
.parse()
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
// Consent, sending side: we only push to peers we trust.
// (The receiver independently requires that it trusts us.)
if !self.meta.is_trusted(&peer.to_string()) {
let peer = self.peer_of(&node_id)?;
// Consent, sending side: we only push to peers we trust or
// hold a push allowance for. (The receiver independently
// requires the same of us.)
if !self.meta.may_push(&peer.to_string()) {
return Err(OpError::InvalidArgument(format!(
"{peer} is not a trusted peer; trust it before pushing"
"{peer} is neither trusted nor allowed to exchange pushes; trust it or allow pushes first"
)));
}
let (_, _, complete) = self.store.presence(parsed).await?;
+60
View File
@@ -40,6 +40,10 @@ struct MetaState {
/// Trusted peer NodeIds (z-base-32).
#[serde(default)]
trusted_peers: BTreeSet<String>,
/// Peers allowed to push to us and be pushed to, until a unix time
/// (`PeerAllowPush`): consent for that one thing, lapsing on its own.
#[serde(default)]
push_peers: BTreeMap<String, u64>,
/// Hashes (hex) the user shared via ticket export: standing consent
/// to serve them to anyone, like an `open_lan` pin.
#[serde(default)]
@@ -164,6 +168,31 @@ impl Meta {
.clone()
}
/// Allow pushes with `node_id` until `until` (unix seconds). Extends,
/// never shortens, an allowance already held; expired ones are
/// dropped on the way.
pub fn allow_push(&self, node_id: &str, until: u64) -> Result<()> {
let now = unix_now();
self.mutate(|s| {
s.push_peers.retain(|_, u| *u > now);
let entry = s.push_peers.entry(node_id.to_string()).or_insert(0);
*entry = (*entry).max(until);
})
}
/// Whether pushes with `node_id` are allowed now: a trusted peer, or
/// one holding an unexpired push allowance.
pub fn may_push(&self, node_id: &str) -> bool {
let state = self.state.lock().expect("meta lock poisoned");
state.trusted_peers.contains(node_id)
|| state.push_peers.get(node_id).is_some_and(|u| *u > unix_now())
}
/// End a push allowance. Returns whether there was one.
pub fn disallow_push(&self, node_id: &str) -> Result<bool> {
self.mutate(|s| s.push_peers.remove(node_id).is_some())
}
pub fn is_trusted(&self, node_id: &str) -> bool {
self.state
.lock()
@@ -173,6 +202,14 @@ impl Meta {
}
}
/// Seconds since the unix epoch.
pub fn unix_now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -201,4 +238,27 @@ mod tests {
assert!(meta.unpin("h").unwrap());
assert!(!meta.is_pinned("h"));
}
#[test]
fn a_push_allowance_lapses_and_never_shortens() {
let dir = tempfile::tempdir().unwrap();
let meta = Meta::load(dir.path()).unwrap();
let now = unix_now();
assert!(!meta.may_push("p"));
meta.allow_push("p", now + 600).unwrap();
assert!(meta.may_push("p"));
assert!(!meta.is_trusted("p"), "a push allowance is not trust");
meta.allow_push("p", now + 10).unwrap();
assert!(meta.may_push("p"), "a shorter ask does not cut it short");
meta.allow_push("q", now.saturating_sub(1)).unwrap();
assert!(!meta.may_push("q"), "expired");
// Survives a reload.
let again = Meta::load(dir.path()).unwrap();
assert!(again.may_push("p"));
assert!(again.disallow_push("p").unwrap());
assert!(!again.may_push("p"));
// Full trust allows pushes too.
again.trust_peer("t").unwrap();
assert!(again.may_push("t"));
}
}
+18 -8
View File
@@ -111,6 +111,8 @@ pub struct Gate {
#[derive(Debug, Clone)]
struct ConnInfo {
trusted: bool,
/// Trusted, or holding a push allowance (`PeerAllowPush`).
may_push: bool,
endpoint_id: Option<String>,
}
@@ -142,6 +144,11 @@ pub fn provider_events(gate: Gate) -> EventSender {
.endpoint_id
.map(|id| gate.meta.is_trusted(&id.to_string()))
.unwrap_or(false);
let may_push = m
.inner
.endpoint_id
.map(|id| gate.meta.may_push(&id.to_string()))
.unwrap_or(false);
let ClientConnected {
connection_id,
endpoint_id,
@@ -151,6 +158,7 @@ pub fn provider_events(gate: Gate) -> EventSender {
connection_id,
ConnInfo {
trusted,
may_push,
endpoint_id: endpoint_id.map(|id| id.to_string()),
},
);
@@ -192,11 +200,12 @@ pub fn provider_events(gate: Gate) -> EventSender {
ProviderMessage::ObserveRequestReceived(m) => {
// Presence is information too: gate it like data.
// Bitfields are metadata, not payload, so trusted
// peers may observe even while serving is off or the
// connection is metered (push confirmation needs it).
// peers - and peers allowed to push, whose push is
// confirmed by observing it - may observe even while
// serving is off or the connection is metered.
let trusted = conns
.get(&m.inner.connection_id)
.map(|i| i.trusted)
.map(|i| i.trusted || i.may_push)
.unwrap_or(false);
let allowed = trusted
|| allow(&gate, &conns, m.inner.connection_id, [m.inner.request.hash]);
@@ -208,12 +217,13 @@ pub fn provider_events(gate: Gate) -> EventSender {
m.tx.send(verdict).await.ok();
}
ProviderMessage::PushRequestReceived(m) => {
// Inbound writes: trusted peers only, deferred while
// metered (RateLimited invites a retry later).
// Inbound writes: trusted peers and push allowances
// only, deferred while metered (RateLimited invites a
// retry later).
let info = conns.get(&m.inner.connection_id);
let trusted = info.map(|i| i.trusted).unwrap_or(false);
debug!(hash = %m.inner.request.hash.to_hex(), trusted, "push request received");
let verdict = if !trusted {
let may_push = info.map(|i| i.may_push).unwrap_or(false);
debug!(hash = %m.inner.request.hash.to_hex(), may_push, "push request received");
let verdict = if !may_push {
Err(AbortReason::Permission)
} else if gate.metered.is_metered() {
Err(AbortReason::RateLimited)
+9
View File
@@ -298,6 +298,15 @@ impl Transfer {
Ok(ticket.to_string())
}
/// Teach the endpoint where a peer can be reached (the addresses a
/// ticket carries), so a push dials it directly instead of waiting on
/// discovery.
pub fn remember(&self, addr: EndpointAddr) {
if !addr.addrs.is_empty() {
self.known_addrs.add_endpoint_info(addr);
}
}
/// Queue a background fetch of `content` from `providers`. Emits
/// progress events and [`Event::PinComplete`] when fully verified.
pub fn spawn_fetch(&self, content: HashAndFormat, providers: Vec<EndpointAddr>) {
+58
View File
@@ -422,3 +422,61 @@ 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 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);
// A knows B by a ticket B handed out (as redoal peers do), not by
// its bare node id.
let b_src = dir.path().join("b-own.bin");
std::fs::write(&b_src, vec![1u8; 1_000]).unwrap();
let b_hash = add_file(&mut client_b, &b_src);
let b_ticket = match client_b.request(&Request::TicketExport { hash: b_hash }).data {
Some(ResponseData::Ticket { ticket }) => ticket,
other => panic!("unexpected ticket reply: {other:?}"),
};
assert!(client_a.request(&Request::PeerAllowPush { node_id: b_ticket.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: b_ticket.clone() });
if reply.ok || Instant::now() > deadline {
break reply;
}
std::thread::sleep(Duration::from_millis(500));
};
if !reply.ok {
let message = reply.error.map(|e| e.message).unwrap_or_default();
// Only an unreachable peer is the environment's fault; any other
// refusal is a real failure.
assert!(message.contains("connect"), "push failed: {message}");
eprintln!("SKIP: push never reached the peer (multicast unavailable?): {message}");
return;
}
assert!(wait_complete(&b.socket, &hash, Duration::from_secs(60)), "pushed content not complete on receiver");
}
+20
View File
@@ -20,6 +20,9 @@ use serde::{Deserialize, Serialize};
/// Bumped on incompatible changes; reported in [`GlobalStatus`].
pub const PROTOCOL_VERSION: u32 = 2;
/// The longest a [`Request::PeerAllowPush`] allowance may last: a day.
pub const MAX_PUSH_TTL_SECS: u64 = 24 * 60 * 60;
/// The most bytes a [`Request::Put`] or a [`Request::Read`] reply carries
/// inline. Larger content goes through `Add`/`Materialize` and a path.
pub const MAX_INLINE_BYTES: u64 = 16 * 1024 * 1024;
@@ -116,6 +119,20 @@ pub enum Request {
/// The peer's iroh NodeId (z-base-32).
node_id: String,
},
/// Allow pushes between this daemon and a peer for `ttl_secs` (at most
/// [`MAX_PUSH_TTL_SECS`]): we may push to it, and accept what it pushes
/// to us. Nothing else - unlike [`Request::PeerTrust`] it neither
/// syncs the peer's pins nor serves it our content - so an app can
/// grant it to strangers it shares something with for a while (two
/// phones at the same place) and let it lapse. Asking again extends
/// it; [`Request::PeerUntrust`] ends it early. Added in varde 0.1.5.
PeerAllowPush {
/// The peer's iroh NodeId (z-base-32), or a blob ticket it issued
/// (varde 0.1.6+), whose addresses are then used to reach it.
node_id: String,
/// How long the allowance lasts, in seconds.
ttl_secs: u64,
},
/// List trusted peers and their current connectivity.
PeerList {},
/// Push fully-present content to a trusted peer, unprompted.
@@ -126,6 +143,9 @@ pub enum Request {
/// policy), so the content survives gc and shows up in `List`.
Push {
/// Hash (hex) of the fully-present blob or HashSeq root to push.
///
/// The receiver below may be a NodeId or, from varde 0.1.6, a blob
/// ticket it issued.
hash: String,
/// The receiving peer's iroh NodeId (z-base-32).
node_id: String,