fix: actual mime type checking in submit route
This commit is contained in:
parent
48c99e442f
commit
b17478a718
3 changed files with 80 additions and 1 deletions
|
|
@ -19,6 +19,7 @@
|
|||
"dayjs": "^1.11.13",
|
||||
"downshift": "^9.0.9",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"file-type": "^20.4.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"next": "15.2.4",
|
||||
"next-auth": "5.0.0-beta.25",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ importers:
|
|||
embla-carousel-react:
|
||||
specifier: ^8.6.0
|
||||
version: 8.6.0(react@19.1.0)
|
||||
file-type:
|
||||
specifier: ^20.4.1
|
||||
version: 20.4.1
|
||||
jsqr:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
|
|
@ -792,6 +795,13 @@ packages:
|
|||
'@tailwindcss/postcss@4.1.3':
|
||||
resolution: {integrity: sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg==}
|
||||
|
||||
'@tokenizer/inflate@0.2.7':
|
||||
resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@tokenizer/token@0.3.0':
|
||||
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
||||
|
||||
'@trafficlunar/asmcrypto.js@1.0.2':
|
||||
resolution: {integrity: sha512-Iv0EnYsr8PdZo4iipddzZAV790VbQoDAEr9ZdNvwlrtaAZDoSl5ivweMOBEHV2smMzFqkRlSQIyo+HKUPyFkjQ==}
|
||||
|
||||
|
|
@ -1382,6 +1392,9 @@ packages:
|
|||
picomatch:
|
||||
optional: true
|
||||
|
||||
fflate@0.8.2:
|
||||
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
|
@ -1390,6 +1403,10 @@ packages:
|
|||
resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
file-type@20.4.1:
|
||||
resolution: {integrity: sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
fill-range@7.1.1:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -1492,6 +1509,9 @@ packages:
|
|||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
ignore@5.3.2:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
|
@ -1879,6 +1899,10 @@ packages:
|
|||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
peek-readable@7.0.0:
|
||||
resolution: {integrity: sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
|
|
@ -2132,6 +2156,10 @@ packages:
|
|||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strtok3@10.2.2:
|
||||
resolution: {integrity: sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
styled-jsx@5.1.6:
|
||||
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
|
@ -2176,6 +2204,10 @@ packages:
|
|||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
token-types@6.0.0:
|
||||
resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
ts-api-utils@2.1.0:
|
||||
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
|
||||
engines: {node: '>=18.12'}
|
||||
|
|
@ -2213,6 +2245,10 @@ packages:
|
|||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uint8array-extras@1.4.0:
|
||||
resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -2788,6 +2824,16 @@ snapshots:
|
|||
postcss: 8.5.3
|
||||
tailwindcss: 4.1.3
|
||||
|
||||
'@tokenizer/inflate@0.2.7':
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
fflate: 0.8.2
|
||||
token-types: 6.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@tokenizer/token@0.3.0': {}
|
||||
|
||||
'@trafficlunar/asmcrypto.js@1.0.2': {}
|
||||
|
||||
'@tybys/wasm-util@0.9.0':
|
||||
|
|
@ -3572,6 +3618,8 @@ snapshots:
|
|||
optionalDependencies:
|
||||
picomatch: 4.0.2
|
||||
|
||||
fflate@0.8.2: {}
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 4.0.1
|
||||
|
|
@ -3580,6 +3628,15 @@ snapshots:
|
|||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
file-type@20.4.1:
|
||||
dependencies:
|
||||
'@tokenizer/inflate': 0.2.7
|
||||
strtok3: 10.2.2
|
||||
token-types: 6.0.0
|
||||
uint8array-extras: 1.4.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
fill-range@7.1.1:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
|
@ -3687,6 +3744,8 @@ snapshots:
|
|||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
|
|
@ -4058,6 +4117,8 @@ snapshots:
|
|||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
peek-readable@7.0.0: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
|
@ -4390,6 +4451,11 @@ snapshots:
|
|||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
strtok3@10.2.2:
|
||||
dependencies:
|
||||
'@tokenizer/token': 0.3.0
|
||||
peek-readable: 7.0.0
|
||||
|
||||
styled-jsx@5.1.6(react@19.1.0):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
|
|
@ -4422,6 +4488,11 @@ snapshots:
|
|||
dependencies:
|
||||
is-number: 7.0.0
|
||||
|
||||
token-types@6.0.0:
|
||||
dependencies:
|
||||
'@tokenizer/token': 0.3.0
|
||||
ieee754: 1.2.1
|
||||
|
||||
ts-api-utils@2.1.0(typescript@5.8.3):
|
||||
dependencies:
|
||||
typescript: 5.8.3
|
||||
|
|
@ -4474,6 +4545,8 @@ snapshots:
|
|||
|
||||
typescript@5.8.3: {}
|
||||
|
||||
uint8array-extras@1.4.0: {}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// import * as tf from "@tensorflow/tfjs-node";
|
||||
// import * as nsfwjs from "nsfwjs";
|
||||
import sharp from "sharp";
|
||||
import { fileTypeFromBuffer } from "file-type";
|
||||
|
||||
const MIN_IMAGE_DIMENSIONS = 128;
|
||||
const MAX_IMAGE_DIMENSIONS = 1024;
|
||||
|
|
@ -23,12 +24,16 @@ const MAX_IMAGE_SIZE = 1024 * 1024; // 1 MB
|
|||
|
||||
export async function validateImage(file: File): Promise<{ valid: boolean; error?: string; status?: number }> {
|
||||
if (!file || file.size == 0) return { valid: false, error: "Empty image file" };
|
||||
if (!file.type.startsWith("image/")) return { valid: false, error: "Invalid file type. Only images are allowed" };
|
||||
if (file.size > MAX_IMAGE_SIZE)
|
||||
return { valid: false, error: `One or more of your images are too large. Maximum size is ${MAX_IMAGE_SIZE / (1024 * 1024)}MB` };
|
||||
|
||||
try {
|
||||
const buffer = Buffer.from(await file.arrayBuffer());
|
||||
|
||||
// Check mime type
|
||||
const fileType = await fileTypeFromBuffer(buffer);
|
||||
if (!fileType || !fileType.mime.startsWith("image/")) return { valid: false, error: "Invalid image file type. Only actual images are allowed" };
|
||||
|
||||
const metadata = await sharp(buffer).metadata();
|
||||
|
||||
// Check image dimensions
|
||||
|
|
|
|||
Loading…
Reference in a new issue