From f8f7c19f654621995e31fb320b0dd473292fe1c3 Mon Sep 17 00:00:00 2001 From: Geoffroy BONNEVILLE Date: Tue, 12 May 2020 17:14:30 +0200 Subject: [PATCH] Display a big database size warning Auto rename additional field when it matches standard Treated all fields as new Field class Added the Is Protected property --- ModernKeePass.Application/Application.csproj | 1 + .../Common/Interfaces/IDatabaseProxy.cs | 2 +- .../Common/Interfaces/IEntityVm.cs | 1 - .../CreateDatabase/CreateDatabaseCommand.cs | 18 ++-- .../UpsertField/UpsertFieldCommand.cs | 3 +- .../Entry/Models/EntryVm.cs | 32 ++++--- .../Entry/Models/FieldVm.cs | 20 +++++ .../SortEntries/SortEntriesCommand.cs | 2 +- ModernKeePass.Domain/Domain.csproj | 1 + ModernKeePass.Domain/Entities/EntryEntity.cs | 10 +-- ModernKeePass.Domain/Entities/FieldEntity.cs | 9 ++ ModernKeePass.Domain/Enums/EntryFieldName.cs | 18 +++- .../Infrastructure.csproj | 3 +- .../KeePass/GroupMappingProfile.cs | 23 ----- .../KeePass/KeePassDatabaseClient.cs | 6 +- ...ryMappingProfile.cs => MappingProfiles.cs} | 32 ++++--- ModernKeePass.Infrastructure/project.json | 2 +- ModernKeePass/Strings/en-US/CodeBehind.resw | 6 ++ ModernKeePass/Strings/en-US/Resources.resw | 14 +++- ModernKeePass/Strings/fr-FR/CodeBehind.resw | 6 ++ ModernKeePass/Strings/fr-FR/Resources.resw | 14 +++- ModernKeePass/ViewModels/EntryDetailVm.cs | 69 +++++++-------- ModernKeePass/ViewModels/GroupDetailVm.cs | 2 +- ModernKeePass/Views/EntryDetailPage.xaml | 83 +++++++++++-------- .../UserControls/TopMenuUserControl.xaml.cs | 2 +- ModernKeePass/Win81App.csproj | 4 +- .../en-us/baselisting/releaseNotes.txt | 3 +- .../fr-fr/baselisting/releaseNotes.txt | 3 +- ModernKeePass/packages.config | 2 +- .../Messages/EntryFieldNameChangedMessage.cs | 1 + .../Messages/EntryFieldValueChangedMessage.cs | 1 + WinAppCommon/ViewModels/Items/EntryFieldVm.cs | 51 ++++++++++++ .../UserControls/OpenDatabaseControlVm.cs | 13 ++- WinAppCommon/WinAppCommon.projitems | 2 +- 34 files changed, 300 insertions(+), 159 deletions(-) create mode 100644 ModernKeePass.Application/Entry/Models/FieldVm.cs create mode 100644 ModernKeePass.Domain/Entities/FieldEntity.cs delete mode 100644 ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs rename ModernKeePass.Infrastructure/KeePass/{EntryMappingProfile.cs => MappingProfiles.cs} (53%) create mode 100644 WinAppCommon/ViewModels/Items/EntryFieldVm.cs diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj index fa6c468..5343467 100644 --- a/ModernKeePass.Application/Application.csproj +++ b/ModernKeePass.Application/Application.csproj @@ -94,6 +94,7 @@ + diff --git a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs index 7683686..b3fd6e0 100644 --- a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs +++ b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs @@ -33,7 +33,7 @@ namespace ModernKeePass.Application.Common.Interfaces EntryEntity GetEntry(string id); Task AddEntry(string parentGroupId, string entryId); Task MoveEntry(string parentGroupId, string entryId, int index); - void UpdateEntry(string entryId, string fieldName, object fieldValue); + void UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected); void DeleteField(string entryId, string fieldName); Task RemoveEntry(string parentGroupId, string entryId); EntryEntity CreateEntry(string parentGroupId); diff --git a/ModernKeePass.Application/Common/Interfaces/IEntityVm.cs b/ModernKeePass.Application/Common/Interfaces/IEntityVm.cs index c6b12e0..b1a2293 100644 --- a/ModernKeePass.Application/Common/Interfaces/IEntityVm.cs +++ b/ModernKeePass.Application/Common/Interfaces/IEntityVm.cs @@ -5,7 +5,6 @@ namespace ModernKeePass.Application.Common.Interfaces public interface IEntityVm { string Id { get; set; } - string Title { get; set; } Icon Icon { get; set; } string ParentGroupId { get; set; } string ParentGroupName { get; set; } diff --git a/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs b/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs index 7888154..c8cd341 100644 --- a/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs +++ b/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs @@ -64,17 +64,17 @@ namespace ModernKeePass.Application.Database.Commands.CreateDatabase _database.UpdateGroup(internetGroup); var sample1 = _database.CreateEntry(_database.RootGroupId); - _database.UpdateEntry(sample1.Id, EntryFieldName.Title, "Sample Entry" ); - _database.UpdateEntry(sample1.Id, EntryFieldName.UserName, "Username" ); - _database.UpdateEntry(sample1.Id, EntryFieldName.Password, "Password" ); - _database.UpdateEntry(sample1.Id, EntryFieldName.Url, "https://keepass.info/" ); - _database.UpdateEntry(sample1.Id, EntryFieldName.Notes, "You may safely delete this sample" ); + _database.UpdateEntry(sample1.Id, EntryFieldName.Title, "Sample Entry", true); + _database.UpdateEntry(sample1.Id, EntryFieldName.UserName, "Username", true); + _database.UpdateEntry(sample1.Id, EntryFieldName.Password, "Password", true); + _database.UpdateEntry(sample1.Id, EntryFieldName.Url, "https://keepass.info/", true); + _database.UpdateEntry(sample1.Id, EntryFieldName.Notes, "You may safely delete this sample", true); var sample2 = _database.CreateEntry(_database.RootGroupId); - _database.UpdateEntry(sample2.Id, EntryFieldName.Title, "Sample Entry #2" ); - _database.UpdateEntry(sample2.Id, EntryFieldName.UserName, "Michael321" ); - _database.UpdateEntry(sample2.Id, EntryFieldName.Password, "12345" ); - _database.UpdateEntry(sample2.Id, EntryFieldName.Url, "https://keepass.info/help/kb/testform.html" ); + _database.UpdateEntry(sample2.Id, EntryFieldName.Title, "Sample Entry #2", true); + _database.UpdateEntry(sample2.Id, EntryFieldName.UserName, "Michael321", true); + _database.UpdateEntry(sample2.Id, EntryFieldName.Password, "12345", true); + _database.UpdateEntry(sample2.Id, EntryFieldName.Url, "https://keepass.info/help/kb/testform.html", true); } } } diff --git a/ModernKeePass.Application/Entry/Commands/UpsertField/UpsertFieldCommand.cs b/ModernKeePass.Application/Entry/Commands/UpsertField/UpsertFieldCommand.cs index 50bb55a..5fcbb0b 100644 --- a/ModernKeePass.Application/Entry/Commands/UpsertField/UpsertFieldCommand.cs +++ b/ModernKeePass.Application/Entry/Commands/UpsertField/UpsertFieldCommand.cs @@ -9,6 +9,7 @@ namespace ModernKeePass.Application.Entry.Commands.UpsertField public string EntryId { get; set; } public string FieldName { get; set; } public object FieldValue { get; set; } + public bool IsProtected { get; set; } = true; public class UpsertFieldCommandHandler : IRequestHandler { @@ -23,7 +24,7 @@ namespace ModernKeePass.Application.Entry.Commands.UpsertField { if (!_database.IsOpen) throw new DatabaseClosedException(); - _database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue); + _database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue, message.IsProtected); } } } diff --git a/ModernKeePass.Application/Entry/Models/EntryVm.cs b/ModernKeePass.Application/Entry/Models/EntryVm.cs index d327f88..281ad3d 100644 --- a/ModernKeePass.Application/Entry/Models/EntryVm.cs +++ b/ModernKeePass.Application/Entry/Models/EntryVm.cs @@ -15,13 +15,13 @@ namespace ModernKeePass.Application.Entry.Models public string ParentGroupId { get; set; } public string ParentGroupName { get; set; } public string Id { get; set; } - public string Title { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public string Notes { get; set; } - public string Url { get; set; } - public bool HasUrl => !string.IsNullOrEmpty(Url); - public Dictionary AdditionalFields { get; set; } + public FieldVm Title { get; set; } + public FieldVm Username { get; set; } + public FieldVm Password { get; set; } + public FieldVm Notes { get; set; } + public FieldVm Url { get; set; } + public bool HasUrl => !string.IsNullOrEmpty(Url.Value); + public List AdditionalFields { get; set; } public List History { get; set; } public Icon Icon { get; set; } public Color ForegroundColor { get; set; } @@ -42,12 +42,18 @@ namespace ModernKeePass.Application.Entry.Models .ForMember(d => d.ParentGroupId, opts => opts.MapFrom(s => s.ParentId)) .ForMember(d => d.ParentGroupName, opts => opts.MapFrom(s => s.ParentName)) .ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id)) - .ForMember(d => d.Title, opts => opts.MapFrom(s => s.Name)) - .ForMember(d => d.Username, opts => opts.MapFrom(s => s.UserName)) - .ForMember(d => d.Password, opts => opts.MapFrom(s => s.Password)) - .ForMember(d => d.Url, opts => opts.MapFrom(s => s.Url)) - .ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Notes)) - .ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s => s.AdditionalFields)) + .ForMember(d => d.Title, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f => + f.Name.Equals(EntryFieldName.Title, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Title, IsProtected = true } )) + .ForMember(d => d.Username, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f => + f.Name.Equals(EntryFieldName.UserName, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.UserName, IsProtected = true } )) + .ForMember(d => d.Password, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f => + f.Name.Equals(EntryFieldName.Password, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Password, IsProtected = true } )) + .ForMember(d => d.Url, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f => + f.Name.Equals(EntryFieldName.Url, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Url, IsProtected = true } )) + .ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f => + f.Name.Equals(EntryFieldName.Notes, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Notes, IsProtected = true } )) + .ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s => + s.Fields.Where(f => !EntryFieldName.StandardFieldNames.Contains(f.Name, StringComparer.OrdinalIgnoreCase)))) .ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse())) .ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate)) .ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate)) diff --git a/ModernKeePass.Application/Entry/Models/FieldVm.cs b/ModernKeePass.Application/Entry/Models/FieldVm.cs new file mode 100644 index 0000000..3336051 --- /dev/null +++ b/ModernKeePass.Application/Entry/Models/FieldVm.cs @@ -0,0 +1,20 @@ +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Entry.Models +{ + public class FieldVm: IMapFrom + { + public string Name { get; set; } + public string Value { get; set; } + public bool IsProtected { get; set; } + + public override string ToString() => Value; + + public void Mapping(Profile profile) + { + profile.CreateMap(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs b/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs index d161379..5d17924 100644 --- a/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs +++ b/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs @@ -24,7 +24,7 @@ namespace ModernKeePass.Application.Group.Commands.SortEntries if (!_database.IsOpen) throw new DatabaseClosedException(); _database.SortEntries(message.Group.Id); - message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title).ToList(); + message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title.Value).ToList(); } } } diff --git a/ModernKeePass.Domain/Domain.csproj b/ModernKeePass.Domain/Domain.csproj index 1530133..7d5fce7 100644 --- a/ModernKeePass.Domain/Domain.csproj +++ b/ModernKeePass.Domain/Domain.csproj @@ -82,6 +82,7 @@ + diff --git a/ModernKeePass.Domain/Entities/EntryEntity.cs b/ModernKeePass.Domain/Entities/EntryEntity.cs index 088574c..d47b152 100644 --- a/ModernKeePass.Domain/Entities/EntryEntity.cs +++ b/ModernKeePass.Domain/Entities/EntryEntity.cs @@ -7,17 +7,13 @@ namespace ModernKeePass.Domain.Entities { public class EntryEntity: BaseEntity { - public string UserName { get; set; } - public string Password { get; set; } - public string Url { get; set; } - public string Notes { get; set; } - public DateTimeOffset ExpirationDate { get; set; } - public Dictionary AdditionalFields { get; set; } = new Dictionary(); + public IEnumerable Fields { get; set; } = new List(); public IEnumerable History { get; set; } = new List(); + public Dictionary Attachments { get; set; } = new Dictionary(); + public DateTimeOffset ExpirationDate { get; set; } public Icon Icon { get; set; } public Color ForegroundColor { get; set; } public Color BackgroundColor { get; set; } public bool HasExpirationDate { get; set; } - public Dictionary Attachments { get; set; } = new Dictionary(); } } \ No newline at end of file diff --git a/ModernKeePass.Domain/Entities/FieldEntity.cs b/ModernKeePass.Domain/Entities/FieldEntity.cs new file mode 100644 index 0000000..3cd972b --- /dev/null +++ b/ModernKeePass.Domain/Entities/FieldEntity.cs @@ -0,0 +1,9 @@ +namespace ModernKeePass.Domain.Entities +{ + public class FieldEntity + { + public string Name { get; set; } + public string Value { get; set; } + public bool IsProtected { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Enums/EntryFieldName.cs b/ModernKeePass.Domain/Enums/EntryFieldName.cs index e94a425..0c9ed66 100644 --- a/ModernKeePass.Domain/Enums/EntryFieldName.cs +++ b/ModernKeePass.Domain/Enums/EntryFieldName.cs @@ -1,4 +1,6 @@ -namespace ModernKeePass.Domain.Enums +using System.Collections.Generic; + +namespace ModernKeePass.Domain.Enums { public static class EntryFieldName { @@ -12,5 +14,19 @@ public const string HasExpirationDate = nameof(HasExpirationDate); public const string BackgroundColor = nameof(BackgroundColor); public const string ForegroundColor = nameof(ForegroundColor); + + public static IEnumerable StandardFieldNames = new[] + { + Title, + UserName, + Password, + Url, + Notes, + Icon, + ExpirationDate, + HasExpirationDate, + BackgroundColor, + ForegroundColor + }; } } \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/Infrastructure.csproj b/ModernKeePass.Infrastructure/Infrastructure.csproj index bcf0d3d..7e4acc0 100644 --- a/ModernKeePass.Infrastructure/Infrastructure.csproj +++ b/ModernKeePass.Infrastructure/Infrastructure.csproj @@ -80,8 +80,7 @@ - - + diff --git a/ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs b/ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs deleted file mode 100644 index 973f4f0..0000000 --- a/ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs +++ /dev/null @@ -1,23 +0,0 @@ -using AutoMapper; -using ModernKeePass.Domain.Entities; -using ModernKeePassLib; - -namespace ModernKeePass.Infrastructure.KeePass -{ - public class GroupMappingProfile : Profile - { - public GroupMappingProfile() - { - CreateMap() - .ForMember(d => d.ParentId, opts => opts.MapFrom(s => s.ParentGroup.Uuid.ToHexString())) - .ForMember(d => d.ParentName, opts => opts.MapFrom(s => s.ParentGroup.Name)) - .ForMember(d => d.Id, opts => opts.MapFrom(s => s.Uuid.ToHexString())) - .ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name)) - .ForMember(d => d.Icon, opts => opts.MapFrom(s => IconMapper.MapPwIconToIcon(s.IconId))) - .ForMember(d => d.LastModificationDate, opts => opts.MapFrom(s => s.LastModificationTime)) - .ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries)) - .ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.Groups)) - .MaxDepth(2); - } - } -} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs index c91e497..8398d70 100644 --- a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs +++ b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs @@ -228,7 +228,7 @@ namespace ModernKeePass.Infrastructure.KeePass _pwDatabase.DeletedObjects.Add(new PwDeletedObject(BuildIdFromString(entityId), _dateTime.Now)); } - public void UpdateEntry(string entryId, string fieldName, object fieldValue) + public void UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected) { var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true); @@ -239,7 +239,7 @@ namespace ModernKeePass.Infrastructure.KeePass case EntryFieldName.Password: case EntryFieldName.Notes: case EntryFieldName.Url: - pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(true, fieldValue.ToString())); + pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(isProtected, fieldValue.ToString())); break; case EntryFieldName.HasExpirationDate: pwEntry.Expires = (bool)fieldValue; @@ -257,7 +257,7 @@ namespace ModernKeePass.Infrastructure.KeePass pwEntry.ForegroundColor = (Color)fieldValue; break; default: - pwEntry.Strings.Set(fieldName, new ProtectedString(true, fieldValue.ToString())); + pwEntry.Strings.Set(fieldName, new ProtectedString(isProtected, fieldValue.ToString())); break; } } diff --git a/ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs b/ModernKeePass.Infrastructure/KeePass/MappingProfiles.cs similarity index 53% rename from ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs rename to ModernKeePass.Infrastructure/KeePass/MappingProfiles.cs index 5c99915..592d09c 100644 --- a/ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs +++ b/ModernKeePass.Infrastructure/KeePass/MappingProfiles.cs @@ -4,34 +4,42 @@ using System.Linq; using AutoMapper; using ModernKeePass.Domain.Entities; using ModernKeePassLib; +using ModernKeePassLib.Security; namespace ModernKeePass.Infrastructure.KeePass { - public class EntryMappingProfile: Profile + public class MappingProfiles: Profile { - public EntryMappingProfile() + public MappingProfiles() { + CreateMap, FieldEntity>() + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Key)) + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Value.ReadString())) + .ForMember(dest => dest.IsProtected, opt => opt.MapFrom(src => src.Value.IsProtected)); + CreateMap() .ForMember(dest => dest.ParentId, opt => opt.MapFrom(src => src.ParentGroup.Uuid.ToHexString())) .ForMember(dest => dest.ParentName, opt => opt.MapFrom(src => src.ParentGroup.Name)) .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Uuid.ToHexString())) - .ForMember(dest => dest.Name, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.TitleField))) - .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UserNameField))) - .ForMember(dest => dest.Password, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.PasswordField))) - .ForMember(dest => dest.Url, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UrlField))) - .ForMember(dest => dest.Notes, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.NotesField))) + .ForMember(dest => dest.Fields, opt => opt.MapFrom(src => src.Strings)) .ForMember(dest => dest.ForegroundColor, opt => opt.MapFrom(src => src.ForegroundColor)) .ForMember(dest => dest.BackgroundColor, opt => opt.MapFrom(src => src.BackgroundColor)) .ForMember(dest => dest.ExpirationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.ExpiryTime))) .ForMember(dest => dest.HasExpirationDate, opt => opt.MapFrom(src => src.Expires)) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => IconMapper.MapPwIconToIcon(src.IconId))) - .ForMember(dest => dest.AdditionalFields, opt => opt.MapFrom(src => - src.Strings.Where(s => !PwDefs.GetStandardFields().Contains(s.Key)) - .ToDictionary(s => s.Key, s => GetEntryValue(src, s.Key)))) .ForMember(dest => dest.LastModificationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.LastModificationTime))) .ForMember(dest => dest.Attachments, opt => opt.MapFrom(src => src.Binaries.Select(b => new KeyValuePair (b.Key, b.Value.ReadData()) ))); + + CreateMap() + .ForMember(d => d.ParentId, opts => opts.MapFrom(s => s.ParentGroup.Uuid.ToHexString())) + .ForMember(d => d.ParentName, opts => opts.MapFrom(s => s.ParentGroup.Name)) + .ForMember(d => d.Id, opts => opts.MapFrom(s => s.Uuid.ToHexString())) + .ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name)) + .ForMember(d => d.Icon, opts => opts.MapFrom(s => IconMapper.MapPwIconToIcon(s.IconId))) + .ForMember(d => d.LastModificationDate, opts => opts.MapFrom(s => s.LastModificationTime)) + .ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries)) + .ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.Groups)) + .MaxDepth(2); } - - private string GetEntryValue(PwEntry entry, string key) => entry.Strings.GetSafe(key).ReadString(); } } \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/project.json b/ModernKeePass.Infrastructure/project.json index fdab3b7..52c35b1 100644 --- a/ModernKeePass.Infrastructure/project.json +++ b/ModernKeePass.Infrastructure/project.json @@ -3,7 +3,7 @@ "dependencies": { "AutoMapper": "5.2.0", "Microsoft.NETCore.Portable.Compatibility": "1.0.1", - "ModernKeePassLib": "2.44.3", + "ModernKeePassLib": "2.45.1", "NETStandard.Library": "2.0.3" }, "frameworks": { diff --git a/ModernKeePass/Strings/en-US/CodeBehind.resw b/ModernKeePass/Strings/en-US/CodeBehind.resw index a533d92..3b04d80 100644 --- a/ModernKeePass/Strings/en-US/CodeBehind.resw +++ b/ModernKeePass/Strings/en-US/CodeBehind.resw @@ -276,4 +276,10 @@ Key + + Database size is too big for auto-save on suspend. Please save your changes before closing the app ! + + + Attention + \ No newline at end of file diff --git a/ModernKeePass/Strings/en-US/Resources.resw b/ModernKeePass/Strings/en-US/Resources.resw index e0ed937..715bc93 100644 --- a/ModernKeePass/Strings/en-US/Resources.resw +++ b/ModernKeePass/Strings/en-US/Resources.resw @@ -376,7 +376,7 @@ New group - Navigation + Groups History @@ -546,4 +546,16 @@ Invalid field name + + Enable protection ? + + + No + + + Yes + + + Restore + \ No newline at end of file diff --git a/ModernKeePass/Strings/fr-FR/CodeBehind.resw b/ModernKeePass/Strings/fr-FR/CodeBehind.resw index c8e960a..41e78b6 100644 --- a/ModernKeePass/Strings/fr-FR/CodeBehind.resw +++ b/ModernKeePass/Strings/fr-FR/CodeBehind.resw @@ -279,4 +279,10 @@ Ajouter un champ + + La base de données est trop grosse pour sauvegarder automatiquement lors de la suspension. Pensez à bien sauvegarder vos changements avant de fermer l'app ! + + + Attention + \ No newline at end of file diff --git a/ModernKeePass/Strings/fr-FR/Resources.resw b/ModernKeePass/Strings/fr-FR/Resources.resw index 74a1271..d38b04e 100644 --- a/ModernKeePass/Strings/fr-FR/Resources.resw +++ b/ModernKeePass/Strings/fr-FR/Resources.resw @@ -379,7 +379,7 @@ Nouveau groupe - Navigation + Groupes Historique @@ -543,4 +543,16 @@ Nom de champ invalide + + Activer la protection ? + + + Non + + + Oui + + + Restaurer + \ No newline at end of file diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs index 1470c4c..18a320c 100644 --- a/ModernKeePass/ViewModels/EntryDetailVm.cs +++ b/ModernKeePass/ViewModels/EntryDetailVm.cs @@ -68,7 +68,7 @@ namespace ModernKeePass.ViewModels } public ObservableCollection History { get; private set; } - public ObservableCollection AdditionalFields { get; private set; } + public ObservableCollection AdditionalFields { get; private set; } public ObservableCollection Attachments { get; private set; } /// @@ -85,8 +85,8 @@ namespace ModernKeePass.ViewModels if (value != null) { AdditionalFields = - new ObservableCollection( - SelectedItem.AdditionalFields.Select(f => new FieldVm(f.Key, f.Value))); + new ObservableCollection( + SelectedItem.AdditionalFields.Select(f => new EntryFieldVm(f.Name, f.Value, f.IsProtected))); Attachments = new ObservableCollection(SelectedItem.Attachments.Select(f => new Attachment { Name = f.Key, @@ -131,32 +131,32 @@ namespace ModernKeePass.ViewModels public string Title { - get { return SelectedItem.Title; } + get { return SelectedItem.Title.Value; } set { - SelectedItem.Title = value; - SetFieldValue(nameof(Title), value).Wait(); + SelectedItem.Title.Value = value; + SetFieldValue(nameof(Title), value, true).Wait(); } } public string UserName { - get { return SelectedItem.Username; } + get { return SelectedItem.Username.Value; } set { - SelectedItem.Username = value; - SetFieldValue(nameof(UserName), value).Wait(); + SelectedItem.Username.Value = value; + SetFieldValue(nameof(UserName), value, true).Wait(); RaisePropertyChanged(nameof(UserName)); } } public string Password { - get { return SelectedItem.Password; } + get { return SelectedItem.Password.Value; } set { - SelectedItem.Password = value; - SetFieldValue(nameof(Password), value).Wait(); + SelectedItem.Password.Value = value; + SetFieldValue(nameof(Password), value, true).Wait(); RaisePropertyChanged(nameof(Password)); RaisePropertyChanged(nameof(PasswordComplexityIndicator)); } @@ -164,22 +164,22 @@ namespace ModernKeePass.ViewModels public string Url { - get { return SelectedItem.Url; } + get { return SelectedItem.Url.Value; } set { - SelectedItem.Url = value; - SetFieldValue(nameof(Url), value).Wait(); + SelectedItem.Url.Value = value; + SetFieldValue(nameof(Url), value, true).Wait(); RaisePropertyChanged(nameof(Url)); } } public string Notes { - get { return SelectedItem.Notes; } + get { return SelectedItem.Notes.Value; } set { - SelectedItem.Notes = value; - SetFieldValue(nameof(Notes), value).Wait(); + SelectedItem.Notes.Value = value; + SetFieldValue(nameof(Notes), value, true).Wait(); } } @@ -189,7 +189,7 @@ namespace ModernKeePass.ViewModels set { SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString()); - SetFieldValue(nameof(Icon), SelectedItem.Icon).Wait(); + SetFieldValue(nameof(Icon), SelectedItem.Icon, true).Wait(); } } @@ -201,7 +201,7 @@ namespace ModernKeePass.ViewModels if (!HasExpirationDate) return; SelectedItem.ExpirationDate = value.Date; - SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait(); + SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, true).Wait(); } } @@ -213,7 +213,7 @@ namespace ModernKeePass.ViewModels if (!HasExpirationDate) return; SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value); - SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait(); + SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, true).Wait(); } } @@ -223,7 +223,7 @@ namespace ModernKeePass.ViewModels set { SelectedItem.HasExpirationDate = value; - SetFieldValue(nameof(HasExpirationDate), value).Wait(); + SetFieldValue(nameof(HasExpirationDate), value, true).Wait(); RaisePropertyChanged(nameof(HasExpirationDate)); } } @@ -234,7 +234,7 @@ namespace ModernKeePass.ViewModels set { SelectedItem.BackgroundColor = value.ToColor(); - SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor).Wait(); + SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor, true).Wait(); } } @@ -244,7 +244,7 @@ namespace ModernKeePass.ViewModels set { SelectedItem.ForegroundColor = value.ToColor(); - SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor).Wait(); + SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor, true).Wait(); } } @@ -269,7 +269,7 @@ namespace ModernKeePass.ViewModels public RelayCommand GoBackCommand { get; } public RelayCommand GoToParentCommand { get; set; } public RelayCommand AddAdditionalField { get; set; } - public RelayCommand DeleteAdditionalField { get; set; } + public RelayCommand DeleteAdditionalField { get; set; } public RelayCommand OpenAttachmentCommand { get; set; } public RelayCommand AddAttachmentCommand { get; set; } public RelayCommand DeleteAttachmentCommand { get; set; } @@ -308,14 +308,14 @@ namespace ModernKeePass.ViewModels GoBackCommand = new RelayCommand(() => _navigation.GoBack()); GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id)); AddAdditionalField = new RelayCommand(AddField, () => IsCurrentEntry); - DeleteAdditionalField = new RelayCommand(async field => await DeleteField(field), field => field != null && IsCurrentEntry); + DeleteAdditionalField = new RelayCommand(async field => await DeleteField(field), field => field != null && IsCurrentEntry); OpenAttachmentCommand = new RelayCommand(async attachment => await OpenAttachment(attachment)); AddAttachmentCommand = new RelayCommand(async () => await AddAttachment(), () => IsCurrentEntry); DeleteAttachmentCommand = new RelayCommand(async attachment => await DeleteAttachment(attachment), _ => IsCurrentEntry); MessengerInstance.Register(this, _ => SaveCommand.RaiseCanExecuteChanged()); - MessengerInstance.Register(this, async message => await SetFieldValue(message.FieldName, message.FieldValue)); - MessengerInstance.Register(this, async message => await UpdateFieldName(message.OldName, message.NewName, message.Value)); + MessengerInstance.Register(this, async message => await SetFieldValue(message.FieldName, message.FieldValue, message.IsProtected)); + MessengerInstance.Register(this, async message => await UpdateFieldName(message.OldName, message.NewName, message.Value, message.IsProtected)); } public async Task Initialize(string entryId) @@ -348,6 +348,7 @@ namespace ModernKeePass.ViewModels }); RaisePropertyChanged(nameof(IsRevealPasswordEnabled)); } + public async Task AddHistory() { if (_isDirty) await _mediator.Send(new AddHistoryCommand { Entry = History[0] }); @@ -365,26 +366,26 @@ namespace ModernKeePass.ViewModels GoToGroup(destination); } - private async Task SetFieldValue(string fieldName, object value) + private async Task SetFieldValue(string fieldName, object value, bool isProtected) { - await _mediator.Send(new UpsertFieldCommand { EntryId = Id, FieldName = fieldName, FieldValue = value }); + await _mediator.Send(new UpsertFieldCommand { EntryId = Id, FieldName = fieldName, FieldValue = value, IsProtected = isProtected}); SaveCommand.RaiseCanExecuteChanged(); _isDirty = true; } - private async Task UpdateFieldName(string oldName, string newName, string value) + private async Task UpdateFieldName(string oldName, string newName, string value, bool isProtected) { if (!string.IsNullOrEmpty(oldName)) await _mediator.Send(new DeleteFieldCommand { EntryId = Id, FieldName = oldName }); - await SetFieldValue(newName, value); + await SetFieldValue(newName, value, isProtected); } private void AddField() { - AdditionalFields.Add(new FieldVm(string.Empty, string.Empty)); + AdditionalFields.Add(new EntryFieldVm(string.Empty, string.Empty, false)); AdditionalFieldSelectedIndex = AdditionalFields.Count - 1; } - private async Task DeleteField(FieldVm field) + private async Task DeleteField(EntryFieldVm field) { AdditionalFields.Remove(field); if (!string.IsNullOrEmpty(field.Name)) diff --git a/ModernKeePass/ViewModels/GroupDetailVm.cs b/ModernKeePass/ViewModels/GroupDetailVm.cs index c57d3d3..e156a96 100644 --- a/ModernKeePass/ViewModels/GroupDetailVm.cs +++ b/ModernKeePass/ViewModels/GroupDetailVm.cs @@ -43,7 +43,7 @@ namespace ModernKeePass.ViewModels public bool IsNotRoot => Database.RootGroupId != _group.Id; public IOrderedEnumerable> EntriesZoomedOut => from e in Entries - group e by e.Title.ToUpper().FirstOrDefault() into grp + group e by e.Title.Name.ToUpper().FirstOrDefault() into grp orderby grp.Key select grp; diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml index cd1cf3f..29ef1d4 100644 --- a/ModernKeePass/Views/EntryDetailPage.xaml +++ b/ModernKeePass/Views/EntryDetailPage.xaml @@ -441,8 +441,8 @@ - - + + @@ -481,40 +481,51 @@ - - - - - - - - - - - - - - -