fix: enforce RSVP idempotency in Firestore rules (#735) - #764
Open
saurabhhhcodes wants to merge 2 commits into
Open
fix: enforce RSVP idempotency in Firestore rules (#735)#764saurabhhhcodes wants to merge 2 commits into
saurabhhhcodes wants to merge 2 commits into
Conversation
added 2 commits
August 12, 2026 03:31
…singh#623) The QR scanner recorded attendance purely client-side without verifying the operator was authorized, so any authenticated user who photographed another attendee's QR could check them in (ghost attendance). Firestore rules already deny such writes, but the client attempted them blindly and surfaced generic errors. Adds an up-front authorization check in handleBarCodeScanned: the scanner must be the event owner or an admin, otherwise the scan is rejected with a clear message before any write is attempted (online or queued-offline).
…h#735) A duplicate RSVP write to an existing participant path fell through to the update rule, which only permits status/buddyPreference/updatedAt, so the full payload was rejected — but the create rule did not state this intent explicitly, and no test covered it. - firestore.rules: add !exists() guard to participant create (defense in depth; mirrors the client transaction check and the cloud function's already-exists guard) - tests/firestore.rules.test.ts: add 'Duplicate RSVP create -> denied' and 'Re-register after withdrawing -> allowed' tests; seed users doc in the existing create test, which previously failed with a null-value error because getUserData() had no user document to read - Rules suite: 49/52 passing (remaining 3 failures are pre-existing and unrelated: campusId seeds, club check-in fixture)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #735
Analysis
The app's RSVP paths were already partly protected: the client
performRsvptoggles via a transaction guarded byrsvpLoading, and the cloud functionregisterForEventthrowsalready-existsinside its transaction. What was missing:events/{eventId}/participants/{participantId}never explicitly stated that a duplicate create is rejected — the protection existed only implicitly (a blindsetDocof a full payload falls through to the update rule, which permits onlystatus/buddyPreference/updatedAt).Changes
firestore.rules: added!exists(.../participants/$(request.auth.uid))to the participant create rule — defense-in-depth so future refactors can't silently allow double RSVPs.tests/firestore.rules.test.ts:Duplicate RSVP create at own participant path -> denied(new)Re-register is allowed after withdrawing (delete then create)(new)Authenticated user creates participant -> allowedtest, which failed with a null-value error because nousers/{uid}document was seeded forgetUserData().Verification
Rules suite via Firestore emulator: 49/52 passing. The 3 remaining failures are pre-existing and unrelated (campusId seeds in event-create tests, club check-in fixture) — confirmed identical on a pristine rules file.