Phase 1 (0.6.0-beta): remove direct PostPush for encrypted posts
Encrypted posts now propagate only via the CDN (ManifestPush + neighbor header updates), eliminating the sender→recipient traffic signal on the wire. Encrypted DMs are indistinguishable from any other encrypted post. - Remove push_post_to_recipients entirely from network.rs - Remove call sites in create_post and re-encrypt-on-revoke - PostPush handler now ignores non-public visibility (kept for public audience push path) Known gap: non-follower DMs won't reach until Phase 3 (merged pull + recipient-match). Followers receive via the existing CDN path — new posts trigger neighbor-manifest updates, ManifestPush fans out to downstream holders, recipients pull missing post IDs from followed authors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
921a0ec40a
commit
e6265b52b6
3 changed files with 31 additions and 68 deletions
|
|
@ -4958,24 +4958,34 @@ impl ConnectionManager {
|
||||||
}
|
}
|
||||||
MessageType::PostPush => {
|
MessageType::PostPush => {
|
||||||
let push: PostPushPayload = read_payload(recv, MAX_PAYLOAD).await?;
|
let push: PostPushPayload = read_payload(recv, MAX_PAYLOAD).await?;
|
||||||
let cm = conn_mgr.lock().await;
|
// Encrypted posts are no longer accepted via direct push — they propagate
|
||||||
let storage = cm.storage.get().await;
|
// via the CDN to eliminate the sender→recipient traffic signal.
|
||||||
if !storage.is_deleted(&push.post.id)?
|
if !matches!(push.post.visibility, crate::types::PostVisibility::Public) {
|
||||||
&& storage.get_post(&push.post.id)?.is_none()
|
debug!(
|
||||||
&& crate::content::verify_post_id(&push.post.id, &push.post.post)
|
|
||||||
{
|
|
||||||
let _ = storage.store_post_with_visibility(
|
|
||||||
&push.post.id,
|
|
||||||
&push.post.post,
|
|
||||||
&push.post.visibility,
|
|
||||||
);
|
|
||||||
let prio = storage.get_post_upstreams(&push.post.id).map(|v| v.len() as u8).unwrap_or(0);
|
|
||||||
let _ = storage.add_post_upstream(&push.post.id, &remote_node_id, prio);
|
|
||||||
info!(
|
|
||||||
peer = hex::encode(remote_node_id),
|
peer = hex::encode(remote_node_id),
|
||||||
post_id = hex::encode(push.post.id),
|
post_id = hex::encode(push.post.id),
|
||||||
"Received direct post push"
|
"Ignoring non-public PostPush"
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
let cm = conn_mgr.lock().await;
|
||||||
|
let storage = cm.storage.get().await;
|
||||||
|
if !storage.is_deleted(&push.post.id)?
|
||||||
|
&& storage.get_post(&push.post.id)?.is_none()
|
||||||
|
&& crate::content::verify_post_id(&push.post.id, &push.post.post)
|
||||||
|
{
|
||||||
|
let _ = storage.store_post_with_visibility(
|
||||||
|
&push.post.id,
|
||||||
|
&push.post.post,
|
||||||
|
&push.post.visibility,
|
||||||
|
);
|
||||||
|
let prio = storage.get_post_upstreams(&push.post.id).map(|v| v.len() as u8).unwrap_or(0);
|
||||||
|
let _ = storage.add_post_upstream(&push.post.id, &remote_node_id, prio);
|
||||||
|
info!(
|
||||||
|
peer = hex::encode(remote_node_id),
|
||||||
|
post_id = hex::encode(push.post.id),
|
||||||
|
"Received direct post push"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageType::AudienceRequest => {
|
MessageType::AudienceRequest => {
|
||||||
|
|
|
||||||
|
|
@ -902,50 +902,6 @@ impl Network {
|
||||||
self.send_to_audience(MessageType::PostNotification, &payload).await
|
self.send_to_audience(MessageType::PostNotification, &payload).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a full post directly to recipients (persistent if available, ephemeral otherwise).
|
|
||||||
pub async fn push_post_to_recipients(
|
|
||||||
&self,
|
|
||||||
post_id: &crate::types::PostId,
|
|
||||||
post: &Post,
|
|
||||||
visibility: &PostVisibility,
|
|
||||||
) -> usize {
|
|
||||||
let recipients: Vec<NodeId> = match visibility {
|
|
||||||
PostVisibility::Public => return 0,
|
|
||||||
PostVisibility::Encrypted { recipients } => {
|
|
||||||
recipients.iter().map(|wk| wk.recipient).collect()
|
|
||||||
}
|
|
||||||
PostVisibility::GroupEncrypted { group_id, .. } => {
|
|
||||||
// Push to all group members
|
|
||||||
match self.storage.get().await.get_all_group_members() {
|
|
||||||
Ok(map) => map.get(group_id).cloned().unwrap_or_default().into_iter().collect(),
|
|
||||||
Err(_) => return 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let payload = PostPushPayload {
|
|
||||||
post: SyncPost {
|
|
||||||
id: *post_id,
|
|
||||||
post: post.clone(),
|
|
||||||
visibility: visibility.clone(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut pushed = 0;
|
|
||||||
for recipient in &recipients {
|
|
||||||
if self.send_to_peer_uni(recipient, MessageType::PostPush, &payload).await.is_ok() {
|
|
||||||
pushed += 1;
|
|
||||||
debug!(
|
|
||||||
recipient = hex::encode(recipient),
|
|
||||||
post_id = hex::encode(post_id),
|
|
||||||
"Pushed post to recipient"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pushed
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push a profile update to all audience members (ephemeral-capable).
|
/// Push a profile update to all audience members (ephemeral-capable).
|
||||||
pub async fn push_profile(&self, profile: &PublicProfile) -> usize {
|
pub async fn push_profile(&self, profile: &PublicProfile) -> usize {
|
||||||
// Sanitize: if public_visible=false, strip display_name/bio from pushed profile
|
// Sanitize: if public_visible=false, strip display_name/bio from pushed profile
|
||||||
|
|
|
||||||
|
|
@ -836,13 +836,12 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For encrypted posts, push directly to recipients
|
// For public posts, push to audience members. Encrypted posts propagate
|
||||||
let pushed = self.network.push_post_to_recipients(&post_id, &post, &visibility).await;
|
// via the CDN (ManifestPush + header-diff) to eliminate the sender→recipient
|
||||||
|
// traffic signal.
|
||||||
// For public posts, push to audience members
|
|
||||||
let audience_pushed = self.network.push_to_audience(&post_id, &post, &visibility).await;
|
let audience_pushed = self.network.push_to_audience(&post_id, &post, &visibility).await;
|
||||||
|
|
||||||
info!(post_id = hex::encode(post_id), pushed, audience_pushed, "Created new post");
|
info!(post_id = hex::encode(post_id), audience_pushed, "Created new post");
|
||||||
Ok((post_id, post, visibility))
|
Ok((post_id, post, visibility))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2108,12 +2107,10 @@ impl Node {
|
||||||
storage.store_post_with_visibility(&new_post_id, &new_post, &new_vis)?;
|
storage.store_post_with_visibility(&new_post_id, &new_post, &new_vis)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete_post already pushes the DeleteRecord
|
// delete_post already pushes the DeleteRecord.
|
||||||
|
// Replacement post propagates via the CDN to remaining recipients.
|
||||||
self.delete_post(post_id).await?;
|
self.delete_post(post_id).await?;
|
||||||
|
|
||||||
// Push replacement post directly to remaining recipients
|
|
||||||
self.network.push_post_to_recipients(&new_post_id, &new_post, &new_vis).await;
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
old_id = hex::encode(post_id),
|
old_id = hex::encode(post_id),
|
||||||
new_id = hex::encode(new_post_id),
|
new_id = hex::encode(new_post_id),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue