Esempio n. 1
0
        public void OriginalWagoPasswordsShouldBeValid()
        {
            var pwd = new PasswordFile("lighttpd-htpasswd.user");

            Assert.True(pwd.IsValid("admin", "wago"));
            Assert.True(pwd.IsValid("user", "user"));
        }
Esempio n. 2
0
        public void KnownPasswordsShouldBeValid()
        {
            var pwd = new PasswordFile("htpasswd.txt");

            Assert.True(pwd.IsValid("admin", "test"));
            Assert.True(pwd.IsValid("user", "test"));
        }
Esempio n. 3
0
        public PasswordFileParserTests()
        {
            var fileSystem = new MockFileSystem();
            var dirInfo    = new MockDirectoryInfo(fileSystem, "\\password-store");
            var fileInfo   = new MockFileInfo(fileSystem, "\\password-store\\dummy-password");

            dummyFile = new PasswordFile(fileInfo, dirInfo);
        }
Esempio n. 4
0
        public void DecryptPassword_FileDoesNotExist_ThrowsArgumentException()
        {
            var fileSystem        = new MockFileSystemBuilder().Build();
            var passwordDirectory = new MockDirectoryInfo(fileSystem, passwordStorePath);
            var passwordManager   = new PasswordManager(passwordDirectory, new FakeCryptoService(fileSystem), Mock.Of <IRecipientFinder>(), new PasswordFileParser(new UsernameDetectionConfig()));
            var file = new PasswordFile(fileSystem.FileInfo.FromFileName(@"C:\password-store\password_1"), passwordDirectory);

            Should.Throw <ArgumentException>(() => passwordManager.DecryptPassword(file, true));
        }
Esempio n. 5
0
        public void EditWithTextEditor(PasswordFile selectedFile)
        {
            // Generate a random plaintext filename.
            var plaintextFile = CreateTemporaryPlaintextFile();

            try
            {
                var passwordFile = passwordManager.DecryptPassword(selectedFile, false);
                File.WriteAllText(plaintextFile, passwordFile.Content);
            }
            catch (Exception e)
            {
                EnsureRemoval(plaintextFile);
                notificationService.ShowErrorWindow($"Unable to edit your password (decryption failed): {e.Message}");
                return;
            }

            // Open the file in the user's default editor
            try
            {
                Process.Start(plaintextFile);
            }
            catch (Win32Exception e)
            {
                EnsureRemoval(plaintextFile);
                notificationService.ShowErrorWindow($"Unable to open an editor to edit your password file ({e.Message}).");
                return;
            }

            var result = MessageBox.Show(
                "Please keep this window open until you're done editing the password file.\n" +
                "Then click Yes to save your changes, or No to discard them.",
                $"Save changes to {selectedFile.FileNameWithoutExtension}?",
                MessageBoxButton.YesNo,
                MessageBoxImage.Information);

            if (result == MessageBoxResult.Yes)
            {
                // Fetch the content from the file, and delete it.
                var content = File.ReadAllText(plaintextFile);
                EnsureRemoval(plaintextFile);

                // Re-encrypt the file.
                var newPasswordFile = new DecryptedPasswordFile(selectedFile.PasswordStore, selectedFile.RelativePath, content);
                passwordManager.EncryptPassword(newPasswordFile, true);

                syncService?.EditPassword(selectedFile.RelativePath);
                if (ConfigManager.Config.Notifications.Types.PasswordUpdated)
                {
                    notificationService.Raise($"Password file \"{selectedFile}\" has been updated.", Severity.Info);
                }
            }
            else
            {
                File.Delete(plaintextFile);
            }
        }
Esempio n. 6
0
        public void FindRecipient_NoGpgId_ReturnsEmptyArray()
        {
            var fileSystem = new MockFileSystemBuilder()
                             .Build();
            var passwordStore   = new MockDirectoryInfo(fileSystem, @"C:\password-store");
            var recipientFinder = new GpgRecipientFinder(passwordStore);
            var passwordFile    = new PasswordFile(fileSystem.FileInfo.FromFileName(@"C:\password-store\sub\password"), passwordStore);

            var recipients = recipientFinder.FindRecipients(passwordFile);

            recipients.ShouldBeEmpty();
        }
