2017-10-31 12:14:26 +01:00
|
|
|
|
using System;
|
2018-06-13 18:58:28 +02:00
|
|
|
|
using System.Collections.Generic;
|
2017-10-31 12:14:26 +01:00
|
|
|
|
using System.ComponentModel;
|
2018-06-15 18:07:44 +02:00
|
|
|
|
using System.Globalization;
|
2017-10-17 18:46:05 +02:00
|
|
|
|
using ModernKeePass.Interfaces;
|
2018-02-23 18:09:21 +01:00
|
|
|
|
using ModernKeePass.Services;
|
2017-09-26 15:38:58 +02:00
|
|
|
|
using ModernKeePassLib;
|
2017-10-16 18:31:45 +02:00
|
|
|
|
using ModernKeePassLib.Cryptography.PasswordGenerator;
|
2017-09-26 15:38:58 +02:00
|
|
|
|
using ModernKeePassLib.Security;
|
2017-10-19 16:33:07 +02:00
|
|
|
|
using ModernKeePassLib.Cryptography;
|
2017-09-12 18:20:32 +02:00
|
|
|
|
|
|
|
|
|
namespace ModernKeePass.ViewModels
|
|
|
|
|
{
|
2018-06-15 18:07:44 +02:00
|
|
|
|
public class EntryVm : INotifyPropertyChanged, IPwEntity, ISelectableModel
|
2017-09-12 18:20:32 +02:00
|
|
|
|
{
|
2017-10-31 18:49:18 +01:00
|
|
|
|
public GroupVm ParentGroup { get; private set; }
|
|
|
|
|
public GroupVm PreviousGroup { get; private set; }
|
2017-10-30 18:34:38 +01:00
|
|
|
|
public System.Drawing.Color? BackgroundColor => _pwEntry?.BackgroundColor;
|
|
|
|
|
public System.Drawing.Color? ForegroundColor => _pwEntry?.ForegroundColor;
|
2017-10-12 18:37:49 +02:00
|
|
|
|
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
2017-10-30 18:34:38 +01:00
|
|
|
|
public bool HasExpired => HasExpirationDate && _pwEntry.ExpiryTime < DateTime.Now;
|
2018-06-08 15:39:28 +02:00
|
|
|
|
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
|
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;
|
2017-10-31 12:14:26 +01:00
|
|
|
|
public PwUuid IdUuid => _pwEntry?.Uuid;
|
2017-11-29 19:13:38 +01:00
|
|
|
|
public string Id => _pwEntry?.Uuid.ToHexString();
|
2018-06-14 18:38:05 +02:00
|
|
|
|
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !ParentGroup.IsSelected;
|
|
|
|
|
public IEnumerable<IPwEntity> BreadCrumb => new List<IPwEntity>(ParentGroup.BreadCrumb) {ParentGroup};
|
2018-06-15 18:07:44 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Determines if the Entry is current or from history
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsSelected { get; set; } = true;
|
2017-10-16 18:31:45 +02:00
|
|
|
|
|
2017-11-06 19:01:01 +01:00
|
|
|
|
public double PasswordLength
|
|
|
|
|
{
|
|
|
|
|
get { return _passwordLength; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_passwordLength = value;
|
|
|
|
|
NotifyPropertyChanged("PasswordLength");
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-29 19:13:38 +01:00
|
|
|
|
|
2017-10-17 18:46:05 +02:00
|
|
|
|
public string Name
|
2017-09-26 14:32:15 +02:00
|
|
|
|
{
|
2018-01-09 18:40:11 +01:00
|
|
|
|
get { return GetEntryValue(PwDefs.TitleField); }
|
2017-09-26 14:32:15 +02:00
|
|
|
|
set { SetEntryValue(PwDefs.TitleField, value); }
|
|
|
|
|
}
|
2017-10-11 11:20:05 +02:00
|
|
|
|
|
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string UserName
|
|
|
|
|
{
|
|
|
|
|
get { return GetEntryValue(PwDefs.UserNameField); }
|
|
|
|
|
set { SetEntryValue(PwDefs.UserNameField, value); }
|
|
|
|
|
}
|
2017-11-06 19:01:01 +01:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string Password
|
|
|
|
|
{
|
|
|
|
|
get { return GetEntryValue(PwDefs.PasswordField); }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
SetEntryValue(PwDefs.PasswordField, value);
|
|
|
|
|
NotifyPropertyChanged("Password");
|
2017-10-19 16:33:07 +02:00
|
|
|
|
NotifyPropertyChanged("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
|
|
|
|
|
{
|
|
|
|
|
get { return GetEntryValue(PwDefs.UrlField); }
|
|
|
|
|
set { SetEntryValue(PwDefs.UrlField, value); }
|
|
|
|
|
}
|
2018-06-15 18:07:44 +02:00
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
public string Notes
|
|
|
|
|
{
|
|
|
|
|
get { return GetEntryValue(PwDefs.NotesField); }
|
|
|
|
|
set { SetEntryValue(PwDefs.NotesField, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-14 10:20:00 +02:00
|
|
|
|
public int IconId
|
2017-09-29 18:08:20 +02:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2018-06-14 10:20:00 +02:00
|
|
|
|
if (_pwEntry?.IconId != null) return (int) _pwEntry?.IconId;
|
|
|
|
|
return -1;
|
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
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
get { return new DateTimeOffset(_pwEntry.ExpiryTime.Date); }
|
|
|
|
|
set { if (HasExpirationDate) _pwEntry.ExpiryTime = value.DateTime; }
|
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
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
get { return _pwEntry.ExpiryTime.TimeOfDay; }
|
|
|
|
|
set { if (HasExpirationDate) _pwEntry.ExpiryTime = _pwEntry.ExpiryTime.Date.Add(value); }
|
2017-10-18 13:57:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-06 14:56:16 +02:00
|
|
|
|
public bool IsEditMode
|
|
|
|
|
{
|
2018-06-15 18:07:44 +02:00
|
|
|
|
get { return IsSelected && _isEditMode; }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_isEditMode = value;
|
|
|
|
|
NotifyPropertyChanged("IsEditMode");
|
|
|
|
|
}
|
2017-10-06 14:56:16 +02:00
|
|
|
|
}
|
2017-12-14 17:15:28 +01:00
|
|
|
|
|
|
|
|
|
public bool IsVisible
|
|
|
|
|
{
|
|
|
|
|
get { return _isVisible; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_isVisible = value;
|
|
|
|
|
NotifyPropertyChanged("IsVisible");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-14 18:38:05 +02:00
|
|
|
|
|
2017-10-06 17:57:36 +02:00
|
|
|
|
public bool IsRevealPassword
|
|
|
|
|
{
|
|
|
|
|
get { return _isRevealPassword; }
|
2017-10-13 11:48:58 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_isRevealPassword = value;
|
|
|
|
|
NotifyPropertyChanged("IsRevealPassword");
|
|
|
|
|
}
|
2017-10-06 17:57:36 +02:00
|
|
|
|
}
|
2017-10-18 13:57:10 +02:00
|
|
|
|
public bool HasExpirationDate
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
get { return _pwEntry.Expires; }
|
2017-10-18 13:57:10 +02:00
|
|
|
|
set
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
_pwEntry.Expires = value;
|
2017-10-18 13:57:10 +02:00
|
|
|
|
NotifyPropertyChanged("HasExpirationDate");
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-10-19 16:33:07 +02:00
|
|
|
|
|
2018-06-14 18:38:05 +02:00
|
|
|
|
public IEnumerable<IPwEntity> History
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2018-06-15 18:07:44 +02:00
|
|
|
|
var history = new List<EntryVm> {this};
|
2018-06-14 18:38:05 +02:00
|
|
|
|
foreach (var historyEntry in _pwEntry.History)
|
|
|
|
|
{
|
2018-06-15 18:07:44 +02:00
|
|
|
|
history.Add(new EntryVm(historyEntry, ParentGroup) {IsSelected = false});
|
2018-06-14 18:38:05 +02:00
|
|
|
|
}
|
2018-06-15 18:07:44 +02:00
|
|
|
|
|
|
|
|
|
return history;
|
2018-06-14 18:38:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-10-31 12:14:26 +01:00
|
|
|
|
|
2017-10-13 11:48:58 +02:00
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
2017-10-30 18:34:38 +01:00
|
|
|
|
private readonly PwEntry _pwEntry;
|
2018-02-23 18:09:21 +01:00
|
|
|
|
private readonly IDatabaseService _database;
|
2018-06-15 18:07:44 +02:00
|
|
|
|
private readonly IResourceService _resource;
|
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;
|
2017-10-18 13:57:10 +02:00
|
|
|
|
|
2017-10-13 11:48:58 +02:00
|
|
|
|
private void NotifyPropertyChanged(string propertyName)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
}
|
2017-09-13 18:37:44 +02:00
|
|
|
|
|
2018-06-14 10:50:16 +02:00
|
|
|
|
public EntryVm() { }
|
2017-11-22 18:54:03 +01:00
|
|
|
|
|
2018-06-15 18:07:44 +02:00
|
|
|
|
internal EntryVm(PwEntry entry, GroupVm parent) : this(entry, parent, DatabaseService.Instance, new ResourcesService()) { }
|
2017-11-22 18:54:03 +01:00
|
|
|
|
|
2018-06-15 18:07:44 +02:00
|
|
|
|
public EntryVm(PwEntry entry, GroupVm parent, IDatabaseService database, IResourceService resource)
|
2017-09-13 18:37:44 +02:00
|
|
|
|
{
|
2017-11-23 15:26:57 +01:00
|
|
|
|
_database = database;
|
2018-06-15 18:07:44 +02:00
|
|
|
|
_resource = resource;
|
2017-10-30 18:34:38 +01:00
|
|
|
|
_pwEntry = entry;
|
2017-10-02 18:40:54 +02:00
|
|
|
|
ParentGroup = parent;
|
|
|
|
|
}
|
2017-10-31 12:14:26 +01:00
|
|
|
|
|
2017-10-16 18:31:45 +02:00
|
|
|
|
public void GeneratePassword()
|
|
|
|
|
{
|
2017-11-22 18:54:03 +01:00
|
|
|
|
var pwProfile = new PwProfile
|
2017-10-16 18:31:45 +02:00
|
|
|
|
{
|
|
|
|
|
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());
|
|
|
|
|
|
2017-10-30 18:34:38 +01:00
|
|
|
|
_pwEntry?.Strings.Set(PwDefs.PasswordField, password);
|
2017-10-16 18:31:45 +02:00
|
|
|
|
NotifyPropertyChanged("Password");
|
|
|
|
|
NotifyPropertyChanged("IsRevealPasswordEnabled");
|
2017-10-19 16:33:07 +02:00
|
|
|
|
NotifyPropertyChanged("PasswordComplexityIndicator");
|
2017-10-16 18:31:45 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-26 14:32:15 +02:00
|
|
|
|
private string GetEntryValue(string key)
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
return _pwEntry?.Strings.GetSafe(key).ReadString();
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetEntryValue(string key, string newValue)
|
|
|
|
|
{
|
2017-10-30 18:34:38 +01:00
|
|
|
|
_pwEntry?.Strings.Set(key, new ProtectedString(true, newValue));
|
2017-09-26 14:32:15 +02:00
|
|
|
|
}
|
2017-10-18 10:32:51 +02:00
|
|
|
|
|
2018-03-12 17:30:03 +01:00
|
|
|
|
public void MarkForDelete(string recycleBinTitle)
|
2017-10-18 10:32:51 +02:00
|
|
|
|
{
|
2017-11-23 15:26:57 +01:00
|
|
|
|
if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
|
2018-03-12 17:30:03 +01:00
|
|
|
|
_database.CreateRecycleBin(recycleBinTitle);
|
2017-11-23 15:26:57 +01:00
|
|
|
|
Move(_database.RecycleBinEnabled && !ParentGroup.IsSelected ? _database.RecycleBin : null);
|
2017-10-18 10:32:51 +02:00
|
|
|
|
}
|
2017-10-31 12:14:26 +01:00
|
|
|
|
|
2017-10-31 18:49:18 +01:00
|
|
|
|
public void UndoDelete()
|
2017-10-17 18:46:05 +02:00
|
|
|
|
{
|
2017-10-31 18:49:18 +01:00
|
|
|
|
Move(PreviousGroup);
|
2017-10-17 18:46:05 +02:00
|
|
|
|
}
|
2017-10-18 10:32:51 +02:00
|
|
|
|
|
2017-10-31 18:49:18 +01:00
|
|
|
|
public void Move(GroupVm destination)
|
2017-10-18 10:32:51 +02:00
|
|
|
|
{
|
2017-10-31 18:49:18 +01:00
|
|
|
|
PreviousGroup = ParentGroup;
|
|
|
|
|
PreviousGroup.Entries.Remove(this);
|
|
|
|
|
if (destination == null)
|
|
|
|
|
{
|
2017-11-23 15:26:57 +01:00
|
|
|
|
_database.AddDeletedItem(IdUuid);
|
2017-10-31 18:49:18 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ParentGroup = destination;
|
2017-10-18 10:32:51 +02:00
|
|
|
|
ParentGroup.Entries.Add(this);
|
2017-10-31 18:49:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CommitDelete()
|
|
|
|
|
{
|
|
|
|
|
_pwEntry.ParentGroup.Entries.Remove(_pwEntry);
|
2017-11-28 18:53:10 +01:00
|
|
|
|
if (!_database.RecycleBinEnabled || PreviousGroup.IsSelected) _database.AddDeletedItem(IdUuid);
|
2017-10-18 10:32:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-25 18:29:50 +02:00
|
|
|
|
public void Save()
|
|
|
|
|
{
|
2017-11-23 15:26:57 +01:00
|
|
|
|
_database.Save();
|
2017-10-25 18:29:50 +02:00
|
|
|
|
}
|
2017-11-28 18:53:10 +01:00
|
|
|
|
|
|
|
|
|
public PwEntry GetPwEntry()
|
|
|
|
|
{
|
|
|
|
|
return _pwEntry;
|
|
|
|
|
}
|
2018-06-15 18:07:44 +02:00
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return IsSelected ? _resource.GetResourceValue("EntryCurrent") : _pwEntry.LastModificationTime.ToString("g");
|
|
|
|
|
}
|
2017-09-12 18:20:32 +02:00
|
|
|
|
}
|
|
|
|
|
}
|