diff --git a/Cargo.lock b/Cargo.lock index 9d7882e..78e3ab9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2067,7 +2067,7 @@ dependencies = [ [[package]] name = "dig-node-core" -version = "0.13.7" +version = "0.13.8" dependencies = [ "async-trait", "axum", @@ -2115,7 +2115,7 @@ dependencies = [ [[package]] name = "dig-node-service" -version = "0.47.7" +version = "0.47.8" dependencies = [ "axum", "axum-server", diff --git a/Cargo.toml b/Cargo.toml index a62f4be..8879025 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ edition = "2021" # the ROOT manifest (`[workspace.package].version`), so it MUST be set here for a # release to fire (§3.6). The library crates (dig-node-core/dig-runtime/dig-wallet) # keep their own independent versions — only the released binary tracks the workspace version. -version = "0.47.7" +version = "0.47.8" # Release hardening, matching digstore: keep integer-overflow checks ON in release. # The node parses untrusted serialized input and does offset/length arithmetic over diff --git a/crates/dig-node-core/Cargo.toml b/crates/dig-node-core/Cargo.toml index 78bad06..f482151 100644 --- a/crates/dig-node-core/Cargo.toml +++ b/crates/dig-node-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dig-node-core" -version = "0.13.7" +version = "0.13.8" edition = "2021" license = "GPL-2.0-only" description = "The canonical DIG node ENGINE library (crate `dig_node_core`): the JSON-RPC dispatch (`handle_rpc`, the same contract as rpc.dig.net), local-first content serve/fetch/redirect from LOCAL .dig store modules (via digstore_host::serve_blind), chain-anchored-root resolution, chain-watch + subscriptions + generation gap-fill, the LRU cache, and the full P2P stack. Shared UNCHANGED by both host shells: the `dig-node` OS-service binary (dig-node-service) and the DIG Browser's in-process cdylib (dig-runtime). Native Rust so the compiled-module serve path works." diff --git a/crates/dig-node-core/src/lib.rs b/crates/dig-node-core/src/lib.rs index 27bbb48..51163dc 100644 --- a/crates/dig-node-core/src/lib.rs +++ b/crates/dig-node-core/src/lib.rs @@ -75,6 +75,10 @@ pub use seams::dig_peer::{address_book, dht, net, pex, session, PeerNetwork}; /// `handle_rpc`/`handle_rpc_json` free functions delegate to it; most callers keep using those /// stable entry points and never need this trait in scope directly. pub use seams::dig_rpc::RpcDispatch; +/// The `KeyManager` trait is seam 7's public surface (#1285 W1b-6) — bring it into scope to call +/// `peer_id_hex`/`identity_seed_for_peer`/`peer_cert_dir`/`node_cert_dir` on a `Node`. #908 +/// boundary: this seam holds ONLY the node's machine identity — never a user key. +pub use seams::key_mgmt::KeyManager; /// Cross-seam shared vocabulary (#1285 W1a) — the ONLY types the node's seams (peer, wallet, rpc, /// local-content, capsule, chain, key-management) are allowed to share; see the module doc. pub mod shared; @@ -1724,17 +1728,6 @@ impl Node { // learns what this node already holds. Every byte a peer fetches carries its own merkle proof // (verified by the caller against the chain-anchored root), so the node is never the trust anchor. - /// The node's own `peer_id` (64-hex) = SHA-256(SPKI DER) of its PERSISTENT, CA-signed - /// [`NodeCert`](dig_nat::NodeCert), or `None` if no identity seed is configured. This is the mTLS - /// identity the node presents on every peer path (loaded from — or minted into — the node's cert - /// dir, so it is stable across restarts; see [`peer::load_or_generate_node_cert`]). - pub fn peer_id_hex(&self) -> Option { - let seed = self.identity_seed?; - peer::load_or_generate_node_cert(self.node_cert_dir(), &seed) - .ok() - .map(|cert| cert.peer_id().to_hex()) - } - /// `dig.getAvailability` — answer one queried item against the local inventory, enriching the /// pure presence answer (`peer::availability_presence`) with the per-resource `total_length` + /// `chunk_count` when the item is at resource granularity (`store_id` + `root` + `retrieval_key`) @@ -2143,28 +2136,6 @@ impl Node { }) } - /// The node's persistent identity seed, if configured — the source of the STABLE mTLS `peer_id` - /// for the L7 peer network (see [`peer::load_or_generate_node_cert`]). `None` disables the peer network - /// (the node still serves the HTTP read path). - pub fn identity_seed_for_peer(&self) -> Option<[u8; 32]> { - self.identity_seed - } - - /// The directory the L7 peer network keeps its TLS cert/key + peer address book under (a - /// `peer-net/` subdir of the cache dir, so it shares the node's data root + writability handling). - pub fn peer_cert_dir(&self) -> PathBuf { - self.cache_dir.join("peer-net") - } - - /// The directory the node's PERSISTENT, CA-signed [`NodeCert`](dig_nat::NodeCert) identity - /// (`node.crt` + `node.key`, 0600) lives under — an `identity/` subdir of [`Self::peer_cert_dir`], - /// kept SEPARATE from dig-gossip's own `node.key` in `peer-net/` so the two never clobber each - /// other. This is the node's stable machine transport identity (#908, #1280); its `peer_id` - /// survives restarts because the cert is loaded back from here. - pub fn node_cert_dir(&self) -> PathBuf { - self.peer_cert_dir().join("identity") - } - /// The node's cache dir root — the data root the P2P content engine's download staging /// (`/downloads`) + `.download.tmp` GC live under (shares the node's writability handling). pub fn cache_dir_path(&self) -> &Path { diff --git a/crates/dig-node-core/src/peer.rs b/crates/dig-node-core/src/peer.rs index 5e88406..4a010a7 100644 --- a/crates/dig-node-core/src/peer.rs +++ b/crates/dig-node-core/src/peer.rs @@ -61,7 +61,7 @@ use std::sync::Arc; use serde_json::{json, Value}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use crate::{CachedCapsule, CapsuleStore, PeerNetwork}; +use crate::{CachedCapsule, CapsuleStore, KeyManager, PeerNetwork}; // -- Constants --------------------------------------------------------------------------------------- diff --git a/crates/dig-node-core/src/seams/key_mgmt/key_manager.rs b/crates/dig-node-core/src/seams/key_mgmt/key_manager.rs new file mode 100644 index 0000000..e5b4de2 --- /dev/null +++ b/crates/dig-node-core/src/seams/key_mgmt/key_manager.rs @@ -0,0 +1,66 @@ +//! Seam 7's public surface (#1285/#1303) — the node's MACHINE-key lifecycle: the persistent +//! §21.9 identity seed, the derived stable mTLS `peer_id`, and the on-disk cert directories the +//! L7 peer network's [`dig_nat::NodeCert`] lives under. +//! +//! **#908 boundary (foundational, preserved exactly by this carve):** this seam holds ONLY the +//! node's own MACHINE identity — never a user's DID/wallet signing key. A dig-app proves +//! possession of a profile's identity key over the IPC session (`crate::session`); that key never +//! crosses into the engine. `KeyManager` does not add, and must never grow, a user-key path. +//! +//! `KeyManager` is implemented by [`Node`] with the EXISTING method bodies (carved unchanged +//! from `lib.rs`, #1285 W1b-6) — a behaviour-preserving trait extraction, not a new +//! implementation, and NOT a `dig-keystore` crate adoption (a later wave, coordinated with the +//! key-management family). Plain `Send + Sync` (no async methods) but kept trait-shaped to match +//! the other seams' pattern, so it stays dyn-compatible for the future `Arc` +//! handle (W1c). + +use std::path::PathBuf; + +use crate::Node; + +/// Seam 7 (key management) — the node's machine identity_seed/NodeCert lifecycle. See the module +/// doc for the #908 boundary this seam enforces. +pub trait KeyManager: Send + Sync { + /// The node's own `peer_id` (64-hex) = SHA-256(SPKI DER) of its PERSISTENT, CA-signed + /// [`NodeCert`](dig_nat::NodeCert), or `None` if no identity seed is configured. This is the mTLS + /// identity the node presents on every peer path (loaded from — or minted into — the node's cert + /// dir, so it is stable across restarts; see [`crate::peer::load_or_generate_node_cert`]). + fn peer_id_hex(&self) -> Option; + + /// The node's persistent identity seed, if configured — the source of the STABLE mTLS `peer_id` + /// for the L7 peer network (see [`crate::peer::load_or_generate_node_cert`]). `None` disables the + /// peer network (the node still serves the HTTP read path). + fn identity_seed_for_peer(&self) -> Option<[u8; 32]>; + + /// The directory the L7 peer network keeps its TLS cert/key + peer address book under (a + /// `peer-net/` subdir of the cache dir, so it shares the node's data root + writability handling). + fn peer_cert_dir(&self) -> PathBuf; + + /// The directory the node's PERSISTENT, CA-signed [`NodeCert`](dig_nat::NodeCert) identity + /// (`node.crt` + `node.key`, 0600) lives under — an `identity/` subdir of [`Self::peer_cert_dir`], + /// kept SEPARATE from dig-gossip's own `node.key` in `peer-net/` so the two never clobber each + /// other. This is the node's stable machine transport identity (#908, #1280); its `peer_id` + /// survives restarts because the cert is loaded back from here. + fn node_cert_dir(&self) -> PathBuf; +} + +impl KeyManager for Node { + fn peer_id_hex(&self) -> Option { + let seed = self.identity_seed?; + crate::peer::load_or_generate_node_cert(self.node_cert_dir(), &seed) + .ok() + .map(|cert| cert.peer_id().to_hex()) + } + + fn identity_seed_for_peer(&self) -> Option<[u8; 32]> { + self.identity_seed + } + + fn peer_cert_dir(&self) -> PathBuf { + self.cache_dir.join("peer-net") + } + + fn node_cert_dir(&self) -> PathBuf { + self.peer_cert_dir().join("identity") + } +} diff --git a/crates/dig-node-core/src/seams/key_mgmt/mod.rs b/crates/dig-node-core/src/seams/key_mgmt/mod.rs new file mode 100644 index 0000000..ba04fe7 --- /dev/null +++ b/crates/dig-node-core/src/seams/key_mgmt/mod.rs @@ -0,0 +1,11 @@ +//! Seam 7 — key management (#1285/#1303). Houses the [`KeyManager`] trait (the seam's public +//! surface — the node's MACHINE identity_seed/NodeCert lifecycle, carved unchanged from +//! `lib.rs`, #1285 W1b-6). The `dig-keystore` crate ADOPTION (the canonical keystore, #1024) is +//! a later wave, coordinated with the key-management family — out of scope here. +//! +//! **#908 boundary:** this seam is the machine-key/user-key boundary point. It NEVER holds a +//! user's DID/wallet signing key — see the module doc on [`key_manager::KeyManager`]. + +mod key_manager; + +pub use key_manager::KeyManager; diff --git a/crates/dig-node-core/src/seams/mod.rs b/crates/dig-node-core/src/seams/mod.rs index cbe25fb..99331e0 100644 --- a/crates/dig-node-core/src/seams/mod.rs +++ b/crates/dig-node-core/src/seams/mod.rs @@ -9,3 +9,4 @@ pub mod chia_peer; pub mod content; pub mod dig_peer; pub mod dig_rpc; +pub mod key_mgmt;