isomorphic-git 1.38.5 → 1.38.7
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.
- package/index.cjs +91 -13
- package/index.js +91 -13
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +59 -11
- package/managers/index.d.cts +1 -1
- package/managers/index.d.ts +1 -1
- package/managers/index.js +59 -11
- package/managers/index.umd.min.js +1 -1
- package/managers/index.umd.min.js.map +1 -1
- package/package.json +1 -1
package/managers/index.cjs
CHANGED
|
@@ -2074,7 +2074,13 @@ class GitRefManager {
|
|
|
2074
2074
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2075
2075
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2076
2076
|
*/
|
|
2077
|
-
static async resolve({
|
|
2077
|
+
static async resolve({
|
|
2078
|
+
fs,
|
|
2079
|
+
gitdir,
|
|
2080
|
+
ref,
|
|
2081
|
+
depth = undefined,
|
|
2082
|
+
visited = new Set(),
|
|
2083
|
+
}) {
|
|
2078
2084
|
if (depth !== undefined) {
|
|
2079
2085
|
depth--;
|
|
2080
2086
|
if (depth === -1) {
|
|
@@ -2085,7 +2091,7 @@ class GitRefManager {
|
|
|
2085
2091
|
// Is it a ref pointer?
|
|
2086
2092
|
if (ref.startsWith('ref: ')) {
|
|
2087
2093
|
ref = ref.slice('ref: '.length);
|
|
2088
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2094
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2089
2095
|
}
|
|
2090
2096
|
// Is it a complete and valid SHA?
|
|
2091
2097
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2104,7 +2110,21 @@ class GitRefManager {
|
|
|
2104
2110
|
packedMap.get(ref)
|
|
2105
2111
|
);
|
|
2106
2112
|
if (sha) {
|
|
2107
|
-
|
|
2113
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2114
|
+
// tracking visited refs this recursion would not terminate.
|
|
2115
|
+
if (visited.has(ref)) {
|
|
2116
|
+
throw new InternalError(
|
|
2117
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2118
|
+
)
|
|
2119
|
+
}
|
|
2120
|
+
visited.add(ref);
|
|
2121
|
+
return GitRefManager.resolve({
|
|
2122
|
+
fs,
|
|
2123
|
+
gitdir,
|
|
2124
|
+
ref: sha.trim(),
|
|
2125
|
+
depth,
|
|
2126
|
+
visited,
|
|
2127
|
+
})
|
|
2108
2128
|
}
|
|
2109
2129
|
}
|
|
2110
2130
|
// Do we give up?
|
|
@@ -3619,21 +3639,26 @@ function applyDelta(delta, source) {
|
|
|
3619
3639
|
if (firstOp.byteLength === targetSize) {
|
|
3620
3640
|
target = firstOp;
|
|
3621
3641
|
} else {
|
|
3622
|
-
//
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3642
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
3643
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
3644
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
3645
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
3646
|
+
// still validates the total before concatenating.
|
|
3647
|
+
const chunks = [firstOp];
|
|
3648
|
+
let tell = firstOp.byteLength;
|
|
3626
3649
|
|
|
3627
3650
|
while (!reader.eof()) {
|
|
3628
|
-
|
|
3651
|
+
const op = readOp(reader, source);
|
|
3652
|
+
chunks.push(op);
|
|
3653
|
+
tell += op.byteLength;
|
|
3629
3654
|
}
|
|
3630
3655
|
|
|
3631
|
-
const tell = writer.tell();
|
|
3632
3656
|
if (targetSize !== tell) {
|
|
3633
3657
|
throw new InternalError(
|
|
3634
3658
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
3635
3659
|
)
|
|
3636
3660
|
}
|
|
3661
|
+
target = Buffer.concat(chunks, targetSize);
|
|
3637
3662
|
}
|
|
3638
3663
|
return target
|
|
3639
3664
|
}
|
|
@@ -4890,8 +4915,31 @@ function parseBuffer(buffer) {
|
|
|
4890
4915
|
const type = mode2type$1(mode);
|
|
4891
4916
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
4892
4917
|
|
|
4893
|
-
//
|
|
4894
|
-
|
|
4918
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
4919
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
4920
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
4921
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
4922
|
+
// NTFS 8.3 short name aliases (git~1..git~9), NTFS Alternate Data Streams, and
|
|
4923
|
+
// HFS+ ignorable Unicode characters stripped (zero-width joiners, directional
|
|
4924
|
+
// marks, BOM, etc.).
|
|
4925
|
+
const hfsClean = path.replace(
|
|
4926
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
4927
|
+
''
|
|
4928
|
+
);
|
|
4929
|
+
// NTFS Alternate Data Streams are referenced as `<name>:<stream>:<type>`, and a
|
|
4930
|
+
// directory's default stream lets `.git::$INDEX_ALLOCATION` resolve to the `.git`
|
|
4931
|
+
// directory itself. git forbids *any* ADS, so only the portion before the first
|
|
4932
|
+
// colon names the actual entry we normalize and check.
|
|
4933
|
+
const ntfsClean = hfsClean.split(':')[0];
|
|
4934
|
+
const normalized = ntfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
4935
|
+
if (
|
|
4936
|
+
path.includes('\\') ||
|
|
4937
|
+
path.includes('/') ||
|
|
4938
|
+
hfsClean === '.' ||
|
|
4939
|
+
hfsClean === '..' ||
|
|
4940
|
+
normalized === '.git' ||
|
|
4941
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
4942
|
+
) {
|
|
4895
4943
|
throw new UnsafeFilepathError(path)
|
|
4896
4944
|
}
|
|
4897
4945
|
|
package/managers/index.d.cts
CHANGED
|
@@ -568,7 +568,7 @@ export class GitRefManager {
|
|
|
568
568
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
569
569
|
* @returns {Promise<string>} - The resolved object ID.
|
|
570
570
|
*/
|
|
571
|
-
static resolve({ fs, gitdir, ref, depth }: {
|
|
571
|
+
static resolve({ fs, gitdir, ref, depth, visited, }: {
|
|
572
572
|
fs: FSClient;
|
|
573
573
|
gitdir?: string | undefined;
|
|
574
574
|
ref: string;
|
package/managers/index.d.ts
CHANGED
|
@@ -567,7 +567,7 @@ export class GitRefManager {
|
|
|
567
567
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
568
568
|
* @returns {Promise<string>} - The resolved object ID.
|
|
569
569
|
*/
|
|
570
|
-
static resolve({ fs, gitdir, ref, depth }: {
|
|
570
|
+
static resolve({ fs, gitdir, ref, depth, visited, }: {
|
|
571
571
|
fs: FSClient;
|
|
572
572
|
gitdir?: string | undefined;
|
|
573
573
|
ref: string;
|
package/managers/index.js
CHANGED
|
@@ -2067,7 +2067,13 @@ class GitRefManager {
|
|
|
2067
2067
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2068
2068
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2069
2069
|
*/
|
|
2070
|
-
static async resolve({
|
|
2070
|
+
static async resolve({
|
|
2071
|
+
fs,
|
|
2072
|
+
gitdir,
|
|
2073
|
+
ref,
|
|
2074
|
+
depth = undefined,
|
|
2075
|
+
visited = new Set(),
|
|
2076
|
+
}) {
|
|
2071
2077
|
if (depth !== undefined) {
|
|
2072
2078
|
depth--;
|
|
2073
2079
|
if (depth === -1) {
|
|
@@ -2078,7 +2084,7 @@ class GitRefManager {
|
|
|
2078
2084
|
// Is it a ref pointer?
|
|
2079
2085
|
if (ref.startsWith('ref: ')) {
|
|
2080
2086
|
ref = ref.slice('ref: '.length);
|
|
2081
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2087
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2082
2088
|
}
|
|
2083
2089
|
// Is it a complete and valid SHA?
|
|
2084
2090
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2097,7 +2103,21 @@ class GitRefManager {
|
|
|
2097
2103
|
packedMap.get(ref)
|
|
2098
2104
|
);
|
|
2099
2105
|
if (sha) {
|
|
2100
|
-
|
|
2106
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2107
|
+
// tracking visited refs this recursion would not terminate.
|
|
2108
|
+
if (visited.has(ref)) {
|
|
2109
|
+
throw new InternalError(
|
|
2110
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2111
|
+
)
|
|
2112
|
+
}
|
|
2113
|
+
visited.add(ref);
|
|
2114
|
+
return GitRefManager.resolve({
|
|
2115
|
+
fs,
|
|
2116
|
+
gitdir,
|
|
2117
|
+
ref: sha.trim(),
|
|
2118
|
+
depth,
|
|
2119
|
+
visited,
|
|
2120
|
+
})
|
|
2101
2121
|
}
|
|
2102
2122
|
}
|
|
2103
2123
|
// Do we give up?
|
|
@@ -3612,21 +3632,26 @@ function applyDelta(delta, source) {
|
|
|
3612
3632
|
if (firstOp.byteLength === targetSize) {
|
|
3613
3633
|
target = firstOp;
|
|
3614
3634
|
} else {
|
|
3615
|
-
//
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3635
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
3636
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
3637
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
3638
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
3639
|
+
// still validates the total before concatenating.
|
|
3640
|
+
const chunks = [firstOp];
|
|
3641
|
+
let tell = firstOp.byteLength;
|
|
3619
3642
|
|
|
3620
3643
|
while (!reader.eof()) {
|
|
3621
|
-
|
|
3644
|
+
const op = readOp(reader, source);
|
|
3645
|
+
chunks.push(op);
|
|
3646
|
+
tell += op.byteLength;
|
|
3622
3647
|
}
|
|
3623
3648
|
|
|
3624
|
-
const tell = writer.tell();
|
|
3625
3649
|
if (targetSize !== tell) {
|
|
3626
3650
|
throw new InternalError(
|
|
3627
3651
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
3628
3652
|
)
|
|
3629
3653
|
}
|
|
3654
|
+
target = Buffer.concat(chunks, targetSize);
|
|
3630
3655
|
}
|
|
3631
3656
|
return target
|
|
3632
3657
|
}
|
|
@@ -4877,8 +4902,31 @@ function parseBuffer(buffer) {
|
|
|
4877
4902
|
const type = mode2type$1(mode);
|
|
4878
4903
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
4879
4904
|
|
|
4880
|
-
//
|
|
4881
|
-
|
|
4905
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
4906
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
4907
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
4908
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
4909
|
+
// NTFS 8.3 short name aliases (git~1..git~9), NTFS Alternate Data Streams, and
|
|
4910
|
+
// HFS+ ignorable Unicode characters stripped (zero-width joiners, directional
|
|
4911
|
+
// marks, BOM, etc.).
|
|
4912
|
+
const hfsClean = path.replace(
|
|
4913
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
4914
|
+
''
|
|
4915
|
+
);
|
|
4916
|
+
// NTFS Alternate Data Streams are referenced as `<name>:<stream>:<type>`, and a
|
|
4917
|
+
// directory's default stream lets `.git::$INDEX_ALLOCATION` resolve to the `.git`
|
|
4918
|
+
// directory itself. git forbids *any* ADS, so only the portion before the first
|
|
4919
|
+
// colon names the actual entry we normalize and check.
|
|
4920
|
+
const ntfsClean = hfsClean.split(':')[0];
|
|
4921
|
+
const normalized = ntfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
4922
|
+
if (
|
|
4923
|
+
path.includes('\\') ||
|
|
4924
|
+
path.includes('/') ||
|
|
4925
|
+
hfsClean === '.' ||
|
|
4926
|
+
hfsClean === '..' ||
|
|
4927
|
+
normalized === '.git' ||
|
|
4928
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
4929
|
+
) {
|
|
4882
4930
|
throw new UnsafeFilepathError(path)
|
|
4883
4931
|
}
|
|
4884
4932
|
|