use the new TransformResponse utility for ALL.Net too

This commit is contained in:
beerpsi 2023-11-25 15:32:27 +07:00
parent c63c0f5300
commit 4d280f4f63
5 changed files with 64 additions and 95 deletions

View File

@ -22,7 +22,7 @@
"pnpm": "7"
},
"dependencies": {
"compression": "^1.7.4",
"base64-stream": "^1.0.0",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
@ -43,6 +43,7 @@
"zod-validation-error": "^2.1.0"
},
"devDependencies": {
"@types/base64-stream": "^1.0.5",
"@types/better-sqlite3": "^7.6.7",
"@types/compression": "^1.7.5",
"@types/express": "^4.17.21",

View File

@ -1,6 +1,7 @@
lockfileVersion: 5.4
specifiers:
'@types/base64-stream': ^1.0.5
'@types/better-sqlite3': ^7.6.7
'@types/compression': ^1.7.5
'@types/express': ^4.17.21
@ -11,23 +12,20 @@ specifiers:
'@types/safe-json-stringify': ^1.1.5
'@typescript-eslint/eslint-plugin': 5.47.1
'@typescript-eslint/parser': 5.47.1
compression: ^1.7.4
base64-stream: ^1.0.0
dotenv: ^16.3.1
eslint: 8.18.0
eslint-plugin-cadence: ^0.1.0
express: ^4.18.2
express-async-errors: ^3.1.1
fletcher: ^0.0.3
iconv-lite: ^0.6.3
json5: ^2.2.3
luxon: ^3.4.4
micro-packed: ^0.3.2
on-headers: ^1.0.2
raw-body: ^2.5.2
reflect-metadata: ^0.1.13
safe-json-stringify: ^1.2.0
sqlite3: ^5.1.6
stream-combiner: ^0.2.2
tap: ^18.6.1
tsconfig-paths: ^4.2.0
typed-struct: ^2.3.0
@ -39,21 +37,18 @@ specifiers:
zod-validation-error: ^2.1.0
dependencies:
compression: 1.7.4
base64-stream: 1.0.0
dotenv: 16.3.1
express: 4.18.2
express-async-errors: 3.1.1_express@4.18.2
fletcher: 0.0.3
iconv-lite: 0.6.3
json5: 2.2.3
luxon: 3.4.4
micro-packed: 0.3.2
on-headers: 1.0.2
raw-body: 2.5.2
reflect-metadata: 0.1.13
safe-json-stringify: 1.2.0
sqlite3: 5.1.6
stream-combiner: 0.2.2
tsconfig-paths: 4.2.0
typed-struct: 2.3.0_iconv-lite@0.6.3
typeorm: 0.3.17_sqlite3@5.1.6
@ -63,6 +58,7 @@ dependencies:
zod-validation-error: 2.1.0_zod@3.22.4
devDependencies:
'@types/base64-stream': 1.0.5
'@types/better-sqlite3': 7.6.7
'@types/compression': 1.7.5
'@types/express': 4.17.21
@ -419,10 +415,6 @@ packages:
dev: true
optional: true
/@scure/base/1.1.3:
resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==}
dev: false
/@sigstore/bundle/2.1.0:
resolution: {integrity: sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==}
engines: {node: ^16.14.0 || >=18.0.0}
@ -859,6 +851,12 @@ packages:
minimatch: 9.0.3
dev: true
/@types/base64-stream/1.0.5:
resolution: {integrity: sha512-gXuo/a7pQ1EXlR5ksM2MccBLl6UUgAgnzR01r/QoHnkaSNinmzSdaGcCq5NAxn72dZ5A1zNYQIl+J9hPsBgBrA==}
dependencies:
'@types/node': 16.18.62
dev: true
/@types/better-sqlite3/7.6.7:
resolution: {integrity: sha512-+c2YGPWY5831v3uj2/X0HRTK94u1GXU3sCnLqu7AKlxlSfawswnAiJR//TFzSL5azWsLQkG/uS+YnnqHtuZxPw==}
dependencies:
@ -1352,6 +1350,10 @@ packages:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/base64-stream/1.0.0:
resolution: {integrity: sha512-BQQZftaO48FcE1Kof9CmXMFaAdqkcNorgc8CxesZv9nMbbTF1EFyQe89UOuh//QMmdtfUDXyO8rgUalemL5ODA==}
dev: false
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -1413,11 +1415,6 @@ packages:
semver: 7.5.4
dev: true
/bytes/3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
dev: false
/bytes/3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
@ -1654,28 +1651,6 @@ packages:
text-hex: 1.0.0
dev: false
/compressible/2.0.18:
resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/compression/1.7.4:
resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==}
engines: {node: '>= 0.8.0'}
dependencies:
accepts: 1.3.8
bytes: 3.0.0
compressible: 2.0.18
debug: 2.6.9
on-headers: 1.0.2
safe-buffer: 5.1.2
vary: 1.1.2
transitivePeerDependencies:
- supports-color
dev: false
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@ -1837,10 +1812,6 @@ packages:
engines: {node: '>=12'}
dev: false
/duplexer/0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
dev: false
/eastasianwidth/0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
@ -2449,10 +2420,6 @@ packages:
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
dev: true
/fletcher/0.0.3:
resolution: {integrity: sha512-cyn1RJWoQDCM9A7CLVbYTN0TcQZ7GoN5hMDZAoIaRXD6PO0UjvRlQbrNzAbAJb7MX7rgUGNx5PMMexKL6gD/eQ==}
dev: false
/fn.name/1.1.0:
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
dev: false
@ -3361,12 +3328,6 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/micro-packed/0.3.2:
resolution: {integrity: sha512-D1Bq0/lVOzdxhnX5vylCxZpdw5LylH7Vd81py0DfRsKUP36XYpwvy8ZIsECVo3UfnoROn8pdKqkOzL7Cd82sGA==}
dependencies:
'@scure/base': 1.1.3
dev: false
/micromatch/4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
engines: {node: '>=8.6'}
@ -4282,10 +4243,6 @@ packages:
isarray: 2.0.5
dev: true
/safe-buffer/5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
dev: false
/safe-buffer/5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
@ -4576,13 +4533,6 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/stream-combiner/0.2.2:
resolution: {integrity: sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==}
dependencies:
duplexer: 0.1.2
through: 2.3.8
dev: false
/string-length/6.0.0:
resolution: {integrity: sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==}
engines: {node: '>=16'}
@ -4815,10 +4765,6 @@ packages:
any-promise: 1.3.0
dev: false
/through/2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: false
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}

