WIP Split composite key user control

Some refactoring
This commit is contained in:
Geoffroy BONNEVILLE
2020-04-20 20:02:43 +02:00
parent 73670e8689
commit 310bd777b2
54 changed files with 849 additions and 1200 deletions

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" IgnorableNamespaces= "uap mp">
<Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="2.0.0.0" />
<mp:PhoneIdentity PhoneProductId="0EFC7A82-E22B-471E-A576-65FCCDD6E449" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" IgnorableNamespaces="uap mp">
<Identity Name="wismna.KayPee" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="2.0.0.0" />
<mp:PhoneIdentity PhoneProductId="0EFC7A82-E22B-471E-A576-65FCCDD6E449" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17134.0" MaxVersionTested="10.0.17134.0" />
</Dependencies>
<Properties>
<DisplayName>ModernKeePass</DisplayName>
<DisplayName>KayPee</DisplayName>
<PublisherDisplayName>wismna</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Resources>
<Resource Language="x-generate" />
<Resource uap:Scale="180"/>
<Resource uap:DXFeatureLevel="dx11"/>
<Resource uap:Scale="180" />
<Resource uap:DXFeatureLevel="dx11" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="ModernKeePass.App">
@@ -23,22 +23,6 @@
<uap:SplashScreen Image="Assets\ModernKeePass-SplashScreen.png" BackgroundColor="#7755c4" />
</uap:VisualElements>
<Extensions>
<uap:Extension Category="windows.fileOpenPicker">
<uap:FileOpenPicker>
<uap:SupportedFileTypes>
<uap:FileType>.kdbx</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileOpenPicker>
</uap:Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="kdbx">
<uap:DisplayName>KeePass 2.x database</uap:DisplayName>
<uap:EditFlags OpenIsSafe="true" />
<uap:SupportedFileTypes>
<uap:FileType ContentType="application/xml">.kdbx</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.fileSavePicker">
<uap:FileSavePicker>
<uap:SupportedFileTypes>
@@ -46,6 +30,21 @@
</uap:SupportedFileTypes>
</uap:FileSavePicker>
</uap:Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="kdbx">
<uap:DisplayName>KeePass 2.x database</uap:DisplayName>
<uap:SupportedFileTypes>
<uap:FileType ContentType="application/xml">.kdbx</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.fileOpenPicker">
<uap:FileOpenPicker>
<uap:SupportedFileTypes>
<uap:FileType>.kdbx</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileOpenPicker>
</uap:Extension>
</Extensions>
</Application>
</Applications>

View File

@@ -1,31 +0,0 @@
using System;
using Windows.UI.Xaml.Controls;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.AOP;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels.ListItems
{
public class ListMenuItemViewModel : NotifyPropertyChangedBase, IIsEnabled, ISelectableModel
{
private bool _isSelected;
public string Title { get; set; }
public string Group { get; set; } = "_";
public Type PageType { get; set; }
public Symbol SymbolIcon { get; set; }
public bool IsEnabled { get; set; } = true;
public bool IsSelected
{
get => _isSelected;
set => SetProperty(ref _isSelected, value);
}
public override string ToString()
{
return Title;
}
}
}

View File

@@ -1,10 +0,0 @@
using Windows.UI.Xaml.Controls;
namespace ModernKeePass.ViewModels.ListItems
{
public class MainMenuItemViewModel: ListMenuItemViewModel
{
public object Parameter { get; set; }
public Frame Destination { get; set; }
}
}

View File

@@ -1,36 +0,0 @@
using System.Threading.Tasks;
using Autofac;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.AOP;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels.ListItems
{
public class RecentItemViewModel: NotifyPropertyChangedBase, ISelectableModel
{
private readonly IRecentService _recentService;
private bool _isSelected;
public string Token { get; set; }
public string Name { get; set; }
public bool IsSelected
{
get => _isSelected;
set => SetProperty(ref _isSelected, value);
}
public RecentItemViewModel(): this (App.Container.Resolve<IRecentService>())
{ }
public RecentItemViewModel(IRecentService recentService)
{
_recentService = recentService;
}
public async Task UpdateAccessTime()
{
await _recentService.Get(Token);
}
}
}

