Remediate llm-fe npm audit critical/high vulnerabilities (#69)
## Summary - Closes #53 - `npm audit` in `llm-fe`: **103 → 4** (0 critical, 0 high; 4 moderate remain) - Applied `npm audit fix`, bumped direct floors (`axios`, `react-router-dom`), pinned `styled-components@6.1.15` for CRA typecheck stability - Added npm `overrides` for vulnerable transitive leaves (`tar`, `postcss`, `svgo`, `sharp`, `ws`, `flatted`, etc.) - Vendored CRA-compatible `brace-expansion@5.0.8` shim (v1 default-export API + GHSA-mh99 DoS limits) ## Remaining (documented) - **moderate:** `react-router`/`react-router-dom` — needs v7 (breaking) - **moderate:** `webpack-dev-server` via `react-scripts` — CRA incompatible with patched WDS 5.2.6+; needs CRA → Vite (or similar) follow-up - Deprecation warnings from CRA/`eslint@8`/old `glob` tooling still present until toolchain migrate ## Test plan - [x] `npm ci` in `llm-fe` - [x] `npm audit` → 0 critical / 0 high - [x] `npm run build` - [x] `npm run test:ci` → 25 suites / 112 tests passedReviewed-on: #69
This commit was merged in pull request #69.
This commit is contained in:
Generated
+1605
-1894
File diff suppressed because it is too large
Load Diff
+21
-3
@@ -20,7 +20,7 @@
|
|||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.2",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.13.2",
|
||||||
"babel-loader": "^9.2.1",
|
"babel-loader": "^9.2.1",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"chroma-js": "^3.1.2",
|
"chroma-js": "^3.1.2",
|
||||||
@@ -32,11 +32,11 @@
|
|||||||
"react-bootstrap": "^2.10.6",
|
"react-bootstrap": "^2.10.6",
|
||||||
"react-code-blocks": "^0.1.6",
|
"react-code-blocks": "^0.1.6",
|
||||||
"react-github-btn": "^1.4.0",
|
"react-github-btn": "^1.4.0",
|
||||||
"react-router-dom": "^6.28.0",
|
"react-router-dom": "^6.30.2",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"recharts": "^2.15.1",
|
"recharts": "^2.15.1",
|
||||||
"styled-components": "^6.1.14",
|
"styled-components": "6.1.15",
|
||||||
"stylis-plugin-rtl": "^2.1.1",
|
"stylis-plugin-rtl": "^2.1.1",
|
||||||
"web-vitals": "^4.2.4",
|
"web-vitals": "^4.2.4",
|
||||||
"webpack": "^5.97.1",
|
"webpack": "^5.97.1",
|
||||||
@@ -86,5 +86,23 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-google-recaptcha": "^3.1.0",
|
"react-google-recaptcha": "^3.1.0",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"tar": "7.5.22",
|
||||||
|
"underscore": "1.13.8",
|
||||||
|
"nth-check": "2.1.1",
|
||||||
|
"postcss": "8.5.25",
|
||||||
|
"serialize-javascript": "7.0.7",
|
||||||
|
"svgo": "2.8.3",
|
||||||
|
"sharp": "0.35.3",
|
||||||
|
"brace-expansion": "file:vendor/brace-expansion-compat",
|
||||||
|
"minimatch": "3.1.5",
|
||||||
|
"uuid": "11.1.1",
|
||||||
|
"prismjs": "1.30.0",
|
||||||
|
"bfj": "9.1.3",
|
||||||
|
"form-data": "4.0.6",
|
||||||
|
"ws": "8.21.1",
|
||||||
|
"flatted": "3.4.3",
|
||||||
|
"@tootallnate/once": "3.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
(MIT)
|
||||||
|
|
||||||
|
Original code Copyright Julian Gruber <julian@juliangruber.com>
|
||||||
|
|
||||||
|
Port to TypeScript Copyright Isaac Z. Schlueter <i@izs.me>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# balanced-match
|
||||||
|
|
||||||
|
Match balanced string pairs, like `{` and `}` or `<b>` and
|
||||||
|
`</b>`. Supports regular expressions as well!
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Get the first matching pair of braces:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { balanced } from 'balanced-match'
|
||||||
|
|
||||||
|
console.log(balanced('{', '}', 'pre{in{nested}}post'))
|
||||||
|
console.log(balanced('{', '}', 'pre{first}between{second}post'))
|
||||||
|
console.log(
|
||||||
|
balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post'),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The matches are:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ node example.js
|
||||||
|
{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' }
|
||||||
|
{ start: 3,
|
||||||
|
end: 9,
|
||||||
|
pre: 'pre',
|
||||||
|
body: 'first',
|
||||||
|
post: 'between{second}post' }
|
||||||
|
{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' }
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### const m = balanced(a, b, str)
|
||||||
|
|
||||||
|
For the first non-nested matching pair of `a` and `b` in `str`, return an
|
||||||
|
object with those keys:
|
||||||
|
|
||||||
|
- **start** the index of the first match of `a`
|
||||||
|
- **end** the index of the matching `b`
|
||||||
|
- **pre** the preamble, `a` and `b` not included
|
||||||
|
- **body** the match, `a` and `b` not included
|
||||||
|
- **post** the postscript, `a` and `b` not included
|
||||||
|
|
||||||
|
If there's no match, `undefined` will be returned.
|
||||||
|
|
||||||
|
If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`.
|
||||||
|
|
||||||
|
### const r = balanced.range(a, b, str)
|
||||||
|
|
||||||
|
For the first non-nested matching pair of `a` and `b` in `str`, return an
|
||||||
|
array with indexes: `[ <a index>, <b index> ]`.
|
||||||
|
|
||||||
|
If there's no match, `undefined` will be returned.
|
||||||
|
|
||||||
|
If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export declare const balanced: (a: string | RegExp, b: string | RegExp, str: string) => false | {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
pre: string;
|
||||||
|
body: string;
|
||||||
|
post: string;
|
||||||
|
} | undefined;
|
||||||
|
export declare const range: (a: string, b: string, str: string) => undefined | [number, number];
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,GACnB,GAAG,MAAM,GAAG,MAAM,EAClB,GAAG,MAAM,GAAG,MAAM,EAClB,KAAK,MAAM;;;;;;aAgBZ,CAAA;AAOD,eAAO,MAAM,KAAK,GAChB,GAAG,MAAM,EACT,GAAG,MAAM,EACT,KAAK,MAAM,KACV,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CA2C7B,CAAA"}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.range = exports.balanced = void 0;
|
||||||
|
const balanced = (a, b, str) => {
|
||||||
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
||||||
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
||||||
|
const r = ma !== null && mb != null && (0, exports.range)(ma, mb, str);
|
||||||
|
return (r && {
|
||||||
|
start: r[0],
|
||||||
|
end: r[1],
|
||||||
|
pre: str.slice(0, r[0]),
|
||||||
|
body: str.slice(r[0] + ma.length, r[1]),
|
||||||
|
post: str.slice(r[1] + mb.length),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
exports.balanced = balanced;
|
||||||
|
const maybeMatch = (reg, str) => {
|
||||||
|
const m = str.match(reg);
|
||||||
|
return m ? m[0] : null;
|
||||||
|
};
|
||||||
|
const range = (a, b, str) => {
|
||||||
|
let begs, beg, left, right = undefined, result;
|
||||||
|
let ai = str.indexOf(a);
|
||||||
|
let bi = str.indexOf(b, ai + 1);
|
||||||
|
let i = ai;
|
||||||
|
if (ai >= 0 && bi > 0) {
|
||||||
|
if (a === b) {
|
||||||
|
return [ai, bi];
|
||||||
|
}
|
||||||
|
begs = [];
|
||||||
|
left = str.length;
|
||||||
|
while (i >= 0 && !result) {
|
||||||
|
if (i === ai) {
|
||||||
|
begs.push(i);
|
||||||
|
ai = str.indexOf(a, i + 1);
|
||||||
|
}
|
||||||
|
else if (begs.length === 1) {
|
||||||
|
const r = begs.pop();
|
||||||
|
if (r !== undefined)
|
||||||
|
result = [r, bi];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
beg = begs.pop();
|
||||||
|
if (beg !== undefined && beg < left) {
|
||||||
|
left = beg;
|
||||||
|
right = bi;
|
||||||
|
}
|
||||||
|
bi = str.indexOf(b, i + 1);
|
||||||
|
}
|
||||||
|
i = ai < bi && ai >= 0 ? ai : bi;
|
||||||
|
}
|
||||||
|
if (begs.length && right !== undefined) {
|
||||||
|
result = [left, right];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
exports.range = range;
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export const balanced = (\n a: string | RegExp,\n b: string | RegExp,\n str: string,\n) => {\n const ma = a instanceof RegExp ? maybeMatch(a, str) : a\n const mb = b instanceof RegExp ? maybeMatch(b, str) : b\n\n const r = ma !== null && mb != null && range(ma, mb, str)\n\n return (\n r && {\n start: r[0],\n end: r[1],\n pre: str.slice(0, r[0]),\n body: str.slice(r[0] + ma.length, r[1]),\n post: str.slice(r[1] + mb.length),\n }\n )\n}\n\nconst maybeMatch = (reg: RegExp, str: string) => {\n const m = str.match(reg)\n return m ? m[0] : null\n}\n\nexport const range = (\n a: string,\n b: string,\n str: string,\n): undefined | [number, number] => {\n let begs: number[],\n beg: number | undefined,\n left: number,\n right: number | undefined = undefined,\n result: undefined | [number, number]\n let ai = str.indexOf(a)\n let bi = str.indexOf(b, ai + 1)\n let i = ai\n\n if (ai >= 0 && bi > 0) {\n if (a === b) {\n return [ai, bi]\n }\n begs = []\n left = str.length\n\n while (i >= 0 && !result) {\n if (i === ai) {\n begs.push(i)\n ai = str.indexOf(a, i + 1)\n } else if (begs.length === 1) {\n const r = begs.pop()\n if (r !== undefined) result = [r, bi]\n } else {\n beg = begs.pop()\n if (beg !== undefined && beg < left) {\n left = beg\n right = bi\n }\n\n bi = str.indexOf(b, i + 1)\n }\n\n i = ai < bi && ai >= 0 ? ai : bi\n }\n\n if (begs.length && right !== undefined) {\n result = [left, right]\n }\n }\n\n return result\n}\n"]}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export declare const balanced: (a: string | RegExp, b: string | RegExp, str: string) => false | {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
pre: string;
|
||||||
|
body: string;
|
||||||
|
post: string;
|
||||||
|
} | undefined;
|
||||||
|
export declare const range: (a: string, b: string, str: string) => undefined | [number, number];
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,GACnB,GAAG,MAAM,GAAG,MAAM,EAClB,GAAG,MAAM,GAAG,MAAM,EAClB,KAAK,MAAM;;;;;;aAgBZ,CAAA;AAOD,eAAO,MAAM,KAAK,GAChB,GAAG,MAAM,EACT,GAAG,MAAM,EACT,KAAK,MAAM,KACV,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CA2C7B,CAAA"}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
export const balanced = (a, b, str) => {
|
||||||
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
||||||
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
||||||
|
const r = ma !== null && mb != null && range(ma, mb, str);
|
||||||
|
return (r && {
|
||||||
|
start: r[0],
|
||||||
|
end: r[1],
|
||||||
|
pre: str.slice(0, r[0]),
|
||||||
|
body: str.slice(r[0] + ma.length, r[1]),
|
||||||
|
post: str.slice(r[1] + mb.length),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const maybeMatch = (reg, str) => {
|
||||||
|
const m = str.match(reg);
|
||||||
|
return m ? m[0] : null;
|
||||||
|
};
|
||||||
|
export const range = (a, b, str) => {
|
||||||
|
let begs, beg, left, right = undefined, result;
|
||||||
|
let ai = str.indexOf(a);
|
||||||
|
let bi = str.indexOf(b, ai + 1);
|
||||||
|
let i = ai;
|
||||||
|
if (ai >= 0 && bi > 0) {
|
||||||
|
if (a === b) {
|
||||||
|
return [ai, bi];
|
||||||
|
}
|
||||||
|
begs = [];
|
||||||
|
left = str.length;
|
||||||
|
while (i >= 0 && !result) {
|
||||||
|
if (i === ai) {
|
||||||
|
begs.push(i);
|
||||||
|
ai = str.indexOf(a, i + 1);
|
||||||
|
}
|
||||||
|
else if (begs.length === 1) {
|
||||||
|
const r = begs.pop();
|
||||||
|
if (r !== undefined)
|
||||||
|
result = [r, bi];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
beg = begs.pop();
|
||||||
|
if (beg !== undefined && beg < left) {
|
||||||
|
left = beg;
|
||||||
|
right = bi;
|
||||||
|
}
|
||||||
|
bi = str.indexOf(b, i + 1);
|
||||||
|
}
|
||||||
|
i = ai < bi && ai >= 0 ? ai : bi;
|
||||||
|
}
|
||||||
|
if (begs.length && right !== undefined) {
|
||||||
|
result = [left, right];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export const balanced = (\n a: string | RegExp,\n b: string | RegExp,\n str: string,\n) => {\n const ma = a instanceof RegExp ? maybeMatch(a, str) : a\n const mb = b instanceof RegExp ? maybeMatch(b, str) : b\n\n const r = ma !== null && mb != null && range(ma, mb, str)\n\n return (\n r && {\n start: r[0],\n end: r[1],\n pre: str.slice(0, r[0]),\n body: str.slice(r[0] + ma.length, r[1]),\n post: str.slice(r[1] + mb.length),\n }\n )\n}\n\nconst maybeMatch = (reg: RegExp, str: string) => {\n const m = str.match(reg)\n return m ? m[0] : null\n}\n\nexport const range = (\n a: string,\n b: string,\n str: string,\n): undefined | [number, number] => {\n let begs: number[],\n beg: number | undefined,\n left: number,\n right: number | undefined = undefined,\n result: undefined | [number, number]\n let ai = str.indexOf(a)\n let bi = str.indexOf(b, ai + 1)\n let i = ai\n\n if (ai >= 0 && bi > 0) {\n if (a === b) {\n return [ai, bi]\n }\n begs = []\n left = str.length\n\n while (i >= 0 && !result) {\n if (i === ai) {\n begs.push(i)\n ai = str.indexOf(a, i + 1)\n } else if (begs.length === 1) {\n const r = begs.pop()\n if (r !== undefined) result = [r, bi]\n } else {\n beg = begs.pop()\n if (beg !== undefined && beg < left) {\n left = beg\n right = bi\n }\n\n bi = str.indexOf(b, i + 1)\n }\n\n i = ai < bi && ai >= 0 ? ai : bi\n }\n\n if (begs.length && right !== undefined) {\n result = [left, right]\n }\n }\n\n return result\n}\n"]}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"name": "balanced-match",
|
||||||
|
"description": "Match balanced character pairs, like \"{\" and \"}\"",
|
||||||
|
"version": "4.0.4",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/juliangruber/balanced-match.git"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"import": {
|
||||||
|
"types": "./dist/esm/index.d.ts",
|
||||||
|
"default": "./dist/esm/index.js"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./dist/commonjs/index.d.ts",
|
||||||
|
"default": "./dist/commonjs/index.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"preversion": "npm test",
|
||||||
|
"postversion": "npm publish",
|
||||||
|
"prepublishOnly": "git push origin --follow-tags",
|
||||||
|
"prepare": "tshy",
|
||||||
|
"pretest": "npm run prepare",
|
||||||
|
"presnap": "npm run prepare",
|
||||||
|
"test": "tap",
|
||||||
|
"snap": "tap",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"benchmark": "node benchmark/index.js",
|
||||||
|
"typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/brace-expansion": "^1.1.2",
|
||||||
|
"@types/node": "^25.2.1",
|
||||||
|
"mkdirp": "^3.0.1",
|
||||||
|
"prettier": "^3.3.2",
|
||||||
|
"tap": "^21.6.2",
|
||||||
|
"tshy": "^3.0.2",
|
||||||
|
"typedoc": "^0.28.5"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"match",
|
||||||
|
"regexp",
|
||||||
|
"test",
|
||||||
|
"balanced",
|
||||||
|
"parse"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "18 || 20 || >=22"
|
||||||
|
},
|
||||||
|
"tshy": {
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": "./src/index.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/commonjs/index.js",
|
||||||
|
"types": "./dist/commonjs/index.d.ts",
|
||||||
|
"module": "./dist/esm/index.js"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// minimatch@3 and other CRA tooling expect module.exports to be the expand
|
||||||
|
// function (brace-expansion v1 API). Upstream 5.0.8 exports { expand } and
|
||||||
|
// includes the GHSA-mh99-v99m-4gvg DoS limits.
|
||||||
|
const safe = require('./lib');
|
||||||
|
|
||||||
|
function expandTop(str, options) {
|
||||||
|
return safe.expand(str, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = expandTop;
|
||||||
|
module.exports.expand = safe.expand;
|
||||||
|
module.exports.EXPANSION_MAX = safe.EXPANSION_MAX;
|
||||||
|
module.exports.EXPANSION_MAX_LENGTH = safe.EXPANSION_MAX_LENGTH;
|
||||||
+263
@@ -0,0 +1,263 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
|
||||||
|
exports.expand = expand;
|
||||||
|
const balanced_match_1 = require("../balanced-match");
|
||||||
|
const escSlash = '\0SLASH' + Math.random() + '\0';
|
||||||
|
const escOpen = '\0OPEN' + Math.random() + '\0';
|
||||||
|
const escClose = '\0CLOSE' + Math.random() + '\0';
|
||||||
|
const escComma = '\0COMMA' + Math.random() + '\0';
|
||||||
|
const escPeriod = '\0PERIOD' + Math.random() + '\0';
|
||||||
|
const escSlashPattern = new RegExp(escSlash, 'g');
|
||||||
|
const escOpenPattern = new RegExp(escOpen, 'g');
|
||||||
|
const escClosePattern = new RegExp(escClose, 'g');
|
||||||
|
const escCommaPattern = new RegExp(escComma, 'g');
|
||||||
|
const escPeriodPattern = new RegExp(escPeriod, 'g');
|
||||||
|
const slashPattern = /\\\\/g;
|
||||||
|
const openPattern = /\\{/g;
|
||||||
|
const closePattern = /\\}/g;
|
||||||
|
const commaPattern = /\\,/g;
|
||||||
|
const periodPattern = /\\\./g;
|
||||||
|
exports.EXPANSION_MAX = 100_000;
|
||||||
|
// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
|
||||||
|
// input like `'{a,b}'.repeat(1500)` stays under that count - its output is
|
||||||
|
// truncated to 100k results - while making every result ~1500 characters
|
||||||
|
// long. The result set, and the intermediate arrays built while combining
|
||||||
|
// brace sets, then grow large enough to exhaust memory and crash the process
|
||||||
|
// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
|
||||||
|
// characters the accumulator may hold at any point, so memory stays flat no
|
||||||
|
// matter how many brace groups are chained. The limit sits well above any
|
||||||
|
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
|
||||||
|
// characters) so legitimate input is unaffected.
|
||||||
|
exports.EXPANSION_MAX_LENGTH = 4_000_000;
|
||||||
|
function numeric(str) {
|
||||||
|
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
||||||
|
}
|
||||||
|
function escapeBraces(str) {
|
||||||
|
return str
|
||||||
|
.replace(slashPattern, escSlash)
|
||||||
|
.replace(openPattern, escOpen)
|
||||||
|
.replace(closePattern, escClose)
|
||||||
|
.replace(commaPattern, escComma)
|
||||||
|
.replace(periodPattern, escPeriod);
|
||||||
|
}
|
||||||
|
function unescapeBraces(str) {
|
||||||
|
return str
|
||||||
|
.replace(escSlashPattern, '\\')
|
||||||
|
.replace(escOpenPattern, '{')
|
||||||
|
.replace(escClosePattern, '}')
|
||||||
|
.replace(escCommaPattern, ',')
|
||||||
|
.replace(escPeriodPattern, '.');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Basically just str.split(","), but handling cases
|
||||||
|
* where we have nested braced sections, which should be
|
||||||
|
* treated as individual members, like {a,{b,c},d}
|
||||||
|
*/
|
||||||
|
function parseCommaParts(str) {
|
||||||
|
if (!str) {
|
||||||
|
return [''];
|
||||||
|
}
|
||||||
|
const parts = [];
|
||||||
|
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
||||||
|
if (!m) {
|
||||||
|
return str.split(',');
|
||||||
|
}
|
||||||
|
const { pre, body, post } = m;
|
||||||
|
const p = pre.split(',');
|
||||||
|
p[p.length - 1] += '{' + body + '}';
|
||||||
|
const postParts = parseCommaParts(post);
|
||||||
|
if (post.length) {
|
||||||
|
;
|
||||||
|
p[p.length - 1] += postParts.shift();
|
||||||
|
p.push.apply(p, postParts);
|
||||||
|
}
|
||||||
|
parts.push.apply(parts, p);
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
function expand(str, options = {}) {
|
||||||
|
if (!str) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options;
|
||||||
|
// I don't know why Bash 4.3 does this, but it does.
|
||||||
|
// Anything starting with {} will have the first two bytes preserved
|
||||||
|
// but *only* at the top level, so {},a}b will not expand to anything,
|
||||||
|
// but a{},b}c will be expanded to [a}c,abc].
|
||||||
|
// One could argue that this is a bug in Bash, but since the goal of
|
||||||
|
// this module is to match Bash's rules, we escape a leading {}
|
||||||
|
if (str.slice(0, 2) === '{}') {
|
||||||
|
str = '\\{\\}' + str.slice(2);
|
||||||
|
}
|
||||||
|
return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
|
||||||
|
}
|
||||||
|
function embrace(str) {
|
||||||
|
return '{' + str + '}';
|
||||||
|
}
|
||||||
|
function isPadded(el) {
|
||||||
|
return /^-?0\d/.test(el);
|
||||||
|
}
|
||||||
|
function lte(i, y) {
|
||||||
|
return i <= y;
|
||||||
|
}
|
||||||
|
function gte(i, y) {
|
||||||
|
return i >= y;
|
||||||
|
}
|
||||||
|
// Build `{ acc[a] + pre + values[v] }` for every combination, capping the
|
||||||
|
// number of results at `max` and the total number of characters at `maxLength`.
|
||||||
|
// This is the one place output grows, so bounding it here keeps the single
|
||||||
|
// accumulator - and therefore memory - flat regardless of how many brace groups
|
||||||
|
// are combined (CVE-2026-14257).
|
||||||
|
function combine(acc, pre, values, max, maxLength, dropEmpties) {
|
||||||
|
const out = [];
|
||||||
|
let length = 0;
|
||||||
|
for (let a = 0; a < acc.length; a++) {
|
||||||
|
for (let v = 0; v < values.length; v++) {
|
||||||
|
if (out.length >= max)
|
||||||
|
return out;
|
||||||
|
const expansion = acc[a] + pre + values[v];
|
||||||
|
// Bash drops empty results at the top level. Skip them before they count
|
||||||
|
// against `max`, so `max` bounds the number of *kept* results.
|
||||||
|
if (dropEmpties && !expansion)
|
||||||
|
continue;
|
||||||
|
if (length + expansion.length > maxLength)
|
||||||
|
return out;
|
||||||
|
out.push(expansion);
|
||||||
|
length += expansion.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
|
||||||
|
// sequence body.
|
||||||
|
function expandSequence(body, isAlphaSequence, max) {
|
||||||
|
const n = body.split(/\.\./);
|
||||||
|
const N = [];
|
||||||
|
// A sequence body always splits into two or three parts, but the compiler
|
||||||
|
// can't know that.
|
||||||
|
/* c8 ignore start */
|
||||||
|
if (n[0] === undefined || n[1] === undefined) {
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
/* c8 ignore stop */
|
||||||
|
const x = numeric(n[0]);
|
||||||
|
const y = numeric(n[1]);
|
||||||
|
const width = Math.max(n[0].length, n[1].length);
|
||||||
|
let incr = n.length === 3 && n[2] !== undefined ?
|
||||||
|
Math.max(Math.abs(numeric(n[2])), 1)
|
||||||
|
: 1;
|
||||||
|
let test = lte;
|
||||||
|
const reverse = y < x;
|
||||||
|
if (reverse) {
|
||||||
|
incr *= -1;
|
||||||
|
test = gte;
|
||||||
|
}
|
||||||
|
const pad = n.some(isPadded);
|
||||||
|
for (let i = x; test(i, y) && N.length < max; i += incr) {
|
||||||
|
let c;
|
||||||
|
if (isAlphaSequence) {
|
||||||
|
c = String.fromCharCode(i);
|
||||||
|
if (c === '\\') {
|
||||||
|
c = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c = String(i);
|
||||||
|
if (pad) {
|
||||||
|
const need = width - c.length;
|
||||||
|
if (need > 0) {
|
||||||
|
const z = new Array(need + 1).join('0');
|
||||||
|
if (i < 0) {
|
||||||
|
c = '-' + z + c.slice(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c = z + c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
N.push(c);
|
||||||
|
}
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
function expand_(str, max, maxLength, isTop) {
|
||||||
|
// Consume the string's top-level brace groups left to right, threading a
|
||||||
|
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
|
||||||
|
// rather than recursing on `m.post` once per group - keeps the native stack
|
||||||
|
// depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
|
||||||
|
// longer overflow the stack, and leaves a single accumulator whose size
|
||||||
|
// `maxLength` bounds directly (CVE-2026-14257).
|
||||||
|
let acc = [''];
|
||||||
|
// Bash drops empty results, but only when the *first* top-level group is a
|
||||||
|
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
|
||||||
|
// is on the final strings, so it is applied to whichever `combine` produces
|
||||||
|
// them (the one with no brace set left in the tail).
|
||||||
|
let dropEmpties = false;
|
||||||
|
let firstGroup = true;
|
||||||
|
for (;;) {
|
||||||
|
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
||||||
|
// No brace set left: the rest of the string is literal.
|
||||||
|
if (!m) {
|
||||||
|
return combine(acc, str, [''], max, maxLength, dropEmpties);
|
||||||
|
}
|
||||||
|
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
||||||
|
const pre = m.pre;
|
||||||
|
if (/\$$/.test(pre)) {
|
||||||
|
acc = combine(acc, pre + '{' + m.body + '}', [''], max, maxLength, dropEmpties && !m.post.length);
|
||||||
|
firstGroup = false;
|
||||||
|
if (!m.post.length)
|
||||||
|
break;
|
||||||
|
str = m.post;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
||||||
|
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
||||||
|
const isSequence = isNumericSequence || isAlphaSequence;
|
||||||
|
const isOptions = m.body.indexOf(',') >= 0;
|
||||||
|
if (!isSequence && !isOptions) {
|
||||||
|
// {a},b}
|
||||||
|
if (m.post.match(/,(?!,).*\}/)) {
|
||||||
|
str = m.pre + '{' + m.body + escClose + m.post;
|
||||||
|
isTop = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Nothing here expands, so the whole remaining string is literal.
|
||||||
|
return combine(acc, pre + '{' + m.body + '}' + m.post, [''], max, maxLength, dropEmpties);
|
||||||
|
}
|
||||||
|
if (firstGroup) {
|
||||||
|
dropEmpties = isTop && !isSequence;
|
||||||
|
firstGroup = false;
|
||||||
|
}
|
||||||
|
let values;
|
||||||
|
if (isSequence) {
|
||||||
|
values = expandSequence(m.body, isAlphaSequence, max);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let n = parseCommaParts(m.body);
|
||||||
|
if (n.length === 1 && n[0] !== undefined) {
|
||||||
|
// x{{a,b}}y ==> x{a}y x{b}y
|
||||||
|
n = expand_(n[0], max, maxLength, false).map(embrace);
|
||||||
|
//XXX is this necessary? Can't seem to hit it in tests.
|
||||||
|
/* c8 ignore start */
|
||||||
|
if (n.length === 1) {
|
||||||
|
acc = combine(acc, pre + n[0], [''], max, maxLength, dropEmpties && !m.post.length);
|
||||||
|
if (!m.post.length)
|
||||||
|
break;
|
||||||
|
str = m.post;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* c8 ignore stop */
|
||||||
|
}
|
||||||
|
values = [];
|
||||||
|
for (let j = 0; j < n.length; j++) {
|
||||||
|
values.push.apply(values, expand_(n[j], max, maxLength, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
|
||||||
|
if (!m.post.length)
|
||||||
|
break;
|
||||||
|
str = m.post;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "brace-expansion",
|
||||||
|
"version": "5.0.8",
|
||||||
|
"description": "v1-compatible brace-expansion@5.0.8 shim (GHSA-mh99-v99m-4gvg)",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user