mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
feat(api): ✨ Add safeguard when using formdata without a boundary
This commit is contained in:
parent
3f9ec0bc80
commit
67bee695e6
2
index.ts
2
index.ts
|
|
@ -7,6 +7,7 @@ import { LogLevel, LogManager, type MultiLogManager } from "log-manager";
|
||||||
import { setupDatabase } from "~drizzle/db";
|
import { setupDatabase } from "~drizzle/db";
|
||||||
import { agentBans } from "~middlewares/agent-bans";
|
import { agentBans } from "~middlewares/agent-bans";
|
||||||
import { bait } from "~middlewares/bait";
|
import { bait } from "~middlewares/bait";
|
||||||
|
import { boundaryCheck } from "~middlewares/boundary-check";
|
||||||
import { ipBans } from "~middlewares/ip-bans";
|
import { ipBans } from "~middlewares/ip-bans";
|
||||||
import { logger } from "~middlewares/logger";
|
import { logger } from "~middlewares/logger";
|
||||||
import { Note } from "~packages/database-interface/note";
|
import { Note } from "~packages/database-interface/note";
|
||||||
|
|
@ -113,6 +114,7 @@ app.use(ipBans);
|
||||||
app.use(agentBans);
|
app.use(agentBans);
|
||||||
app.use(bait);
|
app.use(bait);
|
||||||
app.use(logger);
|
app.use(logger);
|
||||||
|
app.use(boundaryCheck);
|
||||||
|
|
||||||
// Inject own filesystem router
|
// Inject own filesystem router
|
||||||
for (const [route, path] of Object.entries(routes)) {
|
for (const [route, path] of Object.entries(routes)) {
|
||||||
|
|
|
||||||
18
middlewares/boundary-check.ts
Normal file
18
middlewares/boundary-check.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { errorResponse } from "@response";
|
||||||
|
import { createMiddleware } from "hono/factory";
|
||||||
|
|
||||||
|
export const boundaryCheck = createMiddleware(async (context, next) => {
|
||||||
|
// Checks that FormData boundary is present
|
||||||
|
const contentType = context.req.header("content-type");
|
||||||
|
|
||||||
|
if (contentType?.includes("multipart/form-data")) {
|
||||||
|
if (!contentType.includes("boundary")) {
|
||||||
|
return errorResponse(
|
||||||
|
"You are sending a request with a multipart/form-data content type but without a boundary. Please include a boundary in the Content-Type header. For more information, visit https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data",
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
@ -60,4 +60,29 @@ describe("API Tests", () => {
|
||||||
await db.delete(Emojis).where(eq(Emojis.shortcode, "test"));
|
await db.delete(Emojis).where(eq(Emojis.shortcode, "test"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Try sending FormData without a boundary", async () => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("test", "test");
|
||||||
|
|
||||||
|
const response = await sendTestRequest(
|
||||||
|
new Request(
|
||||||
|
wrapRelativeUrl(`${base_url}/api/v1/custom_emojis`, base_url),
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].accessToken}`,
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
expect(data.error).toBeString();
|
||||||
|
expect(data.error).toContain("https://stackoverflow.com");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue