Beispiel #1
0
        /// <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.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);
        }
Beispiel #2
0
        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));
            }
        }
Beispiel #3
0
        /// <inheritdoc/>
        public override async Task RunAsync(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);
            await Task.CompletedTask;
        }
Beispiel #4
0
        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);
                }
            }
        }
Beispiel #5
0
        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);
                    }
                });
            }
        }
Beispiel #6
0
        /// <inheritdoc/>
        public override async Task RunAsync(CommandLine commandLine)
        {
            if (commandLine.HasHelpOption)
            {
                Console.WriteLine(usage);
                Program.Exit(0);
            }

            var zipPath   = commandLine.Arguments.ElementAtOrDefault(0);
            var firstName = commandLine.Arguments.ElementAtOrDefault(1);
            var fromStdin = commandLine.HasOption("--stdin");
            var names     = new List <string>();

            if (zipPath == null)
            {
                Console.Error.WriteLine("*** ERROR: PATH argument is required.");
                Program.Exit(1);
            }

            if (firstName == null)
            {
                Console.Error.WriteLine("*** ERROR: At least one NAME argument is required.");
                Program.Exit(1);
            }

            if (firstName == "*")
            {
                foreach (var path in Directory.GetFiles(KubeHelper.PasswordsFolder))
                {
                    names.Add(Path.GetFileName(path));
                }
            }
            else
            {
                foreach (var name in commandLine.Arguments.Skip(1))
                {
                    var validatedName = NeonVault.ValidatePasswordName(name);

                    if (!File.Exists(Path.Combine(KubeHelper.PasswordsFolder, validatedName)))
                    {
                        Console.Error.WriteLine($"*** ERROR: Password [{validatedName}] does not exist.");
                        Program.Exit(1);
                    }

                    names.Add(validatedName);
                }
            }

            if (names.Count == 0)
            {
                Console.Error.WriteLine("*** ERROR: No passwords selected for export.");
                Program.Exit(1);
            }

            var zipPassword = (string)null;

            if (fromStdin)
            {
                // Read the password from STDIN and trim.

                using (var stdin = NeonHelper.OpenStandardInput())
                {
                    using (var reader = new StreamReader(stdin))
                    {
                        zipPassword = reader.ReadLine().Trim();
                    }
                }
            }

retryPassword:

            if (!fromStdin)
            {
                if (string.IsNullOrEmpty(zipPassword))
                {
                    zipPassword = NeonHelper.ReadConsolePassword("Enter Password:   "******"Confirm Password: "******"The passwords don't match.  Please try again:");
                    Console.WriteLine();

                    goto retryPassword;
                }
            }

            using (var zip = ZipFile.Create(zipPath))
            {
                zip.Password = zipPassword;
                zip.BeginUpdate();

                foreach (var name in names)
                {
                    zip.Add(Path.Combine(KubeHelper.PasswordsFolder, name), name);
                }

                zip.CommitUpdate();
            }

            Console.WriteLine();
            Console.WriteLine($"[{names.Count}] passwords exported.");
            Program.Exit(0);
            await Task.CompletedTask;
        }
Beispiel #7
0
        public async Task ReadVariables_Decrypted()
        {
            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 variables from a couple of
                            // unencrypted 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.WriteAllText("var2.txt",
                                              @"# This is a comment.

TEST_C=C-VALUE
TEST_D=D-VALUE
");
                            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;
            }
        }
Beispiel #8
0
        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;
            }
        }
Beispiel #9
0
        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;
                    }
                }
            }
        }
Beispiel #10
0
        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;
                    }
                }
            }
        }
Beispiel #11
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;
                    }
                }
            }
        }
Beispiel #12
0
        /// <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);
        }
Beispiel #13
0
        /// <inheritdoc/>
        public override async Task RunAsync(CommandLine commandLine)
        {
            if (commandLine.HasHelpOption)
            {
                Console.WriteLine(usage);
                Program.Exit(0);
            }

            var nameArg   = commandLine.Arguments.ElementAtOrDefault(0);
            var sourceArg = commandLine.Arguments.ElementAtOrDefault(1);

            if (nameArg == null)
            {
                Console.Error.WriteLine($"*** ERROR: NAME argument is required.");
                Program.Exit(1);
            }

            var passwordName = NeonVault.ValidatePasswordName(nameArg);
            var password     = string.Empty;

            if (sourceArg == null)
            {
                // Generate a 20 character password.

                password = NeonHelper.GetCryptoRandomPassword(20);
            }
            else if (sourceArg == "-")
            {
                // Read the password from STDIN and trim.

                using (var stdin = NeonHelper.OpenStandardInput())
                {
                    using (var reader = new StreamReader(stdin))
                    {
                        password = reader.ReadLine().Trim();
                    }
                }
            }
            else
            {
                // Read the first line from the file.

                using (var input = new FileStream(sourceArg, FileMode.Open, FileAccess.Read))
                {
                    using (var reader = new StreamReader(input))
                    {
                        password = reader.ReadLine().Trim();
                    }
                }
            }

            if (password.Length == 0)
            {
                Console.Error.WriteLine($"*** ERROR: The password cannot be blank.");
                Program.Exit(1);
            }

            File.WriteAllText(Path.Combine(KubeHelper.PasswordsFolder, passwordName), password);
            Program.Exit(0);
            await Task.CompletedTask;
        }
Beispiel #14
0
        /// <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;
        }
Beispiel #15
0
        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;
                    }
                }
            }
        }