feat(events): create and respond (RSVP) API - #758
Conversation
The proto types (EventMessage, EncEventResponseMessage, EventResponseMessage) and the EventResponse addon use-case already existed, but there was no way to create an event or RSVP to one. Add src/features/events.rs (Client::events()): - create(to, EventCreationParams) builds event_message + a 32-byte messageContextInfo.message_secret (events require one, like polls) and sends via the normal path (classify.rs already routes event_message). Returns the secret so the creator can decrypt later RSVPs. - respond(chat, event_msg_id, creator, message_secret, EventResponseType, extra_guest_count) encrypts an EventResponseMessage and sends enc_event_response_message. Add wacore/src/event.rs: encrypt/decrypt_event_response_with_secret, a thin wrapper over secret_enc_addon with ModificationType::EventResponse (mirrors poll.rs). The creator+responder JIDs key the HKDF/AAD, and the responder JID is resolved to the creator's namespace (own LID for a LID event, else PN), matching the poll-vote path. Verified against docs/captured-js/WAWeb/Events/GenerateEventCreationMessageProto.js and GenerateEventResponseMessageProto.js. Tests: event-message field mapping, response encrypt/decrypt roundtrip, and wrong-responder decryption fails.
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds event creation and RSVP APIs with per-message secrets, encrypted RSVP payloads (wacore addon encryption), responder JID resolution, client wiring, public re-exports, and unit tests. ChangesEvent Creation and RSVP Feature
Sequence DiagramsequenceDiagram
participant Client
participant Events
participant Wacore
participant Chat
Client->>Events: Client::events()->Events::create(params)
Events->>Wacore: (for respond) encrypt_event_response_with_secret(response, secret, stanza_id, creator_jid, responder_jid)
Wacore-->>Events: encrypted payload + iv
Events->>Chat: send EncEventResponseMessage(enc_payload, iv)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
Suggested labelsapi-design 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Benchmark Results67 unchanged benchmark(s)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dffe6a265
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@wacore/src/event.rs`:
- Around line 29-35: Validate fixed-size crypto inputs at the API boundary: in
encrypt_event_response_with_secret (and the other function that accepts an iv
slice) check that message_secret.len() == 32 and iv.len() == GCM_IV_SIZE (12)
immediately and return an Err with a clear error if sizes mismatch; do this
before any cryptographic operations so callers get deterministic errors rather
than downstream panics/crypto failures, and reference the functions
encrypt_event_response_with_secret and the corresponding decrypt/iv-handling
function to locate and apply the same checks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d1bf638c-329a-491c-914f-2abe14f9d590
📒 Files selected for processing (4)
src/features/events.rssrc/features/mod.rswacore/src/event.rswacore/src/lib.rs
| pub fn encrypt_event_response_with_secret( | ||
| response: &EventResponseMessage, | ||
| message_secret: &[u8], | ||
| stanza_id: &str, | ||
| event_creator_jid: &str, | ||
| responder_jid: &str, | ||
| ) -> Result<(Vec<u8>, [u8; GCM_IV_SIZE])> { |
There was a problem hiding this comment.
Lock down fixed-size crypto inputs at the API boundary.
Line 29 and Line 48 accept unconstrained slices for message_secret/iv, but this protocol path requires fixed sizes (32-byte secret, 12-byte IV). Reject invalid sizes early so callers get deterministic errors instead of opaque downstream crypto failures.
Proposed patch
-use anyhow::Result;
+use anyhow::{ensure, Result};
@@
pub fn encrypt_event_response_with_secret(
response: &EventResponseMessage,
message_secret: &[u8],
@@
) -> Result<(Vec<u8>, [u8; GCM_IV_SIZE])> {
+ ensure!(
+ message_secret.len() == 32,
+ "message_secret must be exactly 32 bytes"
+ );
let plaintext = response.encode_to_vec();
@@
pub fn decrypt_event_response_with_secret(
enc_payload: &[u8],
iv: &[u8],
message_secret: &[u8],
@@
) -> Result<EventResponseMessage> {
+ ensure!(
+ message_secret.len() == 32,
+ "message_secret must be exactly 32 bytes"
+ );
+ ensure!(
+ iv.len() == GCM_IV_SIZE,
+ "iv must be exactly {} bytes",
+ GCM_IV_SIZE
+ );
let plaintext = decrypt_addon(Also applies to: 48-55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wacore/src/event.rs` around lines 29 - 35, Validate fixed-size crypto inputs
at the API boundary: in encrypt_event_response_with_secret (and the other
function that accepts an iv slice) check that message_secret.len() == 32 and
iv.len() == GCM_IV_SIZE (12) immediately and return an Err with a clear error if
sizes mismatch; do this before any cryptographic operations so callers get
deterministic errors rather than downstream panics/crypto failures, and
reference the functions encrypt_event_response_with_secret and the corresponding
decrypt/iv-handling function to locate and apply the same checks.
Review follow-ups on the events PR:
- Re-export EventCreationParams, EventResponseType, Events from src/lib.rs
(pub use features::{...}), matching how the other high-level feature APIs are
reachable as whatsapp_rust::* per AGENTS.md (Codex).
- Validate message_secret is 32 bytes at the public crypto boundary in
encrypt/decrypt_event_response_with_secret so a wrong-size secret fails with a
clear error instead of an opaque GCM failure (HKDF accepts any ikm length). The
IV length is already validated by decrypt_addon (CodeRabbit).
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
wacore/src/event.rs (1)
54-75:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winConsider early IV length validation for clearer error messages.
Look, I get it—you're delegating IV validation to
decrypt_addon'stry_into [u8; 12]. That works. But when something goes wrong, your users are going to see some cryptic slice conversion error instead of a clear "iv must be 12 bytes" message. We're building something people actually use here.The
message_secretcheck you added is exactly right. The IV is the same deal—fixed-size crypto input that should fail fast with an obvious error at the API boundary rather than deep in the stack.Proposed patch
pub fn decrypt_event_response_with_secret( enc_payload: &[u8], iv: &[u8], message_secret: &[u8], stanza_id: &str, event_creator_jid: &str, responder_jid: &str, ) -> Result<EventResponseMessage> { - // The IV length is validated downstream by decrypt_addon (try_into [u8; 12]). + ensure!( + iv.len() == GCM_IV_SIZE, + "iv must be {GCM_IV_SIZE} bytes, got {}", + iv.len() + ); ensure!( message_secret.len() == MESSAGE_SECRET_SIZE, "message_secret must be {MESSAGE_SECRET_SIZE} bytes, got {}", message_secret.len() );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wacore/src/event.rs` around lines 54 - 75, Add an early IV-length check in decrypt_event_response_with_secret so callers get a clear error instead of a downstream slice conversion panic: validate iv.len() == 12 (the expected IV size used by decrypt_addon/try_into) using ensure! similar to the existing message_secret check (referencing MESSAGE_SECRET_SIZE) before calling decrypt_addon; keep the error text descriptive like "iv must be 12 bytes, got {}" and otherwise leave decrypt_addon and event_response_addon_ctx usage unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@wacore/src/event.rs`:
- Around line 54-75: Add an early IV-length check in
decrypt_event_response_with_secret so callers get a clear error instead of a
downstream slice conversion panic: validate iv.len() == 12 (the expected IV size
used by decrypt_addon/try_into) using ensure! similar to the existing
message_secret check (referencing MESSAGE_SECRET_SIZE) before calling
decrypt_addon; keep the error text descriptive like "iv must be 12 bytes, got
{}" and otherwise leave decrypt_addon and event_response_addon_ctx usage
unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b13a22af-00f8-4484-9f36-76045aee3748
📒 Files selected for processing (2)
src/lib.rswacore/src/event.rs
Closes the features-28 gap.
The proto types (
EventMessage,EncEventResponseMessage,EventResponseMessage) and theEventResponseaddon use-case already existed, but there was no way to create an event or RSVP to one.src/features/events.rs(viaClient::events()):create(to, EventCreationParams)buildsevent_messageplus a 32-bytemessageContextInfo.message_secret(events require one —Events/ValidationErrorhasMISSING_MESSAGE_SECRET, same pattern as polls) and sends through the normal path (classify.rsalready routesevent_message). Returns the secret so the creator can decrypt later RSVPs.respond(chat, event_msg_id, creator, message_secret, EventResponseType, extra_guest_count)encrypts anEventResponseMessageand sendsenc_event_response_message.wacore/src/event.rs:encrypt_event_response_with_secret/decrypt_event_response_with_secret, a thin wrapper oversecret_enc_addonwithModificationType::EventResponse(mirrorspoll.rs). The event-creator + responder JIDs key the HKDF/AAD, and the responder JID is resolved to the creator's namespace (own LID for a LID-addressed event, else PN), matching the poll-vote path.Verified against
docs/captured-js/WAWeb/Events/GenerateEventCreationMessageProto.js(the{ name, description, location, startTime, endTime, joinLink, isScheduleCall, ... }field set) andGenerateEventResponseMessageProto.js({ eventCreationMessageKey, encPayload, encIv }).Tests: event-message field mapping, response encrypt/decrypt roundtrip, wrong-responder decryption fails, and PN responder resolution.
Scope note: inbound decrypt wiring for received RSVPs (
ModificationType::EventResponseon the recv path) is intentionally left as a follow-up; this PR covers the outbound create + respond APIs.