Esempio n. 7
0
        /// <summary>
        ///     Called after reading the initial or changed contents of the <c>/etc/passwd</c> file. This parses the
        ///     contents of the <c>/etc/passwd</c> file and updates the store. If an error occurs parsing the contents of
        ///     the <c>/etc/passwd</c> file, the store is left unchanged.
        /// </summary>
        /// <param name="content">The initial or changed contents of the <c>/etc/passwd</c> file.</param>
        protected override void OnRead(string content)
        {
            var users     = new List <User>();
            var usersById = new Dictionary <uint, User>();

            // Each user entry in the `/etc/passwd` file is stored on a separate line.
            foreach (var line in content.Split('\n').Where(line => line.Length != 0))
            {
                // Each user entry has fields separated by a colon (":").
                var fields = line.Split(':');
                if (fields.Length != FIELD_COUNT)
                {
                    this.logger.LogError("Failed to parse users: expected {FieldCount} fields in {User}", FIELD_COUNT, line);
                    return;
                }

                var name = fields[NAME_FIELD_INDEX];
                if (name.Length == 0)
                {
                    this.logger.LogError("Failed to parse users: expected non-empty name in {User}", line);
                    return;
                }

                if (!uint.TryParse(fields[USER_ID_FIELD_INDEX], NumberStyles.None, NumberFormatInfo.InvariantInfo, out var userId))
                {
                    this.logger.LogError("Failed to parse users: expected unsigned 32-bit integer user identifier (\"uid\") in {User}", line);
                    return;
                }

                if (!uint.TryParse(fields[GROUP_ID_FIELD_INDEX], NumberStyles.None, NumberFormatInfo.InvariantInfo, out var groupId))
                {
                    this.logger.LogError("Failed to parse users: expected unsigned 32-bit integer group identifier (\"gid\") in {User}", line);
                    return;
                }

                var user = new User(name, userId, groupId, fields[COMMENT_FIELD_INDEX], fields[HOME_FIELD_INDEX], fields[SHELL_FIELD_INDEX]);
                if (!usersById.TryAdd(userId, user))
                {
                    this.logger.LogError("Failed to parse users: expected unique user identifier (\"uid\") in {User}", line);
                    return;
                }

                users.Add(user);
            }

            // Sort the list of users to ensure stable API search results.
            users.Sort(UserIdSorter.Instance);

            var passwordFile = new PasswordFile(users, usersById);

            this.store.SetPasswordFile(passwordFile);
        }
Esempio n. 8
0
        public void DecryptPassword_FileExists_DecryptsPassword()
        {
            var fileSystem = new MockFileSystemBuilder()
                             .WithFile(@"C:\password-store\password_1", "password\nmetadata")
                             .Build();
            var passwordDirectory = new MockDirectoryInfo(fileSystem, passwordStorePath);
            var passwordManager   = new PasswordManager(passwordDirectory, new FakeCryptoService(fileSystem), Mock.Of <IRecipientFinder>(), new PasswordFileParser(new UsernameDetectionConfig()));
            var file = new PasswordFile(fileSystem.FileInfo.FromFileName(@"C:\password-store\password_1"), passwordDirectory);

            var decrypted = passwordManager.DecryptPassword(file, true);

            decrypted.Content.ShouldBe("password\nmetadata");
        }
Esempio n. 9
0
        /// <summary>
        /// Click on the Open button.
        /// </summary>
        private void OpenClick(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();

            if (dialog.ShowDialog() == true)
            {
                // Save and display the complete path
                textBoxPath.Text = pathFile = dialog.FileName;

                // Load the file
                file = PasswordFile.Load(pathFile);
            }
        }
Esempio n. 10
0
        public static EncryptedConfig Load()
        {
            FileInfo file = PasswordFile;

            if (!PasswordFile.Exists)
            {
                throw new InvalidOperationException(string.Format("The password file ({0}) was not found.", PasswordFile.FullName));
            }

            EncryptedConfig config = RijndaelEncryptor.Decrypt <EncryptedConfig>(configFile.FullName, PasswordFile.FullName);

            PasswordFile.Delete();
            return(config);
        }
