(api) replace multer as express middleware with matching h3 calls

This commit is contained in:
Valentyne Stigloher 2024-09-09 20:06:51 +02:00
parent 47338e6415
commit 8e00dd04bb
5 changed files with 19 additions and 44 deletions

View File

@ -70,9 +70,6 @@ export default {
const ids = await this.$csrfFetch(this.url, { const ids = await this.$csrfFetch(this.url, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
}); });
this.$emit('uploaded', ids); this.$emit('uploaded', ids);
} catch (e) { } catch (e) {

View File

@ -57,7 +57,6 @@
"markdown-it-sup": "^2.0.0", "markdown-it-sup": "^2.0.0",
"mastodon": "^1.2.2", "mastodon": "^1.2.2",
"memorystore": "^1.6.7", "memorystore": "^1.6.7",
"multer": "^1.4.5-lts.1",
"nepali-calendar-js": "https://github.com/pixunil/nepali-calendar-js", "nepali-calendar-js": "https://github.com/pixunil/nepali-calendar-js",
"node-fetch": "^2.6.12", "node-fetch": "^2.6.12",
"nodemailer": "^6.7.8", "nodemailer": "^6.7.8",

36
pnpm-lock.yaml generated
View File

@ -131,9 +131,6 @@ dependencies:
memorystore: memorystore:
specifier: ^1.6.7 specifier: ^1.6.7
version: 1.6.7 version: 1.6.7
multer:
specifier: ^1.4.5-lts.1
version: 1.4.5-lts.1
nepali-calendar-js: nepali-calendar-js:
specifier: https://github.com/pixunil/nepali-calendar-js specifier: https://github.com/pixunil/nepali-calendar-js
version: github.com/pixunil/nepali-calendar-js/a6e12cb1db54c508c49dc0c619cef0674e7c1cde version: github.com/pixunil/nepali-calendar-js/a6e12cb1db54c508c49dc0c619cef0674e7c1cde
@ -6621,10 +6618,6 @@ packages:
normalize-path: 3.0.0 normalize-path: 3.0.0
picomatch: 2.3.1 picomatch: 2.3.1
/append-field@1.0.0:
resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==}
dev: false
/aproba@1.2.0: /aproba@1.2.0:
resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==}
dev: true dev: true
@ -7319,13 +7312,6 @@ packages:
run-applescript: 7.0.0 run-applescript: 7.0.0
dev: false dev: false
/busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
dependencies:
streamsearch: 1.1.0
dev: false
/bytes@3.1.2: /bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@ -7829,6 +7815,7 @@ packages:
inherits: 2.0.4 inherits: 2.0.4
readable-stream: 2.3.8 readable-stream: 2.3.8
typedarray: 0.0.6 typedarray: 0.0.6
dev: true
/confbox@0.1.7: /confbox@0.1.7:
resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==}
@ -12379,6 +12366,7 @@ packages:
hasBin: true hasBin: true
dependencies: dependencies:
minimist: 1.2.8 minimist: 1.2.8
dev: true
/mkdirp@1.0.4: /mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
@ -12431,19 +12419,6 @@ packages:
/muggle-string@0.4.1: /muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
/multer@1.4.5-lts.1:
resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==}
engines: {node: '>= 6.0.0'}
dependencies:
append-field: 1.0.0
busboy: 1.6.0
concat-stream: 1.6.2
mkdirp: 0.5.6
object-assign: 4.1.1
type-is: 1.6.18
xtend: 4.0.2
dev: false
/nan@2.18.0: /nan@2.18.0:
resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
@ -15244,11 +15219,6 @@ packages:
resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
dev: true dev: true
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
dev: false
/streamx@2.18.0: /streamx@2.18.0:
resolution: {integrity: sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==} resolution: {integrity: sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==}
dependencies: dependencies:
@ -16075,6 +16045,7 @@ packages:
/typedarray@0.0.6: /typedarray@0.0.6:
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
dev: true
/typescript@5.3.3: /typescript@5.3.3:
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
@ -17439,6 +17410,7 @@ packages:
/xtend@4.0.2: /xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'} engines: {node: '>=0.4'}
dev: true
/xxhashjs@0.2.2: /xxhashjs@0.2.2:
resolution: {integrity: sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==} resolution: {integrity: sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==}

