From 3e186fb359a9c177250fbd66fdc32f35140b520d Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 7 May 2024 23:13:10 +0100 Subject: [PATCH] Fix progress update & refactoring --- README.md | 2 - .../DecryptResult.cs | 3 -- src/QnapBackupDecryptor.Console/Options.cs | 9 ++-- src/QnapBackupDecryptor.Console/Output.cs | 16 +++--- src/QnapBackupDecryptor.Console/Program.cs | 52 +++++++------------ src/QnapBackupDecryptor.Console/Prompts.cs | 43 ++++++++++++--- .../QnapBackupDecryptor.Console.csproj | 1 + .../DecryptorTests.cs | 1 - .../FileHelpersTests.cs | 1 - .../JobMakerTests.cs | 1 - src/QnapBackupDecryptor.Core/DecryptResult.cs | 3 -- .../DecryptorService.cs | 40 ++++++++++++++ .../FileInfoExtensions.cs | 1 + .../FileJobExtensions.cs | 4 +- src/QnapBackupDecryptor.Core/FileService.cs | 5 +- src/QnapBackupDecryptor.Core/JobMaker.cs | 10 ++-- .../Models/DecryptResult.cs | 3 ++ .../{ => Models}/DeleteResult.cs | 2 +- .../{ => Models}/FileJob.cs | 2 +- .../{ => Models}/Result.cs | 4 +- src/QnapBackupDecryptor.Core/OpenSsl.cs | 11 ++-- .../QnapBackupDecryptor.Core.csproj | 1 + 22 files changed, 132 insertions(+), 83 deletions(-) delete mode 100644 src/QnapBackupDecryptor.Console/DecryptResult.cs delete mode 100644 src/QnapBackupDecryptor.Core/DecryptResult.cs create mode 100644 src/QnapBackupDecryptor.Core/DecryptorService.cs create mode 100644 src/QnapBackupDecryptor.Core/Models/DecryptResult.cs rename src/QnapBackupDecryptor.Core/{ => Models}/DeleteResult.cs (67%) rename src/QnapBackupDecryptor.Core/{ => Models}/FileJob.cs (72%) rename src/QnapBackupDecryptor.Core/{ => Models}/Result.cs (86%) diff --git a/README.md b/README.md index b7517c4..3903f1a 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ This tool is an alternative to the [QENC Decrypter](https://www.qnap.com/en-uk/u ![See it in action](https://raw.githubusercontent.com/mark-s/QnapBackupDecryptor/master/Images/ExampleDecrypt.gif) - - ## Installation Binaries for Windows, Linux and Mac, are available in [Releases](https://github.com/mark-s/QnapBackupDecryptor/releases). diff --git a/src/QnapBackupDecryptor.Console/DecryptResult.cs b/src/QnapBackupDecryptor.Console/DecryptResult.cs deleted file mode 100644 index 426df7e..0000000 --- a/src/QnapBackupDecryptor.Console/DecryptResult.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace QnapBackupDecryptor.Console; - -public record DecryptResult(FileSystemInfo Source, FileSystemInfo Dest, bool Success, string ErrorMessage); \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Console/Options.cs b/src/QnapBackupDecryptor.Console/Options.cs index 33fd322..a9cf20b 100644 --- a/src/QnapBackupDecryptor.Console/Options.cs +++ b/src/QnapBackupDecryptor.Console/Options.cs @@ -3,16 +3,16 @@ namespace QnapBackupDecryptor.Console; -internal class Options +internal sealed class Options { [Option('p', "password", Required = false, HelpText = "Password")] public string? Password { get; init; } [Option('e', "encrypted", Required = true, HelpText = "Encrypted file or folder")] - public string EncryptedSource { get; init; } = null!; + public required string EncryptedSource { get; init; } [Option('d', "decrypted", Required = true, HelpText = "Where to place the decrypted file(s)")] - public string OutputDestination { get; init; } = null!; + public required string OutputDestination { get; init; } [Option('s', "subfolders", Required = false, HelpText = "Include Subfolders (default: false)")] public bool IncludeSubfolders { get; init; } @@ -26,6 +26,8 @@ internal class Options [Option('r', "removeencrypted", Required = false, HelpText = "Delete encrypted files when decrypted (default: false)")] public bool RemoveEncrypted { get; init; } + [Option('i', "inplace", Required = false, HelpText = "Encrypt files in-place (default: false)")] + public bool InPlace { get; init; } [Usage(ApplicationAlias = "QnapBackupDecryptor")] // ReSharper disable once UnusedMember.Global // Used by the console @@ -40,5 +42,4 @@ public static IEnumerable Examples yield return new Example("Decrypt a folder and all subfolders, and prompt for password", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", IncludeSubfolders = true }); } } - } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Console/Output.cs b/src/QnapBackupDecryptor.Console/Output.cs index 67143e9..f57a760 100644 --- a/src/QnapBackupDecryptor.Console/Output.cs +++ b/src/QnapBackupDecryptor.Console/Output.cs @@ -1,4 +1,4 @@ -using QnapBackupDecryptor.Core; +using QnapBackupDecryptor.Core.Models; using Spectre.Console; namespace QnapBackupDecryptor.Console; @@ -20,7 +20,7 @@ public static void ShowResults(IReadOnlyList decryptResults, IRea ShowTiming(swElapsed); - if (decryptResults.Any(r => r.Success == false) || deleteResults.Any(r => r.DeletedOk == false)) + if (decryptResults.Any(r => r.DecryptedOk == false) || deleteResults.Any(r => r.DeletedOk == false)) Environment.ExitCode = 1; } @@ -36,8 +36,8 @@ private static void ShowSimpleResults(IReadOnlyList decryptResult table.AddRow( $"{decryptResults.Count}", - $"[green]{decryptResults.Count(r => r.Success)}[/]", - $"[red]{decryptResults.Count(r => !r.Success)}[/]", + $"[green]{decryptResults.Count(r => r.DecryptedOk)}[/]", + $"[red]{decryptResults.Count(r => !r.DecryptedOk)}[/]", $"[green]{deleteResults.Count(r => r.DeletedOk)}[/]", $"[red]{deleteResults.Count(r => !r.DeletedOk)}[/]" ); @@ -53,7 +53,7 @@ private static void ShowFileListResults(IReadOnlyList decryptResu .AddColumn("Encrypted") .AddColumn("Decrypted"); - if (decryptResults.Any(r => r.Success == false)) + if (decryptResults.Any(r => r.DecryptedOk == false)) table.AddColumn("Error"); if (deleteResults.Any()) @@ -81,8 +81,8 @@ private static void ShowFileListResults(IReadOnlyList decryptResu private static List DecryptResultToRow(DecryptResult decryptResult) { - var colour = decryptResult.Success ? "green" : "red"; - var status = decryptResult.Success ? "OK" : "Fail"; + var colour = decryptResult.DecryptedOk ? "green" : "red"; + var status = decryptResult.DecryptedOk ? "OK" : "Fail"; var row = new List { @@ -91,7 +91,7 @@ private static List DecryptResultToRow(DecryptResult decryptResult) $"[{colour}]{decryptResult.Dest.FullName}[/]" }; - if (decryptResult.Success == false) + if (decryptResult.DecryptedOk == false) row.Add($"[{colour}]{decryptResult.ErrorMessage}[/]"); return row; diff --git a/src/QnapBackupDecryptor.Console/Program.cs b/src/QnapBackupDecryptor.Console/Program.cs index 62130ed..228dcae 100644 --- a/src/QnapBackupDecryptor.Console/Program.cs +++ b/src/QnapBackupDecryptor.Console/Program.cs @@ -1,5 +1,6 @@ using CommandLine; using QnapBackupDecryptor.Core; +using QnapBackupDecryptor.Core.Models; using Spectre.Console; using System.Collections.Concurrent; using System.Diagnostics; @@ -21,6 +22,10 @@ private static void Run(Options options) if (Prompts.EnsureDeleteWanted(options) == false) return; + // Double check in-place change is wanted + if (Prompts.EnsureInPlaceWanted(options) == false) + return; + var password = Prompts.GetPassword(options); var stopwatch = Stopwatch.StartNew(); @@ -36,28 +41,23 @@ private static void Run(Options options) private static IReadOnlyList GetDecryptJobs(Options options) { - var decryptJobs = new List(); - - // get file list to process - AnsiConsole.Status() + return AnsiConsole + .Status() .Start("Getting Files...", statusContext => { statusContext.Spinner(Spinner.Known.SimpleDots); statusContext.SpinnerStyle(Style.Parse("green")); - decryptJobs.AddRange( - JobMaker.GetDecryptJobs( + return JobMaker.GetDecryptJobs( encryptedSource: options.EncryptedSource, decryptedTarget: options.OutputDestination, overwrite: options.Overwrite, - includeSubFolders: options.IncludeSubfolders) - ); + includeSubFolders: options.IncludeSubfolders); }); - - return decryptJobs; } - private static (IReadOnlyList DecryptResults, IReadOnlyList DeleteResults) DoDecrypt(IReadOnlyCollection decryptJobs, Options options, byte[] password) + private static (IReadOnlyList DecryptResults, IReadOnlyList DeleteResults) + DoDecrypt(IReadOnlyCollection decryptJobs, Options options, byte[] password) { var decryptResults = new ConcurrentBag(); var deleteResults = new ConcurrentBag(); @@ -70,32 +70,18 @@ private static (IReadOnlyList DecryptResults, IReadOnlyList DecryptSingleJob(options, password, currentJob, decryptResults, deleteResults, progressTask)); + Parallel.ForEach(decryptJobs, job => + { + var (decryptResult, deleteResult) = DecryptorService.Decrypt(options.RemoveEncrypted, password, job, progressTask.Increment); + decryptResults.Add(decryptResult); + if (deleteResult != null) + deleteResults.Add(deleteResult); + }); + }); return (decryptResults.ToList(), deleteResults.ToList()); } - private static void DecryptSingleJob( - Options options, byte[] password, FileJob currentJob, ConcurrentBag decryptResults, - ConcurrentBag deleteResults, ProgressTask progressTask) - { - if (currentJob.IsValid) - { - var decryptionResult = OpenSsl.Decrypt(new FileInfo(currentJob.EncryptedFile.FullName), password, new FileInfo(currentJob.OutputFile.FullName)); - - decryptResults.Add(new DecryptResult(currentJob.EncryptedFile, currentJob.OutputFile, decryptionResult.IsSuccess, decryptionResult.ErrorMessage)); - - // Delete encrypted file only if success and option chosen - if (decryptionResult.IsSuccess && options.RemoveEncrypted) - deleteResults.Add(FileService.TryDelete(currentJob.EncryptedFile)); - } - else - decryptResults.Add(new DecryptResult(currentJob.EncryptedFile, currentJob.OutputFile, currentJob.IsValid, currentJob.ErrorMessage)); - - progressTask.Increment(decryptResults.Count); - } } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Console/Prompts.cs b/src/QnapBackupDecryptor.Console/Prompts.cs index d5ae7cd..3ff79e6 100644 --- a/src/QnapBackupDecryptor.Console/Prompts.cs +++ b/src/QnapBackupDecryptor.Console/Prompts.cs @@ -5,10 +5,14 @@ namespace QnapBackupDecryptor.Console; internal static class Prompts { - public static byte[] GetPassword(Options opts) + private const string YES = "y"; + private const string NO = "n"; + private const string INVALID_OPTION_ENTERED = "[yellow]That's not a valid option[/]"; + + public static byte[] GetPassword(Options options) { - if (string.IsNullOrEmpty(opts.Password) == false) - return Encoding.UTF8.GetBytes(opts.Password); + if (string.IsNullOrEmpty(options.Password) == false) + return Encoding.UTF8.GetBytes(options.Password); else { var password = AnsiConsole.Prompt( @@ -26,11 +30,34 @@ public static bool EnsureDeleteWanted(Options options) var response = AnsiConsole.Prompt( new TextPrompt("[bold]>> Are you sure you want to delete the encrypted files?[/]") - .InvalidChoiceMessage("[yellow]That's not a valid option[/]") - .DefaultValue("n") - .AddChoice("y") - .AddChoice("n")); + .WithYesNoOptions(defaultOption: NO)); - return response.Equals("y", StringComparison.InvariantCultureIgnoreCase); + return response.IsYes(); } + + public static bool EnsureInPlaceWanted(Options options) + { + if (options.InPlace == false) + return true; + + var initialResponse = AnsiConsole.Prompt( + new TextPrompt("[bold]>> Are you sure you want to decrypt the files in-place? If a decrypt produces a bad file - you will lose that file![/]") + .WithYesNoOptions(defaultOption: NO)); + + var areYouSureResponse = AnsiConsole.Prompt( + new TextPrompt("[bold]>> Are you really sure? Do you have a backup in case anything goes wrong?[/]") + .WithYesNoOptions(defaultOption: NO)); + + return initialResponse.IsYes() && areYouSureResponse.IsYes(); + } + + private static TextPrompt WithYesNoOptions(this TextPrompt prompt, string defaultOption) + => prompt.InvalidChoiceMessage(INVALID_OPTION_ENTERED) + .DefaultValue(defaultOption) + .AddChoice(YES) + .AddChoice(NO); + + private static bool IsYes(this string? value) + => value?.Equals(YES, StringComparison.OrdinalIgnoreCase) ?? false; + } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Console/QnapBackupDecryptor.Console.csproj b/src/QnapBackupDecryptor.Console/QnapBackupDecryptor.Console.csproj index 20b16f5..9b77572 100644 --- a/src/QnapBackupDecryptor.Console/QnapBackupDecryptor.Console.csproj +++ b/src/QnapBackupDecryptor.Console/QnapBackupDecryptor.Console.csproj @@ -6,6 +6,7 @@ enable enable true + true diff --git a/src/QnapBackupDecryptor.Core.Tests/DecryptorTests.cs b/src/QnapBackupDecryptor.Core.Tests/DecryptorTests.cs index eb0acbd..e82708c 100644 --- a/src/QnapBackupDecryptor.Core.Tests/DecryptorTests.cs +++ b/src/QnapBackupDecryptor.Core.Tests/DecryptorTests.cs @@ -22,7 +22,6 @@ public void OpenSSLDecrypt_ValidPassword_OkResult() sslDecrypt.IsSuccess.ShouldBeTrue(); } - [Test] public void OpenSSLDecrypt_Text() { diff --git a/src/QnapBackupDecryptor.Core.Tests/FileHelpersTests.cs b/src/QnapBackupDecryptor.Core.Tests/FileHelpersTests.cs index 68a12d6..3ae8216 100644 --- a/src/QnapBackupDecryptor.Core.Tests/FileHelpersTests.cs +++ b/src/QnapBackupDecryptor.Core.Tests/FileHelpersTests.cs @@ -38,5 +38,4 @@ public void IsOpenSslEncrypted_NotOpenSslFile_False() // Assert result.Data.ShouldBeFalse(); } - } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core.Tests/JobMakerTests.cs b/src/QnapBackupDecryptor.Core.Tests/JobMakerTests.cs index e0c5165..833f2ba 100644 --- a/src/QnapBackupDecryptor.Core.Tests/JobMakerTests.cs +++ b/src/QnapBackupDecryptor.Core.Tests/JobMakerTests.cs @@ -81,5 +81,4 @@ public void GetDecryptJobs_EncryptedFileExists_TargetExists_OverwriteFalse_Produ result[0].IsValid.ShouldBeFalse(); result[0].ErrorMessage.ShouldBe("Output file already exists, use --overwrite to overwrite files."); } - } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/DecryptResult.cs b/src/QnapBackupDecryptor.Core/DecryptResult.cs deleted file mode 100644 index e363120..0000000 --- a/src/QnapBackupDecryptor.Core/DecryptResult.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace QnapBackupDecryptor.Core; - -public sealed record DecryptResult(FileSystemInfo Source, FileSystemInfo Dest, bool Success, string ErrorMessage); \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/DecryptorService.cs b/src/QnapBackupDecryptor.Core/DecryptorService.cs new file mode 100644 index 0000000..bfeb789 --- /dev/null +++ b/src/QnapBackupDecryptor.Core/DecryptorService.cs @@ -0,0 +1,40 @@ +using QnapBackupDecryptor.Core.Models; + +namespace QnapBackupDecryptor.Core; + +public class DecryptorService +{ + public static (DecryptResult decryptResult, DeleteResult? deleteResult) Decrypt( + bool removeEncrypted, + byte[] password, + FileJob job, + Action progressUpdate) + { + + DecryptResult decrypted; + DeleteResult? deleted =null; + + if (job.IsValid) + { + var decryptionResult = OpenSsl.Decrypt( + encryptedFile: new FileInfo(job.EncryptedFile.FullName), + password: password, + outputFile: new FileInfo(job.OutputFile.FullName)); + + decrypted = new DecryptResult(job.EncryptedFile, job.OutputFile, decryptionResult.IsSuccess, decryptionResult.ErrorMessage); + + // Delete encrypted file only if success and option chosen + if (decryptionResult.IsSuccess && removeEncrypted) + deleted = FileService.TryDelete(job.EncryptedFile); + } + else + { + decrypted = new DecryptResult(job.EncryptedFile, job.OutputFile, job.IsValid, job.ErrorMessage); + } + + progressUpdate(1); + + return (decrypted, deleted); + + } +} diff --git a/src/QnapBackupDecryptor.Core/FileInfoExtensions.cs b/src/QnapBackupDecryptor.Core/FileInfoExtensions.cs index eae6a57..fa91d1e 100644 --- a/src/QnapBackupDecryptor.Core/FileInfoExtensions.cs +++ b/src/QnapBackupDecryptor.Core/FileInfoExtensions.cs @@ -6,6 +6,7 @@ internal static bool TryDelete(this FileInfo fileInfo) { try { + fileInfo.Refresh(); if (fileInfo.Exists) fileInfo.Delete(); diff --git a/src/QnapBackupDecryptor.Core/FileJobExtensions.cs b/src/QnapBackupDecryptor.Core/FileJobExtensions.cs index 03a1d42..3eff2dd 100644 --- a/src/QnapBackupDecryptor.Core/FileJobExtensions.cs +++ b/src/QnapBackupDecryptor.Core/FileJobExtensions.cs @@ -1,4 +1,6 @@ -namespace QnapBackupDecryptor.Core; +using QnapBackupDecryptor.Core.Models; + +namespace QnapBackupDecryptor.Core; internal static class FileJobExtensions { diff --git a/src/QnapBackupDecryptor.Core/FileService.cs b/src/QnapBackupDecryptor.Core/FileService.cs index fca9f97..689631f 100644 --- a/src/QnapBackupDecryptor.Core/FileService.cs +++ b/src/QnapBackupDecryptor.Core/FileService.cs @@ -1,4 +1,6 @@ -namespace QnapBackupDecryptor.Core; +using QnapBackupDecryptor.Core.Models; + +namespace QnapBackupDecryptor.Core; public static class FileService { @@ -14,5 +16,4 @@ public static DeleteResult TryDelete(FileSystemInfo toDelete) return new DeleteResult(toDelete, false, ex.Message); } } - } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/JobMaker.cs b/src/QnapBackupDecryptor.Core/JobMaker.cs index c6104fc..491d137 100644 --- a/src/QnapBackupDecryptor.Core/JobMaker.cs +++ b/src/QnapBackupDecryptor.Core/JobMaker.cs @@ -1,8 +1,10 @@ -namespace QnapBackupDecryptor.Core; +using QnapBackupDecryptor.Core.Models; + +namespace QnapBackupDecryptor.Core; public static class JobMaker { - public static List GetDecryptJobs(string encryptedSource, string decryptedTarget, bool overwrite, bool includeSubFolders) + public static IReadOnlyList GetDecryptJobs(string encryptedSource, string decryptedTarget, bool overwrite, bool includeSubFolders) { if (Directory.Exists(encryptedSource) == false && File.Exists(encryptedSource) == false) return new FileJob(new DirectoryInfo(encryptedSource), new FileInfo(decryptedTarget), false, "Source does not exist").ToList(); @@ -25,7 +27,6 @@ public static List GetDecryptJobs(string encryptedSource, string decryp return GetFileToFileJob(new FileInfo(encryptedSource), new FileInfo(decryptedTarget), overwrite).ToList(); } - private static FileJob GetFileToFileJob(FileInfo encrytedFile, FileInfo outputFile, bool overwrite) { if (encrytedFile.Exists == false) @@ -63,7 +64,4 @@ private static List GetFolderToFolderJobs(DirectoryInfo encrytedFolder, .Select(encrytedFile => GetFileToFolderJob(encrytedFile, outputFolder, overwrite)) .ToList(); } - - - } \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/Models/DecryptResult.cs b/src/QnapBackupDecryptor.Core/Models/DecryptResult.cs new file mode 100644 index 0000000..8c14e60 --- /dev/null +++ b/src/QnapBackupDecryptor.Core/Models/DecryptResult.cs @@ -0,0 +1,3 @@ +namespace QnapBackupDecryptor.Core.Models; + +public sealed record DecryptResult(FileSystemInfo Source, FileSystemInfo Dest, bool DecryptedOk, string ErrorMessage); \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/DeleteResult.cs b/src/QnapBackupDecryptor.Core/Models/DeleteResult.cs similarity index 67% rename from src/QnapBackupDecryptor.Core/DeleteResult.cs rename to src/QnapBackupDecryptor.Core/Models/DeleteResult.cs index 70b6d65..d07f9ef 100644 --- a/src/QnapBackupDecryptor.Core/DeleteResult.cs +++ b/src/QnapBackupDecryptor.Core/Models/DeleteResult.cs @@ -1,3 +1,3 @@ -namespace QnapBackupDecryptor.Core; +namespace QnapBackupDecryptor.Core.Models; public sealed record DeleteResult(FileSystemInfo ToDelete, bool DeletedOk, string ErrorMessage); \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/FileJob.cs b/src/QnapBackupDecryptor.Core/Models/FileJob.cs similarity index 72% rename from src/QnapBackupDecryptor.Core/FileJob.cs rename to src/QnapBackupDecryptor.Core/Models/FileJob.cs index 1528f3b..e013ffc 100644 --- a/src/QnapBackupDecryptor.Core/FileJob.cs +++ b/src/QnapBackupDecryptor.Core/Models/FileJob.cs @@ -1,3 +1,3 @@ -namespace QnapBackupDecryptor.Core; +namespace QnapBackupDecryptor.Core.Models; public sealed record FileJob(FileSystemInfo EncryptedFile, FileSystemInfo OutputFile, bool IsValid, string ErrorMessage); \ No newline at end of file diff --git a/src/QnapBackupDecryptor.Core/Result.cs b/src/QnapBackupDecryptor.Core/Models/Result.cs similarity index 86% rename from src/QnapBackupDecryptor.Core/Result.cs rename to src/QnapBackupDecryptor.Core/Models/Result.cs index 0a388ec..0b4a8de 100644 --- a/src/QnapBackupDecryptor.Core/Result.cs +++ b/src/QnapBackupDecryptor.Core/Models/Result.cs @@ -1,4 +1,4 @@ -namespace QnapBackupDecryptor.Core; +namespace QnapBackupDecryptor.Core.Models; public class Result { @@ -10,7 +10,7 @@ public class Result public T Data { get; } - internal Result(bool isSuccess, string errorMessage, T data, string successMessage, Exception? exception) + private Result(bool isSuccess, string errorMessage, T data, string successMessage, Exception? exception) { IsSuccess = isSuccess; ErrorMessage = errorMessage; diff --git a/src/QnapBackupDecryptor.Core/OpenSsl.cs b/src/QnapBackupDecryptor.Core/OpenSsl.cs index 02f65fb..0d72cca 100644 --- a/src/QnapBackupDecryptor.Core/OpenSsl.cs +++ b/src/QnapBackupDecryptor.Core/OpenSsl.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography; +using QnapBackupDecryptor.Core.Models; namespace QnapBackupDecryptor.Core; @@ -83,20 +84,18 @@ private static (byte[] key, byte[] iv) DeriveKeyAndIV(byte[] password, byte[] sa private static Result DecryptFile(FileInfo encryptedFile, byte[] key, byte[] iv, FileInfo outputFile) { - var aes = CreateAes(key, iv); - var couldOpenOutputFileForWrite = false; + var aes = CreateAes(key, iv); try { - var decryptor = aes.CreateDecryptor(); - using var encryptedFileStream = encryptedFile.OpenRead(); encryptedFileStream.Position = SALT_HEADER_SIZE + SALT_SIZE; using var destination = outputFile.OpenWrite(); couldOpenOutputFileForWrite = true; + var decryptor = aes.CreateDecryptor(); using var cryptoStream = new CryptoStream(encryptedFileStream, decryptor, CryptoStreamMode.Read); FileHelpers.HideFile(outputFile); @@ -109,9 +108,9 @@ private static Result DecryptFile(FileInfo encryptedFile, byte[] key, } catch (Exception ex) { - if(couldOpenOutputFileForWrite == false) + if (couldOpenOutputFileForWrite == false) return Result.ErrorResult("could not decrypt - could not write to output file", outputFile, ex); - + if (outputFile.TryDelete()) return Result.ErrorResult("could not decrypt", outputFile, ex); else diff --git a/src/QnapBackupDecryptor.Core/QnapBackupDecryptor.Core.csproj b/src/QnapBackupDecryptor.Core/QnapBackupDecryptor.Core.csproj index 5ad3690..c198878 100644 --- a/src/QnapBackupDecryptor.Core/QnapBackupDecryptor.Core.csproj +++ b/src/QnapBackupDecryptor.Core/QnapBackupDecryptor.Core.csproj @@ -5,6 +5,7 @@ enable enable true + true