Esempio n. 11
0
        public ParsedPasswordFile(PasswordFile original, string password, string metadata) : base(original)
        {
            Password = password;
            Metadata = metadata;

            if (string.IsNullOrEmpty(metadata))
            {
                // TODO: do we want to include a newline here?
                Content = password;
            }
            else
            {
                Content = $"{Password}\n{Metadata}";
            }
        }
Esempio n. 12
0
        public void FindRecipient_GpgIdInParentDirectory_GetsRecipientsFromGpgId()
        {
            var fileSystem = new MockFileSystemBuilder()
                             .WithFile(@"C:\password-store\.gpg-id", "test_recipient_1\ntest_recipient_2")
                             .Build();
            var passwordStore   = new MockDirectoryInfo(fileSystem, @"C:\password-store");
            var recipientFinder = new GpgRecipientFinder(passwordStore);
            var passwordFile    = new PasswordFile(fileSystem.FileInfo.FromFileName(@"C:\password-store\sub\password"), passwordStore);

            var recipients = recipientFinder.FindRecipients(passwordFile);

            recipients.ShouldBe(new []
            {
                "test_recipient_1",
                "test_recipient_2"
            });
        }
Esempio n. 13
0
        public string GetDisplayPath(PasswordFile file)
        {
            var names = new List <string>
            {
                file.FileNameWithoutExtension
            };

            var current = file.Directory;

            while (!current.PathEquals(file.PasswordStore))
            {
                names.Insert(0, current.Name);
                current = current.Parent;
            }

            return(string.Join(directorySeparator, names));
        }
Esempio n. 14
0
        /// <summary>
        /// Extracts the username and any possible metadata from a password file
        /// by auto-detecting the correct line-endings.
        /// </summary>
        /// <param name="file">A <see cref="PasswordFile"/> specifying the file to be decrypted.</param>
        /// <param name="content">Content of the password file</param>
        /// <param name="entireFile">If set to true, any line endings are considered to be part of the password.</param>
        /// <returns>A <see cref="KeyedPasswordFile"/> structure containing the password and metadata</returns>
        public KeyedPasswordFile Parse(PasswordFile file, string content, bool entireFile)
        {
            if (entireFile)
            {
                // If the password contains any line endings, there is no additional metadata available.
                return(new KeyedPasswordFile(file.PasswordStore, file.RelativePath, content, null, null));
            }
            else
            {
                // The first line contains the password, any other lines contain additional (contextual) content.
                var match    = Regex.Match(content, @"([^\n\r]*)(?:(?:\r\n|\n|\r)(.*))?", RegexOptions.Singleline);
                var password = match.Groups[1].Value;
                var metadata = match.Groups[2].Value;

                var keys = ExtractKeys(metadata);

                return(new KeyedPasswordFile(file.PasswordStore, file.RelativePath, password, metadata, keys.ToList()));
            }
        }
