validate report attachment by file mime type
deploy / build-and-deploy (push) Failing after 35s

This commit is contained in:
bytedream committed 2026-10-31 15:00:30 +01:00
1 parent efe40a4d7d
commit d9a906fc0d
3 files changed
+39 -9

No files matched your search

+16
View File
@@ -19,6 +19,7 @@
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"daisyui": "^5.7.50", "daisyui": "^5.7.50",
"drizzle-orm": "^0.45.4", "drizzle-orm": "^0.45.4",
"mime": "^4.1.2",
"mysql2": "^3.24.6", "mysql2": "^3.24.6",
"nanostores": "^1.5.5", "nanostores": "^1.5.5",
"pino": "^10.4.0", "pino": "^10.4.0",
@@ -5576,6 +5577,21 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/mime": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/mime/-/mime-4.1.2.tgz",
"integrity": "sha512-ikRzZ2RwbUVDyL9SsU0f2Phcmav4yq5r8faH5ZZKHtOZrMBLnrQOrj0uvqZ5R1uQnj+RO7Wcklw/lAf81mP9LQ==",
"funding": [
"https://github.com/sponsors/broofa"
],
"license": "MIT",
"bin": {
"mime": "bin/cli.js"
},
"engines": {
"node": ">=16"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.54.0", "version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+1
View File
@@ -22,6 +22,7 @@
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"daisyui": "^5.7.50", "daisyui": "^5.7.50",
"drizzle-orm": "^0.45.4", "drizzle-orm": "^0.45.4",
"mime": "^4.1.2",
"mysql2": "^3.24.6", "mysql2": "^3.24.6",
"nanostores": "^1.5.5", "nanostores": "^1.5.5",
"pino": "^10.4.0", "pino": "^10.4.0",
+22 -9
View File
@@ -9,6 +9,7 @@ import crypto from 'node:crypto';
import path from 'node:path'; import path from 'node:path';
import { sendWebhook, WebhookAction } from '@util/webhook.ts'; import { sendWebhook, WebhookAction } from '@util/webhook.ts';
import { allowedImageTypes, allowedVideoTypes } from '@util/media.ts'; import { allowedImageTypes, allowedVideoTypes } from '@util/media.ts';
import mime from 'mime/lite';
export const report = { export const report = {
submitReport: defineAction({ submitReport: defineAction({
@@ -26,14 +27,6 @@ export const report = {
.nullable() .nullable()
}), }),
handler: async (input) => { handler: async (input) => {
const fileSize = input.files?.reduce((prev, curr) => prev + curr.size, 0);
if (fileSize && fileSize > MAX_UPLOAD_BYTES) {
throw new ActionError({
code: 'BAD_REQUEST',
message: 'Die Anhänge sind zu groß'
});
}
const report = await db.getReportByUrlHash({ urlHash: input.urlHash }); const report = await db.getReportByUrlHash({ urlHash: input.urlHash });
if (!report) { if (!report) {
throw new ActionError({ throw new ActionError({
@@ -54,13 +47,33 @@ export const report = {
} }
} }
if (!UPLOAD_PATH) { if (input.files && !UPLOAD_PATH) {
throw new ActionError({ throw new ActionError({
code: 'FORBIDDEN', code: 'FORBIDDEN',
message: 'Es dürfen keine Anhänge hochgeladen werden' message: 'Es dürfen keine Anhänge hochgeladen werden'
}); });
} }
let totalFilesSize = 0;
for (const file of (input.files ?? [])) {
const realType = mime.getType(file.name);
if (realType != file.type) {
throw new ActionError({
code: 'NOT_ACCEPTABLE',
message: `Falscher Dateityp für '${file.name}': ${realType}`
});
}
totalFilesSize += file.size;
}
if (totalFilesSize > MAX_UPLOAD_BYTES) {
throw new ActionError({
code: 'BAD_REQUEST',
message: 'Die Anhänge sind zu groß'
});
}
const filePaths = [] as string[]; const filePaths = [] as string[];
try { try {
await db.transaction(async (tx) => { await db.transaction(async (tx) => {