Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f2b0504d5 | ||
|
|
08fcba749a | ||
|
|
6ca859c691 | ||
|
|
c2b9167e1e | ||
|
|
4d9985c9cb | ||
|
|
2063d11890 |
Generated
+33
-75
@@ -780,7 +780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
|
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"syn 2.0.118",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -845,34 +845,13 @@ dependencies = [
|
|||||||
"syn 2.0.118",
|
"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]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more-impl 2.1.1",
|
"derive_more-impl",
|
||||||
]
|
|
||||||
|
|
||||||
[[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",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1818,7 +1797,7 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"ctutils",
|
"ctutils",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
@@ -1830,7 +1809,7 @@ dependencies = [
|
|||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"iroh-relay",
|
"iroh-relay",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"netwatch",
|
"netwatch",
|
||||||
"noq",
|
"noq",
|
||||||
@@ -1866,7 +1845,7 @@ dependencies = [
|
|||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"data-encoding-macro",
|
"data-encoding-macro",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
@@ -1889,7 +1868,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"genawaiter",
|
"genawaiter",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -1901,7 +1880,7 @@ dependencies = [
|
|||||||
"iroh-util",
|
"iroh-util",
|
||||||
"irpc",
|
"irpc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"nested_enum_utils",
|
"nested_enum_utils",
|
||||||
"noq",
|
"noq",
|
||||||
"postcard",
|
"postcard",
|
||||||
@@ -1925,11 +1904,11 @@ checksum = "516e4eedc38e33ab69a6bd325520332dc3d67b25454e2d590ebb84a25240dd9a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"hickory-resolver",
|
"hickory-resolver",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
@@ -1956,17 +1935,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-mdns-address-lookup"
|
name = "iroh-mdns-address-lookup"
|
||||||
version = "0.4.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c1f941695731bc3999d8c13d7e94d50e229427da81ac957eec3818264f17559"
|
checksum = "7afb03c296022fcb724a7bb76dbb8dcca6aac4f4eb65df161e084b7276c93d8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"iroh",
|
"iroh",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"swarm-discovery",
|
"swarm-discovery",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -2011,7 +1990,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"hickory-resolver",
|
"hickory-resolver",
|
||||||
"http",
|
"http",
|
||||||
@@ -2023,7 +2002,7 @@ dependencies = [
|
|||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"lru",
|
"lru",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"noq",
|
"noq",
|
||||||
"noq-proto",
|
"noq-proto",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
@@ -2054,7 +2033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "da53233419ca36bf521ed45683b7748366f9b233032891eefc2d70567a84ac54"
|
checksum = "da53233419ca36bf521ed45683b7748366f9b233032891eefc2d70567a84ac54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"postcard",
|
"postcard",
|
||||||
@@ -2067,10 +2046,10 @@ version = "0.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20e41eb982f15230c55f0a70a74a514360e1f565b07861924fd0e8db172b3d00"
|
checksum = "20e41eb982f15230c55f0a70a74a514360e1f565b07861924fd0e8db172b3d00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"iroh",
|
"iroh",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -2085,7 +2064,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"irpc-derive",
|
"irpc-derive",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"noq",
|
"noq",
|
||||||
"postcard",
|
"postcard",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
@@ -2363,27 +2342,6 @@ dependencies = [
|
|||||||
"syn 2.0.118",
|
"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]]
|
[[package]]
|
||||||
name = "n0-future"
|
name = "n0-future"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -2391,7 +2349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe"
|
checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"futures-buffered",
|
"futures-buffered",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@@ -2411,9 +2369,9 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
|
checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2519,12 +2477,12 @@ dependencies = [
|
|||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"netdev",
|
"netdev",
|
||||||
"netlink-packet-core",
|
"netlink-packet-core",
|
||||||
@@ -2565,7 +2523,7 @@ checksum = "4bf95190af1bd4a00a10e8255ca0c8ddd9e9a9f5e79151d7a7eb6d56aff5dc89"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"noq-proto",
|
"noq-proto",
|
||||||
"noq-udp",
|
"noq-udp",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -2587,7 +2545,7 @@ checksum = "baa7b5ccd819a9c68a0d955e67a881032d09b1a17219b1f90b0997a0888e1a15"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"bytes",
|
"bytes",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"enum-assoc",
|
"enum-assoc",
|
||||||
"fastbloom",
|
"fastbloom",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
@@ -2990,13 +2948,13 @@ checksum = "eb3713e4977408279158444a18c1a01ac9bf2e7eaf1fbfd1a19ac9cd18d90721"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"igd-next",
|
"igd-next",
|
||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"libc",
|
"libc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"netwatch",
|
"netwatch",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
@@ -4005,7 +3963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -4491,7 +4449,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-ctl"
|
name = "varde-ctl"
|
||||||
version = "0.1.4"
|
version = "0.1.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -4504,7 +4462,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-daemon"
|
name = "varde-daemon"
|
||||||
version = "0.1.4"
|
version = "0.1.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -4512,7 +4470,7 @@ dependencies = [
|
|||||||
"iroh-blobs",
|
"iroh-blobs",
|
||||||
"iroh-mdns-address-lookup",
|
"iroh-mdns-address-lookup",
|
||||||
"irpc",
|
"irpc",
|
||||||
"n0-future 0.1.3",
|
"n0-future",
|
||||||
"postcard",
|
"postcard",
|
||||||
"proptest",
|
"proptest",
|
||||||
"reflink-copy",
|
"reflink-copy",
|
||||||
@@ -4530,7 +4488,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-proto"
|
name = "varde-proto"
|
||||||
version = "0.1.4"
|
version = "0.1.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = ["varde-proto", "varde-daemon", "varde-ctl"]
|
members = ["varde-proto", "varde-daemon", "varde-ctl"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.4"
|
version = "0.1.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://project.uhhm.no/uhhm/varde"
|
repository = "https://project.uhhm.no/uhhm/varde"
|
||||||
|
|||||||
Vendored
+2
-2
@@ -5,6 +5,6 @@ post_install() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post_upgrade() {
|
post_upgrade() {
|
||||||
echo ":: Restart a running daemon to pick up the new version:"
|
echo ":: Restart a running daemon to pick up the new version - the socket, not the service:"
|
||||||
echo " systemctl --user try-restart varde.service (and/or: systemctl try-restart varde.service)"
|
echo " systemctl try-restart varde.socket; systemctl --user try-restart varde.socket"
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+4
@@ -16,6 +16,10 @@ Restart=on-failure
|
|||||||
DynamicUser=yes
|
DynamicUser=yes
|
||||||
StateDirectory=varde
|
StateDirectory=varde
|
||||||
RuntimeDirectory=varde
|
RuntimeDirectory=varde
|
||||||
|
# The socket unit's file lives in this directory: removing it on every
|
||||||
|
# service stop (the default) left varde.socket listening on an unlinked
|
||||||
|
# path after any restart - "active" with nothing to connect to.
|
||||||
|
RuntimeDirectoryPreserve=yes
|
||||||
NoNewPrivileges=yes
|
NoNewPrivileges=yes
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=yes
|
ProtectHome=yes
|
||||||
|
|||||||
+13
-1
@@ -73,7 +73,8 @@ enum Command {
|
|||||||
/// Peer trust operations
|
/// Peer trust operations
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
Peer(PeerCommand),
|
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 {
|
Push {
|
||||||
/// BLAKE3 hash (hex)
|
/// BLAKE3 hash (hex)
|
||||||
hash: String,
|
hash: String,
|
||||||
@@ -116,6 +117,14 @@ enum PeerCommand {
|
|||||||
/// iroh NodeId (z-base-32)
|
/// iroh NodeId (z-base-32)
|
||||||
node_id: String,
|
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 trusted peers
|
||||||
List,
|
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::Trust { node_id }) => Request::PeerTrust { node_id },
|
||||||
Command::Peer(PeerCommand::Untrust { node_id }) => Request::PeerUntrust { 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::Peer(PeerCommand::List) => Request::PeerList {},
|
||||||
Command::Push { hash, node_id } => Request::Push { hash, node_id },
|
Command::Push { hash, node_id } => Request::Push { hash, node_id },
|
||||||
Command::Gc => Request::Gc {},
|
Command::Gc => Request::Gc {},
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ iroh-blobs = { workspace = true }
|
|||||||
# Request::Put / Read carry content inline, base64.
|
# Request::Put / Read carry content inline, base64.
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
# mDNS/local-network address lookup left iroh core in 1.0.
|
# 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
|
# Interop with iroh-blobs streams and channels; both are already in the
|
||||||
# dependency tree via iroh-blobs.
|
# dependency tree via iroh-blobs.
|
||||||
n0-future = "0.1"
|
n0-future = "0.3"
|
||||||
irpc = "0.17"
|
irpc = "0.17"
|
||||||
# Feature-gated D-Bus client for NetworkManager metered status.
|
# Feature-gated D-Bus client for NetworkManager metered status.
|
||||||
zbus = { version = "5", optional = true, default-features = false, features = ["tokio"] }
|
zbus = { version = "5", optional = true, default-features = false, features = ["tokio"] }
|
||||||
|
|||||||
@@ -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.
|
/// Trusted peers seen on the LAN recently.
|
||||||
fn present_trusted_peers(&self) -> Vec<PeerInfo> {
|
fn present_trusted_peers(&self) -> Vec<PeerInfo> {
|
||||||
let peers = self.lan_peers.lock().expect("lan peers lock");
|
let peers = self.lan_peers.lock().expect("lan peers lock");
|
||||||
@@ -566,24 +586,33 @@ impl Daemon {
|
|||||||
let parsed: iroh::EndpointId = node_id
|
let parsed: iroh::EndpointId = node_id
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
|
.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")));
|
return Err(OpError::NotFound(format!("{parsed} was not trusted")));
|
||||||
}
|
}
|
||||||
Ok(ResponseData::Done {})
|
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 {
|
Request::PeerList {} => Ok(ResponseData::Peers {
|
||||||
peers: self.present_trusted_peers(),
|
peers: self.present_trusted_peers(),
|
||||||
}),
|
}),
|
||||||
Request::Push { hash, node_id } => {
|
Request::Push { hash, node_id } => {
|
||||||
let parsed = parse_hash(&hash)?;
|
let parsed = parse_hash(&hash)?;
|
||||||
let peer: iroh::EndpointId = node_id
|
let peer = self.peer_of(&node_id)?;
|
||||||
.parse()
|
// Consent, sending side: we only push to peers we trust or
|
||||||
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
|
// hold a push allowance for. (The receiver independently
|
||||||
// Consent, sending side: we only push to peers we trust.
|
// requires the same of us.)
|
||||||
// (The receiver independently requires that it trusts us.)
|
if !self.meta.may_push(&peer.to_string()) {
|
||||||
if !self.meta.is_trusted(&peer.to_string()) {
|
|
||||||
return Err(OpError::InvalidArgument(format!(
|
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?;
|
let (_, _, complete) = self.store.presence(parsed).await?;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ struct MetaState {
|
|||||||
/// Trusted peer NodeIds (z-base-32).
|
/// Trusted peer NodeIds (z-base-32).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
trusted_peers: BTreeSet<String>,
|
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
|
/// Hashes (hex) the user shared via ticket export: standing consent
|
||||||
/// to serve them to anyone, like an `open_lan` pin.
|
/// to serve them to anyone, like an `open_lan` pin.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -164,6 +168,31 @@ impl Meta {
|
|||||||
.clone()
|
.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 {
|
pub fn is_trusted(&self, node_id: &str) -> bool {
|
||||||
self.state
|
self.state
|
||||||
.lock()
|
.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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -201,4 +238,27 @@ mod tests {
|
|||||||
assert!(meta.unpin("h").unwrap());
|
assert!(meta.unpin("h").unwrap());
|
||||||
assert!(!meta.is_pinned("h"));
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ pub struct Gate {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct ConnInfo {
|
struct ConnInfo {
|
||||||
trusted: bool,
|
trusted: bool,
|
||||||
|
/// Trusted, or holding a push allowance (`PeerAllowPush`).
|
||||||
|
may_push: bool,
|
||||||
endpoint_id: Option<String>,
|
endpoint_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +144,11 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
.endpoint_id
|
.endpoint_id
|
||||||
.map(|id| gate.meta.is_trusted(&id.to_string()))
|
.map(|id| gate.meta.is_trusted(&id.to_string()))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
let may_push = m
|
||||||
|
.inner
|
||||||
|
.endpoint_id
|
||||||
|
.map(|id| gate.meta.may_push(&id.to_string()))
|
||||||
|
.unwrap_or(false);
|
||||||
let ClientConnected {
|
let ClientConnected {
|
||||||
connection_id,
|
connection_id,
|
||||||
endpoint_id,
|
endpoint_id,
|
||||||
@@ -151,6 +158,7 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
connection_id,
|
connection_id,
|
||||||
ConnInfo {
|
ConnInfo {
|
||||||
trusted,
|
trusted,
|
||||||
|
may_push,
|
||||||
endpoint_id: endpoint_id.map(|id| id.to_string()),
|
endpoint_id: endpoint_id.map(|id| id.to_string()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -192,11 +200,12 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
ProviderMessage::ObserveRequestReceived(m) => {
|
ProviderMessage::ObserveRequestReceived(m) => {
|
||||||
// Presence is information too: gate it like data.
|
// Presence is information too: gate it like data.
|
||||||
// Bitfields are metadata, not payload, so trusted
|
// Bitfields are metadata, not payload, so trusted
|
||||||
// peers may observe even while serving is off or the
|
// peers - and peers allowed to push, whose push is
|
||||||
// connection is metered (push confirmation needs it).
|
// confirmed by observing it - may observe even while
|
||||||
|
// serving is off or the connection is metered.
|
||||||
let trusted = conns
|
let trusted = conns
|
||||||
.get(&m.inner.connection_id)
|
.get(&m.inner.connection_id)
|
||||||
.map(|i| i.trusted)
|
.map(|i| i.trusted || i.may_push)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let allowed = trusted
|
let allowed = trusted
|
||||||
|| allow(&gate, &conns, m.inner.connection_id, [m.inner.request.hash]);
|
|| 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();
|
m.tx.send(verdict).await.ok();
|
||||||
}
|
}
|
||||||
ProviderMessage::PushRequestReceived(m) => {
|
ProviderMessage::PushRequestReceived(m) => {
|
||||||
// Inbound writes: trusted peers only, deferred while
|
// Inbound writes: trusted peers and push allowances
|
||||||
// metered (RateLimited invites a retry later).
|
// only, deferred while metered (RateLimited invites a
|
||||||
|
// retry later).
|
||||||
let info = conns.get(&m.inner.connection_id);
|
let info = conns.get(&m.inner.connection_id);
|
||||||
let trusted = info.map(|i| i.trusted).unwrap_or(false);
|
let may_push = info.map(|i| i.may_push).unwrap_or(false);
|
||||||
debug!(hash = %m.inner.request.hash.to_hex(), trusted, "push request received");
|
debug!(hash = %m.inner.request.hash.to_hex(), may_push, "push request received");
|
||||||
let verdict = if !trusted {
|
let verdict = if !may_push {
|
||||||
Err(AbortReason::Permission)
|
Err(AbortReason::Permission)
|
||||||
} else if gate.metered.is_metered() {
|
} else if gate.metered.is_metered() {
|
||||||
Err(AbortReason::RateLimited)
|
Err(AbortReason::RateLimited)
|
||||||
|
|||||||
@@ -298,6 +298,15 @@ impl Transfer {
|
|||||||
Ok(ticket.to_string())
|
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
|
/// Queue a background fetch of `content` from `providers`. Emits
|
||||||
/// progress events and [`Event::PinComplete`] when fully verified.
|
/// progress events and [`Event::PinComplete`] when fully verified.
|
||||||
pub fn spawn_fetch(&self, content: HashAndFormat, providers: Vec<EndpointAddr>) {
|
pub fn spawn_fetch(&self, content: HashAndFormat, providers: Vec<EndpointAddr>) {
|
||||||
|
|||||||
@@ -422,3 +422,61 @@ fn push_rejected_without_receiver_trust() {
|
|||||||
// And the receiver holds none of it.
|
// And the receiver holds none of it.
|
||||||
assert!(!is_complete(&b.socket, &hash));
|
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,6 +20,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// Bumped on incompatible changes; reported in [`GlobalStatus`].
|
/// Bumped on incompatible changes; reported in [`GlobalStatus`].
|
||||||
pub const PROTOCOL_VERSION: u32 = 2;
|
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
|
/// The most bytes a [`Request::Put`] or a [`Request::Read`] reply carries
|
||||||
/// inline. Larger content goes through `Add`/`Materialize` and a path.
|
/// inline. Larger content goes through `Add`/`Materialize` and a path.
|
||||||
pub const MAX_INLINE_BYTES: u64 = 16 * 1024 * 1024;
|
pub const MAX_INLINE_BYTES: u64 = 16 * 1024 * 1024;
|
||||||
@@ -116,6 +119,20 @@ pub enum Request {
|
|||||||
/// The peer's iroh NodeId (z-base-32).
|
/// The peer's iroh NodeId (z-base-32).
|
||||||
node_id: String,
|
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.
|
/// List trusted peers and their current connectivity.
|
||||||
PeerList {},
|
PeerList {},
|
||||||
/// Push fully-present content to a trusted peer, unprompted.
|
/// 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`.
|
/// policy), so the content survives gc and shows up in `List`.
|
||||||
Push {
|
Push {
|
||||||
/// Hash (hex) of the fully-present blob or HashSeq root to 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,
|
hash: String,
|
||||||
/// The receiving peer's iroh NodeId (z-base-32).
|
/// The receiving peer's iroh NodeId (z-base-32).
|
||||||
node_id: String,
|
node_id: String,
|
||||||
|
|||||||
Reference in New Issue
Block a user