mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-07 12:36:57 +00:00
fix multipart/form-data decoding
This commit is contained in:
parent
c0f24eaf5d
commit
89cab66898
2 changed files with 42 additions and 10 deletions
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { pipeline } from 'node:stream/promises';
|
||||||
|
import fs from 'node:fs';
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
export function createTemp(): Promise<[string, () => void]> {
|
export function createTemp(): Promise<[string, () => void]> {
|
||||||
|
@ -27,3 +29,14 @@ export function createTempDir(): Promise<[string, () => void]> {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function saveToTempFile(stream: NodeJS.ReadableStream): Promise<string> {
|
||||||
|
const [filepath, cleanup] = await createTemp();
|
||||||
|
try {
|
||||||
|
await pipeline(stream, fs.createWriteStream(filepath));
|
||||||
|
return filepath;
|
||||||
|
} catch (e) {
|
||||||
|
cleanup();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { FastifyInstance } from 'fastify';
|
import { FastifyInstance } from 'fastify';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
import { saveToTempFile } from '@/misc/create-temp.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServerUtilityService {
|
export class ServerUtilityService {
|
||||||
|
@ -29,17 +30,16 @@ export class ServerUtilityService {
|
||||||
// Store to temporary file instead, and copy the body fields while we're at it.
|
// Store to temporary file instead, and copy the body fields while we're at it.
|
||||||
fastify.addHook<{ Body?: Record<string, string | string[] | undefined> }>('onRequest', async request => {
|
fastify.addHook<{ Body?: Record<string, string | string[] | undefined> }>('onRequest', async request => {
|
||||||
if (request.isMultipart()) {
|
if (request.isMultipart()) {
|
||||||
|
// We can't use saveRequestFiles() because it erases all the data fields.
|
||||||
|
// Instead, recreate it manually.
|
||||||
|
// https://github.com/fastify/fastify-multipart/issues/549
|
||||||
|
|
||||||
|
for await (const part of request.parts()) {
|
||||||
|
if (part.type === 'field') {
|
||||||
|
const k = part.fieldname;
|
||||||
|
const v = String(part.value);
|
||||||
const body = request.body ??= {};
|
const body = request.body ??= {};
|
||||||
|
|
||||||
// Save upload to temp directory.
|
|
||||||
// These are attached to request.savedRequestFiles
|
|
||||||
await request.saveRequestFiles();
|
|
||||||
|
|
||||||
// Copy fields to body
|
|
||||||
const formData = await request.formData();
|
|
||||||
formData.forEach((v, k) => {
|
|
||||||
// This can be string or File, and we handle files above.
|
|
||||||
if (typeof(v) === 'string') {
|
|
||||||
// This is just progressive conversion from undefined -> string -> string[]
|
// This is just progressive conversion from undefined -> string -> string[]
|
||||||
if (body[k]) {
|
if (body[k]) {
|
||||||
if (Array.isArray(body[k])) {
|
if (Array.isArray(body[k])) {
|
||||||
|
@ -50,8 +50,27 @@ export class ServerUtilityService {
|
||||||
} else {
|
} else {
|
||||||
body[k] = v;
|
body[k] = v;
|
||||||
}
|
}
|
||||||
}
|
} else { // Otherwise it's a file
|
||||||
|
try {
|
||||||
|
const [filepath] = await saveToTempFile(part.file);
|
||||||
|
|
||||||
|
const tmpUploads = (request.tmpUploads ??= []);
|
||||||
|
tmpUploads.push(filepath);
|
||||||
|
|
||||||
|
const requestSavedFiles = (request.savedRequestFiles ??= []);
|
||||||
|
requestSavedFiles.push({
|
||||||
|
...part,
|
||||||
|
filepath,
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// Cleanup to avoid file leak in case of errors
|
||||||
|
await request.cleanRequestFiles();
|
||||||
|
request.tmpUploads = null;
|
||||||
|
request.savedRequestFiles = null;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue