/// <inheritdoc/> public override async Task RunAsync(CommandLine commandLine) { if (commandLine.HasHelpOption) { Console.WriteLine(usage); Program.Exit(0); } var path = commandLine.Arguments.ElementAtOrDefault(0); var passwordName = commandLine.Arguments.ElementAtOrDefault(1); if (string.IsNullOrEmpty(path)) { Console.Error.WriteLine("*** ERROR: The PATH argument is required."); Program.Exit(1); } if (string.IsNullOrEmpty(passwordName)) { passwordName = Program.GetDefaultPasswordName(path); } if (string.IsNullOrEmpty(passwordName)) { Console.Error.WriteLine("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required."); Program.Exit(1); } var vault = new NeonVault(Program.LookupPassword); var fileName = Path.GetFileName(path); using (var tempFolder = new TempFolder()) { var tempPath = Path.Combine(tempFolder.Path, fileName); // Create an empty temporary file, encrypt it to the target // file, and then launch the editor on the temporary file. File.WriteAllBytes(tempPath, Array.Empty<byte>()); vault.Encrypt(tempPath, path, passwordName); NeonHelper.OpenEditor(tempPath); // Re-encrypt the just edited temporary file to the target. vault.Encrypt(tempPath, path, passwordName); } Program.Exit(0); await Task.CompletedTask; }
public void BadPasswordNames() { // Verify the proper exception when a password name is invalid. var vault = new NeonVault(passwordName => NeonHelper.GetCryptoRandomPassword(20)); using (var source = new MemoryStream(unencryptedBytes)) { Assert.Throws <CryptographicException>(() => vault.Encrypt(source, null)); Assert.Throws <CryptographicException>(() => vault.Encrypt(source, string.Empty)); Assert.Throws <CryptographicException>(() => vault.Encrypt(source, "bad\\name")); Assert.Throws <CryptographicException>(() => vault.Encrypt(source, "bad/name")); Assert.Throws <CryptographicException>(() => vault.Encrypt(source, "bad.name!")); } }
public void GoodPasswordNames() { // Verify valid password names. var vault = new NeonVault(passwordName => NeonHelper.GetCryptoRandomPassword(20)); using (var source = new MemoryStream(unencryptedBytes)) { vault.Encrypt(source, "a"); vault.Encrypt(source, "a_b"); vault.Encrypt(source, "a.b"); vault.Encrypt(source, "a-b"); vault.Encrypt(source, "a1"); } }
public async Task EncryptedFileConfig() { // Restart the service specifying the configuration via // an encrypted physical configuration file. var password = "******"; var vault = new NeonVault(passwordName => password); using (var tempFolder = new TempFolder()) { var decryptedPath = Path.Combine(tempFolder.Path, "decrypted"); var encryptedPath = Path.Combine(tempFolder.Path, "encrypted"); File.WriteAllText(decryptedPath, "From: ENCRYPTED FILE"); vault.Encrypt(decryptedPath, encryptedPath, "foo"); Assert.True(NeonVault.IsEncrypted(encryptedPath)); var service = CreateService(); service.SetConfigFilePath("/etc/web/response", encryptedPath, passwordName => password); fixture.Restart(() => service); Assert.True(fixture.IsRunning); var client = fixture.GetHttpClient(); Assert.Equal("From: ENCRYPTED FILE", await client.GetStringAsync("/")); } }
public async Task VariableInjectEncrypted() { var orgDirectory = Environment.CurrentDirectory; try { using (var testManager = new KubeTestManager()) { using (var runner = new ProgramRunner()) { using (var tempFolder = new TempFolder()) { Environment.CurrentDirectory = tempFolder.Path; var vault = new NeonVault(Program.LookupPassword); // Create a test password and a [.password-name] file in the // temp test folder. var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test"); Assert.Equal(0, result.ExitCode); //------------------------------------------------- // Verify that we can inject variables into an // ENCRYPTED file. File.WriteAllText("test.cmd", "type %1 > output.txt"); File.WriteAllText("file.txt", @" $<<TEST_A>> $<<TEST_B>> $<<TEST_C>> $<<TEST_D>> "); File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test")); Assert.True(NeonVault.IsEncrypted("file.txt")); result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--TEST_A=A-VALUE", "--TEST_B=B-VALUE", "--TEST_C=C-VALUE", "--TEST_D=D-VALUE", "--", "test.cmd", "_..file.txt"); Assert.Equal(0, result.ExitCode); var output = File.ReadAllText("output.txt"); Assert.Contains("A-VALUE", output); Assert.Contains("B-VALUE", output); Assert.Contains("C-VALUE", output); Assert.Contains("D-VALUE", output); File.Delete("output.txt"); File.Delete("file.txt"); } } } } finally { Environment.CurrentDirectory = orgDirectory; } }
public async Task EncryptedEnvironmentFileConfig() { // Restart the service specifying by loading an encrypted file with // the environment variable assignment. var password = "******"; var vault = new NeonVault(passwordName => password); using (var tempFolder = new TempFolder()) { var decryptedPath = Path.Combine(tempFolder.Path, "decrypted"); var encryptedPath = Path.Combine(tempFolder.Path, "encrypted"); File.WriteAllText(decryptedPath, @"# This is a comment. WEB_RESULT=HELLO WORLD! (encrypted) "); var service = CreateService(); service.LoadEnvironmentVariableFile(decryptedPath); vault.Encrypt(decryptedPath, encryptedPath, "foo"); Assert.True(NeonVault.IsEncrypted(encryptedPath)); fixture.Restart(() => service); Assert.True(fixture.IsRunning); var client = fixture.GetHttpClient(); Assert.Equal("HELLO WORLD! (encrypted)", await client.GetStringAsync("/")); } }
public void StreamToStream() { var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); File.WriteAllText(sourcePath, unencryptedText); using (var source = new FileStream(sourcePath, FileMode.Open, FileAccess.Read)) { using (var target = new FileStream(targetPath, FileMode.Create, FileAccess.ReadWrite)) { vault.Encrypt(source, target, "password-1"); } } using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } } }
public void WrongPassword() { // Verify that we can detect that the wrong password was used. using (var tempFolder = new TempFolder()) { var vault = new NeonVault(passwordName => password1); var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } vault = new NeonVault(passwordName => password2); // This uses the wrong password. Assert.Throws <CryptographicException>( () => { using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { vault.Decrypt(target); } }); } }
public void NoPassword() { // Verify the proper exception when a named password cannot be found. var vault = new NeonVault(passwordName => throw new KeyNotFoundException()); using (var source = new MemoryStream(unencryptedBytes)) { Assert.Throws <CryptographicException>(() => vault.Encrypt(source, "password-1")); } // Verify the exception when an encrypted file references a password // that doesn't exist. using (var tempFolder = new TempFolder()) { vault = new NeonVault(passwordName => password1); var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); File.WriteAllText(sourcePath, unencryptedText); var encrypted = vault.Encrypt(sourcePath, "password-1"); vault = new NeonVault(passwordName => throw new KeyNotFoundException()); using (var source = new MemoryStream(encrypted)) { Assert.Throws <CryptographicException>(() => vault.Decrypt(source)); } } }
public void TamperDetect() { // Verify that we can detect that the data has been tampered with. var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } // Modify the last HEX digit in the target file and verify // that decryption fails. using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.ReadWrite)) { var encrypted = new byte[(int)target.Length]; target.Read(encrypted, 0, encrypted.Length); var lastHexDigit = (char)encrypted[encrypted.Length - 1]; if (lastHexDigit == '0') { lastHexDigit = '1'; } else { lastHexDigit = '0'; } encrypted[encrypted.Length - 1] = (byte)lastHexDigit; target.Position = 0; target.Write(encrypted); } Assert.Throws <CryptographicException>( () => { using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } }); } }
public void LoadEnvironmentEncrypted() { // Verify that we can load an encryoted settings file into the // environment variables. using (var testManager = new KubeTestManager()) { try { using (var tempFile = new TempFile()) { // Initialze the file. using (var writer = new StreamWriter(tempFile.Path)) { foreach (var item in testSettings) { writer.WriteLine($"{item.Key}={item.Value}"); } } var passwordPath = Path.Combine(KubeHelper.PasswordsFolder, "test"); File.WriteAllText(passwordPath, password); var vault = new NeonVault(KubeHelper.LookupPassword); File.WriteAllBytes(tempFile.Path, vault.Encrypt(tempFile.Path, "test")); Assert.True(NeonVault.IsEncrypted(tempFile.Path)); // Perform the test. Assert.Null(TestContext.Current); using (var testContext = new TestContext()) { Assert.Same(testContext, TestContext.Current); testContext.LoadEnvironment(tempFile.Path, KubeHelper.LookupPassword); foreach (var item in testSettings) { Assert.Equal(item.Value, Environment.GetEnvironmentVariable(item.Key)); } } } } finally { // Be sure to remove the test enmvironment variables. foreach (var item in testSettings) { Environment.SetEnvironmentVariable(item.Key, null); } } } }
public void LowercaseHEX() { // Verify that we can process lower-case HEX digits. var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); var target2Path = Path.Combine(tempFolder.Path, "target2.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var targetReader = new StreamReader(targetPath)) { using (var target2Writer = new StreamWriter(target2Path)) { // Copy the first line as-is and then write the remaining lines // as lowercase. var first = true; foreach (var line in targetReader.Lines()) { if (first) { target2Writer.WriteLine(line); first = false; } else { target2Writer.WriteLine(line.ToUpperInvariant()); } } } } using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } } }
public void LoadSettingsEncrypted() { // Verify that we can load an encrypted settings file into the // [TestContext.Settings] dictionary. using (var testManager = new KubeTestManager()) { using (var tempFile = new TempFile()) { // Initialze the file. using (var writer = new StreamWriter(tempFile.Path)) { foreach (var item in testSettings) { writer.WriteLine($"{item.Key}={item.Value}"); } } var passwordPath = Path.Combine(KubeHelper.PasswordsFolder, "test"); File.WriteAllText(passwordPath, password); var vault = new NeonVault(KubeHelper.LookupPassword); File.WriteAllBytes(tempFile.Path, vault.Encrypt(tempFile.Path, "test")); Assert.True(NeonVault.IsEncrypted(tempFile.Path)); // Perform the test. Assert.Null(TestContext.Current); using (var testContext = new TestContext()) { Assert.Same(testContext, TestContext.Current); testContext.LoadSettings(tempFile.Path, KubeHelper.LookupPassword); foreach (var item in testSettings) { Assert.Equal(item.Value, testContext.Settings[item.Key]); } } } } }
public void StreamToBytes() { var vault = new NeonVault(GetPassword); var encrypted = (byte[])null; using (var source = new MemoryStream(unencryptedBytes)) { encrypted = vault.Encrypt(source, "password-1"); } using (var source = new MemoryStream(encrypted)) { var decrypted = vault.Decrypt(source); Assert.Equal(unencryptedBytes, decrypted); } }
public void FileToBytes() { var vault = new NeonVault(GetPassword); var encrypted = (byte[])null; using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); File.WriteAllText(sourcePath, unencryptedText); encrypted = vault.Encrypt(sourcePath, "password-1"); using (var source = new MemoryStream(encrypted)) { var decrypted = vault.Decrypt(source); Assert.Equal(unencryptedBytes, decrypted); } } }
/// <inheritdoc/> public override async Task RunAsync(CommandLine commandLine) { if (commandLine.HasHelpOption) { Console.WriteLine(usage); Program.Exit(0); } var path = commandLine.Arguments.ElementAtOrDefault(0); if (string.IsNullOrEmpty(path)) { Console.Error.WriteLine("*** ERROR: The PATH argument is required."); Program.Exit(1); } if (!NeonVault.IsEncrypted(path, out var passwordName)) { Console.Error.WriteLine($"*** ERROR: The [{path}] file is not encrypted."); Program.Exit(1); } var vault = new NeonVault(Program.LookupPassword); var fileName = Path.GetFileName(path); using (var tempFolder = new TempFolder()) { var tempPath = Path.Combine(tempFolder.Path, fileName); // Decrypt the file to a secure temporary folder, launch the // editor and re-encrypt the file after the editor returns. vault.Decrypt(path, tempPath); NeonHelper.OpenEditor(tempPath); vault.Encrypt(tempPath, path, passwordName); } Program.Exit(0); await Task.CompletedTask; }
public void BOM() { // Verify that [NeonVault] can ignore UTF-8 BOM markers. var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); var target2Path = Path.Combine(tempFolder.Path, "target2.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var targetReader = new StreamReader(targetPath)) { using (var target2 = new FileStream(target2Path, FileMode.Create, FileAccess.ReadWrite)) { // Write the BOM followed by the unmodified encrypted file lines. target2.Write(new byte[] { 0xEF, 0xBB, 0xBF }); // The BOM foreach (var line in targetReader.Lines()) { target2.Write(Encoding.ASCII.GetBytes(line + "\r\n")); } } } using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } } }
public void FileToFile() { var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } Assert.False(NeonVault.IsEncrypted(sourcePath)); Assert.True(NeonVault.IsEncrypted(targetPath)); } }
public void SwitchLineEndings() { // Verify that we can still decrypt en encrypted file after // changing the line endings from CRLF --> LF: var vault = new NeonVault(GetPassword, lineEnding: "\r\n"); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); var target2Path = Path.Combine(tempFolder.Path, "target2.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var targetReader = new StreamReader(targetPath)) { using (var target2Writer = new StreamWriter(target2Path)) { foreach (var line in targetReader.Lines()) { target2Writer.WriteLine(line + "\n"); } } } using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } } // Verify that we can still decrypt en encrypted file after // changing the line endings from LF --> CRLF: vault = new NeonVault(GetPassword, lineEnding: "\n"); using (var tempFolder = new TempFolder()) { var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); var target2Path = Path.Combine(tempFolder.Path, "target2.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var targetReader = new StreamReader(targetPath)) { using (var target2Writer = new StreamWriter(target2Path)) { foreach (var line in targetReader.Lines()) { target2Writer.WriteLine(line + "\r\n"); } } } using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } } }
public void BadHEX() { var vault = new NeonVault(GetPassword); using (var tempFolder = new TempFolder()) { // Verify that an invalid character in the HEX part is detected. var sourcePath = Path.Combine(tempFolder.Path, "source.txt"); var targetPath = Path.Combine(tempFolder.Path, "target.txt"); File.WriteAllText(sourcePath, unencryptedText); vault.Encrypt(sourcePath, targetPath, "password-1"); using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } // Modify the last HEX digit to be the invalid HEX digit 'Z'. using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.ReadWrite)) { var encrypted = new byte[(int)target.Length]; target.Read(encrypted, 0, encrypted.Length); encrypted[encrypted.Length - 1] = (byte)'Z'; target.Position = 0; target.Write(encrypted); } Assert.Throws <CryptographicException>( () => { using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } }); // Verify that an odd number of HEX digits is detected by removing // the last character of the file. using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.ReadWrite)) { var encrypted = new byte[(int)target.Length]; target.Read(encrypted, 0, encrypted.Length); target.Position = 0; target.Write(encrypted, 0, encrypted.Length - 1); } Assert.Throws <CryptographicException>( () => { using (var target = new FileStream(targetPath, FileMode.Open, FileAccess.Read)) { var decrypted = vault.Decrypt(target); Assert.Equal(unencryptedBytes, decrypted); } }); } }
/// <inheritdoc/> public override void Run(CommandLine commandLine) { if (commandLine.HasHelpOption) { Console.WriteLine(usage); Program.Exit(0); } var sourcePath = commandLine.Arguments.ElementAtOrDefault(0); var targetPath = commandLine.Arguments.ElementAtOrDefault(1); var passwordName = commandLine.Arguments.ElementAtOrDefault(2); var inPlace = false; if (string.IsNullOrEmpty(sourcePath)) { Console.Error.WriteLine("*** ERROR: The PATH argument is required."); Program.Exit(1); } if (string.IsNullOrEmpty(targetPath)) { targetPath = sourcePath; inPlace = true; } if (string.IsNullOrEmpty(targetPath) || string.IsNullOrEmpty(passwordName)) { passwordName = commandLine.GetOption("--password-name"); if (passwordName != null && string.IsNullOrWhiteSpace(passwordName)) { Console.Error.WriteLine("*** ERROR: [--password-name] specifies a blank password."); Program.Exit(1); } if (passwordName == null) { passwordName = commandLine.GetOption("-p"); if (passwordName != null && string.IsNullOrWhiteSpace(passwordName)) { Console.Error.WriteLine("*** ERROR: [-p] specifies a blank password."); Program.Exit(1); } } } if (NeonVault.IsEncrypted(sourcePath)) { Console.Error.WriteLine($"*** ERROR: The [{sourcePath}] file is already encrypted."); Program.Exit(1); } if (string.IsNullOrEmpty(passwordName)) { passwordName = Program.GetDefaultPasswordName(targetPath); } if (string.IsNullOrEmpty(passwordName)) { Console.Error.WriteLine("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required."); Program.Exit(1); } var vault = new NeonVault(Program.LookupPassword); if (inPlace) { // For in-place encryption, we'll first copy the file to // a secure folder and then encrypt from there to overwrite // the original file. using (var tempFile = new TempFile()) { File.Copy(sourcePath, tempFile.Path); vault.Encrypt(tempFile.Path, sourcePath, passwordName); } } else { // Otherwise, we can simply encrypt from the source to the target. vault.Encrypt(sourcePath, targetPath, passwordName); } Program.Exit(0); }
public async Task ReadVariables_Ecrypted() { var orgDirectory = Environment.CurrentDirectory; try { using (var testManager = new KubeTestManager()) { using (var runner = new ProgramRunner()) { using (var tempFolder = new TempFolder()) { Environment.CurrentDirectory = tempFolder.Path; var vault = new NeonVault(Program.LookupPassword); // Create a test password and a [.password-name] file in the // temp test folder. var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test"); Assert.Equal(0, result.ExitCode); File.WriteAllText(".password-name", "test"); //------------------------------------------------- // Verify that we can read settings from a couple of // ENCRYPTED variable files. File.WriteAllText("test.cmd", "echo %* > output.txt"); File.WriteAllText("var1.txt", @"# This is a comment. TEST_A=A-VALUE TEST_B=B-VALUE "); File.WriteAllBytes("var1.txt", vault.Encrypt("var1.txt", "test")); Assert.True(NeonVault.IsEncrypted("var1.txt")); File.WriteAllText("var2.txt", @"# This is a comment. TEST_C=C-VALUE TEST_D=D-VALUE "); File.WriteAllBytes("var2.txt", vault.Encrypt("var2.txt", "test")); Assert.True(NeonVault.IsEncrypted("var2.txt")); result = await runner.ExecuteAsync(Program.Main, "tool", "run", "var1.txt", "var2.txt", "--", "test.cmd", "_.TEST_A", "_.TEST_B", "_.TEST_C", "_.TEST_D"); Assert.Equal(0, result.ExitCode); var output = File.ReadAllText("output.txt"); Assert.Contains("A-VALUE", output); Assert.Contains("B-VALUE", output); Assert.Contains("C-VALUE", output); Assert.Contains("D-VALUE", output); File.Delete("output.txt"); File.Delete("var1.txt"); File.Delete("var2.txt"); } } } } finally { Environment.CurrentDirectory = orgDirectory; } }
public async Task DecryptFile() { var orgDirectory = Environment.CurrentDirectory; try { using (var testManager = new KubeTestManager()) { using (var runner = new ProgramRunner()) { using (var tempFolder = new TempFolder()) { Environment.CurrentDirectory = tempFolder.Path; var vault = new NeonVault(Program.LookupPassword); // Create a test password and a [.password-name] file in the // temp test folder. var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test"); Assert.Equal(0, result.ExitCode); //------------------------------------------------- // Verify that we can decrypt a file. File.WriteAllText("test.cmd", "type %1 > output.txt"); const string plainText = "The quick brown fox jumped over the lazy dog."; File.WriteAllText("file.txt", plainText); File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test")); Assert.True(NeonVault.IsEncrypted("file.txt")); result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "test.cmd", "_...file.txt"); Assert.Equal(0, result.ExitCode); var output = File.ReadAllText("output.txt"); Assert.Contains(plainText, output); File.Delete("output.txt"); File.Delete("file.txt"); //------------------------------------------------- // Try this again calling a command directly (batch files seem to have different behavior). File.WriteAllText("type", "%1"); File.WriteAllText("file.txt", plainText); File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test")); Assert.True(NeonVault.IsEncrypted("file.txt")); result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "cat", "_...file.txt"); Assert.Equal(0, result.ExitCode); Assert.Contains(plainText, result.OutputText); File.Delete("output.txt"); File.Delete("file.txt"); } } } } finally { Environment.CurrentDirectory = orgDirectory; } }