stricter image checking
This commit is contained in:
parent
46351fb17d
commit
d8f6d24511
29
package-lock.json
generated
29
package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"cropperjs": "^1.6.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-orm": "^0.30.10",
|
||||
"image-size": "^1.1.1",
|
||||
"jose": "^5.3.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"mysql2": "^3.9.7",
|
||||
@ -3622,6 +3623,20 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz",
|
||||
"integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==",
|
||||
"dependencies": {
|
||||
"queue": "6.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"image-size": "bin/image-size.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
@ -4075,9 +4090,9 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.9.7",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.7.tgz",
|
||||
"integrity": "sha512-KnJT8vYRcNAZv73uf9zpXqNbvBG7DJrs+1nACsjZP1HMJ1TgXEy8wnNilXAn/5i57JizXKtrUtwDB7HxT9DDpw==",
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.0.tgz",
|
||||
"integrity": "sha512-qx0mfWYt1DpTPkw8mAcHW/OwqqyNqBLBHvY5IjN8+icIYTjt6znrgYJ+gxqNNRpVknb5Wc/gcCM4XjbCR0j5tw==",
|
||||
"dependencies": {
|
||||
"denque": "^2.1.0",
|
||||
"generate-function": "^2.3.1",
|
||||
@ -4487,6 +4502,14 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/queue": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
||||
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
@ -43,6 +43,7 @@
|
||||
"cropperjs": "^1.6.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-orm": "^0.30.10",
|
||||
"image-size": "^1.1.1",
|
||||
"jose": "^5.3.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"mysql2": "^3.9.7",
|
||||
|
@ -7,7 +7,7 @@
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import FormControl from '../form/FormControl.svelte';
|
||||
import { allowedImages } from '$lib/constants';
|
||||
import { ALLOWED_IMAGES } from '$lib/constants';
|
||||
|
||||
export let show: Writable<boolean>;
|
||||
export let url: string = '/account';
|
||||
@ -99,7 +99,11 @@
|
||||
{#if picker}
|
||||
<FormControl>
|
||||
<label for="avatar-file">{$t('account.avatar.uploadLabel')}</label>
|
||||
<input type="file" on:change={(e) => readFile(e.target)} accept={allowedImages.join(',')} />
|
||||
<input
|
||||
type="file"
|
||||
on:change={(e) => readFile(e.target)}
|
||||
accept={ALLOWED_IMAGES.join(',')}
|
||||
/>
|
||||
<span>{$t('account.avatar.hint')}</span>
|
||||
</FormControl>
|
||||
{/if}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export const allowedImages = ['image/png', 'image/jpg', 'image/jpeg'];
|
||||
export const ALLOWED_IMAGES = ['image/png', 'image/jpg', 'image/jpeg'];
|
||||
export const OAUTH2_MAX_REDIRECTS = 5;
|
||||
export const OAUTH2_MAX_URLS = 1;
|
||||
export const MAX_FILE_SIZE_MB = 10;
|
||||
|
@ -13,6 +13,9 @@ import { readFile, stat, unlink, writeFile } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import * as mime from 'mime-types';
|
||||
import { OAuth2Clients } from './oauth2';
|
||||
import { MAX_FILE_SIZE_MB, ALLOWED_IMAGES } from '$lib/constants';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import imageSize from 'image-size';
|
||||
|
||||
export class Uploads {
|
||||
static userFallbackImage: Buffer;
|
||||
@ -115,12 +118,31 @@ export class Uploads {
|
||||
.where(eq(oauth2Client.id, client.id));
|
||||
}
|
||||
|
||||
static async ensureAllowedFile(file: File) {
|
||||
if (!ALLOWED_IMAGES.includes(file.type)) {
|
||||
error(400, 'File is not an image');
|
||||
}
|
||||
|
||||
if (file.size > MAX_FILE_SIZE_MB * 1e6) {
|
||||
error(400, 'File too big');
|
||||
}
|
||||
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const result = imageSize(buffer);
|
||||
if (!result?.height || !result?.width || result.height / result.width !== 1) {
|
||||
error(400, 'Invalid image file');
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static async saveAvatar(subject: User, file: File) {
|
||||
const ext = mime.extension(file.type);
|
||||
const newName = `user-${subject.uuid.split('-')[0]}-${Math.floor(Date.now() / 1000)}.${ext}`;
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const buffer = await Uploads.ensureAllowedFile(file);
|
||||
// Write to filesystem
|
||||
await writeFile(join(Uploads.uploads, newName), Buffer.from(arrayBuffer));
|
||||
await writeFile(join(Uploads.uploads, newName), buffer);
|
||||
// Remove old
|
||||
await Uploads.removeAvatar(subject);
|
||||
// Update DB
|
||||
@ -139,9 +161,9 @@ export class Uploads {
|
||||
static async saveClientAvatar(client: OAuth2Client, uploader: User, file: File) {
|
||||
const ext = mime.extension(file.type);
|
||||
const newName = `client-${client.client_id.substring(0, 8)}-${Math.floor(Date.now() / 1000)}.${ext}`;
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const buffer = await Uploads.ensureAllowedFile(file);
|
||||
// Write to filesystem
|
||||
await writeFile(join(Uploads.uploads, newName), Buffer.from(arrayBuffer));
|
||||
await writeFile(join(Uploads.uploads, newName), buffer);
|
||||
// Remove old
|
||||
await Uploads.removeClientAvatar(client);
|
||||
// Update DB
|
||||
|
Loading…
Reference in New Issue
Block a user