View File

@@ -1,101 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Autofac;
using ModernKeePass.Domain.AOP;
using ModernKeePass.Domain.Entities;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels.ListItems
{
// TODO: implement Kdf settings
public class SettingsDatabaseViewModel: NotifyPropertyChangedBase
{
private readonly IDatabaseService _databaseService;
private readonly ICryptographyService _cryptographyService;
public bool HasRecycleBin
{
get => _databaseService.IsRecycleBinEnabled;
set {
// TODO: do something here
}
}
public bool IsNewRecycleBin
{
get => _databaseService.RecycleBin == null;
set
{
// TODO: make this work
if (value) _databaseService.AddEntity(_databaseService.RootGroupEntity, new Entity{Name = "Recycle Bin"});
}
}
public ObservableCollection<GroupEntity> Groups { get; set; }
public ObservableCollection<Entity> Ciphers => new ObservableCollection<Entity>(_cryptographyService.Ciphers);
public IEnumerable<string> Compressions => _cryptographyService.CompressionAlgorithms;
public IEnumerable<Entity> KeyDerivations => _cryptographyService.KeyDerivations;
public Entity SelectedCipher
{
get => Ciphers.FirstOrDefault(c => c.Id == _databaseService.Cipher.Id);
set
{
if (_databaseService.Cipher != value)
{
_databaseService.Cipher = value;
//OnPropertyChanged(nameof(SelectedCipher));
}
}
}
public Entity SelectedKeyDerivation
{
get => _databaseService.KeyDerivation;
set
{
if (_databaseService.KeyDerivation != value)
{
_databaseService.KeyDerivation = value;
OnPropertyChanged(nameof(SelectedKeyDerivation));
}
}
}
public string SelectedCompression
{
get => _databaseService.Compression;
set
{
if (_databaseService.Compression != value)
{
_databaseService.Compression = value;
OnPropertyChanged(nameof(SelectedCompression));
}
}
}
public GroupEntity SelectedRecycleBin
{
get => _databaseService.RecycleBin;
set
{
if (_databaseService.RecycleBin != value)
{
_databaseService.RecycleBin = value;
OnPropertyChanged(nameof(SelectedRecycleBin));
}
}
}
public SettingsDatabaseViewModel() : this(App.Container.Resolve<IDatabaseService>(), App.Container.Resolve<ICryptographyService>()) { }
public SettingsDatabaseViewModel(IDatabaseService databaseService, ICryptographyService cryptographyService)
{
_databaseService = databaseService;
_cryptographyService = cryptographyService;
Groups = new ObservableCollection<GroupEntity>(_databaseService.RootGroupEntity.SubGroups);
}
}
}

View File

@@ -1,33 +0,0 @@
using System.Collections.Generic;
using Autofac;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels.ListItems
{
public class SettingsNewViewModel
{
private readonly ISettingsService _settings;
public SettingsNewViewModel() : this(App.Container.Resolve<ISettingsService>())
{ }
public SettingsNewViewModel(ISettingsService settings)
{
_settings = settings;
}
public bool IsCreateSample
{
get => _settings.GetSetting<bool>("Sample");
set => _settings.PutSetting("Sample", value);
}
public IEnumerable<string> FileFormats => new []{"2", "4"};
public string FileFormatVersion
{
get => _settings.GetSetting("DefaultFileFormat", "2");
set => _settings.PutSetting("DefaultFileFormat", value);
}
}
}

View File

@@ -1,24 +0,0 @@
using Autofac;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels.ListItems
{
public class SettingsSaveViewModel
{
private readonly ISettingsService _settings;
public SettingsSaveViewModel() : this(App.Container.Resolve<ISettingsService>())
{ }
public SettingsSaveViewModel(ISettingsService settings)
{
_settings = settings;
}
public bool IsSaveSuspend
{
get => _settings.GetSetting("SaveSuspend", true);
set => _settings.PutSetting("SaveSuspend", value);
}
}
}

View File

