feat: cap custom CSS length and add validation tests
Bound customCSS to 100000 characters on both the client schema and the server body validation (the server is the enforcement boundary; multer's 1MB field cap was the only limit), regenerate the OpenAPI spec, and add a validation test suite covering acceptance, clearing, the length cap, and type rejection.
This commit is contained in:
1 parent
73f95ac8e1
commit
0f4240d3db
4 files changed
+61
-4
No files matched your search
@@ -35,7 +35,11 @@ export const statusPageSchema = z.object({
|
||||
showUptimePercentage: z.boolean().register(statusPageStepRegistry, { step: 1 }),
|
||||
showAdminLoginLink: z.boolean().register(statusPageStepRegistry, { step: 1 }),
|
||||
showInfrastructure: z.boolean().register(statusPageStepRegistry, { step: 1 }),
|
||||
customCSS: z.string().optional().register(statusPageStepRegistry, { step: 1 }),
|
||||
customCSS: z
|
||||
.string()
|
||||
.max(100000, "Custom CSS must be at most 100000 characters")
|
||||
.optional()
|
||||
.register(statusPageStepRegistry, { step: 1 }),
|
||||
theme: z
|
||||
.enum(STATUS_PAGE_THEMES)
|
||||
.optional()
|
||||
|
||||
+4
-2
@@ -10488,7 +10488,8 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"customCSS": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 100000
|
||||
},
|
||||
"removeLogo": {
|
||||
"anyOf": [
|
||||
@@ -10694,7 +10695,8 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"customCSS": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 100000
|
||||
},
|
||||
"removeLogo": {
|
||||
"anyOf": [
|
||||
|
||||
@@ -32,7 +32,7 @@ export const createStatusPageBodyValidation = z
|
||||
showUptimePercentage: booleanCoercion,
|
||||
showAdminLoginLink: booleanCoercion.optional(),
|
||||
showInfrastructure: booleanCoercion.optional(),
|
||||
customCSS: z.string().optional(),
|
||||
customCSS: z.string().max(100000, "Custom CSS must be at most 100000 characters").optional(),
|
||||
removeLogo: z.union([z.literal("true"), z.literal("false")]).optional(),
|
||||
theme: z.enum(StatusPageThemes).optional(),
|
||||
themeMode: z.enum(StatusPageThemeModes).optional(),
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from "@jest/globals";
|
||||
import { createStatusPageBodyValidation } from "../../../src/api/validation/statusPageValidation.ts";
|
||||
|
||||
const baseCreateBody = (overrides: Record<string, unknown> = {}) => ({
|
||||
type: "uptime",
|
||||
companyName: "Test Co",
|
||||
url: "my-status-page",
|
||||
monitors: ["0123456789abcdef01234567"],
|
||||
isPublished: true,
|
||||
showUptimePercentage: true,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe("createStatusPageBodyValidation", () => {
|
||||
it("accepts a valid body without customCSS", () => {
|
||||
const result = createStatusPageBodyValidation.safeParse(baseCreateBody());
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts and preserves customCSS", () => {
|
||||
const customCSS = ".status-page > footer { display: none; }";
|
||||
const result = createStatusPageBodyValidation.safeParse(baseCreateBody({ customCSS }));
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data.customCSS).toBe(customCSS);
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts an empty customCSS so it can be cleared", () => {
|
||||
const result = createStatusPageBodyValidation.safeParse(baseCreateBody({ customCSS: "" }));
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data.customCSS).toBe("");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects customCSS over the maximum length", () => {
|
||||
const result = createStatusPageBodyValidation.safeParse(baseCreateBody({ customCSS: "a".repeat(100001) }));
|
||||
expect(result.success).toBe(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ message: "Custom CSS must be at most 100000 characters", path: ["customCSS"] })])
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects a non-string customCSS", () => {
|
||||
const result = createStatusPageBodyValidation.safeParse(baseCreateBody({ customCSS: 42 }));
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user