Esempio n. 15
0
        internal static int Execute()
        {
            if (string.IsNullOrEmpty(_controller.Value))
            {
                Console.WriteLine("ERROR: A controller address has to be specified.");
                return(1);
            }

            var packageName = _package.Value;

            if (string.IsNullOrEmpty(packageName))
            {
                var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                packageName = Directory.EnumerateFiles(path, "*.wago").FirstOrDefault();
                if (string.IsNullOrEmpty(packageName))
                {
                    Console.WriteLine("ERROR: No package specified or found locally.");
                    return(1);
                }

                Console.WriteLine($"Using package {Path.GetFileName(packageName)}");
            }

            var ext = Path.GetExtension(packageName);

            if (string.IsNullOrEmpty(ext))
            {
                packageName += ".wago";
            }

            Console.WriteLine();

            Console.WriteLine($"Loading {Path.GetFileName(packageName)} to {_controller.Value} ...");

            var di = WagoService.QueryDeviceInfo(_controller.Value);

            if (di == null)
            {
                Console.WriteLine("ERROR: At the specified address is no WAGO controller.");
                return(1);
            }

            var package = WagoPackage.Load(packageName);

            if (package == null)
            {
                return(1);
            }

            var product = package.Specification.System.Products
                          .FirstOrDefault(p => p.SerialNumber == di.ProductSerialNumber);

            if (product == null)
            {
                Console.WriteLine($"ERROR: The target controller type ({di.ProductSerialNumber}) does not match the package specification.");
                return(1);
            }

            Console.WriteLine();
            Console.WriteLine($"Installing package {Path.GetFileNameWithoutExtension(packageName)}");
            Console.WriteLine($"    {package.Specification.Description} - version {package.Specification.Version}");
            Console.WriteLine($"    on WAGO controller {di.ProductSerialNumber}");
            Console.WriteLine();

            var shell = new RemoteShell(_controller.Value);

            // get root password from package - if already applied
            var specRootPwd = package.Specification.Users.Linux.FirstOrDefault(up => up.Name == "root");
            var rootPwd     = specRootPwd?.Password ?? "";

            // detect current root password from the list to test
            rootPwd = shell.GetRootPassword(new List <string> {
                "wago", rootPwd
            });
            if (rootPwd == null)
            {
                Console.WriteLine("ERROR: Root password not matching.");
                Console.WriteLine();
                Console.WriteLine("Try factory resetting the controller.");
                return(1);
            }

            // set linux users as given in the packet
            foreach (var linuxUser in package.Specification.Users.Linux)
            {
                Console.WriteLine(shell.ChangePassword(rootPwd, linuxUser.Name, linuxUser.Password)
                    ? $"Changed password for linux user {linuxUser.Name}."
                    : $"ERROR: Failed to change password for linux user {linuxUser.Name}.");

                if (linuxUser.Name == "root")
                {
                    // save new root password
                    rootPwd = linuxUser.Password;
                }
            }

            // set timezone
            var timezone = package.Specification.System.Timezone;

            if (!string.IsNullOrEmpty(timezone))
            {
                Console.WriteLine("Setting time zone to " + timezone);
                EchoShellResponse(Timezone.SetTimezone(shell, rootPwd, timezone));
            }

            if (package.Specification.System.SetDateTime)
            {
                var utcNow = DateTime.UtcNow;
                Console.WriteLine("Setting date and time to UTC " + utcNow);
                EchoShellResponse(Clock.SetDateTime(shell, rootPwd, utcNow));
            }

            // set WBM users as given in the packet
            Console.WriteLine("Loading WBM users...");
            const string pwdFileName = "lighttpd-htpasswd.user";

            try
            {
                File.WriteAllText(pwdFileName, "");
                var pwdFile = new PasswordFile(pwdFileName);
                foreach (var wbmUser in package.Specification.Users.Wbm)
                {
                    pwdFile.SetPassword(wbmUser.Name, wbmUser.Password);
                }

                var inf = new FileInfo(pwdFileName);
                using (var scp = new ScpClient(_controller.Value, "root", rootPwd))
                {
                    scp.RemotePathTransformation = RemotePathTransformation.ShellQuote;
                    scp.Connect();
                    if (!scp.IsConnected)
                    {
                        Console.WriteLine("ERROR: Could connect upload SCP.");
                        return(1);
                    }
                    scp.Upload(inf, $"/etc/lighttpd/{pwdFileName}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: Failed to upload WBM passwords: " + ex.Message);
                return(1);
            }
            finally
            {
                File.Delete(pwdFileName);
            }

            // transfer CodeSys project
            var tmpPrg = Path.GetTempFileName();
            var tmpChk = Path.GetTempFileName();

            try
            {
                var prgName = product.PackageName;
                var chkName = Path.ChangeExtension(product.PackageName, "chk");
                Console.WriteLine($"Loading Codesys project {prgName}...");

                using (var scp = new ScpClient(_controller.Value, "root", rootPwd))
                {
                    scp.RemotePathTransformation = RemotePathTransformation.ShellQuote;
                    scp.Connect();
                    if (!scp.IsConnected)
                    {
                        Console.WriteLine("ERROR: Could connect upload project.");
                        return(1);
                    }

                    package.ExtractFile(prgName, tmpPrg);
                    var prg = new FileInfo(tmpPrg);
                    scp.Upload(prg, "/home/codesys/DEFAULT.PRG");

                    package.ExtractFile(chkName, tmpChk);
                    var chk = new FileInfo(tmpChk);
                    scp.Upload(chk, "/home/codesys/DEFAULT.CHK");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: Failed to upload project files: " + ex.Message);
                return(1);
            }
            finally
            {
                if (File.Exists(tmpPrg))
                {
                    File.Delete(tmpPrg);
                }
                if (File.Exists(tmpChk))
                {
                    File.Delete(tmpChk);
                }
            }


            // transfer file system files
            var contentFiles = package.GetPackageFiles()
                               .Where(fn => fn.StartsWith("filesystem", StringComparison.InvariantCultureIgnoreCase))
                               .ToList();

            if (contentFiles.Count > 0)
            {
                Console.WriteLine("Creating file system content directories...");
                var contentDirectories = contentFiles
                                         .Select(cf => Path.GetDirectoryName(cf.Substring("filesystem".Length)).Replace(Path.DirectorySeparatorChar, '/'))
                                         .Distinct()
                                         .ToList();
                foreach (var contentDirectory in contentDirectories)
                {
                    EchoShellResponse(shell.ExecCommand("root", rootPwd, $"mkdir {contentDirectory}"));
                }

                Console.WriteLine($"Loading {contentFiles.Count} file system content files...");
                foreach (var contentFile in contentFiles)
                {
                    var tmpFile = Path.GetTempFileName();
                    try
                    {
                        using (var scp = new ScpClient(_controller.Value, "root", rootPwd))
                        {
                            scp.RemotePathTransformation = RemotePathTransformation.ShellQuote;
                            scp.Connect();
                            if (!scp.IsConnected)
                            {
                                Console.WriteLine();
                                Console.WriteLine("ERROR: Could connect upload content.");
                                return(1);
                            }

                            package.ExtractFile(contentFile, tmpFile);
                            var sourceFile     = new FileInfo(tmpFile);
                            var targetFileName = contentFile.Substring("filesystem".Length).Replace(Path.DirectorySeparatorChar, '/');

                            Console.Write(".");
                            scp.Upload(sourceFile, targetFileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine();
                        Console.WriteLine($"ERROR: Failed to upload content file {contentFile}: " + ex.Message);
                        return(1);
                    }
                    finally
                    {
                        if (File.Exists(tmpFile))
                        {
                            File.Delete(tmpFile);
                        }
                    }
                }
            }
            Console.WriteLine();

            Console.WriteLine("Done.");

            if (_noReboot.HasValue())
            {
                Console.WriteLine("Do NOT restart controller.");
                return(0);
            }

            WagoService.ResetDevice(_controller.Value);
            Console.WriteLine("Restarting controller.");

            return(0);
        }
Esempio n. 16
0
 public DecryptedPasswordFile(PasswordFile original, string content) : base(original)
 {
     Content = content;
 }
Esempio n. 17
0
 /// <summary>
 /// When the software is initializing.
 /// </summary>
 private void Initializing(object sender, EventArgs e)
 {
     file = new PasswordFile();
 }
Esempio n. 18
0
 // Only derived types may call this constructor, since they may want to determine the content themselves.
 protected DecryptedPasswordFile(PasswordFile original) : base(original)
 {
 }
Esempio n. 19
0
 /// <summary>Sets the <c>/etc/passwd</c> file (initially or after a change).</summary>
 /// <param name="passwordFile">The parsed <c>/etc/passwd</c> file.</param>
 /// <exception cref="ArgumentNullException">If <paramref name="passwordFile"/> is <c>null</c>.</exception>
 public void SetPasswordFile(PasswordFile passwordFile) =>
 this.passwordFile = passwordFile ?? throw new ArgumentNullException(nameof(passwordFile));
Esempio n. 20
0
 /// <summary>
 /// Display the settings of the file.
 /// </summary>
 /// <param name="file">Current password file.</param>
 public void Display(PasswordFile file)
 {
     textBoxMasterPassword.Text = file.Password;
     textBoxNote.Text           = file.Note;
 }