Issue 57: AppCheck Enforcement#84
Conversation
(we need to create a reCAPTCHA key in Google Cloud Console)
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughClient routes initialize Firebase App Check; client mutation hooks fetch App Check tokens and attach them to request payloads; new server middleware verifies tokens and injects claims; protected server functions require and validate ChangesFirebase App Check Integration
Sequence DiagramsequenceDiagram
participant Browser
participant MutationHook
participant FirebaseClient as firebase.client.ts
participant ServerFn
participant Middleware as appCheckMiddleware
participant FirebaseAdmin as firebase-admin
Browser->>MutationHook: user submits form / register
MutationHook->>FirebaseClient: getAppCheckToken()
FirebaseClient-->>MutationHook: token string | null
MutationHook->>ServerFn: call with payload + appCheckToken
ServerFn->>Middleware: appCheckMiddleware receives data
Middleware->>FirebaseAdmin: admin.appCheck().verifyToken(appCheckToken)
FirebaseAdmin-->>Middleware: verified claims | error
Middleware-->>ServerFn: next({ context.appCheckClaims })
ServerFn-->>Browser: response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@app/src/hooks/mutations/useRegisterDonor.ts`:
- Around line 16-26: Run the project formatter (oxfmt) on the file containing
useRegisterDonor and commit the formatted output so CI passes; specifically
reformat the mutationFn block that calls getAppCheckToken and registerDonor (the
async callback in useRegisterDonor) using the project's oxfmt settings and then
stage the updated file.
In `@app/src/lib/firebase.client.ts`:
- Around line 3-6: The code is using an unsafe type assertion to call
.getToken() on the AppCheck instance; instead, import and call the typed
getToken(appCheck) helper from firebase/app-check. Locate the AppCheck
initialization where initializeAppCheck(...) and ReCaptchaEnterpriseProvider are
used and remove the "(... as unknown as ...).getToken()" style call; import
getToken from "firebase/app-check" and call await getToken(appCheck) (or pass
the AppCheck instance variable) to obtain the token with proper typing.
In `@app/src/server/middleware/appCheckMiddleware.ts`:
- Around line 1-36: This file fails the repo formatter; run the project's
formatter (oxfmt) on the new middleware file and commit the changes so CI
passes. Specifically, open the file containing appCheckMiddleware (created via
createMiddleware) and run "oxfmt --replace" or the repository's configured
formatting command to apply the expected line breaks/indentation and import
styling, then stage the formatted file and push the commit.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 483991f6-877f-4850-974e-8bccf1a8f6ad
📒 Files selected for processing (8)
app/src/hooks/mutations/useRegisterDonor.tsapp/src/hooks/mutations/useSubmitFamilyForm.tsapp/src/lib/firebase.client.tsapp/src/routes/_storefront/checkout.tsxapp/src/routes/family/drive/$driveId/form.tsxapp/src/server/functions/familyForm.tsapp/src/server/functions/profile.tsapp/src/server/middleware/appCheckMiddleware.ts
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)
app/src/hooks/useCheckoutFlow.ts (1)
105-140:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPreserve the App Check failure message in the toast.
Line 107 can now fail with the explicit App Check refresh guidance from
useRegisterDonor, but this catch path always shows a generic toast. That hides the only actionable recovery step for the new failure mode.Proposed fix
} catch (error) { const message = error instanceof Error ? error.message : "Failed to register or login"; console.error(message); - toast.error("Failed to register or login"); + toast.error(message); }🤖 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 `@app/src/hooks/useCheckoutFlow.ts` around lines 105 - 140, submitRegister's catch path (and the loginMutation onError) currently always shows a generic "Failed to register or login" toast, which hides actionable App Check refresh guidance returned by useRegisterDonor; update the catch block after registerMutation.mutateAsync (and the loginMutation onError handler) to compute the message as done (const message = error instanceof Error ? error.message : "Failed to register or login") and pass that message into toast.error(message) instead of the hardcoded string so the App Check guidance is preserved; references: submitRegister, registerMutation.mutateAsync, loginMutation.mutate, onError.
🤖 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 `@app/src/hooks/useCheckoutFlow.ts`:
- Around line 105-140: submitRegister's catch path (and the loginMutation
onError) currently always shows a generic "Failed to register or login" toast,
which hides actionable App Check refresh guidance returned by useRegisterDonor;
update the catch block after registerMutation.mutateAsync (and the loginMutation
onError handler) to compute the message as done (const message = error
instanceof Error ? error.message : "Failed to register or login") and pass that
message into toast.error(message) instead of the hardcoded string so the App
Check guidance is preserved; references: submitRegister,
registerMutation.mutateAsync, loginMutation.mutate, onError.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 47d2453a-6ac1-4be6-908a-32acaacfad49
📒 Files selected for processing (4)
app/src/hooks/mutations/useRegisterDonor.tsapp/src/hooks/useCheckoutFlow.tsapp/src/lib/firebase.client.tsapp/src/server/middleware/appCheckMiddleware.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- app/src/lib/firebase.client.ts
- app/src/server/middleware/appCheckMiddleware.ts
Pull Request
Description
Added AppCheck enforcement to protect public endpoints from bot abuse. Donor registration and family form submissions now require reCAPTCHA validation on the client side and token verification on the server side before processing.
Type of Change
Related Issues (put task name here from notion)
Issue #57
Additional Notes
@rk234 @ArnavGupta23 -> here's some setup required:
Assuming you both have access to Google Cloud Console, one of y'all needs to do the following to enable AppCheck:
.env.localand share it with us so we can do the same 👍That's everything else that's needed to activate the protection :)
Summary by CodeRabbit