isomorphic-git 1.38.5 → 1.38.6
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 +85 -13
- package/index.js +85 -13
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +53 -11
- package/managers/index.d.cts +1 -1
- package/managers/index.d.ts +1 -1
- package/managers/index.js +53 -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,25 @@ 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), and HFS+ ignorable Unicode
|
|
2545
|
+
// characters stripped (zero-width joiners, directional marks, BOM, etc.).
|
|
2546
|
+
const hfsClean = path.replace(
|
|
2547
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
2548
|
+
''
|
|
2549
|
+
);
|
|
2550
|
+
const normalized = hfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
2551
|
+
if (
|
|
2552
|
+
path.includes('\\') ||
|
|
2553
|
+
path.includes('/') ||
|
|
2554
|
+
hfsClean === '.' ||
|
|
2555
|
+
hfsClean === '..' ||
|
|
2556
|
+
normalized === '.git' ||
|
|
2557
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
2558
|
+
) {
|
|
2522
2559
|
throw new UnsafeFilepathError(path)
|
|
2523
2560
|
}
|
|
2524
2561
|
|
|
@@ -2692,21 +2729,26 @@ function applyDelta(delta, source) {
|
|
|
2692
2729
|
if (firstOp.byteLength === targetSize) {
|
|
2693
2730
|
target = firstOp;
|
|
2694
2731
|
} else {
|
|
2695
|
-
//
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2732
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
2733
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
2734
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
2735
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
2736
|
+
// still validates the total before concatenating.
|
|
2737
|
+
const chunks = [firstOp];
|
|
2738
|
+
let tell = firstOp.byteLength;
|
|
2699
2739
|
|
|
2700
2740
|
while (!reader.eof()) {
|
|
2701
|
-
|
|
2741
|
+
const op = readOp(reader, source);
|
|
2742
|
+
chunks.push(op);
|
|
2743
|
+
tell += op.byteLength;
|
|
2702
2744
|
}
|
|
2703
2745
|
|
|
2704
|
-
const tell = writer.tell();
|
|
2705
2746
|
if (targetSize !== tell) {
|
|
2706
2747
|
throw new InternalError(
|
|
2707
2748
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
2708
2749
|
)
|
|
2709
2750
|
}
|
|
2751
|
+
target = Buffer.concat(chunks, targetSize);
|
|
2710
2752
|
}
|
|
2711
2753
|
return target
|
|
2712
2754
|
}
|
|
@@ -6855,6 +6897,30 @@ const worthWalking = (filepath, root) => {
|
|
|
6855
6897
|
|
|
6856
6898
|
// @ts-check
|
|
6857
6899
|
|
|
6900
|
+
/**
|
|
6901
|
+
* Throw if any leading directory component of `fullpath` (relative to `dir`) is a symbolic
|
|
6902
|
+
* link. git does not follow symlinks in the leading path when writing working-tree files;
|
|
6903
|
+
* matching that avoids writing through a symlinked parent into a location outside `dir`.
|
|
6904
|
+
*
|
|
6905
|
+
* @param {import('../models/FileSystem.js').FileSystem} fs
|
|
6906
|
+
* @param {string} dir
|
|
6907
|
+
* @param {string} fullpath
|
|
6908
|
+
*/
|
|
6909
|
+
async function assertNoSymlinkInLeadingPath(fs, dir, fullpath) {
|
|
6910
|
+
const parts = fullpath.split('/');
|
|
6911
|
+
parts.pop(); // the final segment is the entry being written, not a leading dir
|
|
6912
|
+
let current = dir;
|
|
6913
|
+
for (const part of parts) {
|
|
6914
|
+
if (part === '' || part === '.') continue
|
|
6915
|
+
current = `${current}/${part}`;
|
|
6916
|
+
const stats = await fs.lstat(current);
|
|
6917
|
+
// lstat returns null when the path doesn't exist yet (nothing to traverse).
|
|
6918
|
+
if (stats && stats.isSymbolicLink()) {
|
|
6919
|
+
throw new UnsafeFilepathError(fullpath)
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6858
6924
|
/**
|
|
6859
6925
|
* @param {object} args
|
|
6860
6926
|
* @param {import('../models/FileSystem.js').FileSystem} args.fs
|
|
@@ -7061,6 +7127,7 @@ async function _checkout({
|
|
|
7061
7127
|
.filter(([method]) => method === 'mkdir' || method === 'mkdir-index')
|
|
7062
7128
|
.map(async function ([_, fullpath]) {
|
|
7063
7129
|
const filepath = `${dir}/${fullpath}`;
|
|
7130
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7064
7131
|
await fs.mkdir(filepath);
|
|
7065
7132
|
if (onProgress) {
|
|
7066
7133
|
await onProgress({
|
|
@@ -7130,6 +7197,10 @@ async function _checkout({
|
|
|
7130
7197
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7131
7198
|
const filepath = `${dir}/${fullpath}`;
|
|
7132
7199
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7200
|
+
// Don't write through a symlinked leading path: a parent component that
|
|
7201
|
+
// is a symlink could otherwise redirect the write outside the working
|
|
7202
|
+
// tree. git applies the same check (it does not follow symlinks here).
|
|
7203
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7133
7204
|
const { object } = await _readObject({
|
|
7134
7205
|
fs,
|
|
7135
7206
|
cache,
|
|
@@ -7536,6 +7607,7 @@ async function updateWorkingDir(
|
|
|
7536
7607
|
) {
|
|
7537
7608
|
const filepath = `${dir}/${fullpath}`;
|
|
7538
7609
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7610
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7539
7611
|
const { object } = await _readObject({ fs, cache, gitdir, oid });
|
|
7540
7612
|
if (chmod) {
|
|
7541
7613
|
await fs.rm(filepath);
|
|
@@ -9410,8 +9482,8 @@ function filterCapabilities(server, client) {
|
|
|
9410
9482
|
|
|
9411
9483
|
const pkg = {
|
|
9412
9484
|
name: 'isomorphic-git',
|
|
9413
|
-
version: '1.38.
|
|
9414
|
-
agent: 'git/isomorphic-git@1.38.
|
|
9485
|
+
version: '1.38.6',
|
|
9486
|
+
agent: 'git/isomorphic-git@1.38.6',
|
|
9415
9487
|
};
|
|
9416
9488
|
|
|
9417
9489
|
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,25 @@ 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), and HFS+ ignorable Unicode
|
|
2538
|
+
// characters stripped (zero-width joiners, directional marks, BOM, etc.).
|
|
2539
|
+
const hfsClean = path.replace(
|
|
2540
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
2541
|
+
''
|
|
2542
|
+
);
|
|
2543
|
+
const normalized = hfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
2544
|
+
if (
|
|
2545
|
+
path.includes('\\') ||
|
|
2546
|
+
path.includes('/') ||
|
|
2547
|
+
hfsClean === '.' ||
|
|
2548
|
+
hfsClean === '..' ||
|
|
2549
|
+
normalized === '.git' ||
|
|
2550
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
2551
|
+
) {
|
|
2515
2552
|
throw new UnsafeFilepathError(path)
|
|
2516
2553
|
}
|
|
2517
2554
|
|
|
@@ -2685,21 +2722,26 @@ function applyDelta(delta, source) {
|
|
|
2685
2722
|
if (firstOp.byteLength === targetSize) {
|
|
2686
2723
|
target = firstOp;
|
|
2687
2724
|
} else {
|
|
2688
|
-
//
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2725
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
2726
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
2727
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
2728
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
2729
|
+
// still validates the total before concatenating.
|
|
2730
|
+
const chunks = [firstOp];
|
|
2731
|
+
let tell = firstOp.byteLength;
|
|
2692
2732
|
|
|
2693
2733
|
while (!reader.eof()) {
|
|
2694
|
-
|
|
2734
|
+
const op = readOp(reader, source);
|
|
2735
|
+
chunks.push(op);
|
|
2736
|
+
tell += op.byteLength;
|
|
2695
2737
|
}
|
|
2696
2738
|
|
|
2697
|
-
const tell = writer.tell();
|
|
2698
2739
|
if (targetSize !== tell) {
|
|
2699
2740
|
throw new InternalError(
|
|
2700
2741
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
2701
2742
|
)
|
|
2702
2743
|
}
|
|
2744
|
+
target = Buffer.concat(chunks, targetSize);
|
|
2703
2745
|
}
|
|
2704
2746
|
return target
|
|
2705
2747
|
}
|
|
@@ -6842,6 +6884,30 @@ const worthWalking = (filepath, root) => {
|
|
|
6842
6884
|
|
|
6843
6885
|
// @ts-check
|
|
6844
6886
|
|
|
6887
|
+
/**
|
|
6888
|
+
* Throw if any leading directory component of `fullpath` (relative to `dir`) is a symbolic
|
|
6889
|
+
* link. git does not follow symlinks in the leading path when writing working-tree files;
|
|
6890
|
+
* matching that avoids writing through a symlinked parent into a location outside `dir`.
|
|
6891
|
+
*
|
|
6892
|
+
* @param {import('../models/FileSystem.js').FileSystem} fs
|
|
6893
|
+
* @param {string} dir
|
|
6894
|
+
* @param {string} fullpath
|
|
6895
|
+
*/
|
|
6896
|
+
async function assertNoSymlinkInLeadingPath(fs, dir, fullpath) {
|
|
6897
|
+
const parts = fullpath.split('/');
|
|
6898
|
+
parts.pop(); // the final segment is the entry being written, not a leading dir
|
|
6899
|
+
let current = dir;
|
|
6900
|
+
for (const part of parts) {
|
|
6901
|
+
if (part === '' || part === '.') continue
|
|
6902
|
+
current = `${current}/${part}`;
|
|
6903
|
+
const stats = await fs.lstat(current);
|
|
6904
|
+
// lstat returns null when the path doesn't exist yet (nothing to traverse).
|
|
6905
|
+
if (stats && stats.isSymbolicLink()) {
|
|
6906
|
+
throw new UnsafeFilepathError(fullpath)
|
|
6907
|
+
}
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
|
|
6845
6911
|
/**
|
|
6846
6912
|
* @param {object} args
|
|
6847
6913
|
* @param {import('../models/FileSystem.js').FileSystem} args.fs
|
|
@@ -7048,6 +7114,7 @@ async function _checkout({
|
|
|
7048
7114
|
.filter(([method]) => method === 'mkdir' || method === 'mkdir-index')
|
|
7049
7115
|
.map(async function ([_, fullpath]) {
|
|
7050
7116
|
const filepath = `${dir}/${fullpath}`;
|
|
7117
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7051
7118
|
await fs.mkdir(filepath);
|
|
7052
7119
|
if (onProgress) {
|
|
7053
7120
|
await onProgress({
|
|
@@ -7117,6 +7184,10 @@ async function _checkout({
|
|
|
7117
7184
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7118
7185
|
const filepath = `${dir}/${fullpath}`;
|
|
7119
7186
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7187
|
+
// Don't write through a symlinked leading path: a parent component that
|
|
7188
|
+
// is a symlink could otherwise redirect the write outside the working
|
|
7189
|
+
// tree. git applies the same check (it does not follow symlinks here).
|
|
7190
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7120
7191
|
const { object } = await _readObject({
|
|
7121
7192
|
fs,
|
|
7122
7193
|
cache,
|
|
@@ -7523,6 +7594,7 @@ async function updateWorkingDir(
|
|
|
7523
7594
|
) {
|
|
7524
7595
|
const filepath = `${dir}/${fullpath}`;
|
|
7525
7596
|
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7597
|
+
await assertNoSymlinkInLeadingPath(fs, dir, fullpath);
|
|
7526
7598
|
const { object } = await _readObject({ fs, cache, gitdir, oid });
|
|
7527
7599
|
if (chmod) {
|
|
7528
7600
|
await fs.rm(filepath);
|
|
@@ -9397,8 +9469,8 @@ function filterCapabilities(server, client) {
|
|
|
9397
9469
|
|
|
9398
9470
|
const pkg = {
|
|
9399
9471
|
name: 'isomorphic-git',
|
|
9400
|
-
version: '1.38.
|
|
9401
|
-
agent: 'git/isomorphic-git@1.38.
|
|
9472
|
+
version: '1.38.6',
|
|
9473
|
+
agent: 'git/isomorphic-git@1.38.6',
|
|
9402
9474
|
};
|
|
9403
9475
|
|
|
9404
9476
|
class FIFO {
|