diff --git a/src/Winget.CommunityRepository.Ef/WingetRepositoryWithEf.cs b/src/Winget.CommunityRepository.Ef/WingetRepositoryWithEf.cs index e7dff6e..df7b9c6 100644 --- a/src/Winget.CommunityRepository.Ef/WingetRepositoryWithEf.cs +++ b/src/Winget.CommunityRepository.Ef/WingetRepositoryWithEf.cs @@ -12,7 +12,7 @@ public sealed class WingetRepositoryWithEf : WingetRepository response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); using var zip = new ZipArchive(stream, ZipArchiveMode.Read); - zip.ExtractToDirectory(folder); + ExtractToDirectory(zip, folder); var file = Path.Combine(folder, "Public", "index.db"); var connectionString = $"Data Source='{file}';Pooling=false;"; var results = new List(); @@ -54,4 +54,25 @@ public sealed class WingetRepositoryWithEf : WingetRepository return results; } + + private void ExtractToDirectory(ZipArchive archive, string destinationDirectoryName) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + string filePath = Path.Combine(destinationDirectoryName, entry.FullName); + + if (!filePath.StartsWith(destinationDirectoryName, StringComparison.OrdinalIgnoreCase)) + { + throw new IOException("Extracting Zip entry would have resulted in a file outside the specified destination directory."); + } + + if (string.IsNullOrEmpty(entry.Name)) + { + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + continue; + } + + entry.ExtractToFile(filePath, true); + } + } } diff --git a/src/WingetIntune/Implementations/DefaultFileManager.cs b/src/WingetIntune/Implementations/DefaultFileManager.cs index 41dcb0d..5c0b464 100644 --- a/src/WingetIntune/Implementations/DefaultFileManager.cs +++ b/src/WingetIntune/Implementations/DefaultFileManager.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using System.IO.Compression; using System.Security.Cryptography; @@ -134,7 +134,29 @@ public async Task DownloadFileAsync(string url, string path, string? expectedHas public void ExtractFileToFolder(string zipPath, string destinationFolder) { - ZipFile.ExtractToDirectory(zipPath, destinationFolder); + using (FileStream inputStream = new FileStream(zipPath, FileMode.Open, FileAccess.Read, FileShare.None, bufferSize: 4096, useAsync: false)) + { + using (ZipArchive archive = new ZipArchive(inputStream, ZipArchiveMode.Read, false)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + string filePath = Path.Combine(destinationFolder, entry.FullName); + + if (!filePath.StartsWith(destinationFolder, StringComparison.OrdinalIgnoreCase)) + { + throw new IOException("Extracting Zip entry would have resulted in a file outside the specified destination directory."); + } + + if (string.IsNullOrEmpty(entry.Name)) + { + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + continue; + } + + entry.ExtractToFile(filePath, true); + } + } + } } public async Task ExtractFileToFolderAsync(string zipPath, string destinationFolder, CancellationToken cancellationToken = default) @@ -147,6 +169,13 @@ public async Task ExtractFileToFolderAsync(string zipPath, string destinationFol { if (cancellationToken.IsCancellationRequested) break; + string filePath = Path.Combine(destinationFolder, entry.FullName); + + if (!filePath.StartsWith(destinationFolder, StringComparison.OrdinalIgnoreCase)) + { + throw new IOException("Extracting Zip entry would have resulted in a file outside the specified destination directory."); + } + string directoryName = Path.Combine(destinationFolder, Path.GetDirectoryName(entry.FullName)!); if (!string.IsNullOrEmpty(directoryName)) Directory.CreateDirectory(directoryName);