@@ -1,322 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Input;
using ModernKeePass.Common;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
using ModernKeePassLib;
using ModernKeePassLib.Cryptography.PasswordGenerator;
using ModernKeePassLib.Security;
using ModernKeePassLib.Cryptography;
namespace ModernKeePass.ViewModels
{
public class EntryVm : INotifyPropertyChanged, IPwEntity, ISelectableModel
{
public GroupVm ParentGroup { get; private set; }
public GroupVm PreviousGroup { get; private set; }
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
public bool HasExpired => HasExpirationDate && _pwEntry.ExpiryTime < DateTime.Now;
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
public bool UpperCasePatternSelected { get; set; } = true;
public bool LowerCasePatternSelected { get; set; } = true;
public bool DigitsPatternSelected { get; set; } = true;
public bool MinusPatternSelected { get; set; }
public bool UnderscorePatternSelected { get; set; }
public bool SpacePatternSelected { get; set; }
public bool SpecialPatternSelected { get; set; }
public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; } = string.Empty;
public PwUuid IdUuid => _pwEntry?.Uuid;
public string Id => _pwEntry?.Uuid.ToHexString();
public bool IsRecycleOnDelete => _database.IsRecycleBinEnabled && !ParentGroup.IsSelected;
public IEnumerable<IPwEntity> BreadCrumb => new List<IPwEntity>(ParentGroup.BreadCrumb) {ParentGroup};
/// <summary>
/// Determines if the Entry is current or from history
/// </summary>
public bool IsSelected { get; set; } = true;
public double PasswordLength
{
get => _passwordLength;
set
{
_passwordLength = value;
NotifyPropertyChanged("PasswordLength");
}
}
public string Name
{
get => GetEntryValue(PwDefs.TitleField);
set => SetEntryValue(PwDefs.TitleField, new ProtectedString(true, value));
}
public string UserName
{
get => GetEntryValue(PwDefs.UserNameField);
set => SetEntryValue(PwDefs.UserNameField, new ProtectedString(true, value));
}
public string Password
{
get => GetEntryValue(PwDefs.PasswordField);
set
{
SetEntryValue(PwDefs.PasswordField, new ProtectedString(true, value));
NotifyPropertyChanged("Password");
NotifyPropertyChanged("PasswordComplexityIndicator");
}
}
public string Url
{
get => GetEntryValue(PwDefs.UrlField);
set => SetEntryValue(PwDefs.UrlField, new ProtectedString(true, value));
}
public string Notes
{
get => GetEntryValue(PwDefs.NotesField);
set => SetEntryValue(PwDefs.NotesField, new ProtectedString(true, value));
}
public int IconId
{
get
{
if (HasExpired) return (int) PwIcon.Expired;
if (_pwEntry?.IconId != null) return (int) _pwEntry?.IconId;
return -1;
}
set
{
HandleBackup();
_pwEntry.IconId = (PwIcon)value;
}
}
public DateTimeOffset ExpiryDate
{
get => new DateTimeOffset(_pwEntry.ExpiryTime.Date);
set
{
if (!HasExpirationDate) return;
HandleBackup();
_pwEntry.ExpiryTime = value.DateTime;
}
}
public TimeSpan ExpiryTime
{
get => _pwEntry.ExpiryTime.TimeOfDay;
set
{
if (!HasExpirationDate) return;
HandleBackup();
_pwEntry.ExpiryTime = _pwEntry.ExpiryTime.Date.Add(value);
}
}
public bool IsEditMode
{
get => IsSelected && _isEditMode;
set
{
_isEditMode = value;
NotifyPropertyChanged("IsEditMode");
}
}
public bool IsVisible
{
get => _isVisible;
set
{
_isVisible = value;
NotifyPropertyChanged("IsVisible");
}
}
public bool IsRevealPassword
{
get => _isRevealPassword;
set
{
_isRevealPassword = value;
NotifyPropertyChanged("IsRevealPassword");
}
}
public bool HasExpirationDate
{
get => _pwEntry.Expires;
set
{
_pwEntry.Expires = value;
NotifyPropertyChanged("HasExpirationDate");
}
}
public IEnumerable<IPwEntity> History
{
get
{
var history = new Stack<EntryVm>();
foreach (var historyEntry in _pwEntry.History)
{
history.Push(new EntryVm(historyEntry, ParentGroup) {IsSelected = false});
}
history.Push(this);
return history;
}
}
public Color? BackgroundColor
{
get => _pwEntry?.BackgroundColor;
set
{
if (value != null) _pwEntry.BackgroundColor = (Color) value;
}
}
public Color? ForegroundColor
{
get => _pwEntry?.ForegroundColor;
set
{
if (value != null) _pwEntry.ForegroundColor = (Color)value;
}
}
public ICommand SaveCommand { get; }
public ICommand GeneratePasswordCommand { get; }
public ICommand UndoDeleteCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
private readonly PwEntry _pwEntry;
private readonly IDatabaseService _database;
private readonly IResourceService _resource;
private bool _isEditMode;
private bool _isDirty = true;
private bool _isRevealPassword;
private double _passwordLength = 25;
private bool _isVisible = true;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public EntryVm() { }
internal EntryVm(PwEntry entry, GroupVm parent) : this(entry, parent, DatabaseService.Instance, new ResourcesService()) { }
public EntryVm(PwEntry entry, GroupVm parent, IDatabaseService database, IResourceService resource)
{
_database = database;
_resource = resource;
_pwEntry = entry;
ParentGroup = parent;
SaveCommand = new RelayCommand(() => _database.Save());
GeneratePasswordCommand = new RelayCommand(GeneratePassword);
UndoDeleteCommand = new RelayCommand(() => Move(PreviousGroup), () => PreviousGroup != null);
}
public void GeneratePassword()
{
var pwProfile = new PwProfile
{
GeneratorType = PasswordGeneratorType.CharSet,
Length = (uint)PasswordLength,
CharSet = new PwCharSet()
};
if (UpperCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.UpperCase);
if (LowerCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.LowerCase);
if (DigitsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Digits);
if (SpecialPatternSelected) pwProfile.CharSet.Add(PwCharSet.SpecialChars);
if (MinusPatternSelected) pwProfile.CharSet.Add('-');
if (UnderscorePatternSelected) pwProfile.CharSet.Add('_');
if (SpacePatternSelected) pwProfile.CharSet.Add(' ');
if (BracketsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Brackets);
pwProfile.CharSet.Add(CustomChars);
ProtectedString password;
PwGenerator.Generate(out password, pwProfile, null, new CustomPwGeneratorPool());
SetEntryValue(PwDefs.PasswordField, password);
NotifyPropertyChanged("Password");
NotifyPropertyChanged("IsRevealPasswordEnabled");
NotifyPropertyChanged("PasswordComplexityIndicator");
}
public void MarkForDelete(string recycleBinTitle)
{
if (_database.IsRecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
_database.CreateRecycleBin(recycleBinTitle);
Move(_database.IsRecycleBinEnabled && !ParentGroup.IsSelected ? _database.RecycleBin : null);
}
public void Move(GroupVm destination)
{
PreviousGroup = ParentGroup;
PreviousGroup.Entries.Remove(this);
if (destination == null)
{
_database.AddDeletedItem(IdUuid);
return;
}
ParentGroup = destination;
ParentGroup.Entries.Add(this);
}
public void CommitDelete()
{
_pwEntry.ParentGroup.Entries.Remove(_pwEntry);
if (!_database.IsRecycleBinEnabled || PreviousGroup.IsSelected) _database.AddDeletedItem(IdUuid);
}
public PwEntry GetPwEntry()
{
return _pwEntry;
}
public void Reset()
{
_isDirty = false;
}
public override string ToString()
{
return IsSelected ? _resource.GetResourceValue("EntryCurrent") : _pwEntry.LastModificationTime.ToString("g");
}
private void HandleBackup()
{
if (_isDirty) return;
_pwEntry?.Touch(true);
_pwEntry?.CreateBackup(null);
_isDirty = true;
}
private string GetEntryValue(string key)
{
return _pwEntry?.Strings.GetSafe(key).ReadString();
}
private void SetEntryValue(string key, ProtectedString newValue)
{
HandleBackup();
_pwEntry?.Strings.Set(key, newValue);
}
}
}

View File

@@ -1,257 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ModernKeePass.Common;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
using ModernKeePassLib;
namespace ModernKeePass.ViewModels
{
public class GroupVm : NotifyPropertyChangedBase, IPwEntity, ISelectableModel
{
public GroupVm ParentGroup { get; private set; }
public GroupVm PreviousGroup { get; private set; }
public ObservableCollection<EntryVm> Entries
{
get => _entries;
private set => SetProperty(ref _entries, value);
}
public IEnumerable<EntryVm> SubEntries
{
get
{
var subEntries = new List<EntryVm>();
subEntries.AddRange(Entries);
foreach (var group in Groups)
{
subEntries.AddRange(group.SubEntries);
}
return subEntries;
}
}
public ObservableCollection<GroupVm> Groups { get; set; } = new ObservableCollection<GroupVm>();
public PwUuid IdUuid => _pwGroup?.Uuid;
public string Id => IdUuid?.ToHexString();
public bool IsNotRoot => ParentGroup != null;
public bool ShowRestore => IsNotRoot && ParentGroup.IsSelected;
public bool IsRecycleOnDelete => _database.IsRecycleBinEnabled && !IsSelected && !ParentGroup.IsSelected;
/// <summary>
/// Is the Group the database Recycle Bin?
/// </summary>
public bool IsSelected
{
get => _database != null && _database.IsRecycleBinEnabled && _database.RecycleBin?.Id == Id;
set
{
if (value && _pwGroup != null) _database.RecycleBin = this;
}
}
public IOrderedEnumerable<IGrouping<char, EntryVm>> EntriesZoomedOut => from e in Entries
group e by e.Name.ToUpper().FirstOrDefault() into grp
orderby grp.Key
select grp;
public string Name
{
get => _pwGroup == null ? string.Empty : _pwGroup.Name;
set => _pwGroup.Name = value;
}
public int IconId
{
get
{
if (_pwGroup?.IconId != null) return (int) _pwGroup?.IconId;
return -1;
}
set => _pwGroup.IconId = (PwIcon)value;
}
public bool IsEditMode
{
get => _isEditMode;
set
{
SetProperty(ref _isEditMode, value);
((RelayCommand)SortEntriesCommand).RaiseCanExecuteChanged();
((RelayCommand)SortGroupsCommand).RaiseCanExecuteChanged();
}
}
public bool IsMenuClosed
{
get => _isMenuClosed;
set => SetProperty(ref _isMenuClosed, value);
}
public IEnumerable<IPwEntity> BreadCrumb
{
get
{
var groups = new Stack<GroupVm>();
var group = this;
while (group.ParentGroup != null)
{
group = group.ParentGroup;
groups.Push(group);
}
return groups;
}
}
public ICommand SaveCommand { get; }
public ICommand SortEntriesCommand { get; }
public ICommand SortGroupsCommand { get; }
public ICommand UndoDeleteCommand { get; }
private readonly PwGroup _pwGroup;
private readonly IDatabaseService _database;
private bool _isEditMode;
private PwEntry _reorderedEntry;
private ObservableCollection<EntryVm> _entries = new ObservableCollection<EntryVm>();
private bool _isMenuClosed = true;
public GroupVm() {}
internal GroupVm(PwGroup pwGroup, GroupVm parent, PwUuid recycleBinId = null) : this(pwGroup, parent,
DatabaseService.Instance, recycleBinId)
{ }
public GroupVm(PwGroup pwGroup, GroupVm parent, IDatabaseService database, PwUuid recycleBinId = null)
{
_pwGroup = pwGroup;
_database = database;
ParentGroup = parent;
SaveCommand = new RelayCommand(() => _database.Save());
SortEntriesCommand = new RelayCommand(async () =>
await SortEntriesAsync().ConfigureAwait(false), () => IsEditMode);
SortGroupsCommand = new RelayCommand(async () =>
await SortGroupsAsync().ConfigureAwait(false), () => IsEditMode);
UndoDeleteCommand = new RelayCommand(() => Move(PreviousGroup), () => PreviousGroup != null);
if (recycleBinId != null && _pwGroup.Uuid.Equals(recycleBinId)) _database.RecycleBin = this;
Entries = new ObservableCollection<EntryVm>(pwGroup.Entries.Select(e => new EntryVm(e, this)));
Entries.CollectionChanged += Entries_CollectionChanged;
Groups = new ObservableCollection<GroupVm>(pwGroup.Groups.Select(g => new GroupVm(g, this, recycleBinId)));
}
private void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove:
var oldIndex = (uint) e.OldStartingIndex;
_reorderedEntry = _pwGroup.Entries.GetAt(oldIndex);
_pwGroup.Entries.RemoveAt(oldIndex);
break;
case NotifyCollectionChangedAction.Add:
if (_reorderedEntry == null) _pwGroup.AddEntry(((EntryVm) e.NewItems[0]).GetPwEntry(), true);
else _pwGroup.Entries.Insert((uint)e.NewStartingIndex, _reorderedEntry);
break;
}
}
public GroupVm AddNewGroup(string name = "")
{
var pwGroup = new PwGroup(true, true, name, PwIcon.Folder);
_pwGroup.AddGroup(pwGroup, true);
var newGroup = new GroupVm(pwGroup, this) {Name = name, IsEditMode = string.IsNullOrEmpty(name)};
Groups.Add(newGroup);
return newGroup;
}
public EntryVm AddNewEntry()
{
var pwEntry = new PwEntry(true, true);
var newEntry = new EntryVm(pwEntry, this) {IsEditMode = true};
newEntry.GeneratePassword();
Entries.Add(newEntry);
return newEntry;
}
public void MarkForDelete(string recycleBinTitle)
{
if (_database.IsRecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
_database.CreateRecycleBin(recycleBinTitle);
Move(_database.IsRecycleBinEnabled && !IsSelected ? _database.RecycleBin : null);
((RelayCommand)UndoDeleteCommand).RaiseCanExecuteChanged();
}
public void UndoDelete()
{
Move(PreviousGroup);
}
public void Move(GroupVm destination)
{
PreviousGroup = ParentGroup;
PreviousGroup.Groups.Remove(this);
PreviousGroup._pwGroup.Groups.Remove(_pwGroup);
if (destination == null)
{
_database.AddDeletedItem(IdUuid);
return;
}
ParentGroup = destination;
ParentGroup.Groups.Add(this);
ParentGroup._pwGroup.AddGroup(_pwGroup, true);
}
public void CommitDelete()
{
_pwGroup.ParentGroup.Groups.Remove(_pwGroup);
if (_database.IsRecycleBinEnabled && !PreviousGroup.IsSelected) _database.RecycleBin._pwGroup.AddGroup(_pwGroup, true);
else _database.AddDeletedItem(IdUuid);
}
public override string ToString()
{
return Name;
}
private async Task SortEntriesAsync()
{
var comparer = new PwEntryComparer(PwDefs.TitleField, true, false);
try
{
_pwGroup.Entries.Sort(comparer);
Entries = new ObservableCollection<EntryVm>(Entries.OrderBy(e => e.Name));
}
catch (Exception e)
{
await MessageDialogHelper.ShowErrorDialog(e);
}
}
private async Task SortGroupsAsync()
{
try
{
_pwGroup.SortSubGroups(false);
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Name).ThenBy(g => g._pwGroup == null));
OnPropertyChanged("Groups");
}
catch (Exception e)
{
await MessageDialogHelper.ShowErrorDialog(e);
}
}
}
}

View File

@@ -1,149 +0,0 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using ModernKeePass.Domain.AOP;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Enums;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels
{
public class CredentialsViewModel: NotifyPropertyChangedBase
{
private bool _hasPassword;
private bool _hasKeyFile;
private bool _hasUserAccount;
private bool _isOpening;
private string _password = string.Empty;
private string _status;
private CredentialStatusTypes _statusType;
private string _keyFilePath = string.Empty;
private string _keyFileText;
private readonly IResourceService _resourceService;
private readonly IDatabaseService _databaseService;
public bool HasPassword
{
get => _hasPassword;
set
{
SetProperty(ref _hasPassword, value);
OnPropertyChanged(nameof(IsValid));
}
}
public bool HasKeyFile
{
get => _hasKeyFile;
set
{
SetProperty(ref _hasKeyFile, value);
OnPropertyChanged(nameof(IsValid));
}
}
public bool HasUserAccount
{
get => _hasUserAccount;
set
{
SetProperty(ref _hasUserAccount, value);
OnPropertyChanged(nameof(IsValid));
}
}
public bool IsValid => !_isOpening && (HasPassword || HasKeyFile && KeyFilePath != string.Empty || HasUserAccount);
public string Status
{
get => _status;
set => SetProperty(ref _status, value);
}
public int StatusType
{
get => (int)_statusType;
set => SetProperty(ref _statusType, (CredentialStatusTypes)value);
}
public string Password
{
get => _password;
set
{
_password = value;
StatusType = (int)CredentialStatusTypes.Normal;
Status = string.Empty;
}
}
public string KeyFilePath
{
get => _keyFilePath;
set
{
_keyFilePath = value;
OnPropertyChanged(nameof(IsValid));
}
}
public string KeyFileText
{
get => _keyFileText;
set => SetProperty(ref _keyFileText, value);
}
public CredentialsViewModel() : this(App.Container.Resolve<IDatabaseService>(), App.Container.Resolve<IResourceService>()) { }
public CredentialsViewModel(IDatabaseService databaseService, IResourceService resourceService)
{
_databaseService = databaseService;
_resourceService = resourceService;
_keyFileText = _resourceService.GetResourceValue("CompositeKeyDefaultKeyFile");
}
public async Task<bool> OpenDatabase(FileInfo fileInfo)
{
try
{
_isOpening = true;
OnPropertyChanged(nameof(IsValid));
var credentials = new Credentials
{
KeyFilePath = HasKeyFile ? KeyFilePath : string.Empty,
Password = HasPassword ? Password : string.Empty
};
await Task.Run(() => _databaseService.Open(fileInfo, credentials));
return true;
}
catch (ArgumentException)
{
var errorMessage = new StringBuilder($"{_resourceService.GetResourceValue("CompositeKeyErrorOpen")}\n");
if (HasPassword) errorMessage.AppendLine(_resourceService.GetResourceValue("CompositeKeyErrorUserPassword"));
if (HasKeyFile) errorMessage.AppendLine(_resourceService.GetResourceValue("CompositeKeyErrorUserKeyFile"));
if (HasUserAccount) errorMessage.AppendLine(_resourceService.GetResourceValue("CompositeKeyErrorUserAccount"));
UpdateStatus(errorMessage.ToString(), CredentialStatusTypes.Error);
}
catch (Exception e)
{
var error = $"{_resourceService.GetResourceValue("CompositeKeyErrorOpen")}{e.Message}";
UpdateStatus(error, CredentialStatusTypes.Error);
}
finally
{
_isOpening = false;
OnPropertyChanged(nameof(IsValid));
}
return false;
}
private void UpdateStatus(string text, CredentialStatusTypes type)
{
Status = text;
StatusType = (int)type;
}
}
}

View File

@@ -1,93 +0,0 @@
using Autofac;
using System;
using System.Threading.Tasks;
using ModernKeePass.Domain.AOP;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Enums;
using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.ViewModels
{
public class UpdateCredentialsViewModel : NotifyPropertyChangedBase
{
private readonly ISecurityService _securityService;
private bool _hasPassword;
private bool _hasKeyFile;
private bool _hasUserAccount;
private string _confirmPassword;
private string _password;
private string _keyFileText;
private string _status;
private CredentialStatusTypes _statusType;
public string Password
{
get => _password;
set
{
SetProperty(ref _password, value);
OnPropertyChanged(nameof(IsValid));
}
}
public string ConfirmPassword
{
get => _confirmPassword;
set => SetProperty(ref _confirmPassword, value);
}
public string KeyFilePath { get; set; }
public bool HasPassword
{
get => _hasPassword;
set => SetProperty(ref _hasPassword, value);
}
public bool HasKeyFile
{
get => _hasKeyFile;
set => SetProperty(ref _hasKeyFile, value);
}
public bool HasUserAccount
{
get => _hasUserAccount;
set => SetProperty(ref _hasUserAccount, value);
}
public string KeyFileText
{
get => _keyFileText;
set => SetProperty(ref _keyFileText, value);
}
public string Status
{
get => _status;
set => SetProperty(ref _status, value);
}
public int StatusType
{
get => (int)_statusType;
set => SetProperty(ref _statusType, (CredentialStatusTypes)value);
}
public double PasswordComplexityIndicator => _securityService.EstimatePasswordComplexity(Password);
public bool IsValid => HasPassword && Password == ConfirmPassword || HasKeyFile && KeyFilePath != string.Empty || HasUserAccount;
public UpdateCredentialsViewModel(): this(App.Container.Resolve<ISecurityService>()) { }
public UpdateCredentialsViewModel(ISecurityService securityService)
{
_securityService = securityService;
}
internal Task<bool> CreateDatabase(FileInfo fileInfo)
{
throw new NotImplementedException();
}
}
}

