Add JS-CATCH-FALLBACK-01 rule and update npm packages
Add PHP-ALIAS-01 rule: prohibit field aliasing in serialization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
107
node_modules/webpack/lib/schemes/HttpUriPlugin.js
generated
vendored
107
node_modules/webpack/lib/schemes/HttpUriPlugin.js
generated
vendored
@@ -34,6 +34,8 @@ const memoize = require("../util/memoize");
|
||||
const getHttp = memoize(() => require("http"));
|
||||
const getHttps = memoize(() => require("https"));
|
||||
|
||||
const MAX_REDIRECTS = 5;
|
||||
|
||||
/**
|
||||
* @param {typeof import("http") | typeof import("https")} request request
|
||||
* @param {string | URL | undefined} proxy proxy
|
||||
@@ -200,6 +202,22 @@ const areLockfileEntriesEqual = (a, b) =>
|
||||
const entryToString = (entry) =>
|
||||
`resolved: ${entry.resolved}, integrity: ${entry.integrity}, contentType: ${entry.contentType}`;
|
||||
|
||||
/**
|
||||
* Sanitize URL for inclusion in error messages
|
||||
* @param {string} href URL string to sanitize
|
||||
* @returns {string} sanitized URL text for logs/errors
|
||||
*/
|
||||
const sanitizeUrlForError = (href) => {
|
||||
try {
|
||||
const u = new URL(href);
|
||||
return `${u.protocol}//${u.host}`;
|
||||
} catch (_err) {
|
||||
return String(href)
|
||||
.slice(0, 200)
|
||||
.replace(/[\r\n]/g, "");
|
||||
}
|
||||
};
|
||||
|
||||
class Lockfile {
|
||||
constructor() {
|
||||
this.version = 1;
|
||||
@@ -317,7 +335,7 @@ const cachedWithoutKey = (fn) => {
|
||||
* @template R
|
||||
* @param {FnWithKey<T, R>} fn function
|
||||
* @param {FnWithKey<T, R>=} forceFn function for the second try
|
||||
* @returns {(FnWithKey<T, R>) & { force: FnWithKey<T, R> }} cached function
|
||||
* @returns {FnWithKey<T, R> & { force: FnWithKey<T, R> }} cached function
|
||||
*/
|
||||
const cachedWithKey = (fn, forceFn = fn) => {
|
||||
/**
|
||||
@@ -636,12 +654,47 @@ class HttpUriPlugin {
|
||||
};
|
||||
|
||||
for (const { scheme, fetch } of schemes) {
|
||||
/**
|
||||
* @param {string} location Location header value (relative or absolute)
|
||||
* @param {string} base current absolute URL
|
||||
* @returns {string} absolute, validated redirect target
|
||||
*/
|
||||
const validateRedirectLocation = (location, base) => {
|
||||
let nextUrl;
|
||||
try {
|
||||
nextUrl = new URL(location, base);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Invalid redirect URL: ${sanitizeUrlForError(location)}`,
|
||||
{ cause: err }
|
||||
);
|
||||
}
|
||||
if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
|
||||
throw new Error(
|
||||
`Redirected URL uses disallowed protocol: ${sanitizeUrlForError(nextUrl.href)}`
|
||||
);
|
||||
}
|
||||
if (!isAllowed(nextUrl.href)) {
|
||||
throw new Error(
|
||||
`${nextUrl.href} doesn't match the allowedUris policy after redirect. These URIs are allowed:\n${allowedUris
|
||||
.map((uri) => ` - ${uri}`)
|
||||
.join("\n")}`
|
||||
);
|
||||
}
|
||||
return nextUrl.href;
|
||||
};
|
||||
/**
|
||||
* @param {string} url URL
|
||||
* @param {string | null} integrity integrity
|
||||
* @param {(err: Error | null, resolveContentResult?: ResolveContentResult) => void} callback callback
|
||||
* @param {number=} redirectCount number of followed redirects
|
||||
*/
|
||||
const resolveContent = (url, integrity, callback) => {
|
||||
const resolveContent = (
|
||||
url,
|
||||
integrity,
|
||||
callback,
|
||||
redirectCount = 0
|
||||
) => {
|
||||
/**
|
||||
* @param {Error | null} err error
|
||||
* @param {FetchResult=} _result fetch result
|
||||
@@ -653,8 +706,18 @@ class HttpUriPlugin {
|
||||
const result = /** @type {FetchResult} */ (_result);
|
||||
|
||||
if ("location" in result) {
|
||||
// Validate redirect target before following
|
||||
let absolute;
|
||||
try {
|
||||
absolute = validateRedirectLocation(result.location, url);
|
||||
} catch (err_) {
|
||||
return callback(/** @type {Error} */ (err_));
|
||||
}
|
||||
if (redirectCount >= MAX_REDIRECTS) {
|
||||
return callback(new Error("Too many redirects"));
|
||||
}
|
||||
return resolveContent(
|
||||
result.location,
|
||||
absolute,
|
||||
integrity,
|
||||
(err, innerResult) => {
|
||||
if (err) return callback(err);
|
||||
@@ -665,7 +728,8 @@ class HttpUriPlugin {
|
||||
content,
|
||||
storeLock: storeLock && result.storeLock
|
||||
});
|
||||
}
|
||||
},
|
||||
redirectCount + 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -781,9 +845,16 @@ class HttpUriPlugin {
|
||||
res.statusCode >= 301 &&
|
||||
res.statusCode <= 308
|
||||
) {
|
||||
const result = {
|
||||
location: new URL(location, url).href
|
||||
};
|
||||
let absolute;
|
||||
try {
|
||||
absolute = validateRedirectLocation(location, url);
|
||||
} catch (err) {
|
||||
logger.log(
|
||||
`GET ${url} [${res.statusCode}] -> ${String(location)} (rejected: ${/** @type {Error} */ (err).message})`
|
||||
);
|
||||
return callback(/** @type {Error} */ (err));
|
||||
}
|
||||
const result = { location: absolute };
|
||||
if (
|
||||
!cachedResult ||
|
||||
!("location" in cachedResult) ||
|
||||
@@ -882,12 +953,28 @@ class HttpUriPlugin {
|
||||
* @returns {boolean} true when allowed, otherwise false
|
||||
*/
|
||||
const isAllowed = (uri) => {
|
||||
let parsedUri;
|
||||
try {
|
||||
// Parse the URI to prevent userinfo bypass attacks
|
||||
// (e.g., http://allowed@malicious/path where @malicious is the actual host)
|
||||
parsedUri = new URL(uri);
|
||||
} catch (_err) {
|
||||
return false;
|
||||
}
|
||||
for (const allowed of allowedUris) {
|
||||
if (typeof allowed === "string") {
|
||||
if (uri.startsWith(allowed)) return true;
|
||||
let parsedAllowed;
|
||||
try {
|
||||
parsedAllowed = new URL(allowed);
|
||||
} catch (_err) {
|
||||
continue;
|
||||
}
|
||||
if (parsedUri.href.startsWith(parsedAllowed.href)) {
|
||||
return true;
|
||||
}
|
||||
} else if (typeof allowed === "function") {
|
||||
if (allowed(uri)) return true;
|
||||
} else if (allowed.test(uri)) {
|
||||
if (allowed(parsedUri.href)) return true;
|
||||
} else if (allowed.test(parsedUri.href)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user