Fix audit #14 (body size limits), #17 (duplicate session_id), #22 (unused import)
All checks were successful
Deploy to Production / Deploy to Server (push) Successful in 2m53s

This commit is contained in:
OpenClaw 2026-02-16 19:51:24 +00:00
parent 6cc30db5c6
commit 09c6feb06e
9 changed files with 36 additions and 10 deletions

View file

@ -99,8 +99,9 @@ app.use("/v1/recover", recoverRouter);
app.use("/v1/billing", billingRouter);
app.use("/v1/email-change", emailChangeRouter);
// Authenticated routes
app.use("/v1/convert", authMiddleware, usageMiddleware, pdfRateLimitMiddleware, convertRouter);
// Authenticated routes — conversion routes get tighter body limits (500KB)
const convertBodyLimit = express.json({ limit: "500kb" });
app.use("/v1/convert", convertBodyLimit, authMiddleware, usageMiddleware, pdfRateLimitMiddleware, convertRouter);
app.use("/v1/templates", authMiddleware, usageMiddleware, templatesRouter);
// Admin: usage stats (admin key required)

View file

@ -19,6 +19,9 @@ function getStripe(): Stripe {
const router = Router();
// Track provisioned session IDs to prevent duplicate key creation
const provisionedSessions = new Set<string>();
// Create a Stripe Checkout session for Pro subscription
router.post("/checkout", async (_req: Request, res: Response) => {
try {
@ -47,6 +50,12 @@ router.get("/success", async (req: Request, res: Response) => {
return;
}
// Prevent duplicate provisioning from same session
if (provisionedSessions.has(sessionId)) {
res.status(409).send("This checkout session has already been used to provision a key. If you lost your key, use the key recovery feature.");
return;
}
try {
const session = await getStripe().checkout.sessions.retrieve(sessionId);
const customerId = session.customer as string;
@ -58,6 +67,7 @@ router.get("/success", async (req: Request, res: Response) => {
}
const keyInfo = await createProKey(email, customerId);
provisionedSessions.add(session.id);
// Return a nice HTML page instead of raw JSON
res.send(`<!DOCTYPE html>
@ -142,6 +152,7 @@ router.post("/webhook", async (req: Request, res: Response) => {
}
const keyInfo = await createProKey(email, customerId);
provisionedSessions.add(session.id);
logger.info({ email, customerId }, "checkout.session.completed: provisioned pro key");
break;
}

View file

@ -1,5 +1,5 @@
import { Router, Request, Response } from "express";
import { renderPdf, renderUrlPdf, getPoolStats } from "../services/browser.js";
import { renderPdf, renderUrlPdf } from "../services/browser.js";
import { markdownToHtml, wrapHtml } from "../services/markdown.js";
import dns from "node:dns/promises";
import logger from "../services/logger.js";