public void OriginalWagoPasswordsShouldBeValid() { var pwd = new PasswordFile("lighttpd-htpasswd.user"); Assert.True(pwd.IsValid("admin", "wago")); Assert.True(pwd.IsValid("user", "user")); }
public void KnownPasswordsShouldBeValid() { var pwd = new PasswordFile("htpasswd.txt"); Assert.True(pwd.IsValid("admin", "test")); Assert.True(pwd.IsValid("user", "test")); }
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); }
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)); }
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); } }
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(); }
/// <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); }
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"); }
/// <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); } }
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); }
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}"; } }
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" }); }
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)); }
/// <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())); } }
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); }
public DecryptedPasswordFile(PasswordFile original, string content) : base(original) { Content = content; }
/// <summary> /// When the software is initializing. /// </summary> private void Initializing(object sender, EventArgs e) { file = new PasswordFile(); }
// Only derived types may call this constructor, since they may want to determine the content themselves. protected DecryptedPasswordFile(PasswordFile original) : base(original) { }
/// <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));
/// <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; }