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("/")); } }
/// <inheritdoc/> public override void Run(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.Write(passwordName); if (!commandLine.HasOption("-n")) { Console.WriteLine(); } } else { Program.Exit(1); } Program.Exit(0); }
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("/")); } }
/// <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); if (string.IsNullOrEmpty(sourcePath)) { Console.Error.WriteLine("*** ERROR: The SOURCE argument is required."); Program.Exit(1); } if (string.IsNullOrEmpty(targetPath)) { Console.Error.WriteLine("*** ERROR: The TARGET argument is required."); Program.Exit(1); } if (!NeonVault.IsEncrypted(sourcePath)) { Console.Error.WriteLine($"*** ERROR: The [{sourcePath}] file is not encrypted."); Program.Exit(1); } var vault = new NeonVault(Program.LookupPassword); vault.Decrypt(sourcePath, targetPath); Program.Exit(0); }
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 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); } } } }
/// <summary> /// Examines the file at <paramref name="path"/>, decrypting it to a temporary file /// if necessary. The method will then call <paramref name="action"/> passing the /// path to the original file (if it wasn't encrypted or to the decrypted file. /// </summary> /// <param name="path">The file path.</param> /// <param name="action">Called with the path to a decrypted file.</param> private void DecryptWithAction(string path, Action <string> action) { if (!NeonVault.IsEncrypted(path)) { action(path); } else { using (var tempFile = new TempFile()) { vault.Decrypt(path, tempFile.Path); action(tempFile.Path); } } }
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 Unencrypted() { // Verify that "decrypting" an unencrypted file simply copies // the data to the output. 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.Decrypt(sourcePath, targetPath); Assert.Equal(unencryptedText, File.ReadAllText(targetPath)); Assert.False(NeonVault.IsEncrypted(sourcePath)); Assert.False(NeonVault.IsEncrypted(targetPath)); } }
/// <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 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 VaultDecrypt() { using (var manager = new KubeTestManager()) { using (var tempFolder = new TempFolder()) { var orgDir = Environment.CurrentDirectory; Environment.CurrentDirectory = tempFolder.Path; NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText); try { using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder)) { File.WriteAllText(passwordFile.Path, testPassword); var vault = new NeonVault(passwordName => testPassword); using (var runner = new ProgramRunner()) { // Verify that the SOURCE argument is required. var result = runner.Execute(Program.Main, "vault", "decrypt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The SOURCE argument is required.", result.ErrorText); // Verify that the TARGET argument is required. result = runner.Execute(Program.Main, "vault", "decrypt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The SOURCE argument is required.", result.ErrorText); // Verify that the SOURCE-PATH argument is required. result = runner.Execute(Program.Main, "vault", "decrypt", "test.txt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The TARGET argument is required.", result.ErrorText); // Verify that we can create an encrypted file with an explicitly // named password. result = runner.Execute(Program.Main, "vault", "create", "test1.txt", passwordFile.Name); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt"))); // Verify that we can decrypt the file. result = runner.Execute(Program.Main, "vault", "decrypt", "test1.txt", "decrypted.txt"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test1.txt", out passwordName)); Assert.True(!NeonVault.IsEncrypted("decrypted.txt", out passwordName)); Assert.Equal(plainText, File.ReadAllText("decrypted.txt")); } } } finally { Environment.CurrentDirectory = orgDir; NeonHelper.OpenEditorHandler = null; } } } }
/// <inheritdoc/> public override async Task RunAsync(CommandLine commandLine) { if (commandLine.HasHelpOption) { Console.WriteLine(usage); Program.Exit(0); } var splitCommandLine = commandLine.Split("--"); var leftCommandLine = splitCommandLine.Left; var rightCommandLine = splitCommandLine.Right; if (rightCommandLine == null || rightCommandLine.Arguments.Length == 0) { Console.Error.WriteLine("*** ERROR: Expected a command after a [--] argument."); Program.Exit(1); } // All arguments on the left command line should be VARIABLES files. // We're going to open each of these and set any enviroment variables // like [NAME=VALUE] we find. // // Note that these files may be encrypted. If any are, we'll decrypt // to a temporary file before we read them. foreach (var path in leftCommandLine.Arguments) { if (!File.Exists(path)) { Console.Error.WriteLine($"*** ERROR: File [{path}] does not exist."); Program.Exit(1); } DecryptWithAction(path, decryptedPath => { var lineNumber = 1; foreach (var line in File.ReadAllLines(decryptedPath)) { var trimmed = line.Trim(); if (line == string.Empty || line.StartsWith("#")) { continue; } var fields = line.Split('=', 2); if (fields.Length != 2 || fields[0] == string.Empty) { Console.Error.WriteLine($"*** ERROR: [{path}:{lineNumber}] is not formatted like: NAME=VALUE"); Program.Exit(1); } var name = fields[0].Trim(); var value = fields[1].Trim(); Environment.SetEnvironmentVariable(name, value); lineNumber++; } }); } // Any left command line options with a "--" prefix also specify environment variables. foreach (var option in leftCommandLine.Options.Where(o => o.Key.StartsWith("--"))) { Environment.SetEnvironmentVariable(option.Key.Substring(2), option.Value); } // We've read all of the variable files and left command line options // and initialized all environment variables. Now we need to process // and then execute the right command line. var tempFiles = new List <TempFile>(); try { var subcommand = rightCommandLine.Items; // Note that the first element of the subcommand specifies the // executable so we don't need to process that. for (int i = 1; i < subcommand.Length; i++) { var arg = subcommand[i]; if (arg.StartsWith("_...")) { // Argument is a reference to a potentially encrypted // file that needs to be passed decrypted. var path = arg.Substring(4); if (!File.Exists(path)) { Console.Error.WriteLine($"*** ERROR: File [{path}] does not exist."); Program.Exit(1); } if (NeonVault.IsEncrypted(path)) { var tempFile = new TempFile(); tempFiles.Add(tempFile); vault.Decrypt(path, tempFile.Path); path = tempFile.Path; } subcommand[i] = path; } else if (arg.StartsWith("_..")) { // Argument is a reference to a potentially encrypted text file // with environment variable references we'll need to update. var path = arg.Substring(3); if (!File.Exists(path)) { Console.Error.WriteLine($"*** ERROR: File [{path}] does not exist."); Program.Exit(1); } if (NeonVault.IsEncrypted(path)) { var tempFile = new TempFile(); tempFiles.Add(tempFile); vault.Decrypt(path, tempFile.Path); path = tempFile.Path; } subcommand[i] = path; // Perform the subsitutions. var unprocessed = File.ReadAllText(path); var processed = string.Empty; var linuxLineEndings = !unprocessed.Contains("\r\n"); using (var reader = new StreamReader(path)) { using (var preprocessor = new PreprocessReader(reader)) { preprocessor.ExpandVariables = true; preprocessor.LineEnding = linuxLineEndings ? LineEnding.LF : LineEnding.CRLF; preprocessor.ProcessStatements = false; preprocessor.StripComments = false; preprocessor.VariableExpansionRegex = PreprocessReader.AngleVariableExpansionRegex; processed = preprocessor.ReadToEnd(); } } File.WriteAllText(path, processed); } else if (arg.StartsWith("_.")) { // Argument is a reference to an environment variable. var name = arg.Substring(2); if (name == string.Empty) { Console.Error.WriteLine($"*** ERROR: Subcommand argument [{arg}] is not valid."); Program.Exit(1); } var value = Environment.GetEnvironmentVariable(name); if (value == null) { Console.Error.WriteLine($"*** ERROR: Subcommand argument [{arg}] references an undefined environment variable."); Program.Exit(2); } subcommand[i] = value; } else if (arg.StartsWith("-")) { // Argument is a command line option. We'll check to see if // it contains a reference to an environment variable. var valuePos = arg.IndexOf("=_."); if (valuePos != -1) { var optionPart = arg.Substring(0, valuePos); var name = arg.Substring(valuePos + 3); if (name == string.Empty) { Console.Error.WriteLine($"*** ERROR: Subcommand argument [{arg}] is not valid."); Program.Exit(1); } var value = Environment.GetEnvironmentVariable(name); if (value == null) { Console.Error.WriteLine($"*** ERROR: Subcommand argument [{arg}] references an undefined environment variable."); Program.Exit(1); } subcommand[i] = $"{optionPart}={value}"; } } else { // Otherwise, expand any envrionment variable references. subcommand[i] = Environment.ExpandEnvironmentVariables(subcommand[i]); } } // Execute the subcommand. var subcommandArgs = new List <object>(); foreach (var subcommandArg in subcommand) { subcommandArgs.Add(subcommandArg); } var exitCode = NeonHelper.Execute(subcommand[0], subcommandArgs.Skip(1).ToArray()); Program.Exit(exitCode); } finally { foreach (var tempFile in tempFiles) { tempFile.Dispose(); } } Program.Exit(0); await Task.CompletedTask; }
/// <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 VaultEncrypt() { using (var testManager = new KubeTestManager()) { using (var tempFolder = new TempFolder()) { var orgDir = Environment.CurrentDirectory; Environment.CurrentDirectory = tempFolder.Path; NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText); try { using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder)) { File.WriteAllText(passwordFile.Path, testPassword); var vault = new NeonVault(passwordName => testPassword); using (var runner = new ProgramRunner()) { // Verify that the PATH argument is required. var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText); // Verify that the TARGET argument is required when [--password-name] // or [--p] is not present. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "decrypt", "source.txt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The TARGET argument is required.", result.ErrorText); // Verify that we can encrypt a file in-place, specifying an // explicit password name (using --password-name=NAME). File.WriteAllText("test1.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test1.txt", $"--password-name={passwordFile.Name}"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt"))); // Verify that we can encrypt a file in-place, specifying an // explicit password name (using --p=NAME). File.WriteAllText("test2.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test2.txt", $"-p={passwordFile.Name}"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test2.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test2.txt"))); // Verify that we get an error trying to encrypt in-place without a // password name being explicitly specified and also without a // [.password-name] file present. File.WriteAllText("test3.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test3.txt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText); // Verify that we get an error trying to encrypt (not in-place) without a // password name being explicitly specified and also without a // [.password-name] file present. File.WriteAllText("test4.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test4.txt", "test4.encypted.txt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText); // Verify that we can encrypt a file to another with // and explicit password argument. File.WriteAllText("test5.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test5.txt", "test5.encypted.txt", passwordName); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test5.encypted.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test5.encypted.txt"))); // Verify that we can encrypt a file to another with // and explicit [--password-name] option. File.WriteAllText("test6.txt", plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test6.txt", "test6.encypted.txt", $"--password-name={passwordName}"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test6.encypted.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test6.encypted.txt"))); // Verify that we can encrypt a file in-place using a [.password-name] file. File.WriteAllText("test7.txt", plainText); File.WriteAllText(".password-name", passwordName); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test7.txt"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test7.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test7.txt"))); // Verify that we can encrypt a file (not in-place) to another where // the source file is located in a different directory from the target // to ensure that we look for the [.password-name] file starting at // the target directory. using (var tempFile = new TempFile()) { File.WriteAllText(tempFile.Path, plainText); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", tempFile.Path, "test8.encrypted.txt"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test8.encrypted.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test8.encrypted.txt"))); } } } } finally { Environment.CurrentDirectory = orgDir; NeonHelper.OpenEditorHandler = null; } } } }
public async Task VaultPasswordName() { using (var testManager = new KubeTestManager()) { using (var tempFolder = new TempFolder()) { var orgDir = Environment.CurrentDirectory; Environment.CurrentDirectory = tempFolder.Path; NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText); try { using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder)) { File.WriteAllText(passwordFile.Path, testPassword); var vault = new NeonVault(passwordName => testPassword); using (var runner = new ProgramRunner()) { // Verify that the PATH argument is required. var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText); // Verify that we can create an encrypted file with an explicitly // named password. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test1.txt", passwordFile.Name); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt"))); // Verify that we can get the password with a line ending. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name", "test1.txt", passwordFile.Name); Assert.Equal(0, result.ExitCode); Assert.Contains(passwordFile.Name, result.OutputText); Assert.Contains('\n', result.OutputText); // Verify that we can get the password without a line ending. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name", "-n", "test1.txt", passwordFile.Name); Assert.Equal(0, result.ExitCode); Assert.Equal(passwordFile.Name, result.OutputText); } } } finally { Environment.CurrentDirectory = orgDir; NeonHelper.OpenEditorHandler = null; } } } }
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; } }
public async Task VaultCreate() { using (var testManager = new KubeTestManager()) { using (var tempFolder = new TempFolder()) { var orgDir = Environment.CurrentDirectory; Environment.CurrentDirectory = tempFolder.Path; NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText); try { using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder)) { File.WriteAllText(passwordFile.Path, testPassword); var vault = new NeonVault(passwordName => testPassword); using (var runner = new ProgramRunner()) { // Verify that the PATH argument is required. var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText); // Verify that the PASSWORD-NAME argument is required when there's // no default [.password-name] file. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test1.txt"); Assert.NotEqual(0, result.ExitCode); Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText); // Verify that we can create an encrypted file with an explicitly // named password. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test2.txt", passwordFile.Name); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test2.txt", out var passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test2.txt"))); // Verify that we see an error for a missing password. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test3.txt", missingPasswordName); Assert.NotEqual(0, result.ExitCode); Assert.Contains($"*** ERROR: [System.Security.Cryptography.CryptographicException]: Password named [{missingPasswordName}] not found or is blank or whitespace.", result.ErrorText); // Verify that we see an error for an invalid password. result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test4.txt", badPasswordName); Assert.NotEqual(0, result.ExitCode); Assert.Contains($"*** ERROR: [System.Security.Cryptography.CryptographicException]: Password name [bad/password] contains invalid characters. Only ASCII letters, digits, underscores, dashs and dots are allowed.", result.ErrorText); // Verify that a local [.password-name] file is used successfully when we don't // explicitly pass a password name. File.WriteAllText(".password-name", passwordFile.Name); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test5.txt"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test5.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test5.txt"))); // Verify that a [.password-name] file in the parent directory is used successfully // when we don't explicitly pass a password name. Directory.CreateDirectory("subfolder"); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, "subfolder"); result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test6.txt"); Assert.Equal(0, result.ExitCode); Assert.True(NeonVault.IsEncrypted("test6.txt", out passwordName)); Assert.Equal(passwordFile.Name, passwordName); Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test6.txt"))); } } } finally { Environment.CurrentDirectory = orgDir; NeonHelper.OpenEditorHandler = null; } } } }
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; } }