2017-10-31 12:14:26 +01:00
|
|
|
|
using System;
|
2018-06-13 18:58:28 +02:00
|
|
|
|
using System.Collections.Generic;
|
2018-06-26 15:01:02 +02:00
|
|
|
|
using System.Drawing;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
using System.Threading.Tasks;
|
2018-06-20 18:41:56 +02:00
|
|
|
|
using System.Windows.Input;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
using Windows.UI.Xaml.Controls;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
using MediatR;
|
2020-04-06 20:20:45 +02:00
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
2020-03-27 18:45:13 +01:00
|
|
|
|
using ModernKeePass.Application.Database.Models;
|
|
|
|
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
|
2020-04-02 19:12:16 +02:00
|
|
|
|
using ModernKeePass.Application.Entry.Models;
|
|
|
|
|
using ModernKeePass.Application.Entry.Queries.GetEntry;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
using ModernKeePass.Application.Group.Commands.AddEntry;
|
2020-04-02 19:12:16 +02:00
|
|
|
|
using ModernKeePass.Application.Group.Commands.DeleteEntry;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
using ModernKeePass.Application.Group.Commands.RemoveEntry;
|
2020-04-02 19:12:16 +02:00
|
|
|
|
using ModernKeePass.Application.Group.Queries.GetGroup;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
using ModernKeePass.Application.Security.Commands.GeneratePassword;
|
|
|
|
|
using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity;
|
2018-06-20 18:41:56 +02:00
|
|
|
|
using ModernKeePass.Common;
|
2020-03-31 19:19:02 +02:00
|
|
|
|
using ModernKeePass.Domain.Enums;
|
2020-03-28 16:13:17 +01:00
|
|
|
|
using ModernKeePass.Domain.Interfaces;
|
2017-10-17 18:46:05 +02:00
|
|
|
|
using ModernKeePass.Interfaces;
|
2020-04-02 19:12:16 +02:00
|
|
|
|
using ModernKeePass.Application.Group.Models;
|
2020-04-06 20:20:45 +02:00
|
|
|
|
using ModernKeePass.Domain.AOP;
|
2017-09-12 18:20:32 +02:00
|
|
|
|
|
|
|
|
|
namespace ModernKeePass.ViewModels
|
|
|
|
|
{
|
2020-04-01 12:48:36 +02:00
|
|
|
|
public class EntryDetailVm : NotifyPropertyChangedBase, IVmEntity, ISelectableModel
|
2017-09-12 18:20:32 +02:00
|
|
|
|
{
|
2017-10-12 18:37:49 +02:00
|
|
|
|
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
2020-03-27 13:27:29 +01:00
|
|
|
|
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
|
|
|
|
public double PasswordComplexityIndicator => _mediator.Send(new EstimatePasswordComplexityQuery {Password = Password}).GetAwaiter().GetResult();
|
2017-10-16 18:31:45 +02:00
|
|
|
|
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;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
public string Id => _entry.Id;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
|
2020-04-02 19:12:16 +02:00
|
|
|
|
public IEnumerable<GroupVm> BreadCrumb => new List<GroupVm> { _parent };
|
2020-03-30 19:43:04 +02:00
|
|
|
|
|
2018-06-15 18:07:44 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Determines if the Entry is current or from history
|
|
|
|
|
/// </summary>
|
2020-04-03 17:33:53 +02:00
|
|
|
|
public bool IsSelected
|
|
|
|
|
{
|
|
|
|
|
get { return _isSelected; }
|
2020-04-06 20:20:45 +02:00
|
|
|
|
set { SetProperty(ref _isSelected, value); }
|
2020-04-03 17:33:53 +02:00
|
|
|
|
}
|
2017-10-16 18:31:45 +02:00
|
|
|
|
|
2017-11-06 19:01:01 +01:00
|
|
|
|
public double PasswordLength
|
|
|
|
|
{
|
|
|
|
|
get { return _passwordLength; }
|
2020-04-06 20:20:45 +02:00
|
|
|
|
set { SetProperty(ref _passwordLength, value); }
|
2017-11-06 19:01:01 +01:00
|
|
|
|
}
|
2017-11-29 19:13:38 +01:00
|
|
|
|
|
2020-03-27 13:27:29 +01:00
|
|
|
|
public string Title
|
2017-09-26 14:32:15 +02:00
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.Title; }
|
2020-03-31 19:19:02 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Title), FieldValue = value}).Wait();
|
|
|
|
|
_entry.Title = value;
|
|
|
|
|
}
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
2017-10-11 11:20:05 +02:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string UserName
|
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.Username; }
|
2020-04-01 12:48:36 +02:00
|
|
|
|
set { _entry.Username = value; }
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
2017-11-06 19:01:01 +01:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string Password
|
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.Password; }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Password), FieldValue = value }).Wait();
|
|
|
|
|
_entry.Password = value;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
OnPropertyChanged(nameof(PasswordComplexityIndicator));
|
2017-10-13 11:48:58 +02:00
|
|
|
|
}
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
2018-02-23 18:09:21 +01:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string Url
|
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _entry.Url?.ToString(); }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Url), FieldValue = value }).Wait();
|
|
|
|
|
_entry.Url = new Uri(value);
|
|
|
|
|
}
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
2018-06-15 18:07:44 +02:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string Notes
|
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.Notes; }
|
2020-03-31 19:19:02 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Notes), FieldValue = value }).Wait();
|
|
|
|
|
_entry.Notes = value;
|
|
|
|
|
}
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 19:43:04 +02:00
|
|
|
|
public Symbol Icon
|
2017-09-29 18:08:20 +02:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2020-03-30 19:43:04 +02:00
|
|
|
|
if (HasExpired) return Symbol.ReportHacked;
|
|
|
|
|
return (Symbol) _entry.Icon;
|
2018-07-24 17:52:44 +02:00
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Icon), FieldValue = value }).Wait();
|
|
|
|
|
_entry.Icon = (Icon)value;
|
|
|
|
|
}
|
2017-09-29 18:08:20 +02:00
|
|
|
|
}
|
2017-10-06 14:56:16 +02:00
|
|
|
|
|
2017-10-18 13:57:10 +02:00
|
|
|
|
public DateTimeOffset ExpiryDate
|
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.ExpirationDate; }
|
2018-07-24 17:52:44 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (!HasExpirationDate) return;
|
2020-03-31 19:19:02 +02:00
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = value.Date }).Wait();
|
|
|
|
|
_entry.ExpirationDate = value.Date;
|
2018-07-24 17:52:44 +02:00
|
|
|
|
}
|
2017-10-18 13:57:10 +02:00
|
|
|
|
}
|
2017-11-06 19:01:01 +01:00
|
|
|
|
|
2017-10-18 13:57:10 +02:00
|
|
|
|
public TimeSpan ExpiryTime
|
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
get { return _entry.ExpirationDate.TimeOfDay; }
|
2018-07-24 17:52:44 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (!HasExpirationDate) return;
|
2020-03-31 19:19:02 +02:00
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = ExpiryDate.Date.Add(value) }).Wait();
|
|
|
|
|
_entry.ExpirationDate = _entry.ExpirationDate.Date.Add(value);
|
2018-07-24 17:52:44 +02:00
|
|
|
|
}
|
2017-10-18 13:57:10 +02:00
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public bool HasExpirationDate
|
2017-10-06 14:56:16 +02:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _entry.HasExpirationDate; }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(HasExpirationDate), FieldValue = value }).Wait();
|
|
|
|
|
_entry.HasExpirationDate = value;
|
2020-03-27 13:27:29 +01:00
|
|
|
|
OnPropertyChanged();
|
2017-10-13 11:48:58 +02:00
|
|
|
|
}
|
2017-10-06 14:56:16 +02:00
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public Color? BackgroundColor
|
2017-12-14 17:15:28 +01:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _entry?.BackgroundColor; }
|
2017-12-14 17:15:28 +01:00
|
|
|
|
set
|
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
if (value != null)
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(BackgroundColor), FieldValue = value }).Wait();
|
|
|
|
|
_entry.BackgroundColor = (Color)value;
|
|
|
|
|
}
|
2017-12-14 17:15:28 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public Color? ForegroundColor
|
2017-10-06 17:57:36 +02:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _entry?.ForegroundColor; }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
if (value != null)
|
|
|
|
|
{
|
|
|
|
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(ForegroundColor), FieldValue = value }).Wait();
|
|
|
|
|
_entry.ForegroundColor = (Color)value;
|
|
|
|
|
}
|
2017-10-13 11:48:58 +02:00
|
|
|
|
}
|
2017-10-06 17:57:36 +02:00
|
|
|
|
}
|
2020-04-03 17:33:53 +02:00
|
|
|
|
public IEnumerable<EntryVm> History => _history;
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public bool IsEditMode
|
2017-10-18 13:57:10 +02:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return IsSelected && _isEditMode; }
|
2020-04-06 20:20:45 +02:00
|
|
|
|
set { SetProperty(ref _isEditMode, value); }
|
2017-10-18 13:57:10 +02:00
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public bool IsVisible
|
2018-06-26 15:01:02 +02:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _isVisible; }
|
2020-04-06 20:20:45 +02:00
|
|
|
|
set { SetProperty(ref _isVisible, value); }
|
2018-06-26 15:01:02 +02:00
|
|
|
|
}
|
2020-03-31 19:19:02 +02:00
|
|
|
|
|
|
|
|
|
public bool IsRevealPassword
|
2018-06-26 15:01:02 +02:00
|
|
|
|
{
|
2020-03-31 19:19:02 +02:00
|
|
|
|
get { return _isRevealPassword; }
|
2020-04-06 20:20:45 +02:00
|
|
|
|
set { SetProperty(ref _isRevealPassword, value); }
|
2018-06-26 15:01:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 19:12:16 +02:00
|
|
|
|
public bool CanRestore => _entry.ParentGroupId == _database.RecycleBinId;
|
2020-04-03 17:33:53 +02:00
|
|
|
|
|
2018-06-20 18:41:56 +02:00
|
|
|
|
public ICommand SaveCommand { get; }
|
|
|
|
|
public ICommand GeneratePasswordCommand { get; }
|
|
|
|
|
public ICommand UndoDeleteCommand { get; }
|
2020-03-27 13:27:29 +01:00
|
|
|
|
|
|
|
|
|
private readonly IMediator _mediator;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
private readonly DatabaseVm _database;
|
2020-04-03 17:33:53 +02:00
|
|
|
|
private readonly GroupVm _parent;
|
|
|
|
|
private readonly IEnumerable<EntryVm> _history;
|
|
|
|
|
private EntryVm _entry;
|
2017-10-06 14:56:16 +02:00
|
|
|
|
private bool _isEditMode;
|
2017-10-06 17:57:36 +02:00
|
|
|
|
private bool _isRevealPassword;
|
2017-11-06 19:01:01 +01:00
|
|
|
|
private double _passwordLength = 25;
|
2017-12-14 17:15:28 +01:00
|
|
|
|
private bool _isVisible = true;
|
2020-04-03 17:33:53 +02:00
|
|
|
|
private bool _isSelected;
|
2020-03-28 16:13:17 +01:00
|
|
|
|
|
2020-04-01 12:48:36 +02:00
|
|
|
|
public EntryDetailVm() { }
|
2017-11-22 18:54:03 +01:00
|
|
|
|
|
2020-04-09 19:43:06 +02:00
|
|
|
|
internal EntryDetailVm(string entryId, bool isNewEntry = false) : this(entryId, App.Services.GetRequiredService<IMediator>(), isNewEntry) { }
|
2017-11-22 18:54:03 +01:00
|
|
|
|
|
2020-04-02 19:12:16 +02:00
|
|
|
|
public EntryDetailVm(string entryId, IMediator mediator, bool isNewEntry = false)
|
2017-09-13 18:37:44 +02:00
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
_mediator = mediator;
|
2020-03-28 16:13:17 +01:00
|
|
|
|
_database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
2020-04-02 19:12:16 +02:00
|
|
|
|
_entry = _mediator.Send(new GetEntryQuery {Id = entryId}).GetAwaiter().GetResult();
|
|
|
|
|
_parent = _mediator.Send(new GetGroupQuery {Id = _entry.ParentGroupId}).GetAwaiter().GetResult();
|
2020-04-03 17:33:53 +02:00
|
|
|
|
_history = _entry.History;
|
2020-03-30 19:43:04 +02:00
|
|
|
|
_isEditMode = isNewEntry;
|
|
|
|
|
if (isNewEntry) GeneratePassword().GetAwaiter().GetResult();
|
2020-04-03 17:33:53 +02:00
|
|
|
|
IsSelected = true;
|
2018-06-20 18:41:56 +02:00
|
|
|
|
|
2020-04-09 19:43:06 +02:00
|
|
|
|
SaveCommand = new RelayCommand(async () => await _mediator.Send(new SaveDatabaseCommand()));
|
2020-03-27 13:27:29 +01:00
|
|
|
|
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
|
2020-04-02 19:12:16 +02:00
|
|
|
|
UndoDeleteCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null);
|
2017-10-02 18:40:54 +02:00
|
|
|
|
}
|
2017-10-31 12:14:26 +01:00
|
|
|
|
|
2020-03-27 13:27:29 +01:00
|
|
|
|
public async Task GeneratePassword()
|
2017-10-16 18:31:45 +02:00
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
Password = await _mediator.Send(new GeneratePasswordCommand
|
2017-10-16 18:31:45 +02:00
|
|
|
|
{
|
2020-03-27 13:27:29 +01:00
|
|
|
|
BracketsPatternSelected = BracketsPatternSelected,
|
|
|
|
|
CustomChars = CustomChars,
|
|
|
|
|
DigitsPatternSelected = DigitsPatternSelected,
|
|
|
|
|
LowerCasePatternSelected = LowerCasePatternSelected,
|
|
|
|
|
MinusPatternSelected = MinusPatternSelected,
|
|
|
|
|
PasswordLength = (int)PasswordLength,
|
|
|
|
|
SpacePatternSelected = SpacePatternSelected,
|
|
|
|
|
SpecialPatternSelected = SpecialPatternSelected,
|
|
|
|
|
UnderscorePatternSelected = UnderscorePatternSelected,
|
|
|
|
|
UpperCasePatternSelected = UpperCasePatternSelected
|
|
|
|
|
});
|
|
|
|
|
OnPropertyChanged(nameof(IsRevealPasswordEnabled));
|
2017-10-16 18:31:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-27 18:45:13 +01:00
|
|
|
|
public async Task MarkForDelete(string recycleBinTitle)
|
2017-10-18 10:32:51 +02:00
|
|
|
|
{
|
2020-04-02 19:12:16 +02:00
|
|
|
|
await _mediator.Send(new DeleteEntryCommand {EntryId = _entry.Id, ParentGroupId = _entry.ParentGroupId, RecycleBinName = recycleBinTitle});
|
2017-10-18 10:32:51 +02:00
|
|
|
|
}
|
2018-06-20 18:41:56 +02:00
|
|
|
|
|
2020-04-02 19:12:16 +02:00
|
|
|
|
public async Task Move(GroupVm destination)
|
2017-10-18 10:32:51 +02:00
|
|
|
|
{
|
2020-04-01 12:48:36 +02:00
|
|
|
|
await _mediator.Send(new AddEntryCommand { ParentGroup = destination, Entry = _entry });
|
2020-04-02 19:12:16 +02:00
|
|
|
|
await _mediator.Send(new RemoveEntryCommand { ParentGroup = _parent, Entry = _entry });
|
2017-10-31 18:49:18 +01:00
|
|
|
|
}
|
2020-04-03 17:33:53 +02:00
|
|
|
|
|
|
|
|
|
public async Task SetFieldValue(string fieldName, object value)
|
2018-06-18 18:40:00 +02:00
|
|
|
|
{
|
2020-04-03 17:33:53 +02:00
|
|
|
|
await _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = fieldName, FieldValue = value });
|
2018-06-18 18:40:00 +02:00
|
|
|
|
}
|
2020-04-01 12:48:36 +02:00
|
|
|
|
|
2020-04-03 17:33:53 +02:00
|
|
|
|
internal void SetEntry(EntryVm entry, int index)
|
2020-04-01 12:48:36 +02:00
|
|
|
|
{
|
2020-04-03 17:33:53 +02:00
|
|
|
|
_entry = entry;
|
|
|
|
|
IsSelected = index == 0;
|
2020-04-01 12:48:36 +02:00
|
|
|
|
}
|
2017-09-12 18:20:32 +02:00
|
|
|
|
}
|
|
|
|
|
}
|