@nestjs/platform-fastify 10.4.20 → 10.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { FastifyInstance, FastifyPluginCallback } from 'fastify';
|
|
2
|
+
import * as http from 'node:http';
|
|
3
|
+
export type MiddlewareFn<Req extends {
|
|
4
|
+
url: string;
|
|
5
|
+
originalUrl?: string;
|
|
6
|
+
}, Res extends {
|
|
7
|
+
finished?: boolean;
|
|
8
|
+
writableEnded?: boolean;
|
|
9
|
+
}, Ctx = unknown> = (req: Req, res: Res, next: (err?: unknown) => void) => void;
|
|
10
|
+
declare const supportedHooks: readonly ["onError", "onSend", "preParsing", "preSerialization", "onRequest", "onResponse", "onTimeout", "preHandler", "preValidation"];
|
|
11
|
+
type SupportedHook = (typeof supportedHooks)[number];
|
|
12
|
+
interface MiddieOptions {
|
|
13
|
+
hook?: SupportedHook;
|
|
14
|
+
}
|
|
15
|
+
declare function fastifyMiddie(fastify: FastifyInstance, options: MiddieOptions, next: (err?: Error) => void): void;
|
|
16
|
+
declare namespace fastifyMiddie {
|
|
17
|
+
export interface FastifyMiddieOptions {
|
|
18
|
+
hook?: 'onRequest' | 'preParsing' | 'preValidation' | 'preHandler' | 'preSerialization' | 'onSend' | 'onResponse' | 'onTimeout' | 'onError';
|
|
19
|
+
}
|
|
20
|
+
type FastifyMiddie = FastifyPluginCallback<fastifyMiddie.FastifyMiddieOptions>;
|
|
21
|
+
export interface IncomingMessageExtended {
|
|
22
|
+
body?: any;
|
|
23
|
+
query?: any;
|
|
24
|
+
}
|
|
25
|
+
export type NextFunction = (err?: any) => void;
|
|
26
|
+
export type SimpleHandleFunction = (req: http.IncomingMessage & IncomingMessageExtended, res: http.ServerResponse) => void;
|
|
27
|
+
export type NextHandleFunction = (req: http.IncomingMessage & IncomingMessageExtended, res: http.ServerResponse, next: NextFunction) => void;
|
|
28
|
+
export type Handler = SimpleHandleFunction | NextHandleFunction;
|
|
29
|
+
export const fastifyMiddie: FastifyMiddie;
|
|
30
|
+
export { fastifyMiddie as default };
|
|
31
|
+
}
|
|
32
|
+
declare module 'fastify' {
|
|
33
|
+
interface FastifyInstance {
|
|
34
|
+
use(fn: fastifyMiddie.Handler): this;
|
|
35
|
+
use(route: string, fn: fastifyMiddie.Handler): this;
|
|
36
|
+
use(routes: string[], fn: fastifyMiddie.Handler): this;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A clone of `@fastify/middie` engine https://github.com/fastify/middie
|
|
41
|
+
* with an extra vulnerability fix. Path is now decoded before matching to
|
|
42
|
+
* avoid bypassing middleware with encoded characters.
|
|
43
|
+
*/
|
|
44
|
+
declare const _default: typeof fastifyMiddie;
|
|
45
|
+
export default _default;
|
|
46
|
+
export { fastifyMiddie };
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fastifyMiddie = fastifyMiddie;
|
|
4
|
+
const fastify_plugin_1 = require("fastify-plugin");
|
|
5
|
+
const url_sanitizer_1 = require("find-my-way/lib/url-sanitizer");
|
|
6
|
+
const path_to_regexp_1 = require("path-to-regexp");
|
|
7
|
+
const reusify = require("reusify");
|
|
8
|
+
/**
|
|
9
|
+
* A clone of `@fastify/middie` engine https://github.com/fastify/middie
|
|
10
|
+
* with an extra vulnerability fix. Path is now decoded before matching to
|
|
11
|
+
* avoid bypassing middleware with encoded characters.
|
|
12
|
+
*/
|
|
13
|
+
function middie(complete) {
|
|
14
|
+
const middlewares = [];
|
|
15
|
+
const pool = reusify(Holder);
|
|
16
|
+
return {
|
|
17
|
+
use,
|
|
18
|
+
run,
|
|
19
|
+
};
|
|
20
|
+
function use(url, f) {
|
|
21
|
+
if (f === undefined) {
|
|
22
|
+
f = url;
|
|
23
|
+
url = null;
|
|
24
|
+
}
|
|
25
|
+
let regexp;
|
|
26
|
+
if (typeof url === 'string') {
|
|
27
|
+
const pathRegExp = (0, path_to_regexp_1.pathToRegexp)(sanitizePrefixUrl(url), {
|
|
28
|
+
end: false,
|
|
29
|
+
});
|
|
30
|
+
regexp = pathRegExp.regexp;
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(f)) {
|
|
33
|
+
for (const val of f) {
|
|
34
|
+
middlewares.push({ regexp, fn: val });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
middlewares.push({ regexp, fn: f });
|
|
39
|
+
}
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
function run(req, res, ctx) {
|
|
43
|
+
if (!middlewares.length) {
|
|
44
|
+
complete(null, req, res, ctx);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
req.originalUrl = req.url;
|
|
48
|
+
const holder = pool.get();
|
|
49
|
+
holder.req = req;
|
|
50
|
+
holder.res = res;
|
|
51
|
+
holder.url = sanitizeUrl(req.url);
|
|
52
|
+
holder.context = ctx;
|
|
53
|
+
holder.done();
|
|
54
|
+
}
|
|
55
|
+
function Holder() {
|
|
56
|
+
this.req = null;
|
|
57
|
+
this.res = null;
|
|
58
|
+
this.url = null;
|
|
59
|
+
this.context = null;
|
|
60
|
+
this.i = 0;
|
|
61
|
+
const that = this;
|
|
62
|
+
this.done = function (err) {
|
|
63
|
+
const req = that.req;
|
|
64
|
+
const res = that.res;
|
|
65
|
+
const url = that.url;
|
|
66
|
+
const context = that.context;
|
|
67
|
+
const i = that.i++;
|
|
68
|
+
req.url = req.originalUrl;
|
|
69
|
+
if (res.finished === true || res.writableEnded === true) {
|
|
70
|
+
cleanup();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (err || middlewares.length === i) {
|
|
74
|
+
complete(err, req, res, context);
|
|
75
|
+
cleanup();
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const { fn, regexp } = middlewares[i];
|
|
79
|
+
if (regexp) {
|
|
80
|
+
// Decode URL before matching to avoid bypassing middleware
|
|
81
|
+
const decodedUrl = (0, url_sanitizer_1.safeDecodeURI)(url).path;
|
|
82
|
+
const result = regexp.exec(decodedUrl);
|
|
83
|
+
if (result) {
|
|
84
|
+
req.url = req.url.replace(result[0], '');
|
|
85
|
+
if (req.url[0] !== '/')
|
|
86
|
+
req.url = '/' + req.url;
|
|
87
|
+
fn(req, res, that.done);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
that.done();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
fn(req, res, that.done);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function cleanup() {
|
|
99
|
+
that.req = null;
|
|
100
|
+
that.res = null;
|
|
101
|
+
that.context = null;
|
|
102
|
+
that.i = 0;
|
|
103
|
+
pool.release(that);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function sanitizeUrl(url) {
|
|
108
|
+
for (let i = 0, len = url.length; i < len; i++) {
|
|
109
|
+
const charCode = url.charCodeAt(i);
|
|
110
|
+
if (charCode === 63 || charCode === 35) {
|
|
111
|
+
return url.slice(0, i);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return url;
|
|
115
|
+
}
|
|
116
|
+
function sanitizePrefixUrl(url) {
|
|
117
|
+
if (url === '/')
|
|
118
|
+
return '';
|
|
119
|
+
if (url[url.length - 1] === '/')
|
|
120
|
+
return url.slice(0, -1);
|
|
121
|
+
return url;
|
|
122
|
+
}
|
|
123
|
+
const kMiddlewares = Symbol('fastify-middie-middlewares');
|
|
124
|
+
const kMiddie = Symbol('fastify-middie-instance');
|
|
125
|
+
const kMiddieHasMiddlewares = Symbol('fastify-middie-has-middlewares');
|
|
126
|
+
const supportedHooksWithPayload = [
|
|
127
|
+
'onError',
|
|
128
|
+
'onSend',
|
|
129
|
+
'preParsing',
|
|
130
|
+
'preSerialization',
|
|
131
|
+
];
|
|
132
|
+
const supportedHooksWithoutPayload = [
|
|
133
|
+
'onRequest',
|
|
134
|
+
'onResponse',
|
|
135
|
+
'onTimeout',
|
|
136
|
+
'preHandler',
|
|
137
|
+
'preValidation',
|
|
138
|
+
];
|
|
139
|
+
const supportedHooks = [
|
|
140
|
+
...supportedHooksWithPayload,
|
|
141
|
+
...supportedHooksWithoutPayload,
|
|
142
|
+
];
|
|
143
|
+
function fastifyMiddie(fastify, options, next) {
|
|
144
|
+
fastify.decorate('use', use);
|
|
145
|
+
fastify[kMiddlewares] = [];
|
|
146
|
+
fastify[kMiddieHasMiddlewares] = false;
|
|
147
|
+
fastify[kMiddie] = middie(onMiddieEnd);
|
|
148
|
+
const hook = options.hook || 'onRequest';
|
|
149
|
+
if (!supportedHooks.includes(hook)) {
|
|
150
|
+
next(new Error(`The hook "${hook}" is not supported by fastify-middie`));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
fastify
|
|
154
|
+
.addHook(hook, supportedHooksWithPayload.includes(hook)
|
|
155
|
+
? runMiddieWithPayload
|
|
156
|
+
: runMiddie)
|
|
157
|
+
.addHook('onRegister', onRegister);
|
|
158
|
+
function use(path, fn) {
|
|
159
|
+
if (typeof path === 'string') {
|
|
160
|
+
const prefix = this.prefix;
|
|
161
|
+
path = prefix + (path === '/' && prefix.length > 0 ? '' : path);
|
|
162
|
+
}
|
|
163
|
+
this[kMiddlewares].push([path, fn]);
|
|
164
|
+
if (fn == null) {
|
|
165
|
+
this[kMiddie].use(path);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
this[kMiddie].use(path, fn);
|
|
169
|
+
}
|
|
170
|
+
this[kMiddieHasMiddlewares] = true;
|
|
171
|
+
return this;
|
|
172
|
+
}
|
|
173
|
+
function runMiddie(req, reply, next) {
|
|
174
|
+
if (this[kMiddieHasMiddlewares]) {
|
|
175
|
+
const raw = req.raw;
|
|
176
|
+
raw.id = req.id;
|
|
177
|
+
raw.hostname = req.hostname;
|
|
178
|
+
raw.protocol = req.protocol;
|
|
179
|
+
raw.ip = req.ip;
|
|
180
|
+
raw.ips = req.ips;
|
|
181
|
+
raw.log = req.log;
|
|
182
|
+
req.raw.query = req.query;
|
|
183
|
+
reply.raw.log = req.log;
|
|
184
|
+
if (req.body !== undefined)
|
|
185
|
+
req.raw.body = req.body;
|
|
186
|
+
this[kMiddie].run(req.raw, reply.raw, next);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
next();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function runMiddieWithPayload(req, reply, _payload, next) {
|
|
193
|
+
runMiddie.bind(this)(req, reply, next);
|
|
194
|
+
}
|
|
195
|
+
function onMiddieEnd(err, _req, _res, next) {
|
|
196
|
+
next(err);
|
|
197
|
+
}
|
|
198
|
+
function onRegister(instance) {
|
|
199
|
+
const middlewares = instance[kMiddlewares].slice();
|
|
200
|
+
instance[kMiddlewares] = [];
|
|
201
|
+
instance[kMiddie] = middie(onMiddieEnd);
|
|
202
|
+
instance[kMiddieHasMiddlewares] = false;
|
|
203
|
+
instance.decorate('use', use);
|
|
204
|
+
for (const middleware of middlewares) {
|
|
205
|
+
instance.use(...middleware);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
next();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* A clone of `@fastify/middie` engine https://github.com/fastify/middie
|
|
212
|
+
* with an extra vulnerability fix. Path is now decoded before matching to
|
|
213
|
+
* avoid bypassing middleware with encoded characters.
|
|
214
|
+
*/
|
|
215
|
+
exports.default = (0, fastify_plugin_1.default)(fastifyMiddie, {
|
|
216
|
+
fastify: '5.x',
|
|
217
|
+
name: '@fastify/middie',
|
|
218
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/platform-fastify",
|
|
3
|
-
"version": "10.4.
|
|
3
|
+
"version": "10.4.22",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@platform-fastify)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,5 +39,6 @@
|
|
|
39
39
|
"@fastify/view": {
|
|
40
40
|
"optional": true
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
},
|
|
43
|
+
"gitHead": "e88b270cb5497d122183d7cad423dcbaaae037f0"
|
|
43
44
|
}
|