View File

@ -1,9 +1,14 @@
import { Base64Encode } from "base64-stream";
import iconv from "iconv-lite";
import CreateLogCtx from "lib/logger/logger";
import getRawBody from "raw-body";
import { TransformResponse } from "utils/transform-response";
import { Transform } from "stream";
import { promisify } from "util";
import { inflate } from "zlib";
import zlib, { inflate } from "zlib";
import type { RequestHandler } from "express";
const logger = CreateLogCtx(__filename);
const inflateAsync = promisify(inflate);
export const DFIRequestResponse: (mustUseDfi: boolean) => RequestHandler = (mustUseDfi) => {
@ -16,6 +21,9 @@ export const DFIRequestResponse: (mustUseDfi: boolean) => RequestHandler = (must
const isUsingDfi = req.headers.pragma?.toUpperCase() === "DFI";
if (mustUseDfi && !isUsingDfi) {
logger.error("Received request that was not DFI-encoded.", {
pragma: req.headers.pragma ?? null,
});
return res.status(200).send("");
}
@ -32,33 +40,42 @@ export const DFIRequestResponse: (mustUseDfi: boolean) => RequestHandler = (must
body = rawBody.trim();
}
// Keys and values are not URL escaped.
// Keys and values are not URL escaped, but interpolated in (why)
// This should be fine. I think.
// eslint-disable-next-line require-atomic-updates
req.body = Object.fromEntries(body.split("&").map((s) => s.split("=")));
req.safeBody = req.body as Record<string, unknown>;
const originalSend = res.send;
const transformers: Array<NodeJS.ReadWriteStream> = [
iconv.encodeStream(req.body.encode ?? "EUC-JP"),
];
if (req.headers.pragma?.toUpperCase() === "DFI") {
transformers.push(
zlib.createDeflate({ flush: zlib.constants.Z_SYNC_FLUSH }),
new Base64Encode()
);
}
transformers.push(
new Transform({
transform(chunk, _encoding, callback) {
callback(null, chunk);
},
final(callback) {
this.push(Buffer.from("\r\n", "utf-8"));
callback(null);
},
})
);
TransformResponse(res, ...transformers);
const _send = res.send;
res.send = (params) => {
const body = `${new URLSearchParams(params).toString()}\n`;
const body = `${new URLSearchParams(params).toString()}`;
const encoding = req.body.encode ?? "EUC-JP";
const encodedBody = iconv.encode(body, encoding);
res.header("Content-Type", `text/plain; charset=${encoding}`);
// TODO: I don't know what black magic SEGA did, but I have been woefully
// unable to DFI-encode my responses...
return originalSend.apply(res, [encodedBody]);
// if (req.headers.pragma?.toUpperCase() !== "DFI") {
// return originalSend.apply(res, [encodedBody]);
// }
// res.header("Pragma", "DFI");
// return originalSend.apply(res, [deflateSync(encodedBody).toString("base64")]);
return _send.call(res, body);
};
next();

View File

@ -1,6 +1,6 @@
import { VERSIONS } from "./versions";
import { TransformResponse } from "../../../utils/transform-response";
import { GetClassMethods } from "../utils/reflection";
import { TransformResponse } from "../utils/response";
import { Router } from "express";
import { ChunithmVersions } from "lib/constants/game-versions";
import CreateLogCtx from "lib/logger/logger";

View File

@ -1,7 +1,6 @@
import { ChunkLength, ToBuffer } from "./buffer";
import { ChunkLength, ToBuffer } from "../servers/titles/utils/buffer";
import onHeaders from "on-headers";
import type { Response } from "express";
import type { Transform } from "stream";
/**
* Pipe the response through a series of transformations.
@ -10,7 +9,7 @@ import type { Transform } from "stream";
* @param res The response to transform.
* @param transformers stream.Transform items.
*/
export function TransformResponse(res: Response, ...transformers: Array<Transform>) {
export function TransformResponse(res: Response, ...transformers: Array<NodeJS.ReadWriteStream>) {
const head = transformers[0];
const tail = transformers.at(-1);
@ -77,8 +76,14 @@ export function TransformResponse(res: Response, ...transformers: Array<Transfor
ended = true;
// write Buffer for Node.js 0.8
// @ts-expect-error bruh
return chunk ? head.end(ToBuffer(chunk, encoding)) : head.end();
if (chunk) {
// @ts-expect-error hhh
head.end(ToBuffer(chunk, encoding));
} else {
head.end();
}
return this;
};
// @ts-expect-error zzz