龙腾猫跃 3 месяцев назад
Родитель
Сommit
a1fcb5241a

+ 2 - 3
Shared/Utils/DirectoryUtils.cs

@@ -169,7 +169,7 @@ public static class DirectoryUtils {
         folder = PathUtils.ForCompare(folder);
         if (folder == PathUtils.ForCompare(Path.GetPathRoot(folder)))
             throw new UnauthorizedAccessException($"不应操作磁盘根目录:{folder}");
-        if (criticalFolders.Value.Any(f => f.StartsWithF(folder, ignoreCase: true)))
+        if (criticalFolders.Value.Any(f => PathUtils.IsParentOf(f, folder)))
             throw new UnauthorizedAccessException($"不应操作文件夹:{folder}");
     }
     private static readonly Lazy<HashSet<string>> criticalFolders = new(() => new(new[] {
@@ -179,7 +179,6 @@ public static class DirectoryUtils {
         Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
         Environment.GetFolderPath(Environment.SpecialFolder.Windows),
         Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads") // 下载文件夹没有 SpecialFolder 枚举
-    }.Where(f => f.Contains(Path.VolumeSeparatorChar)) // 当缺少某个文件夹时,GetFolderPath 会返回空字符串(#8636)
-     .Select(f => PathUtils.ForCompare(f))));
+    }.Where(f => f.Contains(Path.VolumeSeparatorChar)))); // 当缺少某个文件夹时,GetFolderPath 会返回空字符串(#8636)
 
 }

+ 3 - 5
Shared/Utils/FileUtils.cs

@@ -1,4 +1,3 @@
-using Newtonsoft.Json.Linq;
 using System.IO.Compression;
 
 namespace MeloongCore;
@@ -359,15 +358,14 @@ public static class FileUtils {
             if (totalCount > 0) progressHandler?.Invoke((double) doneCount / totalCount);
             if (string.IsNullOrEmpty(entry.Name)) continue; // 跳过文件夹条目(ZipArchive 会将文件夹也作为一个 entry,但它们的 Name 为空)
             // ZipSlip 修复
-            string outputFilePath = PathUtils.ForCompare(Path.Combine(outputDirectory, entry.FullName));
-            if (!outputFilePath.StartsWithF(PathUtils.AddSlashSuffix(PathUtils.ForCompare(outputDirectory)), ignoreCase:true))
-                throw new ZipSlipException($"Zip 文件项 {entry.FullName} 的路径在压缩包之外,这可能导致安全问题");
+            string outputFilePath = Path.Combine(outputDirectory, entry.FullName);
+            if (!PathUtils.IsParentOf(outputDirectory, outputFilePath))
+                throw new InvalidDataException($"Zip 文件项 {entry.FullName} 的路径在压缩包之外,这可能导致安全问题");
             // 实际的解压
             using var entryStream = entry.Open();
             FileUtils.Write(outputFilePath, entryStream);
         }
     }
-    public class ZipSlipException(string message) : Exception(message) {}
 
     /// <summary>
     /// 将指定文件夹的内容打包为 zip 文件。

+ 9 - 0
Shared/Utils/PathUtils.cs

@@ -178,6 +178,15 @@ public static class PathUtils {
 
     #endregion
 
+    /// <summary>
+    /// 判断 <param name="parentPath"/> 是否为 <paramref name="childPath"/> 的父路径,或两者是否相同。
+    /// </summary>
+    public static bool IsParentOf(string parentPath, string childPath) {
+        parentPath = PathUtils.ForCompare(parentPath);
+        childPath = PathUtils.ForCompare(childPath);
+        return childPath.StartsWithF(parentPath + @"\") || childPath == parentPath;
+    }
+
 }
 
 /// <summary>

+ 3 - 3
Tests/General/ProgressTest.cs

@@ -6,7 +6,7 @@ public class ProgressTest : TestBase {
     public async Task ProgressChanged_主进度实际改变时触发() {
         var progress = new ProgressProvider();
         int changedCount = 0;
-        progress.ProgressChanged += () => changedCount++;
+        progress.ProgressChanged += _ => changedCount++;
 
         progress.Set(0.2);
         progress.Set(0.2);
@@ -21,7 +21,7 @@ public class ProgressTest : TestBase {
     public async Task ProgressChanged_子进度改变时向父级传播() {
         var progress = new ProgressProvider();
         int changedCount = 0;
-        progress.ProgressChanged += () => changedCount++;
+        progress.ProgressChanged += _ => changedCount++;
 
         var sub = progress.SplitBy(0.5).Single();
         sub.Set(0.5);
@@ -34,7 +34,7 @@ public class ProgressTest : TestBase {
     public async Task ProgressChanged_不会触发Observe() {
         var progress = new ProgressProvider();
         int changedCount = 0;
-        progress.ProgressChanged += () => changedCount++;
+        progress.ProgressChanged += _ => changedCount++;
 
         progress.Set(0.5);
         progress.Set(0.75, skiped: true);

+ 1 - 1
Tests/General/WorkerTest.cs

@@ -32,7 +32,7 @@ public class WorkerTest : TestBase {
             if (currentRun == 1) {
                 firstStarted.Set();
                 while (true) {
-                    ct.ThrowIfCancellationRequested();
+                    ct?.ThrowIfCancellationRequested();
                     Thread.Sleep(10);
                 }
             }

+ 2 - 6
Tests/Utils/FileUtilsTest.cs

@@ -30,14 +30,10 @@ public class FileUtilsTest : TestWithFolder {
     [Test]
     [Arguments("Corrupted.zip")]
     [Arguments("Not zip.zip")]
-    public void 解压_ReadBad(string testFile)
-        => Assert.Throws<InvalidDataException>(() => FileUtils.ExtractToDirectory(GetTestFile(testFile), tempFolder));
-
-    [Test]
     [Arguments("DotDot ZipSlip.zip")]
     [Arguments("AbsPath ZipSlip.zip")]
-    public void 解压_ZipSlip(string testFile)
-        => Assert.Throws<FileUtils.ZipSlipException>(() => FileUtils.ExtractToDirectory(GetTestFile(testFile), tempFolder));
+    public void 解压_ReadBad(string testFile)
+        => Assert.Throws<InvalidDataException>(() => FileUtils.ExtractToDirectory(GetTestFile(testFile), tempFolder));
 
     #endregion