mirror of
https://github.com/PretendoNetwork/BOSS.git
synced 2026-03-21 17:34:19 -05:00
chore: replace dicer with formidable
This commit is contained in:
parent
f432d2d3dc
commit
28f77dcf77
133
package-lock.json
generated
133
package-lock.json
generated
|
|
@ -14,9 +14,9 @@
|
|||
"@pretendonetwork/grpc": "^1.0.6",
|
||||
"@typegoose/auto-increment": "^4.13.0",
|
||||
"commander": "^14.0.0",
|
||||
"dicer": "^0.3.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^5.1.0",
|
||||
"formidable": "^3.5.4",
|
||||
"fs-extra": "^11.2.0",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^8.18.1",
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
"@smithy/types": "^4.0.0",
|
||||
"@types/dicer": "^0.2.4",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/formidable": "^3.4.5",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^22.10.5",
|
||||
"axios": "^1.7.9",
|
||||
|
|
@ -1917,6 +1918,18 @@
|
|||
"@tybys/wasm-util": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -2000,6 +2013,15 @@
|
|||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@paralleldrive/cuid2": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz",
|
||||
"integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
|
|
@ -3198,6 +3220,16 @@
|
|||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/formidable": {
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.5.tgz",
|
||||
"integrity": "sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
|
||||
|
|
@ -4187,6 +4219,12 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/async-function": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||
|
|
@ -4722,15 +4760,14 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/dicer": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.1.tgz",
|
||||
"integrity": "sha512-ObioMtXnmjYs3aRtpIJt9rgQSPCIhKVkFPip+E9GUDyWl8N435znUxK/JfNwGZJ2wnn5JKQ7Ly3vOK5Q5dylGA==",
|
||||
"node_modules/dezalgo": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
|
||||
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
"asap": "^2.0.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
|
|
@ -5997,6 +6034,23 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formidable": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz",
|
||||
"integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"dezalgo": "^1.0.4",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
|
@ -8749,14 +8803,6 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
@ -11123,6 +11169,11 @@
|
|||
"@tybys/wasm-util": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"@noble/hashes": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -11185,6 +11236,14 @@
|
|||
"integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@paralleldrive/cuid2": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz",
|
||||
"integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==",
|
||||
"requires": {
|
||||
"@noble/hashes": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
|
|
@ -12051,6 +12110,15 @@
|
|||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"@types/formidable": {
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.5.tgz",
|
||||
"integrity": "sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/fs-extra": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
|
||||
|
|
@ -12671,6 +12739,11 @@
|
|||
"is-array-buffer": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
|
||||
},
|
||||
"async-function": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||
|
|
@ -13025,12 +13098,13 @@
|
|||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
|
||||
},
|
||||
"dicer": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.1.tgz",
|
||||
"integrity": "sha512-ObioMtXnmjYs3aRtpIJt9rgQSPCIhKVkFPip+E9GUDyWl8N435znUxK/JfNwGZJ2wnn5JKQ7Ly3vOK5Q5dylGA==",
|
||||
"dezalgo": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
|
||||
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
|
||||
"requires": {
|
||||
"streamsearch": "^1.1.0"
|
||||
"asap": "^2.0.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"doctrine": {
|
||||
|
|
@ -13935,6 +14009,16 @@
|
|||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"formidable": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz",
|
||||
"integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==",
|
||||
"requires": {
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"dezalgo": "^1.0.4",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
|
@ -15747,11 +15831,6 @@
|
|||
"internal-slot": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@
|
|||
"@pretendonetwork/grpc": "^1.0.6",
|
||||
"@typegoose/auto-increment": "^4.13.0",
|
||||
"commander": "^14.0.0",
|
||||
"dicer": "^0.3.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^5.1.0",
|
||||
"formidable": "^3.5.4",
|
||||
"fs-extra": "^11.2.0",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^8.18.1",
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
"@smithy/types": "^4.0.0",
|
||||
"@types/dicer": "^0.2.4",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/formidable": "^3.4.5",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^22.10.5",
|
||||
"axios": "^1.7.9",
|
||||
|
|
|
|||
|
|
@ -1,87 +1,38 @@
|
|||
import crypto from 'node:crypto';
|
||||
import { Stream } from 'node:stream';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { formidable } from 'formidable';
|
||||
import express from 'express';
|
||||
import Dicer from 'dicer';
|
||||
import { getDuplicateCECData, getRandomCECData } from '@/database';
|
||||
import { getFriends } from '@/util';
|
||||
import { CECData } from '@/models/cec-data';
|
||||
import { CECSlot } from '@/models/cec-slot';
|
||||
import { SendMode } from '@/types/common/spr-slot';
|
||||
import RequestException from '@/request-exception';
|
||||
import { config } from '@/config-manager';
|
||||
import { restrictHostnames } from '@/middleware/host-limit';
|
||||
import { logger } from '@/logger';
|
||||
import { getCDNFileAsBuffer, uploadCDNFile } from '@/cdn';
|
||||
import RequestException from '@/request-exception';
|
||||
import type { File } from 'formidable';
|
||||
import type { Request } from 'express';
|
||||
import type { SPRSlot } from '@/types/common/spr-slot';
|
||||
|
||||
const spr = express.Router();
|
||||
|
||||
function multipartParser(request: express.Request, response: express.Response, next: express.NextFunction): void {
|
||||
const RE_BOUNDARY = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i;
|
||||
const RE_FILE_NAME = /name="(.*)"/;
|
||||
|
||||
const contentType = request.header('content-type');
|
||||
|
||||
if (!contentType) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const boundary = RE_BOUNDARY.exec(contentType);
|
||||
|
||||
if (!boundary) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const dicer = new Dicer({ boundary: boundary[1] || boundary[2] });
|
||||
const files: Record<string, Buffer> = {};
|
||||
|
||||
dicer.on('part', (part: Dicer.PartStream) => {
|
||||
let fileBuffer = Buffer.alloc(0);
|
||||
let fileName = '';
|
||||
|
||||
part.on('header', (header) => {
|
||||
const contentDisposition = header['content-disposition' as keyof object];
|
||||
const regexResult = RE_FILE_NAME.exec(contentDisposition);
|
||||
|
||||
if (regexResult) {
|
||||
fileName = regexResult[1];
|
||||
}
|
||||
});
|
||||
|
||||
part.on('data', (data: Buffer | string) => {
|
||||
if (typeof data === 'string') {
|
||||
data = Buffer.from(data);
|
||||
}
|
||||
|
||||
fileBuffer = Buffer.concat([fileBuffer, data]);
|
||||
});
|
||||
|
||||
part.on('end', () => {
|
||||
files[fileName] = fileBuffer;
|
||||
});
|
||||
|
||||
part.on('error', (error: Error) => {
|
||||
return next(new RequestException(error.message, 400));
|
||||
});
|
||||
async function parseMultipart(request: Request): Promise<Record<string, File>> {
|
||||
const form = formidable({
|
||||
multiples: false
|
||||
});
|
||||
const parsedForm = await form.parse(request).catch((err: Error) => {
|
||||
throw new RequestException(err.message, 400);
|
||||
});
|
||||
|
||||
dicer.on('finish', function () {
|
||||
request.files = files;
|
||||
return next();
|
||||
});
|
||||
|
||||
Stream.pipeline(request, dicer, (error: Error | null) => {
|
||||
if (error) {
|
||||
return next(new RequestException(error.message, 400));
|
||||
}
|
||||
});
|
||||
const entries = Object.entries(parsedForm[1]);
|
||||
const entriesWithSinglefile = entries.map(v => [v[0], (v[1] ?? [])[0]]);
|
||||
return Object.fromEntries(entriesWithSinglefile);
|
||||
}
|
||||
|
||||
spr.post('/relay/0', multipartParser, async (request, response) => {
|
||||
if (!request.files) {
|
||||
response.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
spr.post('/relay/0', async (request, response) => {
|
||||
const files = await parseMultipart(request);
|
||||
|
||||
if (!request.pid || !request.nexAccount) {
|
||||
response.sendStatus(401);
|
||||
|
|
@ -90,15 +41,15 @@ spr.post('/relay/0', multipartParser, async (request, response) => {
|
|||
|
||||
// * Check that the account is a 3DS and isn't banned
|
||||
if (!request.nexAccount.friendCode || request.nexAccount.accessLevel < 0) {
|
||||
logger.info(`{request.pid}: User is not a 3DS or is banned`);
|
||||
logger.info(`${request.pid}: User is not a 3DS or is banned`);
|
||||
response.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
const sprMetadataBuffer: Buffer | undefined = request.files['spr-meta'];
|
||||
const sprMetadataFile: File | undefined = files['spr-meta'];
|
||||
|
||||
if (!sprMetadataBuffer) {
|
||||
logger.warn(`{request.pid}: Missing spr-meta file`);
|
||||
if (!sprMetadataFile) {
|
||||
logger.warn(`${request.pid}: Missing spr-meta file`);
|
||||
response.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
|
@ -106,7 +57,7 @@ spr.post('/relay/0', multipartParser, async (request, response) => {
|
|||
const sprSlots: SPRSlot[] = [];
|
||||
|
||||
// * Check spr-meta metadata headers
|
||||
const sprMetadata = sprMetadataBuffer.toString();
|
||||
const sprMetadata = await readFile(sprMetadataFile.filepath, 'utf-8');
|
||||
const metadataHeaders = sprMetadata.split('\r\n'); // * Split header lines
|
||||
|
||||
if (metadataHeaders.length < 1) {
|
||||
|
|
@ -177,15 +128,15 @@ spr.post('/relay/0', multipartParser, async (request, response) => {
|
|||
let data: Buffer = Buffer.alloc(0);
|
||||
if (size > 0 && sendMode !== SendMode.RecvOnly) {
|
||||
const slot = i.toString().padStart(2, '0');
|
||||
const slotData: Buffer | undefined = request.files['spr-slot' + slot];
|
||||
const slotDataFile: File | undefined = files['spr-slot' + slot];
|
||||
|
||||
if (!slotData) {
|
||||
if (!slotDataFile) {
|
||||
logger.warn(`${request.pid}: Missing slot data file`);
|
||||
response.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
if (slotData.length !== size) {
|
||||
if (slotDataFile.size !== size) {
|
||||
logger.warn(`${request.pid}: Invalid slot data size`);
|
||||
response.sendStatus(400);
|
||||
return;
|
||||
|
|
@ -200,12 +151,13 @@ spr.post('/relay/0', multipartParser, async (request, response) => {
|
|||
// * This is then followed by a CecMessageHeader (see https://github.com/NarcolepticK/CECDocs/blob/master/Structs/CecMessageHeader.md)
|
||||
|
||||
// * Check that we at least have enough size for the StreetPass header
|
||||
if (slotData.length < 0x12) {
|
||||
if (slotDataFile.size < 0x12) {
|
||||
logger.warn(`${request.pid}: Slot is too short`);
|
||||
response.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const slotData = await readFile(slotDataFile.filepath);
|
||||
if (slotData.readUInt32LE() !== 0x6161) {
|
||||
logger.warn(`${request.pid}: Slot header missmatch`);
|
||||
response.sendStatus(400);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user