View File

@ -1,6 +1,6 @@
import { Router } from 'express'; import { Router } from 'express';
import { getH3Event } from 'h3-express';
import { ulid } from 'ulid'; import { ulid } from 'ulid';
import multer from 'multer';
import { loadImage, createCanvas } from 'canvas'; import { loadImage, createCanvas } from 'canvas';
import type { Canvas } from 'canvas'; import type { Canvas } from 'canvas';
import { handleErrorAsync } from '../../src/helpers.ts'; import { handleErrorAsync } from '../../src/helpers.ts';
@ -58,7 +58,12 @@ const scaleDownTo = (image: Canvas, size: number): Canvas => {
const router = Router(); const router = Router();
router.post('/images/upload', multer({ limits: { fileSize: 10 * 1024 * 1024 } }).any(), handleErrorAsync(async (req, res) => { router.post('/images/upload', handleErrorAsync(async (req, res) => {
const files = await readMultipartFormData(getH3Event(req));
if (!files) {
return res.status(400);
}
const s3 = new S3(awsConfig); const s3 = new S3(awsConfig);
const requestedSizes = req.query.sizes === undefined || req.query.sizes === 'all' const requestedSizes = req.query.sizes === undefined || req.query.sizes === 'all'
@ -66,11 +71,11 @@ router.post('/images/upload', multer({ limits: { fileSize: 10 * 1024 * 1024 } })
: (req.query.sizes as string).split(','); : (req.query.sizes as string).split(',');
const ids = []; const ids = [];
for (const file of req.files as Express.Multer.File[]) { for (const file of files) {
const id = ulid(); const id = ulid();
let image; let image;
try { try {
image = await loadImage(await sharp(file.buffer).png() image = await loadImage(await sharp(file.data).png()
.toBuffer()); .toBuffer());
} catch { } catch {
return res.status(400).json({ error: 'error.invalidImage' }); return res.status(400).json({ error: 'error.invalidImage' });

View File

@ -1,5 +1,6 @@
import type { Request, Response } from 'express'; import type { Request, Response } from 'express';
import { Router } from 'express'; import { Router } from 'express';
import { getH3Event } from 'h3-express';
import SQL from 'sql-template-strings'; import SQL from 'sql-template-strings';
import md5 from 'js-md5'; import md5 from 'js-md5';
import { ulid } from 'ulid'; import { ulid } from 'ulid';
@ -22,7 +23,6 @@ import crypto from '../crypto.ts';
import { awsConfig, awsParams } from '../aws.ts'; import { awsConfig, awsParams } from '../aws.ts';
import { S3, NoSuchKey } from '@aws-sdk/client-s3'; import { S3, NoSuchKey } from '@aws-sdk/client-s3';
import zlib from 'zlib'; import zlib from 'zlib';
import multer from 'multer';
import type { Database } from '../db.ts'; import type { Database } from '../db.ts';
import type { AuthenticatorRow, UserRow } from './user.ts'; import type { AuthenticatorRow, UserRow } from './user.ts';
import type { import type {
@ -1079,16 +1079,18 @@ router.get('/profile/export', handleErrorAsync(async (req: Request, res: Respons
signature}`)); signature}`));
})); }));
router.post('/profile/import', multer({ limits: { fileSize: 10 * 1024 * 1024 } }).array('files', 1), handleErrorAsync(async (req, res) => { router.post('/profile/import', handleErrorAsync(async (req, res) => {
if (!req.user) { if (!req.user) {
return res.status(401).json({ error: 'Unauthorised' }); return res.status(401).json({ error: 'Unauthorised' });
} }
if (req.files.length !== 1) { const files = await readMultipartFormData(getH3Event(req));
if (!files || files.length !== 1) {
return res.status(401).json({ error: 'One file expected' }); return res.status(401).json({ error: 'One file expected' });
} }
const contentParts = zlib.gunzipSync((req.files as Express.Multer.File[])[0].buffer).toString('utf-8') const contentParts = zlib.gunzipSync(files[0].data).toString('utf-8')
.split('\n'); .split('\n');
if (contentParts.length !== 2) { if (contentParts.length !== 2) {
return res.status(401).json({ error: 'profile.backup.error.signature' }); return res.status(401).json({ error: 'profile.backup.error.signature' });