Updated the project.

This commit is contained in:
Batuhan Berk Başoğlu 2024-06-03 15:44:25 -04:00
parent 5dfe9f128d
commit 7919556077
1550 changed files with 17063 additions and 40183 deletions

0
my-app/node_modules/webpack-dev-server/node_modules/webpack-dev-middleware/LICENSE generated vendored Executable file → Normal file
View file

View file

View file

View file

@ -14,7 +14,8 @@ const {
getHeaderFromResponse,
setHeaderForResponse,
setStatusCode,
send
send,
sendError
} = require("./utils/compatibleAPI");
const ready = require("./utils/ready");
@ -86,15 +87,26 @@ function wrapper(context) {
}
async function processRequest() {
/** @type {import("./utils/getFilenameFromUrl").Extra} */
const extra = {};
const filename = getFilenameFromUrl(context,
/** @type {string} */
req.url);
req.url, extra);
if (!filename) {
await goNext();
return;
}
if (extra.errorCode) {
if (extra.errorCode === 403) {
context.logger.error(`Malicious path "${filename}".`);
}
sendError(req, res, extra.errorCode);
return;
}
let {
headers
} = context.options;

View file

View file

@ -161,6 +161,125 @@ function send(req, res, bufferOtStream, byteLength) {
res.end(bufferOtStream);
}
}
/**
* @template {ServerResponse} Response
* @param {Response} res
*/
function clearHeadersForResponse(res) {
const headers = getHeaderNames(res);
for (let i = 0; i < headers.length; i++) {
res.removeHeader(headers[i]);
}
}
const matchHtmlRegExp = /["'&<>]/;
/**
* @param {string} string raw HTML
* @returns {string} escaped HTML
*/
function escapeHtml(string) {
const str = `${string}`;
const match = matchHtmlRegExp.exec(str);
if (!match) {
return str;
}
let escape;
let html = "";
let index = 0;
let lastIndex = 0;
for (({
index
} = match); index < str.length; index++) {
switch (str.charCodeAt(index)) {
// "
case 34:
escape = "&quot;";
break;
// &
case 38:
escape = "&amp;";
break;
// '
case 39:
escape = "&#39;";
break;
// <
case 60:
escape = "&lt;";
break;
// >
case 62:
escape = "&gt;";
break;
default:
// eslint-disable-next-line no-continue
continue;
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index);
}
lastIndex = index + 1;
html += escape;
}
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}
/** @type {Record<number, string>} */
const statuses = {
400: "Bad Request",
403: "Forbidden",
404: "Not Found",
416: "Range Not Satisfiable",
500: "Internal Server Error"
};
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {Request} req response
* @param {Response} res response
* @param {number} status status
* @returns {void}
*/
function sendError(req, res, status) {
const content = statuses[status] || String(status);
const document = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>${escapeHtml(content)}</pre>
</body>
</html>`; // Clear existing headers
clearHeadersForResponse(res); // Send basic response
setStatusCode(res, status);
setHeaderForResponse(res, "Content-Type", "text/html; charset=utf-8");
setHeaderForResponse(res, "Content-Security-Policy", "default-src 'none'");
setHeaderForResponse(res, "X-Content-Type-Options", "nosniff");
const byteLength = Buffer.byteLength(document);
setHeaderForResponse(res, "Content-Length", byteLength);
res.end(document);
}
module.exports = {
getHeaderNames,
@ -168,5 +287,6 @@ module.exports = {
getHeaderFromResponse,
setHeaderForResponse,
setStatusCode,
send
send,
sendError
};

View file

@ -16,14 +16,17 @@ const getPaths = require("./getPaths");
const cacheStore = new WeakMap();
/**
* @template T
* @param {Function} fn
* @param {{ cache?: Map<any, any> }} [cache]
* @param {{ cache?: Map<string, { data: T }> } | undefined} cache
* @param {(value: T) => T} callback
* @returns {any}
*/
// @ts-ignore
const mem = (fn, {
cache = new Map()
} = {}) => {
} = {}, callback) => {
/**
* @param {any} arguments_
* @return {any}
@ -36,7 +39,8 @@ const mem = (fn, {
return cacheItem.data;
}
const result = fn.apply(void 0, arguments_);
let result = fn.apply(void 0, arguments_);
result = callback(result);
cache.set(key, {
data: result
});
@ -45,23 +49,56 @@ const mem = (fn, {
cacheStore.set(memoized, cache);
return memoized;
};
}; // eslint-disable-next-line no-undefined
const memoizedParse = mem(parse);
const memoizedParse = mem(parse, undefined, value => {
if (value.pathname) {
// eslint-disable-next-line no-param-reassign
value.pathname = decode(value.pathname);
}
return value;
});
const UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
/**
* @typedef {Object} Extra
* @property {import("fs").Stats=} stats
* @property {number=} errorCode
*/
/**
* decodeURIComponent.
*
* Allows V8 to only deoptimize this fn instead of all of send().
*
* @param {string} input
* @returns {string}
*/
function decode(input) {
return querystring.unescape(input);
}
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
function getFilenameFromUrl(context, url) {
function getFilenameFromUrl(context, url, extra = {}) {
const {
options
} = context;
const paths = getPaths(context);
/** @type {string | undefined} */
let foundFilename;
/** @type {URL} */
let urlObject;
try {
@ -75,7 +112,10 @@ function getFilenameFromUrl(context, url) {
publicPath,
outputPath
} of paths) {
/** @type {string | undefined} */
let filename;
/** @type {URL} */
let publicPathObject;
try {
@ -85,20 +125,37 @@ function getFilenameFromUrl(context, url) {
continue;
}
if (urlObject.pathname && urlObject.pathname.startsWith(publicPathObject.pathname)) {
filename = outputPath; // Strip the `pathname` property from the `publicPath` option from the start of requested url
const {
pathname
} = urlObject;
const {
pathname: publicPathPathname
} = publicPathObject;
if (pathname && pathname.startsWith(publicPathPathname)) {
// Null byte(s)
if (pathname.includes("\0")) {
// eslint-disable-next-line no-param-reassign
extra.errorCode = 400;
return;
} // ".." is malicious
if (UP_PATH_REGEXP.test(path.normalize(`./${pathname}`))) {
// eslint-disable-next-line no-param-reassign
extra.errorCode = 403;
return;
} // Strip the `pathname` property from the `publicPath` option from the start of requested url
// `/complex/foo.js` => `foo.js`
// and add outputPath
// `foo.js` => `/home/user/my-project/dist/foo.js`
const pathname = urlObject.pathname.slice(publicPathObject.pathname.length);
if (pathname) {
filename = path.join(outputPath, querystring.unescape(pathname));
}
let fsStats;
filename = path.join(outputPath, pathname.slice(publicPathPathname.length));
try {
fsStats =
// eslint-disable-next-line no-param-reassign
extra.stats =
/** @type {import("fs").statSync} */
context.outputFileSystem.statSync(filename);
} catch (_ignoreError) {
@ -106,15 +163,16 @@ function getFilenameFromUrl(context, url) {
continue;
}
if (fsStats.isFile()) {
if (extra.stats.isFile()) {
foundFilename = filename;
break;
} else if (fsStats.isDirectory() && (typeof options.index === "undefined" || options.index)) {
} else if (extra.stats.isDirectory() && (typeof options.index === "undefined" || options.index)) {
const indexValue = typeof options.index === "undefined" || typeof options.index === "boolean" ? "index.html" : options.index;
filename = path.join(filename, indexValue);
try {
fsStats =
// eslint-disable-next-line no-param-reassign
extra.stats =
/** @type {import("fs").statSync} */
context.outputFileSystem.statSync(filename);
} catch (__ignoreError) {
@ -122,7 +180,7 @@ function getFilenameFromUrl(context, url) {
continue;
}
if (fsStats.isFile()) {
if (extra.stats.isFile()) {
foundFilename = filename;
break;
}

View file

View file

View file

View file

@ -1,6 +1,6 @@
{
"name": "webpack-dev-middleware",
"version": "5.3.3",
"version": "5.3.4",
"description": "A development middleware for webpack",
"license": "MIT",
"repository": "webpack/webpack-dev-middleware",

View file

View file

View file

@ -84,3 +84,15 @@ export function send<
bufferOtStream: string | Buffer | import("fs").ReadStream,
byteLength: number
): void;
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {Request} req response
* @param {Response} res response
* @param {number} status status
* @returns {void}
*/
export function sendError<
Request_1 extends import("http").IncomingMessage,
Response_1 extends import("../index.js").ServerResponse
>(req: Request_1, res: Response_1, status: number): void;

View file

@ -5,6 +5,7 @@ export = getFilenameFromUrl;
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
declare function getFilenameFromUrl<
@ -12,10 +13,15 @@ declare function getFilenameFromUrl<
Response_1 extends import("../index.js").ServerResponse
>(
context: import("../index.js").Context<Request_1, Response_1>,
url: string
url: string,
extra?: Extra | undefined
): string | undefined;
declare namespace getFilenameFromUrl {
export { IncomingMessage, ServerResponse };
export { Extra, IncomingMessage, ServerResponse };
}
type Extra = {
stats?: import("fs").Stats | undefined;
errorCode?: number | undefined;
};
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;

View file