v0.4.1: Security hardening, lock contention fixes, data cleanup
Security: - Reaction signatures: ed25519 sign/verify (sign_reaction, verify_reaction_signature) Backward-compatible — unsigned reactions from old nodes still accepted - Comment signature verification: verify_comment_signature now called on receipt - Reaction removal authorization: only reactor or post author can remove - BlobHeader author verification: lookup actual author from storage, don't trust payload Lock contention (4 fixes): - ManifestPush discovery: cm lock released before PostFetch I/O - Pull request handler: load under lock, filter without lock, brief re-lock for is_deleted - Pull sender: split into two brief locks (store posts, then batch upstream+sync) - Engagement checker: batch all chunk results, single lock for writes Data cleanup: - Post deletion cleans post_downstream, post_upstream, seen_engagement tables - Added TODO-hardening.md documenting remaining DOS/security/lock/data issues Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bbaacf9b6c
commit
bb6f2b64b0
11 changed files with 500 additions and 138 deletions
|
|
@ -2197,12 +2197,18 @@ impl Storage {
|
|||
Ok(inserted > 0)
|
||||
}
|
||||
|
||||
/// Apply a delete: remove the post from the posts table if author matches.
|
||||
/// Apply a delete: remove the post from the posts table if author matches,
|
||||
/// and clean up associated downstream/upstream/engagement tracking rows.
|
||||
pub fn apply_delete(&self, record: &DeleteRecord) -> anyhow::Result<bool> {
|
||||
let deleted = self.conn.execute(
|
||||
"DELETE FROM posts WHERE id = ?1 AND author = ?2",
|
||||
params![record.post_id.as_slice(), record.author.as_slice()],
|
||||
)?;
|
||||
if deleted > 0 {
|
||||
self.conn.execute("DELETE FROM post_downstream WHERE post_id = ?1", params![record.post_id.as_slice()])?;
|
||||
self.conn.execute("DELETE FROM post_upstream WHERE post_id = ?1", params![record.post_id.as_slice()])?;
|
||||
self.conn.execute("DELETE FROM seen_engagement WHERE post_id = ?1", params![record.post_id.as_slice()])?;
|
||||
}
|
||||
Ok(deleted > 0)
|
||||
}
|
||||
|
||||
|
|
@ -4253,6 +4259,7 @@ impl Storage {
|
|||
timestamp_ms: ts as u64,
|
||||
encrypted_payload: enc,
|
||||
deleted_at: None,
|
||||
signature: vec![],
|
||||
});
|
||||
}
|
||||
Ok(result)
|
||||
|
|
@ -4286,6 +4293,7 @@ impl Storage {
|
|||
timestamp_ms: ts as u64,
|
||||
encrypted_payload: enc,
|
||||
deleted_at: del.map(|v| v as u64),
|
||||
signature: vec![],
|
||||
});
|
||||
}
|
||||
Ok(result)
|
||||
|
|
@ -5894,6 +5902,7 @@ mod tests {
|
|||
timestamp_ms: 1000,
|
||||
encrypted_payload: None,
|
||||
deleted_at: None,
|
||||
signature: vec![],
|
||||
}).unwrap();
|
||||
|
||||
s.store_reaction(&Reaction {
|
||||
|
|
@ -5903,6 +5912,7 @@ mod tests {
|
|||
timestamp_ms: 1001,
|
||||
encrypted_payload: None,
|
||||
deleted_at: None,
|
||||
signature: vec![],
|
||||
}).unwrap();
|
||||
|
||||
s.store_reaction(&Reaction {
|
||||
|
|
@ -5912,6 +5922,7 @@ mod tests {
|
|||
timestamp_ms: 1002,
|
||||
encrypted_payload: None,
|
||||
deleted_at: None,
|
||||
signature: vec![],
|
||||
}).unwrap();
|
||||
|
||||
let reactions = s.get_reactions(&post_id).unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue