diff --git a/src/KeyKeeper/PasswordStore/IPassStore.cs b/src/KeyKeeper/PasswordStore/IPassStore.cs index 617df9b..e7fbe14 100644 --- a/src/KeyKeeper/PasswordStore/IPassStore.cs +++ b/src/KeyKeeper/PasswordStore/IPassStore.cs @@ -7,6 +7,7 @@ public interface IPassStore bool Locked { get; } IPassStoreDirectory GetRootDirectory(); + IPassStoreDirectory? GetGroupByType(byte groupType); int GetTotalEntryCount(); void Unlock(CompositeKey key); void Lock(); diff --git a/src/KeyKeeper/PasswordStore/IPassStoreDirectory.cs b/src/KeyKeeper/PasswordStore/IPassStoreDirectory.cs index 044c30d..beb0718 100644 --- a/src/KeyKeeper/PasswordStore/IPassStoreDirectory.cs +++ b/src/KeyKeeper/PasswordStore/IPassStoreDirectory.cs @@ -6,4 +6,5 @@ namespace KeyKeeper.PasswordStore; public interface IPassStoreDirectory : IEnumerable { bool DeleteEntry(Guid id); + void AddEntry(PassStoreEntry entry); } diff --git a/src/KeyKeeper/PasswordStore/PassStoreEntryGroup.cs b/src/KeyKeeper/PasswordStore/PassStoreEntryGroup.cs index bf627d9..4bed5da 100644 --- a/src/KeyKeeper/PasswordStore/PassStoreEntryGroup.cs +++ b/src/KeyKeeper/PasswordStore/PassStoreEntryGroup.cs @@ -64,6 +64,12 @@ public class PassStoreEntryGroup : PassStoreEntry, IPassStoreDirectory } } + public void AddEntry(PassStoreEntry entry) + { + entry.Parent = this; + ChildEntries.Add(entry); + } + public bool DeleteEntry(Guid id) { if (ChildEntries == null) diff --git a/src/KeyKeeper/PasswordStore/PassStoreFileAccessor.cs b/src/KeyKeeper/PasswordStore/PassStoreFileAccessor.cs index 640c87e..7b8f471 100644 --- a/src/KeyKeeper/PasswordStore/PassStoreFileAccessor.cs +++ b/src/KeyKeeper/PasswordStore/PassStoreFileAccessor.cs @@ -49,6 +49,15 @@ public class PassStoreFileAccessor : IPassStore return (IPassStoreDirectory)root!; } + public IPassStoreDirectory? GetGroupByType(byte groupType) + { + if (Locked) + throw new InvalidOperationException(); + return (root as PassStoreEntryGroup)?.ChildEntries + .OfType() + .FirstOrDefault(g => g.GroupType == groupType); + } + public int GetTotalEntryCount() { throw new NotImplementedException(); @@ -252,15 +261,24 @@ public class PassStoreFileAccessor : IPassStore private PassStoreEntry WriteInitialStoreTree(OuterEncryptionWriter w) { - PassStoreEntry root = - new PassStoreEntryGroup( - Guid.NewGuid(), - DateTime.UtcNow, - DateTime.UtcNow, - Guid.Empty, - "", - GROUP_TYPE_ROOT - ); + PassStoreEntryGroup defaultGroup = new( + Guid.NewGuid(), + DateTime.UtcNow, + DateTime.UtcNow, + Guid.Empty, + "", + GROUP_TYPE_DEFAULT + ); + PassStoreEntryGroup root = new( + Guid.NewGuid(), + DateTime.UtcNow, + DateTime.UtcNow, + Guid.Empty, + "", + GROUP_TYPE_ROOT, + [defaultGroup] + ); + defaultGroup.Parent = root; root.WriteToStream(w); return root; } diff --git a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs index 6626261..d576097 100644 --- a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs +++ b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using KeyKeeper.PasswordStore; +using static KeyKeeper.PasswordStore.FileFormatConstants; namespace KeyKeeper.ViewModels; @@ -33,7 +34,9 @@ public partial class RepositoryWindowViewModel : ViewModelBase private void SwitchToUnlocked() { - CurrentPage = new UnlockedRepositoryViewModel(passStore); + var directory = passStore.GetGroupByType(GROUP_TYPE_DEFAULT) + ?? passStore.GetRootDirectory(); + CurrentPage = new UnlockedRepositoryViewModel(passStore, directory); } private void SwitchToLocked() diff --git a/src/KeyKeeper/ViewModels/UnlockedRepositoryViewModel.cs b/src/KeyKeeper/ViewModels/UnlockedRepositoryViewModel.cs index 7458814..2aeaf39 100644 --- a/src/KeyKeeper/ViewModels/UnlockedRepositoryViewModel.cs +++ b/src/KeyKeeper/ViewModels/UnlockedRepositoryViewModel.cs @@ -8,13 +8,14 @@ namespace KeyKeeper.ViewModels; public class UnlockedRepositoryViewModel : ViewModelBase { private IPassStore passStore; + private IPassStoreDirectory currentDirectory; private bool hasUnsavedChanges; public IEnumerable Passwords { get { - return passStore.GetRootDirectory() + return currentDirectory .Where(entry => entry is PassStoreEntryPassword) .Select(entry => (entry as PassStoreEntryPassword)!); } @@ -30,9 +31,10 @@ public class UnlockedRepositoryViewModel : ViewModelBase } } - public UnlockedRepositoryViewModel(IPassStore store) + public UnlockedRepositoryViewModel(IPassStore store, IPassStoreDirectory directory) { passStore = store; + currentDirectory = directory; HasUnsavedChanges = false; } @@ -40,7 +42,7 @@ public class UnlockedRepositoryViewModel : ViewModelBase { if (entry is PassStoreEntryPassword) { - (passStore.GetRootDirectory() as PassStoreEntryGroup)!.ChildEntries.Add(entry); + currentDirectory.AddEntry(entry); HasUnsavedChanges = true; OnPropertyChanged(nameof(Passwords)); } @@ -48,14 +50,21 @@ public class UnlockedRepositoryViewModel : ViewModelBase public void DeleteEntry(Guid id) { - (passStore.GetRootDirectory() as PassStoreEntryGroup)!.DeleteEntry(id); + currentDirectory.DeleteEntry(id); HasUnsavedChanges = true; OnPropertyChanged(nameof(Passwords)); } + public void UpdateEntry(PassStoreEntryPassword updatedEntry) + { + currentDirectory.DeleteEntry(updatedEntry.Id); + currentDirectory.AddEntry(updatedEntry); + OnPropertyChanged(nameof(Passwords)); + } + public void Save() { passStore.Save(); HasUnsavedChanges = false; } -} \ No newline at end of file +} diff --git a/src/KeyKeeper/Views/CreateVaultDialog.axaml b/src/KeyKeeper/Views/CreateVaultDialog.axaml new file mode 100644 index 0000000..ec10c2e --- /dev/null +++ b/src/KeyKeeper/Views/CreateVaultDialog.axaml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + +