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/index.cjs
CHANGED
|
@@ -2231,7 +2231,13 @@ class GitRefManager {
|
|
|
2231
2231
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2232
2232
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2233
2233
|
*/
|
|
2234
|
-
static async resolve({
|
|
2234
|
+
static async resolve({
|
|
2235
|
+
fs,
|
|
2236
|
+
gitdir,
|
|
2237
|
+
ref,
|
|
2238
|
+
depth = undefined,
|
|
2239
|
+
visited = new Set(),
|
|
2240
|
+
}) {
|
|
2235
2241
|
if (depth !== undefined) {
|
|
2236
2242
|
depth--;
|
|
2237
2243
|
if (depth === -1) {
|
|
@@ -2242,7 +2248,7 @@ class GitRefManager {
|
|
|
2242
2248
|
// Is it a ref pointer?
|
|
2243
2249
|
if (ref.startsWith('ref: ')) {
|
|
2244
2250
|
ref = ref.slice('ref: '.length);
|
|
2245
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2251
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2246
2252
|
}
|
|
2247
2253
|
// Is it a complete and valid SHA?
|
|
2248
2254
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2261,7 +2267,21 @@ class GitRefManager {
|
|
|
2261
2267
|
packedMap.get(ref)
|
|
2262
2268
|
);
|
|
2263
2269
|
if (sha) {
|
|
2264
|
-
|
|
2270
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2271
|
+
// tracking visited refs this recursion would not terminate.
|
|
2272
|
+
if (visited.has(ref)) {
|
|
2273
|
+
throw new InternalError(
|
|
2274
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2275
|
+
)
|
|
2276
|
+
}
|
|
2277
|
+
visited.add(ref);
|
|
2278
|
+
return GitRefManager.resolve({
|
|
2279
|
+
fs,
|
|
2280
|
+
gitdir,
|
|
2281
|
+
ref: sha.trim(),
|
|
2282
|
+
depth,
|
|
2283
|
+
visited,
|
|
2284
|
+
})
|
|
2265
2285
|
}
|
|
2266
2286
|
}
|
|
2267
2287
|
// Do we give up?
|
|
@@ -2517,8 +2537,31 @@ function parseBuffer(buffer) {
|
|
|
2517
2537
|
const type = mode2type$1(mode);
|
|
2518
2538
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
2519
2539
|
|
|
2520
|
-
//
|
|
2521
|
-
|
|
2540
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
2541
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
2542
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
2543
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
2544
|
+
// NTFS 8.3 short name aliases (git~1..git~9), NTFS Alternate Data Streams, and
|
|
2545
|
+
// HFS+ ignorable Unicode characters stripped (zero-width joiners, directional
|
|
2546
|
+
// marks, BOM, etc.).
|
|
2547
|
+
const hfsClean = path.replace(
|
|
2548
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
2549
|
+
''
|
|
2550
|
+
);
|
|
2551
|
+
// NTFS Alternate Data Streams are referenced as `<name>:<stream>:<type>`, and a
|
|
2552
|
+
// directory's default stream lets `.git::$INDEX_ALLOCATION` resolve to the `.git`
|
|
2553
|
+
// directory itself. git forbids *any* ADS, so only the portion before the first
|
|
2554
|
+
// colon names the actual entry we normalize and check.
|
|
2555
|
+
const ntfsClean = hfsClean.split(':')[0];
|
|
2556
|
+
const normalized = ntfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
2557
|
+
if (
|
|
2558
|
+
path.includes('\\') ||
|
|
2559
|
+
path.includes('/') ||
|
|
2560
|
+
hfsClean === '.' ||
|
|
2561
|
+
hfsClean === '..' ||
|
|
2562
|
+
normalized === '.git' ||
|
|
2563
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
2564
|
+
) {
|
|
2522
2565
|
throw new UnsafeFilepathError(path)
|
|
2523
2566
|
}
|
|
2524
2567
|
|
|
@@ -2692,21 +2735,26 @@ function applyDelta(delta, source) {
|
|
|
2692
2735
|
if (firstOp.byteLength === targetSize) {
|
|
2693
2736
|
target = firstOp;
|
|
2694
2737
|
} else {
|
|
2695
|
-
//
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2738
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
2739
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
2740
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
2741
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
2742
|
+
// still validates the total before concatenating.
|
|
2743
|
+
const chunks = [firstOp];
|
|
2744
|
+
let tell = firstOp.byteLength;
|
|
2699
2745
|
|
|
2700
2746
|
while (!reader.eof()) {
|
|
2701
|
-
|
|
2747
|
+
const op = readOp(reader, source);
|
|
2748
|
+
chunks.push(op);
|
|
2749
|
+
tell += op.byteLength;
|
|
2702
2750
|
}
|
|
2703
2751
|
|
|
2704
|
-
const tell = writer.tell();
|
|
2705
2752
|
if (targetSize !== tell) {
|
|
2706
2753
|
throw new InternalError(
|
|
2707
2754
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
2708
2755
|
)
|
|
2709
2756
|
}
|
|
2757
|
+
target = Buffer.concat(chunks, targetSize);
|
|
2710
2758
|
}
|
|
2711
2759
|
return target
|
|
2712
2760
|
}
|
|
@@ -6855,6 +6903,30 @@ const worthWalking = (filepath, root) => {
|
|
|
6855
6903
|
|
|
6856
6904
|
// @ts-check
|
|
6857
6905
|
|
|
6906
|
+
/**
|
|
6907
|
+
* Throw if any leading directory component of `fullpath` (relative to `dir`) is a symbolic
|
|
6908
|
+
* link. git does not follow symlinks in the leading path when writing working-tree files;
|
|
6909
|
+
* matching that avoids writing through a symlinked parent into a location outside `dir`.
|
|
6910
|
+
*
|
|
6911
|
+
* @param {import('../models/FileSystem.js').FileSystem} fs
|
|
6912
|
+
* @param {string} dir
|
|
6913
|
+
* @param {string} fullpath
|
|
6914
|
+
*/
|
|
6915
|
+
async function assertNoSymlinkInLeadingPath(fs, dir, fullpath) {
|
|
6916
|
+
const parts = fullpath.split('/');
|
|
6917
|
+
parts.pop(); // the final segment is the entry being written, not a leading dir
|
|
6918
|
+
let current = dir;
|
|
6919
|
+
for (const part of parts) {
|
|
6920
|
+
if (part === '' || part === '.') continue
|
|
6921
|
+
current = `${current}/${part}`;
|
|
6922
|
+
const stats = await fs.lstat(current);
|
|
6923
|
+
// lstat returns null when the path doesn't exist yet (nothing to traverse).
|
|
6924
|
+
if (stats && stats.isSymbolicLink()) {
|
|
6925
|
+
throw new UnsafeFilepathError(fullpath)
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
}
|
|
6929
|
+
|
|
6858
6930
|
/**
|
|
6859
6931
|
* @param {object} args
|
|
6860
6932
|
* @param {import('../models/FileSystem.js').FileSystem} args.fs
|
|
@@ -7061,6 +7133,7 @@ async function _checkout({
|
|
|
7061
7133
|
.filter(([method]) => method === 'mkdir' || method === 'mkdir-index')
|
|
7062
7134
|
.map(async function ([_, fullpath]) {
|
|
7063
7135
|
const filepath = `${dir}/${fullpath}`;
|
|
7136
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7064
7137
|
await fs.mkdir(filepath);
|
|
7065
7138
|
if (onProgress) {
|
|
7066
7139
|
await onProgress({
|
|
@@ -7130,6 +7203,10 @@ async function _checkout({
|
|
|
7130
7203
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7131
7204
|
const filepath = `${dir}/${fullpath}`;
|
|
7132
7205
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7206
|
+
// Don't write through a symlinked leading path: a parent component that
|
|
7207
|
+
// is a symlink could otherwise redirect the write outside the working
|
|
7208
|
+
// tree. git applies the same check (it does not follow symlinks here).
|
|
7209
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7133
7210
|
const { object } = await _readObject({
|
|
7134
7211
|
fs,
|
|
7135
7212
|
cache,
|
|
@@ -7536,6 +7613,7 @@ async function updateWorkingDir(
|
|
|
7536
7613
|
) {
|
|
7537
7614
|
const filepath = `${dir}/${fullpath}`;
|
|
7538
7615
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7616
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7539
7617
|
const { object } = await _readObject({ fs, cache, gitdir, oid });
|
|
7540
7618
|
if (chmod) {
|
|
7541
7619
|
await fs.rm(filepath);
|
|
@@ -9410,8 +9488,8 @@ function filterCapabilities(server, client) {
|
|
|
9410
9488
|
|
|
9411
9489
|
const pkg = {
|
|
9412
9490
|
name: 'isomorphic-git',
|
|
9413
|
-
version: '1.38.
|
|
9414
|
-
agent: 'git/isomorphic-git@1.38.
|
|
9491
|
+
version: '1.38.7',
|
|
9492
|
+
agent: 'git/isomorphic-git@1.38.7',
|
|
9415
9493
|
};
|
|
9416
9494
|
|
|
9417
9495
|
class FIFO {
|
package/index.js
CHANGED
|
@@ -2224,7 +2224,13 @@ class GitRefManager {
|
|
|
2224
2224
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2225
2225
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2226
2226
|
*/
|
|
2227
|
-
static async resolve({
|
|
2227
|
+
static async resolve({
|
|
2228
|
+
fs,
|
|
2229
|
+
gitdir,
|
|
2230
|
+
ref,
|
|
2231
|
+
depth = undefined,
|
|
2232
|
+
visited = new Set(),
|
|
2233
|
+
}) {
|
|
2228
2234
|
if (depth !== undefined) {
|
|
2229
2235
|
depth--;
|
|
2230
2236
|
if (depth === -1) {
|
|
@@ -2235,7 +2241,7 @@ class GitRefManager {
|
|
|
2235
2241
|
// Is it a ref pointer?
|
|
2236
2242
|
if (ref.startsWith('ref: ')) {
|
|
2237
2243
|
ref = ref.slice('ref: '.length);
|
|
2238
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2244
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2239
2245
|
}
|
|
2240
2246
|
// Is it a complete and valid SHA?
|
|
2241
2247
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2254,7 +2260,21 @@ class GitRefManager {
|
|
|
2254
2260
|
packedMap.get(ref)
|
|
2255
2261
|
);
|
|
2256
2262
|
if (sha) {
|
|
2257
|
-
|
|
2263
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2264
|
+
// tracking visited refs this recursion would not terminate.
|
|
2265
|
+
if (visited.has(ref)) {
|
|
2266
|
+
throw new InternalError(
|
|
2267
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2268
|
+
)
|
|
2269
|
+
}
|
|
2270
|
+
visited.add(ref);
|
|
2271
|
+
return GitRefManager.resolve({
|
|
2272
|
+
fs,
|
|
2273
|
+
gitdir,
|
|
2274
|
+
ref: sha.trim(),
|
|
2275
|
+
depth,
|
|
2276
|
+
visited,
|
|
2277
|
+
})
|
|
2258
2278
|
}
|
|
2259
2279
|
}
|
|
2260
2280
|
// Do we give up?
|
|
@@ -2510,8 +2530,31 @@ function parseBuffer(buffer) {
|
|
|
2510
2530
|
const type = mode2type$1(mode);
|
|
2511
2531
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
2512
2532
|
|
|
2513
|
-
//
|
|
2514
|
-
|
|
2533
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
2534
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
2535
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
2536
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
2537
|
+
// NTFS 8.3 short name aliases (git~1..git~9), NTFS Alternate Data Streams, and
|
|
2538
|
+
// HFS+ ignorable Unicode characters stripped (zero-width joiners, directional
|
|
2539
|
+
// marks, BOM, etc.).
|
|
2540
|
+
const hfsClean = path.replace(
|
|
2541
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
2542
|
+
''
|
|
2543
|
+
);
|
|
2544
|
+
// NTFS Alternate Data Streams are referenced as `<name>:<stream>:<type>`, and a
|
|
2545
|
+
// directory's default stream lets `.git::$INDEX_ALLOCATION` resolve to the `.git`
|
|
2546
|
+
// directory itself. git forbids *any* ADS, so only the portion before the first
|
|
2547
|
+
// colon names the actual entry we normalize and check.
|
|
2548
|
+
const ntfsClean = hfsClean.split(':')[0];
|
|
2549
|
+
const normalized = ntfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
2550
|
+
if (
|
|
2551
|
+
path.includes('\\') ||
|
|
2552
|
+
path.includes('/') ||
|
|
2553
|
+
hfsClean === '.' ||
|
|
2554
|
+
hfsClean === '..' ||
|
|
2555
|
+
normalized === '.git' ||
|
|
2556
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
2557
|
+
) {
|
|
2515
2558
|
throw new UnsafeFilepathError(path)
|
|
2516
2559
|
}
|
|
2517
2560
|
|
|
@@ -2685,21 +2728,26 @@ function applyDelta(delta, source) {
|
|
|
2685
2728
|
if (firstOp.byteLength === targetSize) {
|
|
2686
2729
|
target = firstOp;
|
|
2687
2730
|
} else {
|
|
2688
|
-
//
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2731
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
2732
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
2733
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
2734
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
2735
|
+
// still validates the total before concatenating.
|
|
2736
|
+
const chunks = [firstOp];
|
|
2737
|
+
let tell = firstOp.byteLength;
|
|
2692
2738
|
|
|
2693
2739
|
while (!reader.eof()) {
|
|
2694
|
-
|
|
2740
|
+
const op = readOp(reader, source);
|
|
2741
|
+
chunks.push(op);
|
|
2742
|
+
tell += op.byteLength;
|
|
2695
2743
|
}
|
|
2696
2744
|
|
|
2697
|
-
const tell = writer.tell();
|
|
2698
2745
|
if (targetSize !== tell) {
|
|
2699
2746
|
throw new InternalError(
|
|
2700
2747
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
2701
2748
|
)
|
|
2702
2749
|
}
|
|
2750
|
+
target = Buffer.concat(chunks, targetSize);
|
|
2703
2751
|
}
|
|
2704
2752
|
return target
|
|
2705
2753
|
}
|
|
@@ -6842,6 +6890,30 @@ const worthWalking = (filepath, root) => {
|
|
|
6842
6890
|
|
|
6843
6891
|
// @ts-check
|
|
6844
6892
|
|
|
6893
|
+
/**
|
|
6894
|
+
* Throw if any leading directory component of `fullpath` (relative to `dir`) is a symbolic
|
|
6895
|
+
* link. git does not follow symlinks in the leading path when writing working-tree files;
|
|
6896
|
+
* matching that avoids writing through a symlinked parent into a location outside `dir`.
|
|
6897
|
+
*
|
|
6898
|
+
* @param {import('../models/FileSystem.js').FileSystem} fs
|
|
6899
|
+
* @param {string} dir
|
|
6900
|
+
* @param {string} fullpath
|
|
6901
|
+
*/
|
|
6902
|
+
async function assertNoSymlinkInLeadingPath(fs, dir, fullpath) {
|
|
6903
|
+
const parts = fullpath.split('/');
|
|
6904
|
+
parts.pop(); // the final segment is the entry being written, not a leading dir
|
|
6905
|
+
let current = dir;
|
|
6906
|
+
for (const part of parts) {
|
|
6907
|
+
if (part === '' || part === '.') continue
|
|
6908
|
+
current = `${current}/${part}`;
|
|
6909
|
+
const stats = await fs.lstat(current);
|
|
6910
|
+
// lstat returns null when the path doesn't exist yet (nothing to traverse).
|
|
6911
|
+
if (stats && stats.isSymbolicLink()) {
|
|
6912
|
+
throw new UnsafeFilepathError(fullpath)
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
6915
|
+
}
|
|
6916
|
+
|
|
6845
6917
|
/**
|
|
6846
6918
|
* @param {object} args
|
|
6847
6919
|
* @param {import('../models/FileSystem.js').FileSystem} args.fs
|
|
@@ -7048,6 +7120,7 @@ async function _checkout({
|
|
|
7048
7120
|
.filter(([method]) => method === 'mkdir' || method === 'mkdir-index')
|
|
7049
7121
|
.map(async function ([_, fullpath]) {
|
|
7050
7122
|
const filepath = `${dir}/${fullpath}`;
|
|
7123
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7051
7124
|
await fs.mkdir(filepath);
|
|
7052
7125
|
if (onProgress) {
|
|
7053
7126
|
await onProgress({
|
|
@@ -7117,6 +7190,10 @@ async function _checkout({
|
|
|
7117
7190
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7118
7191
|
const filepath = `${dir}/${fullpath}`;
|
|
7119
7192
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7193
|
+
// Don't write through a symlinked leading path: a parent component that
|
|
7194
|
+
// is a symlink could otherwise redirect the write outside the working
|
|
7195
|
+
// tree. git applies the same check (it does not follow symlinks here).
|
|
7196
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7120
7197
|
const { object } = await _readObject({
|
|
7121
7198
|
fs,
|
|
7122
7199
|
cache,
|
|
@@ -7523,6 +7600,7 @@ async function updateWorkingDir(
|
|
|
7523
7600
|
) {
|
|
7524
7601
|
const filepath = `${dir}/${fullpath}`;
|
|
7525
7602
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7603
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7526
7604
|
const { object } = await _readObject({ fs, cache, gitdir, oid });
|
|
7527
7605
|
if (chmod) {
|
|
7528
7606
|
await fs.rm(filepath);
|
|
@@ -9397,8 +9475,8 @@ function filterCapabilities(server, client) {
|
|
|
9397
9475
|
|
|
9398
9476
|
const pkg = {
|
|
9399
9477
|
name: 'isomorphic-git',
|
|
9400
|
-
version: '1.38.
|
|
9401
|
-
agent: 'git/isomorphic-git@1.38.
|
|
9478
|
+
version: '1.38.7',
|
|
9479
|
+
agent: 'git/isomorphic-git@1.38.7',
|
|
9402
9480
|
};
|
|
9403
9481
|
|
|
9404
9482
|
class FIFO {
|