From adbe4a8c83fd735a1be93418b0966ea8dc3459e0 Mon Sep 17 00:00:00 2001 From: ChK Date: Wed, 11 Mar 2026 08:52:04 +0100 Subject: [PATCH] npm version --- .gitignore | 1 + app/node_modules/.package-lock.json | 7 +- app/node_modules/minimatch/README.md | 37 ++++ app/node_modules/minimatch/minimatch.js | 262 ++++++++++++++---------- app/node_modules/minimatch/package.json | 2 +- app/package-lock.json | 7 +- package-lock.json | 6 + 7 files changed, 208 insertions(+), 114 deletions(-) create mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index cca076b..afad62f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ pgdata/ +app/node_modules/ diff --git a/app/node_modules/.package-lock.json b/app/node_modules/.package-lock.json index 14b3aa4..ab7da11 100644 --- a/app/node_modules/.package-lock.json +++ b/app/node_modules/.package-lock.json @@ -566,10 +566,9 @@ } }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dependencies": { "brace-expansion": "^2.0.1" }, diff --git a/app/node_modules/minimatch/README.md b/app/node_modules/minimatch/README.md index a5bdefa..761a004 100644 --- a/app/node_modules/minimatch/README.md +++ b/app/node_modules/minimatch/README.md @@ -10,6 +10,43 @@ This is the matching library used internally by npm. It works by converting glob expressions into JavaScript `RegExp` objects. +## Important Security Consideration! + +> [!WARNING] +> This library uses JavaScript regular expressions. Please read +> the following warning carefully, and be thoughtful about what +> you provide to this library in production systems. + +_Any_ library in JavaScript that deals with matching string +patterns using regular expressions will be subject to +[ReDoS](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) +if the pattern is generated using untrusted input. + +Efforts have been made to mitigate risk as much as is feasible in +such a library, providing maximum recursion depths and so forth, +but these measures can only ultimately protect against accidents, +not malice. A dedicated attacker can _always_ find patterns that +cannot be defended against by a bash-compatible glob pattern +matching system that uses JavaScript regular expressions. + +To be extremely clear: + +> [!WARNING] +> **If you create a system where you take user input, and use +> that input as the source of a Regular Expression pattern, in +> this or any extant glob matcher in JavaScript, you will be +> pwned.** + +A future version of this library _may_ use a different matching +algorithm which does not exhibit backtracking problems. If and +when that happens, it will likely be a sweeping change, and those +improvements will **not** be backported to legacy versions. + +In the near term, it is not reasonable to continue to play +whack-a-mole with security advisories, and so any future ReDoS +reports will be considered "working as intended", and resolved +entirely by this warning. + ## Usage ```javascript diff --git a/app/node_modules/minimatch/minimatch.js b/app/node_modules/minimatch/minimatch.js index 6c8bfc3..8545b3a 100644 --- a/app/node_modules/minimatch/minimatch.js +++ b/app/node_modules/minimatch/minimatch.js @@ -168,6 +168,8 @@ class Minimatch { if (!options) options = {} this.options = options + this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined + ? options.maxGlobstarRecursion : 200 this.set = [] this.pattern = pattern this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || @@ -255,114 +257,172 @@ class Minimatch { // out of pattern, then that's fine, as long as all // the parts match. matchOne (file, pattern, partial) { - var options = this.options + if (pattern.indexOf(GLOBSTAR) !== -1) { + return this._matchGlobstar(file, pattern, partial, 0, 0) + } + return this._matchOne(file, pattern, partial, 0, 0) + } - this.debug('matchOne', - { 'this': this, file: file, pattern: pattern }) + _matchGlobstar (file, pattern, partial, fileIndex, patternIndex) { + // find first globstar from patternIndex + let firstgs = -1 + for (let i = patternIndex; i < pattern.length; i++) { + if (pattern[i] === GLOBSTAR) { firstgs = i; break } + } - this.debug('matchOne', file.length, pattern.length) + // find last globstar + let lastgs = -1 + for (let i = pattern.length - 1; i >= 0; i--) { + if (pattern[i] === GLOBSTAR) { lastgs = i; break } + } - for (var fi = 0, - pi = 0, - fl = file.length, - pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi++, pi++) { + const head = pattern.slice(patternIndex, firstgs) + const body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs) + const tail = partial ? [] : pattern.slice(lastgs + 1) + + // check the head + if (head.length) { + const fileHead = file.slice(fileIndex, fileIndex + head.length) + if (!this._matchOne(fileHead, head, partial, 0, 0)) { + return false + } + fileIndex += head.length + } + + // check the tail + let fileTailMatch = 0 + if (tail.length) { + if (tail.length + fileIndex > file.length) return false + + const tailStart = file.length - tail.length + if (this._matchOne(file, tail, partial, tailStart, 0)) { + fileTailMatch = tail.length + } else { + // affordance for stuff like a/**/* matching a/b/ + if (file[file.length - 1] !== '' || + fileIndex + tail.length === file.length) { + return false + } + if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) { + return false + } + fileTailMatch = tail.length + 1 + } + } + + // if body is empty (single ** between head and tail) + if (!body.length) { + let sawSome = !!fileTailMatch + for (let i = fileIndex; i < file.length - fileTailMatch; i++) { + const f = String(file[i]) + sawSome = true + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { + return false + } + } + return partial || sawSome + } + + // split body into segments at each GLOBSTAR + const bodySegments = [[[], 0]] + let currentBody = bodySegments[0] + let nonGsParts = 0 + const nonGsPartsSums = [0] + for (const b of body) { + if (b === GLOBSTAR) { + nonGsPartsSums.push(nonGsParts) + currentBody = [[], 0] + bodySegments.push(currentBody) + } else { + currentBody[0].push(b) + nonGsParts++ + } + } + + let idx = bodySegments.length - 1 + const fileLength = file.length - fileTailMatch + for (const b of bodySegments) { + b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length) + } + + return !!this._matchGlobStarBodySections( + file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch + ) + } + + // return false for "nope, not matching" + // return null for "not matching, cannot keep trying" + _matchGlobStarBodySections ( + file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail + ) { + const bs = bodySegments[bodyIndex] + if (!bs) { + // just make sure there are no bad dots + for (let i = fileIndex; i < file.length; i++) { + sawTail = true + const f = file[i] + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { + return false + } + } + return sawTail + } + + const [body, after] = bs + while (fileIndex <= after) { + const m = this._matchOne( + file.slice(0, fileIndex + body.length), + body, + partial, + fileIndex, + 0 + ) + // if limit exceeded, no match. intentional false negative, + // acceptable break in correctness for security. + if (m && globStarDepth < this.maxGlobstarRecursion) { + const sub = this._matchGlobStarBodySections( + file, bodySegments, + fileIndex + body.length, bodyIndex + 1, + partial, globStarDepth + 1, sawTail + ) + if (sub !== false) { + return sub + } + } + const f = file[fileIndex] + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { + return false + } + fileIndex++ + } + return partial || null + } + + _matchOne (file, pattern, partial, fileIndex, patternIndex) { + let fi, pi, fl, pl + for ( + fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi++, pi++ + ) { this.debug('matchOne loop') - var p = pattern[pi] - var f = file[fi] + const p = pattern[pi] + const f = file[fi] this.debug(pattern, p, f) // should be impossible. // some invalid regexp stuff in the set. /* istanbul ignore if */ - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - var pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) return false - } - return true - } - - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr] - - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) - - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr) - break - } - - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr++ - } - } - - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - /* istanbul ignore if */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr) - if (fr === fl) return true - } - return false - } + if (p === false || p === GLOBSTAR) return false // something other than ** // non-magic patterns just have to match exactly // patterns with magic have been turned into regexps. - var hit + let hit if (typeof p === 'string') { hit = f === p this.debug('string match', p, f, hit) @@ -374,17 +434,6 @@ class Minimatch { if (!hit) return false } - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - // now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { // ran out of pattern and filename at the same time. @@ -533,6 +582,9 @@ class Minimatch { continue } + // coalesce consecutive non-globstar * characters + if (c === '*' && stateChar === '*') continue + // if we already have a stateChar, then it means // that there was something like ** or +? in there. // Handle the stateChar, then proceed with this one. diff --git a/app/node_modules/minimatch/package.json b/app/node_modules/minimatch/package.json index c8809db..cac30ab 100644 --- a/app/node_modules/minimatch/package.json +++ b/app/node_modules/minimatch/package.json @@ -5,7 +5,7 @@ "publishConfig": { "tag": "legacy-v5" }, - "version": "5.1.6", + "version": "5.1.9", "repository": { "type": "git", "url": "git://github.com/isaacs/minimatch.git" diff --git a/app/package-lock.json b/app/package-lock.json index fef4311..3ed7622 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -576,10 +576,9 @@ } }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dependencies": { "brace-expansion": "^2.0.1" }, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..fec3d25 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "appServerInfo", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}