View File

@@ -12,8 +12,8 @@
<AssemblyName>ModernKeePass</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
@@ -97,7 +97,6 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\UserControls\UpdateCredentialsViewModel.cs" />
<Compile Include="Views\UserControls\UpdateCredentialsUserControl.xaml.cs">
<DependentUpon>UpdateCredentialsUserControl.xaml</DependentUpon>
</Compile>
@@ -108,7 +107,6 @@
<Compile Include="ViewModels\ListItems\EntryItemViewModel.cs" />
<Compile Include="ViewModels\GroupsViewModel.cs" />
<Compile Include="ViewModels\ListItems\GroupItemViewModel.cs" />
<Compile Include="ViewModels\ListItems\SettingsSaveViewModel.cs" />
<Compile Include="ViewModels\SettingsViewModel.cs" />
<Compile Include="Views\EntriesPage.xaml.cs">
<DependentUpon>EntriesPage.xaml</DependentUpon>
@@ -171,10 +169,6 @@
<Compile Include="Views\MainPageFrames\WelcomePage.xaml.cs">
<DependentUpon>WelcomePage.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\UserControls\CredentialsViewModel.cs" />
<Compile Include="ViewModels\ListItems\ListMenuItemViewModel.cs" />
<Compile Include="ViewModels\ListItems\MainMenuItemViewModel.cs" />
<Compile Include="ViewModels\ListItems\RecentItemViewModel.cs" />
<Content Include="Views\Old\EntryDetailPage.xaml.cs">
<DependentUpon>EntryDetailPage.xaml</DependentUpon>
</Content>
@@ -191,14 +185,10 @@
<DependentUpon>SaveDatabasePage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Content Include="ViewModels\Old\EntryVm.cs" />
<Content Include="ViewModels\Old\GroupVm.cs" />
<Compile Include="ViewModels\ListItems\SettingsNewViewModel.cs" />
<Compile Include="ViewModels\NewViewModel.cs" />
<Compile Include="ViewModels\OpenViewModel.cs" />
<Compile Include="ViewModels\RecentViewModel.cs" />
<Compile Include="ViewModels\SaveViewModel.cs" />
<Compile Include="ViewModels\ListItems\SettingsDatabaseViewModel.cs" />
<Compile Include="Views\UserControls\HamburgerMenuUserControl.xaml.cs">
<DependentUpon>HamburgerMenuUserControl.xaml</DependentUpon>
</Compile>
@@ -451,9 +441,6 @@
<Content Include="Assets\Wide310x150Logo.scale-80.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac">
<Version>5.1.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.AppCenter.Analytics">
<Version>3.0.0</Version>
</PackageReference>