diff --git a/src/ui/Logic/Download/YtDlpDownloadService.cs b/src/ui/Logic/Download/YtDlpDownloadService.cs index 1b3e9c4043e..43a8b01524d 100644 --- a/src/ui/Logic/Download/YtDlpDownloadService.cs +++ b/src/ui/Logic/Download/YtDlpDownloadService.cs @@ -197,6 +197,11 @@ public async Task DownloadYtDlp(IProgress? progress, CancellationToken ca internal static async Task VerifyChecksumAsync(string filePath, string version, CancellationToken cancellationToken) { var assetName = Path.GetFileName(filePath); + if (assetName.EndsWith(".part", StringComparison.Ordinal)) + { + assetName = assetName[..^".part".Length]; + } + if (!KnownSha256.TryGetValue(version, out var byAsset) || !byAsset.TryGetValue(assetName, out var expected)) { diff --git a/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs b/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs index c1781ba55d8..4431ba57c16 100644 --- a/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs +++ b/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs @@ -162,6 +162,26 @@ await Assert.ThrowsAsync(() => } } + [Fact] + public async Task VerifyChecksumAsync_PartFile_Mismatch_ThrowsAndDeletesFile() + { + var dir = Path.Combine(Path.GetTempPath(), "VerifyPartMismatch_" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(dir); + var path = Path.Combine(dir, "yt-dlp.exe.part"); + await File.WriteAllTextAsync(path, "this is not really yt-dlp", TestContext.Current.CancellationToken); + try + { + await Assert.ThrowsAsync(() => + YtDlpDownloadService.VerifyChecksumAsync(path, YtDlpDownloadService.CurrentVersion, TestContext.Current.CancellationToken)); + + Assert.False(File.Exists(path), "A downloaded .part binary that fails verification must be deleted."); + } + finally + { + Directory.Delete(dir, recursive: true); + } + } + [Fact] public async Task VerifyChecksumAsync_UnknownAsset_IsNoOp_AndKeepsFile() {