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
|
|
@ -4353,31 +4353,11 @@ impl Storage {
|
|||
self.set_setting("active_default_posting_id", &hex::encode(node_id))
|
||||
}
|
||||
|
||||
/// Ensure the posting_identities table has at least one entry. On first
|
||||
/// launch after 0.6.3 upgrade, copies the network key from
|
||||
/// `identity.key` on disk into posting_identities and sets it as default,
|
||||
/// preserving signature validity of all existing content.
|
||||
pub fn seed_posting_identity_from_network(
|
||||
&self,
|
||||
network_node_id: &NodeId,
|
||||
network_secret: &[u8; 32],
|
||||
) -> anyhow::Result<()> {
|
||||
let existing: i64 = self.conn.prepare(
|
||||
pub fn count_posting_identities(&self) -> anyhow::Result<u64> {
|
||||
let n: i64 = self.conn.prepare(
|
||||
"SELECT COUNT(*) FROM posting_identities",
|
||||
)?.query_row([], |row| row.get(0))?;
|
||||
if existing == 0 {
|
||||
let now = now_ms();
|
||||
self.conn.execute(
|
||||
"INSERT INTO posting_identities (node_id, secret_seed, display_name, created_at)
|
||||
VALUES (?1, ?2, '', ?3)",
|
||||
params![network_node_id.as_slice(), network_secret.as_slice(), now as i64],
|
||||
)?;
|
||||
}
|
||||
// Always ensure a default is set (no-op if already pointing at a valid identity).
|
||||
if self.get_default_posting_id()?.is_none() {
|
||||
self.set_default_posting_id(network_node_id)?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(n as u64)
|
||||
}
|
||||
|
||||
// --- File holders (flat, per-file, LRU-capped at 5) ---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue