Core: network/posting key split + decrypt-all-personas
Fresh installs now generate two independent ed25519 keys — one as the network (QUIC) identity in identity.key, and a SEPARATE one as the default posting identity in posting_identities. They share nothing. v0.6.0 upgraders: if the default posting key equals the network key (the state Phase 4's migration left us in), rotate identity.key to a fresh random value. The old key stays in posting_identities as the default persona — peers keep seeing the same author on our posts; only the QUIC NodeId changes. A one-shot reconnect-churn on upgrade, then back to normal. Storage: - Drop seed_posting_identity_from_network (v0.6.0-specific helper) - Add count_posting_identities() Node::open_with_bind: - Load identity.key (network secret — network-only from now on) - Ensure posting_identities has at least one entry; if empty, generate an INDEPENDENT random posting key as the default - Detect default-posting-key == network-key collision and rotate identity.key, logging the migration - default_posting_id / default_posting_secret resolved from storage Decrypt: - decrypt_posts now takes &[PostingIdentity] and tries each held persona as a recipient candidate. Past DMs to any persona on this device (including ones added via Import as personas) decrypt correctly. Callers pre-load list_posting_identities() alongside group_seeds. - decrypt_just_created looks up the author's specific posting identity rather than assuming the default. Profile broadcasts (wire-level privacy): - Profile stays keyed by network NodeId — the field is load-bearing for N1/N2/N3 social routing (anchors/recent_peers/preferred_peers feed build_preferred_tree_for and peer-anchor reachability lookup). - But push_profile and InitialExchange now STRIP display_name, bio, and avatar_cid before sending, via new PublicProfile::sanitized_for_network_broadcast(). A name attached to the network id would correlate the QUIC endpoint to a human. Until v0.6.2 introduces persona-signed profile posts, peers display authors as hex. Auto-follow only the default posting id (network id is never an author, following it would be dead weight). All 111 core tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b789ab5a19
commit
4a1db1ce7f
5 changed files with 134 additions and 72 deletions
|
|
@ -1513,7 +1513,11 @@ impl ConnectionManager {
|
|||
let storage = self.storage.get().await;
|
||||
let n1 = storage.build_n1_share()?;
|
||||
let n2 = storage.build_n2_share()?;
|
||||
let profile = storage.get_profile(&self.our_node_id)?;
|
||||
// Profile keyed by network id (used for N1/N2/N3 routing).
|
||||
// Strip persona display data before sending so peers don't learn
|
||||
// a human-readable name for our network id.
|
||||
let profile = storage.get_profile(&self.our_node_id)?
|
||||
.map(|p| p.sanitized_for_network_broadcast());
|
||||
let deletes = storage.list_delete_records()?;
|
||||
let post_ids = storage.list_post_ids()?;
|
||||
let peer_addresses = storage.build_peer_addresses_for(&self.our_node_id)?;
|
||||
|
|
@ -1656,7 +1660,11 @@ impl ConnectionManager {
|
|||
let storage = self.storage.get().await;
|
||||
let n1 = storage.build_n1_share()?;
|
||||
let n2 = storage.build_n2_share()?;
|
||||
let profile = storage.get_profile(&self.our_node_id)?;
|
||||
// Profile keyed by network id (used for N1/N2/N3 routing).
|
||||
// Strip persona display data before sending so peers don't learn
|
||||
// a human-readable name for our network id.
|
||||
let profile = storage.get_profile(&self.our_node_id)?
|
||||
.map(|p| p.sanitized_for_network_broadcast());
|
||||
let deletes = storage.list_delete_records()?;
|
||||
let post_ids = storage.list_post_ids()?;
|
||||
let peer_addresses = storage.build_peer_addresses_for(&self.our_node_id)?;
|
||||
|
|
@ -8391,7 +8399,9 @@ pub async fn initial_exchange_connect(
|
|||
let storage = storage.get().await;
|
||||
let n1 = storage.build_n1_share()?;
|
||||
let n2 = storage.build_n2_share()?;
|
||||
let profile = storage.get_profile(our_node_id)?;
|
||||
// Profile keyed by network id; strip persona display before send.
|
||||
let profile = storage.get_profile(our_node_id)?
|
||||
.map(|p| p.sanitized_for_network_broadcast());
|
||||
let deletes = storage.list_delete_records()?;
|
||||
let post_ids = storage.list_post_ids()?;
|
||||
let peer_addresses = storage.build_peer_addresses_for(our_node_id)?;
|
||||
|
|
@ -8470,7 +8480,9 @@ pub async fn initial_exchange_accept(
|
|||
let storage = storage.get().await;
|
||||
let n1 = storage.build_n1_share()?;
|
||||
let n2 = storage.build_n2_share()?;
|
||||
let profile = storage.get_profile(our_node_id)?;
|
||||
// Profile keyed by network id; strip persona display before send.
|
||||
let profile = storage.get_profile(our_node_id)?
|
||||
.map(|p| p.sanitized_for_network_broadcast());
|
||||
let deletes = storage.list_delete_records()?;
|
||||
let post_ids = storage.list_post_ids()?;
|
||||
let peer_addresses = storage.build_peer_addresses_for(our_node_id)?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue