Add framework examples and tighten Express raw-body handling#55
Add framework examples and tighten Express raw-body handling#55Prateek32177 wants to merge 1 commit intomainfrom
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
| createWebhookMiddleware({ | ||
| platform: 'stripe', | ||
| secret: process.env.STRIPE_WEBHOOK_SECRET ?? '', | ||
| }), |
Check failure
Code scanning / CodeQL
Missing rate limiting High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 days ago
To fix the problem, introduce an Express rate‑limiting middleware and apply it to the webhook route (and optionally to other routes) so that expensive verification work in createWebhookMiddleware cannot be abused by unbounded request rates. The fix should not alter the existing behavior of the route for legitimate traffic, just bound the number of requests per time window.
The best way to do this in this context is to use the widely‑used express-rate-limit package. In examples/express/src/index.ts, we will:
- Import
rateLimitfromexpress-rate-limit. - Define a
stripeWebhookLimiterconfigured with a reasonablewindowMsandmaxrequests. - Insert
stripeWebhookLimiteras middleware in theapp.post('/webhooks/stripe', ...)call, beforecreateWebhookMiddleware(...), ensuring that abusive traffic is rejected before the verification work runs. - Leave the rest of the app structure unchanged, respecting the existing comment about the critical middleware order (webhook route before
express.json()).
Concretely:
- Add a new import line after the existing
expressimport. - Add a small configuration block for the limiter after
const app = express();. - Modify the
app.post('/webhooks/stripe', ...)definition to include the limiter as an additional argument between the route path andcreateWebhookMiddleware({ ... }).
| @@ -1,8 +1,14 @@ | ||
| import express from 'express'; | ||
| import { createWebhookMiddleware } from '@hookflo/tern/express'; | ||
| import rateLimit from 'express-rate-limit'; | ||
|
|
||
| const app = express(); | ||
|
|
||
| const stripeWebhookLimiter = rateLimit({ | ||
| windowMs: 15 * 60 * 1000, // 15 minutes | ||
| max: 100, // limit each IP to 100 Stripe webhook requests per windowMs | ||
| }); | ||
|
|
||
| // ─── CRITICAL ORDER ─────────────────────────────────────────────────────────── | ||
| // Register the webhook route BEFORE app.use(express.json()). | ||
| // If express.json() runs first it consumes the raw body and signature | ||
| @@ -18,6 +21,7 @@ | ||
| // and attaches the verified payload to req.webhook before calling next(). | ||
| app.post( | ||
| '/webhooks/stripe', | ||
| stripeWebhookLimiter, | ||
| createWebhookMiddleware({ | ||
| platform: 'stripe', | ||
| secret: process.env.STRIPE_WEBHOOK_SECRET ?? '', |
| @@ -9,7 +9,8 @@ | ||
| }, | ||
| "dependencies": { | ||
| "@hookflo/tern": "../../", | ||
| "express": "^4.21.2" | ||
| "express": "^4.21.2", | ||
| "express-rate-limit": "^8.3.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/express": "^5.0.1", |
| Package | Version | Security advisories |
| express-rate-limit (npm) | 8.3.1 | None |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41a636f8e2
ℹ️ 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".
| if (body instanceof Uint8Array) { | ||
| return body; |
There was a problem hiding this comment.
Convert ArrayBuffer raw bodies before parsed-body fallback
hasUsableRawBody now treats ArrayBuffer as a valid raw payload, but extractRawBody does not have an ArrayBuffer branch, so requests with req.rawBody as ArrayBuffer fall through to the parsed-body warning path (or stream read) instead of using the raw bytes. In strict mode this can let the middleware proceed and then fail signature verification because the body is re-serialized/empty, which breaks the new raw-body compatibility this commit is trying to add.
Useful? React with 👍 / 👎.
Motivation
@hookflo/ternbuild to make onboarding and testing with the Stripe CLI straightforward.express.json()consumption of the body causes signature verification to fail silently.npx @hookflo/tern-cliand run local tests without external storage.Description
examples/workspace and per-framework example packages withpackage.json,tsconfig.json,src/handlers, and per-exampleREADME.mdfiles for Hono, Next.js, Cloudflare Workers, and Express, and a top-levelexamples/README.mdwith quick starts and CLI guidance.@hookflo/ternto the local repo via"@hookflo/tern": "../../"so examples use the local build.src/adapters/shared.tsto accept an optionalrawBodyonMinimalNodeRequestand addhasRawByteBodyandhasUsableRawBodyhelpers and preferrawBodywhen extracting bytes.createWebhookMiddleware) to only return a strict-mode error when the request body was parsed (hasParsedBody) and no usable raw bytes are present (!hasUsableRawBody), preserving existing strict safety but allowing frameworks/middleware that provide raw bytes to work.Testing
npm run buildat the repo root completed successfully.npm installinside each example directory was attempted but blocked by registry policy in this environment (returned403 Forbidden).node --loader tsx src/adapters/testExpress.ts) failed in this environment due to thetsxloader not being available.Codex Task