public static void TestCanceledDecryptAndLaunch() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Cancel = true; }; FileOperationStatus status = controller.DecryptAndLaunch(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Canceled), "The status should indicate cancellation."); }
public static void TestSimpleDecryptAndLaunchOnThreadWorker() { FakeLauncher launcher = null; FakeRuntimeEnvironment environment = (FakeRuntimeEnvironment)OS.Current; environment.Launcher = ((string path) => { launcher = new FakeLauncher(path); return launcher; }); FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "a"; }; FileOperationStatus status = FileOperationStatus.Unknown; controller.Completed += (object sender, FileOperationEventArgs e) => { status = e.Status; }; using (ThreadWorker worker = new ThreadWorker(new ProgressContext())) { controller.DecryptAndLaunch(_helloWorldAxxPath, worker); worker.Join(); } Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(launcher, Is.Not.Null, "There should be a call to launch."); Assert.That(Path.GetFileName(launcher.Path), Is.EqualTo("HelloWorld-Key-a.txt"), "The file should be decrypted and the name should be the original from the encrypted headers."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(launcher.Path); Assert.That(destinationInfo.Exists, "After decryption the destination file should be created."); string fileContent; using (Stream stream = destinationInfo.OpenRead()) { fileContent = new StreamReader(stream).ReadToEnd(); } Assert.That(fileContent.Contains("Hello"), "A file named Hello World should contain that text when decrypted."); }
public static void TestEncryptFileWithDefaultEncryptionKey() { _fileSystemState.KnownKeys.DefaultEncryptionKey = new Passphrase("default").DerivedPassphrase; FileOperationsController controller = new FileOperationsController(_fileSystemState); bool queryEncryptionPassphraseWasCalled = false; controller.QueryEncryptionPassphrase += (object sender, FileOperationEventArgs e) => { queryEncryptionPassphraseWasCalled = true; }; string destinationPath = String.Empty; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; FileOperationStatus status = controller.EncryptFile(_davidCopperfieldTxtPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(!queryEncryptionPassphraseWasCalled, "No query of encryption passphrase should be needed since there is a default set."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After encryption the destination file should be created."); using (AxCryptDocument document = new AxCryptDocument()) { using (Stream stream = destinationInfo.OpenRead()) { document.Load(stream, new Passphrase("default").DerivedPassphrase); Assert.That(document.PassphraseIsValid, "The encrypted document should be valid and encrypted with the default passphrase given."); } } }
public static void TestEncryptFileWhenDestinationExists() { IRuntimeFileInfo sourceInfo = OS.Current.FileInfo(_davidCopperfieldTxtPath); IRuntimeFileInfo expectedDestinationInfo = OS.Current.FileInfo(AxCryptFile.MakeAxCryptFileName(sourceInfo)); using (Stream stream = expectedDestinationInfo.OpenWrite()) { } FileOperationsController controller = new FileOperationsController(_fileSystemState); string destinationPath = String.Empty; controller.QueryEncryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "allan"; }; controller.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { e.SaveFileFullName = Path.Combine(Path.GetDirectoryName(e.SaveFileFullName), "alternative-name.axx"); }; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; FileOperationStatus status = controller.EncryptFile(_davidCopperfieldTxtPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(Path.GetFileName(destinationPath), Is.EqualTo("alternative-name.axx"), "The alternative name should be used, since the default existed."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After encryption the destination file should be created."); using (AxCryptDocument document = new AxCryptDocument()) { using (Stream stream = destinationInfo.OpenRead()) { document.Load(stream, new Passphrase("allan").DerivedPassphrase); Assert.That(document.PassphraseIsValid, "The encrypted document should be valid and encrypted with the passphrase given."); } } }
private void DecryptFile(string file, IThreadWorker worker, ProgressContext progress) { FileOperationsController operationsController = new FileOperationsController(persistentState.Current, progress); operationsController.QueryDecryptionPassphrase += HandleQueryDecryptionPassphraseEvent; operationsController.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { string extension = Path.GetExtension(e.SaveFileFullName); using (SaveFileDialog sfd = new SaveFileDialog()) { sfd.AddExtension = !String.IsNullOrEmpty(extension); sfd.CheckPathExists = true; sfd.DefaultExt = extension; sfd.Filter = Resources.DecryptedSaveAsFileDialogFilterPattern.InvariantFormat(extension); sfd.InitialDirectory = Path.GetDirectoryName(file); sfd.FileName = Path.GetFileName(e.SaveFileFullName); sfd.OverwritePrompt = true; sfd.RestoreDirectory = true; sfd.Title = Resources.DecryptedSaveAsFileDialogTitle; DialogResult result = sfd.ShowDialog(); if (result != DialogResult.OK) { e.Cancel = true; return; } e.SaveFileFullName = sfd.FileName; } return; }; operationsController.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { persistentState.Current.KnownKeys.Add(e.Key); }; operationsController.Completed += (object sender, FileOperationEventArgs e) => { if (CheckStatusAndShowMessage(e.Status, e.OpenFileFullName)) { persistentState.Current.RemoveRecentFiles(new string[] { e.OpenFileFullName }, progress); } }; operationsController.DecryptFile(file, worker); }
public static void TestWipeWithConfirmAll() { ProgressContext progress = new ProgressContext(); FileOperationsController controller = new FileOperationsController(_fileSystemState, progress); int confirmationCount = 0; controller.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) => { if (confirmationCount++ > 0) { throw new InvalidOperationException("The event should not be raised a second time."); } e.ConfirmAll = true; }; progress.NotifyLevelStart(); FileOperationStatus status = controller.WipeFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success."); IRuntimeFileInfo fileInfo = OS.Current.FileInfo(_helloWorldAxxPath); Assert.That(!fileInfo.Exists, "The file should not exist after wiping."); Assert.DoesNotThrow(() => { status = controller.WipeFile(_davidCopperfieldTxtPath); }); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success."); progress.NotifyLevelFinished(); fileInfo = OS.Current.FileInfo(_davidCopperfieldTxtPath); Assert.That(!fileInfo.Exists, "The file should not exist after wiping."); }
public static void TestDecryptWithCancelDuringQuerySaveAs() { IRuntimeFileInfo expectedDestinationInfo = OS.Current.FileInfo(Path.Combine(Path.GetDirectoryName(_helloWorldAxxPath), "HelloWorld-Key-a.txt")); using (Stream stream = expectedDestinationInfo.OpenWrite()) { } FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "a"; }; controller.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { e.Cancel = true; }; FileOperationStatus status = controller.DecryptFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Canceled), "The status should indicate cancellation."); }
public static void TestSimpleWipe() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) => { e.Cancel = false; e.Skip = false; e.ConfirmAll = false; }; FileOperationStatus status = controller.WipeFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success."); IRuntimeFileInfo fileInfo = OS.Current.FileInfo(_helloWorldAxxPath); Assert.That(!fileInfo.Exists, "The file should not exist after wiping."); }
public static void TestDecryptWithAlternativeDestinationName() { IRuntimeFileInfo expectedDestinationInfo = OS.Current.FileInfo(Path.Combine(Path.GetDirectoryName(_helloWorldAxxPath), "HelloWorld-Key-a.txt")); using (Stream stream = expectedDestinationInfo.OpenWrite()) { } FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "a"; }; controller.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { e.SaveFileFullName = Path.Combine(Path.GetDirectoryName(e.SaveFileFullName), "Other Hello World.txt"); }; string destinationPath = String.Empty; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; FileOperationStatus status = controller.DecryptFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); string fileContent; using (Stream stream = destinationInfo.OpenRead()) { fileContent = new StreamReader(stream).ReadToEnd(); } Assert.That(fileContent.Contains("Hello"), "A file named 'Other Hello World.txt' should contain that text when decrypted."); }
public static void TestDecryptWithCancelDuringQueryDecryptionPassphraseOnThreadWorker() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Cancel = true; }; FileOperationStatus status = FileOperationStatus.Unknown; controller.Completed += (object sender, FileOperationEventArgs e) => { status = e.Status; }; using (ThreadWorker worker = new ThreadWorker(new ProgressContext())) { controller.DecryptFile(_helloWorldAxxPath, worker); worker.Join(); } Assert.That(status, Is.EqualTo(FileOperationStatus.Canceled), "The status should indicate cancellation."); }
public static void TestDecryptFileWithRepeatedPassphraseQueries() { FileOperationsController controller = new FileOperationsController(_fileSystemState); int passphraseTry = 0; controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { switch (++passphraseTry) { case 1: e.Passphrase = "b"; break; case 2: e.Passphrase = "d"; break; case 3: e.Passphrase = "a"; break; case 4: e.Passphrase = "e"; break; }; }; string destinationPath = String.Empty; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; bool knownKeyWasAdded = false; controller.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { knownKeyWasAdded = e.Key == new Passphrase("a").DerivedPassphrase; }; FileOperationStatus status = controller.DecryptFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(knownKeyWasAdded, "A new known key was used, so the KnownKeyAdded event should have been raised."); Assert.That(passphraseTry, Is.EqualTo(3), "The third key was the correct one."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After decryption the destination file should be created."); string fileContent; using (Stream stream = destinationInfo.OpenRead()) { fileContent = new StreamReader(stream).ReadToEnd(); } Assert.That(fileContent.Contains("Hello"), "A file named Hello World should contain that text when decrypted."); }
private void OpenEncrypted(string file, IThreadWorker worker, ProgressContext progress) { FileOperationsController operationsController = new FileOperationsController(persistentState.Current, progress); operationsController.QueryDecryptionPassphrase += HandleQueryDecryptionPassphraseEvent; operationsController.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { persistentState.Current.KnownKeys.Add(e.Key); }; operationsController.Completed += (object sender, FileOperationEventArgs e) => { if (e.Status == FileOperationStatus.Canceled) { return; } CheckStatusAndShowMessage(e.Status, e.OpenFileFullName); }; operationsController.DecryptAndLaunch(file, worker); }
private void EncryptFile(string file, IThreadWorker worker, ProgressContext progress) { FileOperationsController operationsController = new FileOperationsController(persistentState.Current, progress); operationsController.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { using (SaveFileDialog sfd = new SaveFileDialog()) { sfd.Title = Resources.EncryptFileSaveAsDialogTitle; sfd.AddExtension = true; sfd.ValidateNames = true; sfd.CheckPathExists = true; sfd.DefaultExt = OS.Current.AxCryptExtension; sfd.FileName = e.SaveFileFullName; sfd.Filter = Resources.EncryptedFileDialogFilterPattern.InvariantFormat(OS.Current.AxCryptExtension); sfd.InitialDirectory = Path.GetDirectoryName(e.SaveFileFullName); sfd.ValidateNames = true; DialogResult saveAsResult = sfd.ShowDialog(); if (saveAsResult != DialogResult.OK) { e.Cancel = true; return; } e.SaveFileFullName = sfd.FileName; } }; operationsController.QueryEncryptionPassphrase += (object sender, FileOperationEventArgs e) => { string passphrase = AskForEncryptionPassphrase(); if (String.IsNullOrEmpty(passphrase)) { e.Cancel = true; return; } e.Passphrase = passphrase; AesKey defaultEncryptionKey = new Passphrase(e.Passphrase).DerivedPassphrase; persistentState.Current.KnownKeys.DefaultEncryptionKey = defaultEncryptionKey; }; operationsController.Completed += (object sender, FileOperationEventArgs e) => { if (e.Status == FileOperationStatus.FileAlreadyEncrypted) { e.Status = FileOperationStatus.Success; return; } if (CheckStatusAndShowMessage(e.Status, e.OpenFileFullName)) { IRuntimeFileInfo encryptedInfo = OS.Current.FileInfo(e.SaveFileFullName); IRuntimeFileInfo decryptedInfo = OS.Current.FileInfo(FileOperation.GetTemporaryDestinationName(e.OpenFileFullName)); ActiveFile activeFile = new ActiveFile(encryptedInfo, decryptedInfo, e.Key, ActiveFileStatus.NotDecrypted, null); persistentState.Current.Add(activeFile); persistentState.Current.Save(); } }; operationsController.EncryptFile(file, worker); }
public static void TestSimpleDecryptFileOnThreadWorker() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "a"; }; bool knownKeyWasAdded = false; controller.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { knownKeyWasAdded = e.Key == new Passphrase("a").DerivedPassphrase; }; string destinationPath = String.Empty; FileOperationStatus status = FileOperationStatus.Unknown; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; status = e.Status; }; using (ThreadWorker worker = new ThreadWorker(new ProgressContext())) { controller.DecryptFile(_helloWorldAxxPath, worker); worker.Join(); } Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(knownKeyWasAdded, "A new known key was used, so the KnownKeyAdded event should have been raised."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After decryption the destination file should be created."); string fileContent; using (Stream stream = destinationInfo.OpenRead()) { fileContent = new StreamReader(stream).ReadToEnd(); } Assert.That(fileContent.Contains("Hello"), "A file named Hello World should contain that text when decrypted."); }
public static void TestDecryptWithKnownKey() { FileOperationsController controller = new FileOperationsController(_fileSystemState); _fileSystemState.KnownKeys.Add(new Passphrase("b").DerivedPassphrase); _fileSystemState.KnownKeys.Add(new Passphrase("c").DerivedPassphrase); _fileSystemState.KnownKeys.Add(new Passphrase("a").DerivedPassphrase); _fileSystemState.KnownKeys.Add(new Passphrase("e").DerivedPassphrase); bool passphraseWasQueried = false; controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { passphraseWasQueried = true; }; string destinationPath = String.Empty; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; bool knownKeyWasAdded = false; controller.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { knownKeyWasAdded = true; }; FileOperationStatus status = controller.DecryptFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); Assert.That(!knownKeyWasAdded, "An already known key was used, so the KnownKeyAdded event should not have been raised."); Assert.That(!passphraseWasQueried, "An already known key was used, so the there should be no need to query for a passphrase."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After decryption the destination file should be created."); string fileContent; using (Stream stream = destinationInfo.OpenRead()) { fileContent = new StreamReader(stream).ReadToEnd(); } Assert.That(fileContent.Contains("Hello"), "A file named Hello World should contain that text when decrypted."); }
public static void TestSimpleEncryptFileOnThreadWorker() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryEncryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "allan"; }; string destinationPath = String.Empty; FileOperationStatus status = FileOperationStatus.Unknown; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; status = e.Status; }; using (ThreadWorker worker = new ThreadWorker(new ProgressContext())) { controller.EncryptFile(_davidCopperfieldTxtPath, worker); worker.Join(); } Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(destinationInfo.Exists, "After encryption the destination file should be created."); using (AxCryptDocument document = new AxCryptDocument()) { using (Stream stream = destinationInfo.OpenRead()) { document.Load(stream, new Passphrase("allan").DerivedPassphrase); Assert.That(document.PassphraseIsValid, "The encrypted document should be valid and encrypted with the passphrase given."); } } }
public static void TestEncryptFileThatIsAlreadyEncrypted() { FileOperationsController controller = new FileOperationsController(_fileSystemState); FileOperationStatus status = controller.EncryptFile("test" + OS.Current.AxCryptExtension); Assert.That(status, Is.EqualTo(FileOperationStatus.FileAlreadyEncrypted), "The status should indicate that it was already encrypted."); }
public static void TestSimpleWipeOnThreadWorker() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) => { e.Cancel = false; e.Skip = false; e.ConfirmAll = false; }; string destinationPath = String.Empty; FileOperationStatus status = FileOperationStatus.Unknown; controller.Completed += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; status = e.Status; }; using (ThreadWorker worker = new ThreadWorker(new ProgressContext())) { controller.WipeFile(_davidCopperfieldTxtPath, worker); } Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The status should indicate success."); IRuntimeFileInfo destinationInfo = OS.Current.FileInfo(destinationPath); Assert.That(!destinationInfo.Exists, "After wiping the destination file should not exist."); }
public static void TestEncryptFileWhenCanceledDuringQueryPassphrase() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryEncryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Cancel = true; }; FileOperationStatus status = controller.EncryptFile(_davidCopperfieldTxtPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Canceled), "The status should indicate cancellation."); }
public static void TestWipeWithSkip() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) => { e.Skip = true; }; FileOperationStatus status = controller.WipeFile(_helloWorldAxxPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success even when skipping."); IRuntimeFileInfo fileInfo = OS.Current.FileInfo(_helloWorldAxxPath); Assert.That(fileInfo.Exists, "The file should still exist after wiping that was skipped during confirmation."); }
public static void TestEncryptFileWhenCanceledDuringQuerySaveAs() { IRuntimeFileInfo sourceInfo = OS.Current.FileInfo(_davidCopperfieldTxtPath); IRuntimeFileInfo expectedDestinationInfo = OS.Current.FileInfo(AxCryptFile.MakeAxCryptFileName(sourceInfo)); using (Stream stream = expectedDestinationInfo.OpenWrite()) { } FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QuerySaveFileAs += (object sender, FileOperationEventArgs e) => { e.Cancel = true; }; FileOperationStatus status = controller.EncryptFile(_davidCopperfieldTxtPath); Assert.That(status, Is.EqualTo(FileOperationStatus.Canceled), "The status should indicate cancellation."); }
public static void TestDecryptFileWithExceptionBeforeStartingDecryption() { FileOperationsController controller = new FileOperationsController(_fileSystemState); controller.QueryDecryptionPassphrase += (object sender, FileOperationEventArgs e) => { e.Passphrase = "a"; }; controller.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { throw new FileNotFoundException("Just kidding, but we're faking...", e.OpenFileFullName); }; string destinationPath = String.Empty; controller.KnownKeyAdded += (object sender, FileOperationEventArgs e) => { destinationPath = e.SaveFileFullName; }; FileOperationStatus status = FileOperationStatus.Unknown; Assert.DoesNotThrow(() => { status = controller.DecryptFile(_helloWorldAxxPath); }); Assert.That(status, Is.EqualTo(FileOperationStatus.FileDoesNotExist), "The status should indicate an exception occurred."); Assert.That(String.IsNullOrEmpty(destinationPath), "Since an exception occurred, the destination file should not be created."); }
private void WipeFile(string file, IThreadWorker worker, ProgressContext progress) { FileOperationsController operationsController = new FileOperationsController(persistentState.Current, progress); operationsController.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) => { using (ConfirmWipeDialog cwd = new ConfirmWipeDialog()) { cwd.FileNameLabel.Text = Path.GetFileName(file); DialogResult confirmResult = cwd.ShowDialog(); e.ConfirmAll = cwd.ConfirmAllCheckBox.Checked; if (confirmResult == DialogResult.Yes) { e.Skip = false; } if (confirmResult == DialogResult.No) { e.Skip = true; } if (confirmResult == DialogResult.Cancel) { e.Cancel = true; } } }; operationsController.Completed += (object sender, FileOperationEventArgs e) => { if (CheckStatusAndShowMessage(e.Status, e.OpenFileFullName)) { if (!e.Skip) { persistentState.Current.RemoveRecentFiles(new string[] { e.SaveFileFullName }, progress); } } }; operationsController.WipeFile(file, worker); }