feat: v0.8 Iteration A — ID-class fixes, manifest privacy, registry + greetings
A1 — ID-class bug family (v0.6.1 persona split left network-NodeId comparisons
where posting IDs live). ~14 sites fixed with multi-persona semantics ("author is
one of MY posting identities", not == default):
- revoke_post_access / revoke_circle_access (revocation was broken for every post)
- group key create/add-member/rotate (add-member distribution now works)
- circle profile set/delete/get, encrypted-attachment CEK unwrap
- receipt/comment slot authorship, replication cycle, blob eviction own-tier
- orphaned GroupKeyRequest/Response (0xA1/0xA2) deleted (no send side existed)
A2 — Manifest privacy: AuthorManifest.author_addresses removed from struct AND
signature digest; CdnManifest tree-era fields dropped. Startup migrations re-sign
own manifests, purge unverifiable foreign copies, strip persona fields from legacy
network-id profile rows. Posting identities are now location-anonymous.
A3 — Discovery & first contact:
- Open-slot comments: derivable slot V_x (blake3 from author + slot_binder_nonce)
so strangers pass the CDN comment-verification gate; OpenSlotDecl in FoF gating
- Greetings: HPKE-style sealed GreetingBody (return_path + fresh reply_pubkey),
throwaway outer ID, size-bucketed; messaging-first (Reply/Dismiss, no vouch)
- Registry: frozen canonical registry post + REGISTRY_POST_ID, signed registration
comments (self-certifying deletes), newest-wins per persona, --publish-registry
- Comment TTL: expires_at_ms inside signed digest v2 (context bump), rand 30-365d
ordinary / fixed 30d registrations, expiry sweep on the eviction cycle
- Single accept_incoming_comment() gate wired into all three ingest sites, closing
a pre-existing hole where both pull paths stored comments with no verification
- UI: consent panel (visible/listed/greetings, active choice at first publish),
registry search in Discover, sealed "Say hi" compose, greetings inbox
Security fixes from review: forged-tombstone injection, delete-by-sender-trust,
remote SetPolicy poisoning, stored XSS (escapeHtml quotes, 7 pre-existing sites),
greeting off-switch now revokes prior bios' slots.
No PoW (rejected: inverted cost). Session-relay gating untouched.
201 core tests pass; CLI + desktop build; 3-node integration green.
DEPLOY GATE: wire-incompatible with v0.7.3 — ALPN bump to itsgoin/4 lands in
Iteration B. Do not build/deploy/anchor-swap before that.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGiPD2cF75mnvneSCjdDC5
This commit is contained in:
parent
66c9851061
commit
17dbf076cb
19 changed files with 5237 additions and 524 deletions
|
|
@ -175,6 +175,9 @@ pub fn scan_vouch_grants_for_all_personas(
|
|||
/// batch distributing the persona's current `V_me` to vouched personas.
|
||||
/// `bio_epoch` is a monotonic per-persona counter that lets receivers
|
||||
/// short-circuit re-scanning unchanged bios.
|
||||
/// v0.8 (A3): `fof_gating` carries the bio's comment gating — including
|
||||
/// the Greeting open slot when the persona's `greetings_open` consent is
|
||||
/// on. `None` publishes a bio that accepts no greetings.
|
||||
pub fn build_profile_post(
|
||||
author: &NodeId,
|
||||
author_secret: &[u8; 32],
|
||||
|
|
@ -183,6 +186,7 @@ pub fn build_profile_post(
|
|||
avatar_cid: Option<[u8; 32]>,
|
||||
vouch_grants: Option<crate::types::VouchGrantBatch>,
|
||||
bio_epoch: u32,
|
||||
fof_gating: Option<crate::types::FoFCommentGating>,
|
||||
) -> Post {
|
||||
let timestamp_ms = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
|
|
@ -203,8 +207,8 @@ pub fn build_profile_post(
|
|||
content: serde_json::to_string(&content).unwrap_or_default(),
|
||||
attachments: vec![],
|
||||
timestamp_ms,
|
||||
fof_gating: None,
|
||||
supersedes_post_id: None,
|
||||
fof_gating,
|
||||
supersedes_post_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +349,7 @@ mod tests {
|
|||
let s = temp_storage();
|
||||
let (sec, pub_id) = make_keypair(11);
|
||||
|
||||
let post = build_profile_post(&pub_id, &sec, "Alice", "hello world", None, None, 0);
|
||||
let post = build_profile_post(&pub_id, &sec, "Alice", "hello world", None, None, 0, None);
|
||||
apply_profile_post_if_applicable(&s, &post, Some(&VisibilityIntent::Profile)).unwrap();
|
||||
|
||||
let stored = s.get_profile(&pub_id).unwrap().expect("profile stored");
|
||||
|
|
@ -360,7 +364,7 @@ mod tests {
|
|||
let (sec_b, _pub_b) = make_keypair(2);
|
||||
|
||||
// Build a post claiming `pub_a` but signing with `sec_b`.
|
||||
let post = build_profile_post(&pub_a, &sec_b, "Impostor", "", None, None, 0);
|
||||
let post = build_profile_post(&pub_a, &sec_b, "Impostor", "", None, None, 0, None);
|
||||
let res = apply_profile_post_if_applicable(&s, &post, Some(&VisibilityIntent::Profile));
|
||||
assert!(res.is_err());
|
||||
assert!(s.get_profile(&pub_a).unwrap().is_none());
|
||||
|
|
@ -372,7 +376,7 @@ mod tests {
|
|||
let (sec, pub_id) = make_keypair(3);
|
||||
|
||||
// Seed with a newer profile.
|
||||
let mut newer = build_profile_post(&pub_id, &sec, "NewName", "", None, None, 0);
|
||||
let mut newer = build_profile_post(&pub_id, &sec, "NewName", "", None, None, 0, None);
|
||||
// Hack the timestamp to make it clearly newer.
|
||||
let mut content: ProfilePostContent = serde_json::from_str(&newer.content).unwrap();
|
||||
content.timestamp_ms = 10_000;
|
||||
|
|
@ -382,7 +386,7 @@ mod tests {
|
|||
apply_profile_post_if_applicable(&s, &newer, Some(&VisibilityIntent::Profile)).unwrap();
|
||||
|
||||
// Apply an older profile — should be ignored.
|
||||
let mut older = build_profile_post(&pub_id, &sec, "OldName", "", None, None, 0);
|
||||
let mut older = build_profile_post(&pub_id, &sec, "OldName", "", None, None, 0, None);
|
||||
let mut content_o: ProfilePostContent = serde_json::from_str(&older.content).unwrap();
|
||||
content_o.timestamp_ms = 5_000;
|
||||
content_o.signature = crypto::sign_profile(&sec, &content_o.display_name, &content_o.bio, &content_o.avatar_cid, content_o.timestamp_ms);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue