v0.0.6: Delivery receipts (sent/delivered/read)
Protocol:
- WireMessage::Receipt { sender_fingerprint, message_id, receipt_type }
- ReceiptType enum: Delivered, Read
- id field added to KeyExchange and Message variants
- Receipts are plaintext (not encrypted) — contain only ID + type
Web client:
- Auto-sends Delivered receipt on successful decrypt
- Tracks sent message IDs with receipt status
- Displays: ✓ (sent, gray), ✓✓ (delivered, white), ✓✓ (read, blue)
- Receipt indicators update live via DOM reference
CLI TUI:
- Auto-sends Delivered receipt back to sender on decrypt
- Tracks receipt status per message ID
- Displays receipt indicators after sent messages
WASM:
- create_receipt() function for web client
- encrypt_with_id/encrypt_key_exchange_with_id for tracking
- decrypt_wire_message handles Receipt variant
17/17 protocol tests pass. Zero warnings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ pub async fn run(server_url: &str, identity: &IdentityKeyPair) -> Result<()> {
|
||||
for raw in &messages {
|
||||
match bincode::deserialize::<WireMessage>(raw) {
|
||||
Ok(WireMessage::KeyExchange {
|
||||
id: _,
|
||||
sender_fingerprint,
|
||||
sender_identity_encryption_key,
|
||||
ephemeral_public,
|
||||
@@ -80,6 +81,7 @@ pub async fn run(server_url: &str, identity: &IdentityKeyPair) -> Result<()> {
|
||||
}
|
||||
}
|
||||
Ok(WireMessage::Message {
|
||||
id: _,
|
||||
sender_fingerprint,
|
||||
ratchet_message,
|
||||
}) => {
|
||||
@@ -105,6 +107,16 @@ pub async fn run(server_url: &str, identity: &IdentityKeyPair) -> Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(WireMessage::Receipt {
|
||||
sender_fingerprint,
|
||||
message_id,
|
||||
receipt_type,
|
||||
}) => {
|
||||
println!(
|
||||
" [receipt] {} acknowledged message {} ({:?})",
|
||||
sender_fingerprint, message_id, receipt_type
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(" failed to deserialize message: {}", e);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ pub async fn run(recipient_fp: &str, message: &str, server_url: &str, identity:
|
||||
db.save_session(&recipient, state)?;
|
||||
|
||||
WireMessage::Message {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
sender_fingerprint: our_pub.fingerprint.to_string(),
|
||||
ratchet_message: encrypted,
|
||||
}
|
||||
@@ -51,6 +52,7 @@ pub async fn run(recipient_fp: &str, message: &str, server_url: &str, identity:
|
||||
db.save_session(&recipient, &state)?;
|
||||
|
||||
WireMessage::KeyExchange {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
sender_fingerprint: our_pub.fingerprint.to_string(),
|
||||
sender_identity_encryption_key: *our_pub.encryption.as_bytes(),
|
||||
ephemeral_public: *x3dh_result.ephemeral_public.as_bytes(),
|
||||
|
||||
Reference in New Issue
Block a user