mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
Added lots of commands
Simplified KeePass client
This commit is contained in:
@@ -65,8 +65,19 @@
|
||||
<Compile Include="Database\Queries\IsDatabaseOpen\IsDatabaseOpenQuery.cs" />
|
||||
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQuery.cs" />
|
||||
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQueryValidator.cs" />
|
||||
<Compile Include="Database\Queries\ReOpenDatabase\ReOpenDatabaseQuery.cs" />
|
||||
<Compile Include="DependencyInjection.cs" />
|
||||
<Compile Include="Entry\Models\EntryVm.cs" />
|
||||
<Compile Include="Group\Commands\AddEntry\AddEntryCommand.cs" />
|
||||
<Compile Include="Group\Commands\AddGroup\AddGroupCommand.cs" />
|
||||
<Compile Include="Group\Commands\CreateEntry\CreateEntryCommand.cs" />
|
||||
<Compile Include="Group\Commands\CreateGroup\CreateGroupCommand.cs" />
|
||||
<Compile Include="Group\Commands\DeleteEntry\DeleteEntryCommand.cs" />
|
||||
<Compile Include="Group\Commands\DeleteGroup\DeleteGroupCommand.cs" />
|
||||
<Compile Include="Group\Commands\RemoveEntry\RemoveEntryCommand.cs" />
|
||||
<Compile Include="Group\Commands\RemoveGroup\RemoveGroupCommand.cs" />
|
||||
<Compile Include="Group\Commands\SortEntries\SortEntriesCommand.cs" />
|
||||
<Compile Include="Group\Commands\SortGroups\SortGroupsCommand.cs" />
|
||||
<Compile Include="Group\Models\GroupVm.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Content Include="Services\CryptographyService.cs" />
|
||||
@@ -79,14 +90,13 @@
|
||||
<Content Include="Services\SettingsService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Entry\Commands\UpdateEntry\" />
|
||||
<Folder Include="Entry\Queries\" />
|
||||
<Folder Include="Group\Commands\CreateEntry\" />
|
||||
<Folder Include="Group\Commands\CreateGroup\" />
|
||||
<Folder Include="Group\Commands\DeleteEntry\" />
|
||||
<Folder Include="Group\Commands\DeleteGroup\" />
|
||||
<Folder Include="Entry\Commands\SetFieldValue\" />
|
||||
<Folder Include="Entry\Queries\GetEntry\" />
|
||||
<Folder Include="Group\Commands\UpdateGroup\" />
|
||||
<Folder Include="Group\Queries\" />
|
||||
<Folder Include="Group\Queries\GetGroup\" />
|
||||
<Folder Include="Parameters\Commands\SetCipher\" />
|
||||
<Folder Include="Parameters\Commands\SetCompression\" />
|
||||
<Folder Include="Parameters\Commands\SetKeyDerivation\" />
|
||||
<Folder Include="Resources\Commands\" />
|
||||
<Folder Include="Resources\Queries\" />
|
||||
<Folder Include="Settings\" />
|
||||
|
@@ -8,22 +8,34 @@ namespace ModernKeePass.Application.Common.Interfaces
|
||||
{
|
||||
bool IsOpen { get; }
|
||||
string Name { get; }
|
||||
GroupEntity RecycleBin { get; set; }
|
||||
BaseEntity Cipher { get; set; }
|
||||
BaseEntity KeyDerivation { get; set; }
|
||||
string Compression { get; set; }
|
||||
GroupEntity RootGroup { get; }
|
||||
|
||||
Task<DatabaseEntity> Open(FileInfo fileInfo, Credentials credentials);
|
||||
Task<DatabaseEntity> Create(FileInfo fileInfo, Credentials credentials);
|
||||
string RecycleBinId { get; set; }
|
||||
string CipherId { get; set; }
|
||||
string KeyDerivationId { get; set; }
|
||||
string Compression { get; set; }
|
||||
bool IsRecycleBinEnabled { get; }
|
||||
|
||||
Task<GroupEntity> Open(FileInfo fileInfo, Credentials credentials);
|
||||
Task<GroupEntity> ReOpen();
|
||||
Task<GroupEntity> Create(FileInfo fileInfo, Credentials credentials);
|
||||
Task SaveDatabase();
|
||||
Task SaveDatabase(FileInfo FileInfo);
|
||||
Task UpdateCredentials(Credentials credentials);
|
||||
void CloseDatabase();
|
||||
Task AddEntry(GroupEntity parentGroup, EntryEntity entity);
|
||||
Task AddGroup(GroupEntity parentGroup, GroupEntity entity);
|
||||
Task UpdateEntry(EntryEntity entity);
|
||||
Task UpdateGroup(GroupEntity entity);
|
||||
Task DeleteEntry(EntryEntity entity);
|
||||
Task DeleteGroup(GroupEntity entity);
|
||||
|
||||
Task AddEntry(string parentGroupId, string entryId);
|
||||
Task AddGroup(string parentGroupId, string groupId);
|
||||
Task UpdateEntry(string entryId);
|
||||
Task UpdateGroup(string groupId);
|
||||
Task RemoveEntry(string parentGroupId, string entryId);
|
||||
Task RemoveGroup(string parentGroupId, string groupId);
|
||||
EntryEntity CreateEntry(string parentGroupId);
|
||||
GroupEntity CreateGroup(string parentGroupId, string nameId, bool isRecycleBin = false);
|
||||
Task DeleteEntry(string entryId);
|
||||
Task DeleteGroup(string groupId);
|
||||
|
||||
void SortEntries(string groupId);
|
||||
void SortSubGroups(string groupId);
|
||||
}
|
||||
}
|
@@ -9,7 +9,6 @@ namespace ModernKeePass.Application.Common.Mappings
|
||||
{
|
||||
public void ApplyMappings()
|
||||
{
|
||||
new DatabaseVm().Mapping(this);
|
||||
new EntryVm().Mapping(this);
|
||||
new GroupVm().Mapping(this);
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Models;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Dtos;
|
||||
@@ -10,12 +9,12 @@ using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Database.Commands.CreateDatabase
|
||||
{
|
||||
public class CreateDatabaseCommand : IRequest<DatabaseVm>
|
||||
public class CreateDatabaseCommand : IRequest<GroupVm>
|
||||
{
|
||||
public FileInfo FileInfo { get; set; }
|
||||
public Credentials Credentials { get; set; }
|
||||
|
||||
public class CreateDatabaseCommandHandler : IAsyncRequestHandler<CreateDatabaseCommand, DatabaseVm>
|
||||
public class CreateDatabaseCommandHandler : IAsyncRequestHandler<CreateDatabaseCommand, GroupVm>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
@@ -28,19 +27,13 @@ namespace ModernKeePass.Application.Database.Commands.CreateDatabase
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<DatabaseVm> Handle(CreateDatabaseCommand message)
|
||||
public async Task<GroupVm> Handle(CreateDatabaseCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (isDatabaseOpen) throw new DatabaseOpenException();
|
||||
|
||||
var database = await _database.Create(message.FileInfo, message.Credentials);
|
||||
var databaseVm = new DatabaseVm
|
||||
{
|
||||
IsOpen = true,
|
||||
Name = database.Name,
|
||||
RootGroup = _mapper.Map<GroupVm>(database.RootGroupEntity)
|
||||
};
|
||||
return databaseVm;
|
||||
var rootGroup = await _database.Create(message.FileInfo, message.Credentials);
|
||||
return _mapper.Map<GroupVm>(rootGroup);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,21 +1,16 @@
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Application.Common.Mappings;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
|
||||
namespace ModernKeePass.Application.Database.Models
|
||||
{
|
||||
public class DatabaseVm: IMapFrom<DatabaseEntity>
|
||||
public class DatabaseVm
|
||||
{
|
||||
public bool IsOpen { get; set; }
|
||||
public string Name { get; set; }
|
||||
public GroupVm RootGroup { get; set; }
|
||||
|
||||
public void Mapping(Profile profile)
|
||||
{
|
||||
profile.CreateMap<DatabaseEntity, DatabaseVm>()
|
||||
.ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name))
|
||||
.ForMember(d => d.RootGroup, opts => opts.MapFrom(s => s.RootGroupEntity));
|
||||
}
|
||||
public string RecycleBinId { get; set; }
|
||||
public bool IsRecycleBinEnabled { get; set; }
|
||||
public string Compression { get; set; }
|
||||
public string CipherId { get; set; }
|
||||
public string KeyDerivationId { get; set; }
|
||||
}
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
using MediatR;
|
||||
using AutoMapper;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Models;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
|
||||
namespace ModernKeePass.Application.Database.Queries.GetDatabase
|
||||
{
|
||||
@@ -9,10 +11,12 @@ namespace ModernKeePass.Application.Database.Queries.GetDatabase
|
||||
public class GetDatabaseQueryHandler : IRequestHandler<GetDatabaseQuery, DatabaseVm>
|
||||
{
|
||||
private readonly IDatabaseProxy _databaseProxy;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public GetDatabaseQueryHandler(IDatabaseProxy databaseProxy)
|
||||
public GetDatabaseQueryHandler(IDatabaseProxy databaseProxy, IMapper mapper)
|
||||
{
|
||||
_databaseProxy = databaseProxy;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public DatabaseVm Handle(GetDatabaseQuery request)
|
||||
@@ -20,7 +24,13 @@ namespace ModernKeePass.Application.Database.Queries.GetDatabase
|
||||
var database = new DatabaseVm
|
||||
{
|
||||
IsOpen = _databaseProxy.IsOpen,
|
||||
Name = _databaseProxy.Name
|
||||
Name = _databaseProxy.Name,
|
||||
RootGroup = _mapper.Map<GroupVm>(_databaseProxy.RootGroup),
|
||||
IsRecycleBinEnabled = _databaseProxy.IsRecycleBinEnabled,
|
||||
RecycleBinId = _databaseProxy.RecycleBinId,
|
||||
Compression = _databaseProxy.Compression,
|
||||
CipherId = _databaseProxy.CipherId,
|
||||
KeyDerivationId = _databaseProxy.CipherId
|
||||
};
|
||||
return database;
|
||||
}
|
||||
|
@@ -1,9 +1,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Models;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Dtos;
|
||||
@@ -11,12 +9,12 @@ using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Database.Queries.OpenDatabase
|
||||
{
|
||||
public class OpenDatabaseQuery: IRequest<DatabaseVm>
|
||||
public class OpenDatabaseQuery: IRequest<GroupVm>
|
||||
{
|
||||
public FileInfo FileInfo { get; set; }
|
||||
public Credentials Credentials { get; set; }
|
||||
|
||||
public class OpenDatabaseQueryHandler : IAsyncRequestHandler<OpenDatabaseQuery, DatabaseVm>
|
||||
public class OpenDatabaseQueryHandler : IAsyncRequestHandler<OpenDatabaseQuery, GroupVm>
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IMediator _mediator;
|
||||
@@ -29,19 +27,13 @@ namespace ModernKeePass.Application.Database.Queries.OpenDatabase
|
||||
_databaseProxy = databaseProxy;
|
||||
}
|
||||
|
||||
public async Task<DatabaseVm> Handle(OpenDatabaseQuery request)
|
||||
public async Task<GroupVm> Handle(OpenDatabaseQuery request)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (isDatabaseOpen) throw new DatabaseOpenException();
|
||||
|
||||
var database = await _databaseProxy.Open(request.FileInfo, request.Credentials);
|
||||
var databaseVm = new DatabaseVm
|
||||
{
|
||||
IsOpen = true,
|
||||
Name = database.Name,
|
||||
RootGroup = _mapper.Map<GroupVm>(database.RootGroupEntity)
|
||||
};
|
||||
return databaseVm;
|
||||
var rootGroup = await _databaseProxy.Open(request.FileInfo, request.Credentials);
|
||||
return _mapper.Map<GroupVm>(rootGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Database.Queries.ReOpenDatabase
|
||||
{
|
||||
public class ReOpenDatabaseQuery: IRequest<GroupVm>
|
||||
{
|
||||
public class ReOpenDatabaseQueryHandler : IAsyncRequestHandler<ReOpenDatabaseQuery, GroupVm>
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IDatabaseProxy _databaseProxy;
|
||||
|
||||
public ReOpenDatabaseQueryHandler(IMapper mapper, IMediator mediator, IDatabaseProxy databaseProxy)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_mediator = mediator;
|
||||
_databaseProxy = databaseProxy;
|
||||
}
|
||||
|
||||
public async Task<GroupVm> Handle(ReOpenDatabaseQuery request)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
var rootGroup = await _databaseProxy.ReOpen();
|
||||
return _mapper.Map<GroupVm>(rootGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Application.Common.Mappings;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
@@ -10,15 +12,33 @@ namespace ModernKeePass.Application.Entry.Models
|
||||
{
|
||||
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 Uri Url { get; set; }
|
||||
public Dictionary<string, string> AdditionalFields { get; set; }
|
||||
public IEnumerable<EntryEntity> History { get; set; }
|
||||
public Icon Icon { get; set; }
|
||||
public Color ForegroundColor { get; set; }
|
||||
public Color BackgroundColor { get; set; }
|
||||
public bool HasExpirationDate { get; internal set; }
|
||||
public DateTimeOffset ExpirationDate { get; internal set; }
|
||||
public DateTimeOffset ModificationDate { get; internal set; }
|
||||
|
||||
public void Mapping(Profile profile)
|
||||
{
|
||||
profile.CreateMap<EntryEntity, EntryVm>()
|
||||
.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.History, opts => opts.MapFrom(s => s.History))
|
||||
.ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate))
|
||||
.ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate))
|
||||
.ForMember(d => d.ModificationDate, opts => opts.MapFrom(s => s.LastModificationDate))
|
||||
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.Icon))
|
||||
.ForMember(d => d.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor))
|
||||
.ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor));
|
||||
|
@@ -0,0 +1,54 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.AddEntry
|
||||
{
|
||||
public class AddEntryCommand : IRequest
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
public EntryVm Entry { get; set; }
|
||||
|
||||
public class AddEntryCommandHandler : IAsyncRequestHandler<AddEntryCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public AddEntryCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(AddEntryCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
/*var entryEntity = new EntryEntity
|
||||
{
|
||||
Id = message.Entry.Id,
|
||||
Name = message.Entry.Title,
|
||||
UserName = message.Entry.Username,
|
||||
Password = message.Entry.Password,
|
||||
Url = message.Entry.Url,
|
||||
Notes = message.Entry.Notes,
|
||||
HasExpirationDate = message.Entry.HasExpirationDate,
|
||||
ExpirationDate = message.Entry.ExpirationDate,
|
||||
LastModificationDate = message.Entry.ModificationDate,
|
||||
BackgroundColor = message.Entry.BackgroundColor,
|
||||
ForegroundColor = message.Entry.ForegroundColor,
|
||||
Icon = message.Entry.Icon,
|
||||
AdditionalFields = message.Entry.AdditionalFields,
|
||||
History = message.Entry.History
|
||||
};*/
|
||||
|
||||
await _database.AddEntry(message.ParentGroup.Id, message.Entry.Id);
|
||||
message.ParentGroup.Entries.Add(message.Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.AddGroup
|
||||
{
|
||||
public class AddGroupCommand : IRequest
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
public GroupVm Group { get; set; }
|
||||
|
||||
public class AddGroupCommandHandler : IAsyncRequestHandler<AddGroupCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public AddGroupCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(AddGroupCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
await _database.AddGroup(message.ParentGroup.Id, message.Group.Id);
|
||||
message.ParentGroup.SubGroups.Add(message.Group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.CreateEntry
|
||||
{
|
||||
public class CreateEntryCommand : IRequest<EntryVm>
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
|
||||
public class CreateEntryCommandHandler : IAsyncRequestHandler<CreateEntryCommand, EntryVm>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CreateEntryCommandHandler(IDatabaseProxy database, IMediator mediator, IMapper mapper)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<EntryVm> Handle(CreateEntryCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
var entry = _database.CreateEntry(message.ParentGroup.Id);
|
||||
var entryVm = _mapper.Map<EntryVm>(entry);
|
||||
message.ParentGroup.Entries.Add(entryVm);
|
||||
return entryVm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.CreateGroup
|
||||
{
|
||||
public class CreateGroupCommand : IRequest<GroupVm>
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsRecycleBin { get; set; }
|
||||
|
||||
public class CreateGroupCommandHandler : IAsyncRequestHandler<CreateGroupCommand, GroupVm>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CreateGroupCommandHandler(IDatabaseProxy database, IMediator mediator, IMapper mapper)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<GroupVm> Handle(CreateGroupCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
var group = _database.CreateGroup(message.ParentGroup.Id, message.Name, message.IsRecycleBin);
|
||||
var groupVm = _mapper.Map<GroupVm>(group);
|
||||
message.ParentGroup.SubGroups.Add(groupVm);
|
||||
return groupVm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.DeleteEntry
|
||||
{
|
||||
public class DeleteEntryCommand : IRequest
|
||||
{
|
||||
public EntryVm Entry { get; set; }
|
||||
|
||||
public class DeleteEntryCommandHandler : IAsyncRequestHandler<DeleteEntryCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public DeleteEntryCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(DeleteEntryCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
await _database.DeleteEntry(message.Entry.Id);
|
||||
message.Entry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.DeleteGroup
|
||||
{
|
||||
public class DeleteGroupCommand : IRequest
|
||||
{
|
||||
public GroupVm Group { get; set; }
|
||||
|
||||
public class DeleteGroupCommandHandler : IAsyncRequestHandler<DeleteGroupCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public DeleteGroupCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(DeleteGroupCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
await _database.DeleteGroup(message.Group.Id);
|
||||
message.Group = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.RemoveEntry
|
||||
{
|
||||
public class RemoveEntryCommand : IRequest
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
public EntryVm Entry { get; set; }
|
||||
|
||||
public class RemoveEntryCommandHandler : IAsyncRequestHandler<RemoveEntryCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public RemoveEntryCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(RemoveEntryCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
await _database.RemoveEntry(message.ParentGroup.Id, message.Entry.Id);
|
||||
message.ParentGroup.Entries.Remove(message.Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.RemoveGroup
|
||||
{
|
||||
public class RemoveGroupCommand : IRequest
|
||||
{
|
||||
public GroupVm ParentGroup { get; set; }
|
||||
public GroupVm Group { get; set; }
|
||||
|
||||
public class RemoveGroupCommandHandler : IAsyncRequestHandler<RemoveGroupCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public RemoveGroupCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(RemoveGroupCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
await _database.RemoveGroup(message.ParentGroup.Id, message.Group.Id);
|
||||
message.ParentGroup.SubGroups.Remove(message.Group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.SortEntries
|
||||
{
|
||||
public class SortEntriesCommand : IRequest
|
||||
{
|
||||
public GroupVm Group { get; set; }
|
||||
|
||||
public class SortEntriesCommandHandler : IAsyncRequestHandler<SortEntriesCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public SortEntriesCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(SortEntriesCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
_database.SortEntries(message.Group.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Database.Queries.IsDatabaseOpen;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Group.Commands.SortGroups
|
||||
{
|
||||
public class SortGroupsCommand : IRequest
|
||||
{
|
||||
public GroupVm Group { get; set; }
|
||||
|
||||
public class SortGroupsCommandHandler : IAsyncRequestHandler<SortGroupsCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public SortGroupsCommandHandler(IDatabaseProxy database, IMediator mediator)
|
||||
{
|
||||
_database = database;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task Handle(SortGroupsCommand message)
|
||||
{
|
||||
var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery());
|
||||
if (!isDatabaseOpen) throw new DatabaseClosedException();
|
||||
|
||||
_database.SortSubGroups(message.Group.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Application.Common.Mappings;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
@@ -13,8 +13,6 @@ namespace ModernKeePass.Application.Group.Models
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public Icon Icon { get; set; }
|
||||
public Color ForegroundColor { get; set; }
|
||||
public Color BackgroundColor { get; set; }
|
||||
public List<GroupVm> SubGroups { get; set; } = new List<GroupVm>();
|
||||
public List<EntryVm> Entries { get; set; } = new List<EntryVm>();
|
||||
|
||||
@@ -24,9 +22,7 @@ namespace ModernKeePass.Application.Group.Models
|
||||
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id))
|
||||
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Name))
|
||||
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.Icon))
|
||||
.ForMember(d => d.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor))
|
||||
.ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor))
|
||||
.ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries))
|
||||
.ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries.OrderBy(e => e.Name)))
|
||||
.ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.SubGroups));
|
||||
}
|
||||
}
|
||||
|
@@ -44,7 +44,6 @@
|
||||
<Compile Include="Dtos\FileInfo.cs" />
|
||||
<Compile Include="Dtos\PasswordGenerationOptions.cs" />
|
||||
<Compile Include="Entities\BaseEntity.cs" />
|
||||
<Compile Include="Entities\DatabaseEntity.cs" />
|
||||
<Compile Include="Entities\EntryEntity.cs" />
|
||||
<Compile Include="Entities\GroupEntity.cs" />
|
||||
<Compile Include="Enums\CredentialStatusTypes.cs" />
|
||||
@@ -54,8 +53,10 @@
|
||||
<Compile Include="Exceptions\DatabaseOpenException.cs" />
|
||||
<Compile Include="Exceptions\NavigationException.cs" />
|
||||
<Compile Include="Exceptions\SaveException.cs" />
|
||||
<Compile Include="Interfaces\IDateTime.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace ModernKeePass.Domain.Entities
|
||||
{
|
||||
@@ -7,8 +6,6 @@ namespace ModernKeePass.Domain.Entities
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Color ForegroundColor { get; set; }
|
||||
public Color BackgroundColor { get; set; }
|
||||
public DateTimeOffset LastModificationDate { get; set; }
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
namespace ModernKeePass.Domain.Entities
|
||||
{
|
||||
public class DatabaseEntity
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public GroupEntity RootGroupEntity { get; set; }
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using ModernKeePass.Domain.Enums;
|
||||
|
||||
namespace ModernKeePass.Domain.Entities
|
||||
@@ -12,8 +13,10 @@ namespace ModernKeePass.Domain.Entities
|
||||
public string Notes { get; set; }
|
||||
public DateTimeOffset ExpirationDate { get; set; }
|
||||
public Dictionary<string, string> AdditionalFields { get; set; } = new Dictionary<string, string>();
|
||||
public IEnumerable<EntryEntity> History { get; set; }
|
||||
public IEnumerable<EntryEntity> History { get; set; } = new List<EntryEntity>();
|
||||
public Icon Icon { get; set; }
|
||||
public Color ForegroundColor { get; set; }
|
||||
public Color BackgroundColor { get; set; }
|
||||
public bool HasExpirationDate { get; set; }
|
||||
}
|
||||
}
|
9
ModernKeePass.Domain/Interfaces/IDateTime.cs
Normal file
9
ModernKeePass.Domain/Interfaces/IDateTime.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace ModernKeePass.Domain.Interfaces
|
||||
{
|
||||
public interface IDateTime
|
||||
{
|
||||
DateTime Now { get; }
|
||||
}
|
||||
}
|
10
ModernKeePass.Infrastructure/Common/MachineDateTime.cs
Normal file
10
ModernKeePass.Infrastructure/Common/MachineDateTime.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using ModernKeePass.Domain.Interfaces;
|
||||
|
||||
namespace ModernKeePass.Infrastructure.Common
|
||||
{
|
||||
public class MachineDateTime: IDateTime
|
||||
{
|
||||
public DateTime Now => DateTime.Now;
|
||||
}
|
||||
}
|
@@ -40,10 +40,12 @@
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Common\MachineDateTime.cs" />
|
||||
<Compile Include="DependencyInjection.cs" />
|
||||
<Compile Include="InfrastructureModule.cs" />
|
||||
<Compile Include="File\CsvImportFormat.cs" />
|
||||
<Compile Include="KeePass\EntryMappingProfile.cs" />
|
||||
<Compile Include="KeePass\GroupMappingProfile.cs" />
|
||||
<Compile Include="KeePass\IconMapper.cs" />
|
||||
<Compile Include="KeePass\KeePassCryptographyClient.cs" />
|
||||
<Compile Include="KeePass\KeePassDatabaseClient.cs" />
|
||||
@@ -71,6 +73,7 @@
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
31
ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs
Normal file
31
ModernKeePass.Infrastructure/KeePass/GroupMappingProfile.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
using ModernKeePassLib;
|
||||
|
||||
namespace ModernKeePass.Infrastructure.KeePass
|
||||
{
|
||||
public class GroupMappingProfile : Profile
|
||||
{
|
||||
public GroupMappingProfile()
|
||||
{
|
||||
FromModelToDto();
|
||||
FromDtoToModel();
|
||||
}
|
||||
|
||||
private void FromDtoToModel()
|
||||
{
|
||||
CreateMap<PwGroup, GroupEntity>()
|
||||
.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));
|
||||
}
|
||||
|
||||
private void FromModelToDto()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,7 +7,6 @@ using ModernKeePass.Domain.Dtos;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
using ModernKeePassLib;
|
||||
using ModernKeePassLib.Cryptography.Cipher;
|
||||
using ModernKeePassLib.Cryptography.KeyDerivation;
|
||||
using ModernKeePassLib.Interfaces;
|
||||
using ModernKeePassLib.Keys;
|
||||
@@ -23,68 +22,41 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
private readonly IMapper _mapper;
|
||||
private readonly PwDatabase _pwDatabase = new PwDatabase();
|
||||
private string _fileAccessToken;
|
||||
private CompositeKey _compositeKey;
|
||||
private Credentials _credentials;
|
||||
|
||||
// Main information
|
||||
public bool IsOpen => (_pwDatabase?.IsOpen).GetValueOrDefault();
|
||||
public string Name => _pwDatabase?.Name;
|
||||
public GroupEntity RootGroup { get; set; }
|
||||
public GroupEntity RootGroup { get; private set; }
|
||||
|
||||
// Settings
|
||||
public GroupEntity RecycleBin
|
||||
public string RecycleBinId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pwDatabase.RecycleBinEnabled)
|
||||
{
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(_pwDatabase.RecycleBinUuid, true);
|
||||
var group = new GroupEntity
|
||||
{
|
||||
Id = pwGroup.Uuid.ToHexString(),
|
||||
Name = pwGroup.Name,
|
||||
Icon = IconMapper.MapPwIconToIcon(pwGroup.IconId),
|
||||
Entries = pwGroup.Entries.Select(e => _mapper.Map<EntryEntity>(e)).ToList(),
|
||||
SubGroups = pwGroup.Groups.Select(BuildHierarchy).ToList()
|
||||
};
|
||||
return group;
|
||||
return pwGroup.Uuid.ToHexString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
set { _pwDatabase.RecycleBinUuid = BuildIdFromString(value); }
|
||||
}
|
||||
}
|
||||
public BaseEntity Cipher
|
||||
public string CipherId
|
||||
{
|
||||
get
|
||||
{
|
||||
var cipher = CipherPool.GlobalPool.GetCipher(_pwDatabase.DataCipherUuid);
|
||||
return new BaseEntity
|
||||
{
|
||||
Id = cipher.CipherUuid.ToHexString(),
|
||||
Name = cipher.DisplayName
|
||||
};
|
||||
}
|
||||
set { _pwDatabase.DataCipherUuid = BuildIdFromString(value.Id); }
|
||||
get { return _pwDatabase.DataCipherUuid.ToHexString(); }
|
||||
set { _pwDatabase.DataCipherUuid = BuildIdFromString(value); }
|
||||
}
|
||||
|
||||
public BaseEntity KeyDerivation
|
||||
public string KeyDerivationId
|
||||
{
|
||||
get
|
||||
{
|
||||
var keyDerivation = KdfPool.Engines.First(e => e.Uuid.Equals(_pwDatabase.KdfParameters.KdfUuid));
|
||||
return new BaseEntity
|
||||
{
|
||||
Id = keyDerivation.Uuid.ToHexString(),
|
||||
Name = keyDerivation.Name
|
||||
};
|
||||
}
|
||||
get { return _pwDatabase.KdfParameters.KdfUuid.ToHexString(); }
|
||||
set
|
||||
{
|
||||
_pwDatabase.KdfParameters = KdfPool.Engines
|
||||
.FirstOrDefault(e => e.Uuid.Equals(BuildIdFromString(value.Name)))?.GetDefaultParameters();
|
||||
.FirstOrDefault(e => e.Uuid.Equals(BuildIdFromString(value)))?.GetDefaultParameters();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +66,8 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
set { _pwDatabase.Compression = (PwCompressionAlgorithm) Enum.Parse(typeof(PwCompressionAlgorithm), value); }
|
||||
}
|
||||
|
||||
public bool IsRecycleBinEnabled => _pwDatabase.RecycleBinEnabled;
|
||||
|
||||
public KeePassDatabaseClient(ISettingsProxy settings, IFileProxy fileService, IMapper mapper)
|
||||
{
|
||||
_settings = settings;
|
||||
@@ -101,22 +75,19 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<DatabaseEntity> Open(FileInfo fileInfo, Credentials credentials)
|
||||
public async Task<GroupEntity> Open(FileInfo fileInfo, Credentials credentials)
|
||||
{
|
||||
try
|
||||
{
|
||||
_compositeKey = await CreateCompositeKey(credentials);
|
||||
var compositeKey = await CreateCompositeKey(credentials);
|
||||
var ioConnection = await BuildConnectionInfo(fileInfo);
|
||||
|
||||
_pwDatabase.Open(ioConnection, _compositeKey, new NullStatusLogger());
|
||||
_pwDatabase.Open(ioConnection, compositeKey, new NullStatusLogger());
|
||||
|
||||
_credentials = credentials;
|
||||
_fileAccessToken = fileInfo.Path;
|
||||
|
||||
return new DatabaseEntity
|
||||
{
|
||||
Name = _pwDatabase.Name,
|
||||
RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup)
|
||||
};
|
||||
return _mapper.Map<GroupEntity>(_pwDatabase.RootGroup);
|
||||
}
|
||||
catch (InvalidCompositeKeyException ex)
|
||||
{
|
||||
@@ -124,12 +95,17 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DatabaseEntity> Create(FileInfo fileInfo, Credentials credentials)
|
||||
public async Task<GroupEntity> ReOpen()
|
||||
{
|
||||
_compositeKey = await CreateCompositeKey(credentials);
|
||||
return await Open(new FileInfo {Path = _fileAccessToken}, _credentials);
|
||||
}
|
||||
|
||||
public async Task<GroupEntity> Create(FileInfo fileInfo, Credentials credentials)
|
||||
{
|
||||
var compositeKey = await CreateCompositeKey(credentials);
|
||||
var ioConnection = await BuildConnectionInfo(fileInfo);
|
||||
|
||||
_pwDatabase.New(ioConnection, _compositeKey);
|
||||
_pwDatabase.New(ioConnection, compositeKey);
|
||||
|
||||
var fileFormat = _settings.GetSetting<string>("DefaultFileFormat");
|
||||
switch (fileFormat)
|
||||
@@ -142,10 +118,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
_fileAccessToken = fileInfo.Path;
|
||||
|
||||
// TODO: create sample data depending on settings
|
||||
return new DatabaseEntity
|
||||
{
|
||||
RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup)
|
||||
};
|
||||
return _mapper.Map<GroupEntity>(_pwDatabase.RootGroup);
|
||||
}
|
||||
|
||||
public async Task SaveDatabase()
|
||||
@@ -185,49 +158,78 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
_fileService.ReleaseFile(_fileAccessToken);
|
||||
}
|
||||
|
||||
public async Task AddEntry(GroupEntity parentGroupEntity, EntryEntity entry)
|
||||
public async Task AddEntry(string parentGroupId, string entryId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true);
|
||||
|
||||
var pwEntry = new PwEntry(true, true);
|
||||
_mapper.Map(entry, pwEntry);
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||
parentPwGroup.AddEntry(pwEntry, true);
|
||||
entry.Id = pwEntry.Uuid.ToHexString();
|
||||
});
|
||||
}
|
||||
public async Task AddGroup(GroupEntity parentGroupEntity, GroupEntity group)
|
||||
public async Task AddGroup(string parentGroupId, string groupId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true);
|
||||
|
||||
var pwGroup = new PwGroup(true, true)
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(groupId), true);
|
||||
parentPwGroup.Groups.Add(pwGroup);
|
||||
});
|
||||
}
|
||||
public async Task RemoveEntry(string parentGroupId, string entryId)
|
||||
{
|
||||
Name = group.Name
|
||||
};
|
||||
parentPwGroup.AddGroup(pwGroup, true);
|
||||
group.Id = pwGroup.Uuid.ToHexString();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
var pwEntry = parentPwGroup.FindEntry(BuildIdFromString(entryId), false);
|
||||
parentPwGroup.Entries.Remove(pwEntry);
|
||||
});
|
||||
}
|
||||
|
||||
public Task UpdateEntry(EntryEntity entry)
|
||||
public async Task RemoveGroup(string parentGroupId, string groupId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
var pwGroup = parentPwGroup.FindGroup(BuildIdFromString(groupId), false);
|
||||
parentPwGroup.Groups.Remove(pwGroup);
|
||||
});
|
||||
}
|
||||
|
||||
public Task UpdateEntry(string entry)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task UpdateGroup(GroupEntity group)
|
||||
public Task UpdateGroup(string group)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task DeleteEntry(EntryEntity entry)
|
||||
public EntryEntity CreateEntry(string parentGroupId)
|
||||
{
|
||||
var pwEntry = new PwEntry(true, true);
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
parentPwGroup.Entries.Add(pwEntry);
|
||||
|
||||
return _mapper.Map<EntryEntity>(pwEntry);
|
||||
}
|
||||
|
||||
public GroupEntity CreateGroup(string parentGroupId, string name, bool isRecycleBin = false)
|
||||
{
|
||||
var pwGroup = new PwGroup(true, true, name, isRecycleBin? PwIcon.TrashBin : PwIcon.Folder);
|
||||
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||
parentPwGroup.Groups.Add(pwGroup);
|
||||
if (isRecycleBin) _pwDatabase.RecycleBinUuid = pwGroup.Uuid;
|
||||
|
||||
return _mapper.Map<GroupEntity>(pwGroup);
|
||||
}
|
||||
|
||||
public async Task DeleteEntry(string entryId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entry.Id), true);
|
||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||
var id = pwEntry.Uuid;
|
||||
pwEntry.ParentGroup.Entries.Remove(pwEntry);
|
||||
|
||||
@@ -237,11 +239,12 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
}
|
||||
});
|
||||
}
|
||||
public async Task DeleteGroup(GroupEntity group)
|
||||
|
||||
public async Task DeleteGroup(string groupId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(group.Id), true);
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(groupId), true);
|
||||
var id = pwGroup.Uuid;
|
||||
pwGroup.ParentGroup.Groups.Remove(pwGroup);
|
||||
|
||||
@@ -252,6 +255,19 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
});
|
||||
}
|
||||
|
||||
public void SortEntries(string groupId)
|
||||
{
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(groupId), true);
|
||||
var comparer = new PwEntryComparer(PwDefs.TitleField, true, false);
|
||||
pwGroup.Entries.Sort(comparer);
|
||||
}
|
||||
|
||||
public void SortSubGroups(string groupId)
|
||||
{
|
||||
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(groupId), true);
|
||||
pwGroup.SortSubGroups(false);
|
||||
}
|
||||
|
||||
public async Task UpdateCredentials(Credentials credentials)
|
||||
{
|
||||
_pwDatabase.MasterKey = await CreateCompositeKey(credentials);
|
||||
@@ -275,20 +291,6 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
return IOConnectionInfo.FromByteArray(fileContents);
|
||||
}
|
||||
|
||||
private GroupEntity BuildHierarchy(PwGroup pwGroup)
|
||||
{
|
||||
// TODO: build entity hierarchy in an iterative way or implement lazy loading
|
||||
var group = new GroupEntity
|
||||
{
|
||||
Id = pwGroup.Uuid.ToHexString(),
|
||||
Name = pwGroup.Name,
|
||||
Icon = IconMapper.MapPwIconToIcon(pwGroup.IconId),
|
||||
Entries = pwGroup.Entries.Select(e => _mapper.Map<EntryEntity>(e)).ToList(),
|
||||
SubGroups = pwGroup.Groups.Select(BuildHierarchy).ToList()
|
||||
};
|
||||
return group;
|
||||
}
|
||||
|
||||
private PwUuid BuildIdFromString(string id)
|
||||
{
|
||||
return new PwUuid(MemUtil.HexStringToByteArray(id));
|
||||
|
95
ModernKeePass.KeePassDatabaseTests/AutomapperProfilesTest.cs
Normal file
95
ModernKeePass.KeePassDatabaseTests/AutomapperProfilesTest.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
using ModernKeePass.Infrastructure.KeePass;
|
||||
using ModernKeePassLib;
|
||||
using ModernKeePassLib.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ModernKeePass.KeePassDatabaseTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutomapperProfilesTest
|
||||
{
|
||||
private IMapper _mapper;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_mapper = new Mapper(new MapperConfiguration(conf => conf.AddProfile(new EntryMappingProfile())));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Assert_Mapping_Configuration_Is_Valid()
|
||||
{
|
||||
_mapper.ConfigurationProvider.AssertConfigurationIsValid();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromDtoToModel_Should_Map_PwEntry_To_Entry()
|
||||
{
|
||||
var pwEntry = new PwEntry(true, true)
|
||||
{
|
||||
ExpiryTime = DateTime.Now,
|
||||
BackgroundColor = Color.White,
|
||||
ForegroundColor = Color.Black
|
||||
};
|
||||
pwEntry.Strings.Set(PwDefs.TitleField, new ProtectedString(true, "Test"));
|
||||
pwEntry.Strings.Set(PwDefs.UserNameField, new ProtectedString(true, "toto"));
|
||||
pwEntry.Strings.Set(PwDefs.PasswordField, new ProtectedString(true, "password"));
|
||||
pwEntry.Strings.Set(PwDefs.UrlField, new ProtectedString(true, "http://google.com"));
|
||||
pwEntry.Strings.Set(PwDefs.NotesField, new ProtectedString(true, "blabla"));
|
||||
pwEntry.Strings.Set("additional", new ProtectedString(true, "custom"));
|
||||
|
||||
var entry = _mapper.Map<PwEntry, EntryEntity>(pwEntry);
|
||||
|
||||
Assert.That(entry.ExpirationDate, Is.Not.EqualTo(default(DateTimeOffset)));
|
||||
Assert.That(entry.BackgroundColor, Is.EqualTo(Color.White));
|
||||
Assert.That(entry.ForegroundColor, Is.EqualTo(Color.Black));
|
||||
Assert.That(entry.Name, Is.EqualTo("Test"));
|
||||
Assert.That(entry.UserName, Is.EqualTo("toto"));
|
||||
Assert.That(entry.Password, Is.EqualTo("password"));
|
||||
Assert.That(entry.Url, Is.EqualTo(new Uri("http://google.com")));
|
||||
Assert.That(entry.Notes, Is.EqualTo("blabla"));
|
||||
Assert.That(entry.AdditionalFields, Is.Not.Empty);
|
||||
Assert.That(entry.AdditionalFields["additional"], Is.EqualTo("custom"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromModelToDto_Should_Map_Entry_To_PwEntry()
|
||||
{
|
||||
var entry = new EntryEntity
|
||||
{
|
||||
Id = "VGhlIHF1aWNrIGJyb3duIA==",
|
||||
Name = "Test",
|
||||
UserName = "toto",
|
||||
Password = "password",
|
||||
Url = new Uri("http://google.com"),
|
||||
Notes = "blabla",
|
||||
ExpirationDate = DateTimeOffset.Now,
|
||||
BackgroundColor = Color.White,
|
||||
ForegroundColor = Color.Black,
|
||||
AdditionalFields = new Dictionary<string, string> {
|
||||
{
|
||||
"additional", "custom"
|
||||
}
|
||||
}
|
||||
};
|
||||
var pwEntry = new PwEntry(false, false);
|
||||
|
||||
_mapper.Map(entry, pwEntry);
|
||||
|
||||
Assert.That(pwEntry.ExpiryTime, Is.Not.EqualTo(default(DateTime)));
|
||||
Assert.That(pwEntry.BackgroundColor, Is.EqualTo(Color.White));
|
||||
Assert.That(pwEntry.ForegroundColor, Is.EqualTo(Color.Black));
|
||||
Assert.That(pwEntry.Strings.GetSafe(PwDefs.TitleField).ReadString(), Is.EqualTo("Test"));
|
||||
Assert.That(pwEntry.Strings.GetSafe(PwDefs.UserNameField).ReadString(), Is.EqualTo("toto"));
|
||||
Assert.That(pwEntry.Strings.GetSafe(PwDefs.PasswordField).ReadString(), Is.EqualTo("password"));
|
||||
Assert.That(pwEntry.Strings.GetSafe(PwDefs.UrlField).ReadString(), Is.EqualTo(new Uri("http://google.com")));
|
||||
Assert.That(pwEntry.Strings.GetSafe(PwDefs.NotesField).ReadString(), Is.EqualTo("blabla"));
|
||||
Assert.That(pwEntry.Strings.GetSafe("additional").ReadString(), Is.EqualTo("custom"));
|
||||
}
|
||||
}
|
||||
}
|
BIN
ModernKeePass.KeePassDatabaseTests/Data/TestDatabase.kdbx
Normal file
BIN
ModernKeePass.KeePassDatabaseTests/Data/TestDatabase.kdbx
Normal file
Binary file not shown.
155
ModernKeePass.KeePassDatabaseTests/KeePassDatabaseClientTests.cs
Normal file
155
ModernKeePass.KeePassDatabaseTests/KeePassDatabaseClientTests.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Application.Services;
|
||||
using ModernKeePass.Domain.Dtos;
|
||||
using ModernKeePass.Domain.Entities;
|
||||
using ModernKeePass.Domain.Interfaces;
|
||||
using ModernKeePass.Infrastructure.KeePass;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using FileInfo = ModernKeePass.Domain.Dtos.FileInfo;
|
||||
|
||||
namespace ModernKeePass.KeePassDatabaseTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DatabaseTests
|
||||
{
|
||||
private IDatabaseProxy _database;
|
||||
private FileInfo _fileInfo;
|
||||
private readonly Credentials _credentials = new Credentials
|
||||
{
|
||||
Password = "test"
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var settingsService = Substitute.For<ISettingsService>();
|
||||
var fileProxy = Substitute.For<IFileProxy>();
|
||||
fileProxy.OpenBinaryFile(Arg.Any<string>()).Returns(async parameters =>
|
||||
{
|
||||
await using var stream = File.Open((string) parameters[0], FileMode.OpenOrCreate);
|
||||
var contents = new byte[stream.Length];
|
||||
await stream.ReadAsync(contents, 0, (int) stream.Length);
|
||||
return contents;
|
||||
});
|
||||
fileProxy.WriteBinaryContentsToFile(Arg.Any<string>(), Arg.Any<byte[]>()).Returns(async parameters =>
|
||||
{
|
||||
await using var stream = File.Open((string)parameters[0], FileMode.OpenOrCreate);
|
||||
var contents = (byte[]) parameters[1];
|
||||
await stream.WriteAsync(contents, 0, contents.Length);
|
||||
});
|
||||
var fileService = new FileService(fileProxy);
|
||||
var mapper = new Mapper(new MapperConfiguration(cfg => { cfg.AddProfile(typeof(EntryMappingProfile)); }));
|
||||
_database = new KeePassDatabaseClient(settingsService, fileService, mapper);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
_database.CloseDatabase();
|
||||
if (!string.IsNullOrEmpty(_fileInfo?.Path)) File.Delete(_fileInfo.Path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestOpen()
|
||||
{
|
||||
var FileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Directory.GetCurrentDirectory(), "Data", "TestDatabase.kdbx")
|
||||
};
|
||||
|
||||
var rootGroup = await _database.Open(FileInfo, _credentials);
|
||||
Assert.That(rootGroup.Name, Is.EqualTo("TestDatabase"));
|
||||
Assert.That(rootGroup.Entries.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestCreateAndSave()
|
||||
{
|
||||
_fileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Path.GetTempPath(), "NewDatabase.kdbx")
|
||||
};
|
||||
|
||||
await _database.Create(_fileInfo, _credentials);
|
||||
await _database.SaveDatabase();
|
||||
_database.CloseDatabase();
|
||||
|
||||
Assert.DoesNotThrowAsync(async () => { await _database.Open(_fileInfo, _credentials); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestSaveAs()
|
||||
{
|
||||
var originalFileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Directory.GetCurrentDirectory(), "Data", "TestDatabase.kdbx")
|
||||
};
|
||||
_fileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Path.GetTempPath(), "SavedDatabase.kdbx")
|
||||
};
|
||||
|
||||
await _database.Open(originalFileInfo, _credentials);
|
||||
await _database.SaveDatabase(_fileInfo);
|
||||
_database.CloseDatabase();
|
||||
|
||||
Assert.DoesNotThrowAsync(async () => { await _database.Open(_fileInfo, _credentials); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestAddGroup()
|
||||
{
|
||||
var originalFileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Directory.GetCurrentDirectory(), "Data", "TestDatabase.kdbx")
|
||||
};
|
||||
_fileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Path.GetTempPath(), "SavedDatabase.kdbx")
|
||||
};
|
||||
var newGroup = new GroupEntity {Name = "New Group Test"};
|
||||
|
||||
var rootGroup = await _database.Open(originalFileInfo, _credentials);
|
||||
await _database.AddEntity(rootGroup, newGroup);
|
||||
await _database.SaveDatabase(_fileInfo);
|
||||
_database.CloseDatabase();
|
||||
rootGroup = await _database.Open(_fileInfo, _credentials);
|
||||
|
||||
Assert.That(newGroup.Id, Is.Not.Empty);
|
||||
Assert.That(rootGroup.SubGroups.Count, Is.EqualTo(7));
|
||||
Assert.That(rootGroup.SubGroups.Last().Name, Is.EqualTo("New Group Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestAddEntry()
|
||||
{
|
||||
var originalFileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Directory.GetCurrentDirectory(), "Data", "TestDatabase.kdbx")
|
||||
};
|
||||
_fileInfo = new FileInfo
|
||||
{
|
||||
Path = Path.Combine(Path.GetTempPath(), "SavedDatabase.kdbx")
|
||||
};
|
||||
var newEntry = new EntryEntity
|
||||
{
|
||||
Name = "New Entry Test"
|
||||
};
|
||||
|
||||
var rootGroup = await _database.Open(originalFileInfo, _credentials);
|
||||
await _database.AddEntity(rootGroup, newEntry);
|
||||
await _database.SaveDatabase(_fileInfo);
|
||||
_database.CloseDatabase();
|
||||
rootGroup = await _database.Open(_fileInfo, _credentials);
|
||||
|
||||
Assert.That(newEntry.Id, Is.Not.Empty);
|
||||
Assert.That(rootGroup.Entries.Count, Is.EqualTo(3));
|
||||
Assert.That(rootGroup.Entries.Last().Name, Is.EqualTo("New Entry Test"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Data\TestDatabase.kdbx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Data\TestDatabase.kdbx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="9.0.0" />
|
||||
<PackageReference Include="ModernKeePassLib" Version="2.44.1" />
|
||||
<PackageReference Include="NSubstitute" Version="4.2.1" />
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="Splat" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ModernKeePass.Application\Application.csproj" />
|
||||
<ProjectReference Include="..\ModernKeePass.Domain\Domain.csproj" />
|
||||
<ProjectReference Include="..\ModernKeePass.Infrastructure\Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29911.84
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win81App", "ModernKeePass\Win81App.csproj", "{A0CFC681-769B-405A-8482-0CDEE595A91F}"
|
||||
EndProject
|
||||
@@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "ModernKeePass.Dom
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "ModernKeePass.Infrastructure\Infrastructure.csproj", "{09577E4C-4899-45B9-BF80-1803D617CCAE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernKeePass.KeePassDatabaseTests", "ModernKeePass.KeePassDatabaseTests\ModernKeePass.KeePassDatabaseTests.csproj", "{52FEA1EE-2FA7-4862-85FE-CB05893D439E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -134,6 +136,22 @@ Global
|
||||
{09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -145,6 +163,7 @@ Global
|
||||
{42353562-5E43-459C-8E3E-2F21E575261D} = {0B30588B-07B8-4A88-A268-F58D06EA1627}
|
||||
{9A0759F1-9069-4841-99E3-3BEC44E17356} = {0B30588B-07B8-4A88-A268-F58D06EA1627}
|
||||
{09577E4C-4899-45B9-BF80-1803D617CCAE} = {0B30588B-07B8-4A88-A268-F58D06EA1627}
|
||||
{52FEA1EE-2FA7-4862-85FE-CB05893D439E} = {107C7C00-56F4-41B0-A8CC-0156C46A3650}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0ADC1BC6-B1CA-427D-A97C-3CA40AAB0428}
|
||||
|
@@ -10,14 +10,14 @@ namespace ModernKeePass.Actions
|
||||
{
|
||||
public class DeleteEntityAction : DependencyObject, IAction
|
||||
{
|
||||
public IPwEntity Entity
|
||||
public IVmEntity Entity
|
||||
{
|
||||
get { return (IPwEntity)GetValue(EntityProperty); }
|
||||
get { return (IVmEntity)GetValue(EntityProperty); }
|
||||
set { SetValue(EntityProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EntityProperty =
|
||||
DependencyProperty.Register("Entity", typeof(IPwEntity), typeof(DeleteEntityAction),
|
||||
DependencyProperty.Register("Entity", typeof(IVmEntity), typeof(DeleteEntityAction),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public ICommand Command
|
||||
|
@@ -17,6 +17,7 @@ using ModernKeePass.Application;
|
||||
using ModernKeePass.Application.Database.Commands.CloseDatabase;
|
||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||
using ModernKeePass.Application.Database.Queries.ReOpenDatabase;
|
||||
using ModernKeePass.Common;
|
||||
using ModernKeePass.Domain.Dtos;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
@@ -157,9 +158,9 @@ namespace ModernKeePass
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
var lauchActivatedEventArgs = e as LaunchActivatedEventArgs;
|
||||
if (lauchActivatedEventArgs != null && rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainPage), lauchActivatedEventArgs.Arguments);
|
||||
var launchActivatedEventArgs = e as LaunchActivatedEventArgs;
|
||||
if (launchActivatedEventArgs != null && rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainPage), launchActivatedEventArgs.Arguments);
|
||||
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
@@ -171,7 +172,7 @@ namespace ModernKeePass
|
||||
|
||||
try
|
||||
{
|
||||
var database = await Mediator.Send(new GetDatabaseQuery());
|
||||
var database = await Mediator.Send(new ReOpenDatabaseQuery());
|
||||
#if DEBUG
|
||||
ToastNotificationHelper.ShowGenericToast(database.Name, "Database reopened (changes were saved)");
|
||||
#endif
|
||||
@@ -207,7 +208,6 @@ namespace ModernKeePass
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
try
|
||||
{
|
||||
var database = await Mediator.Send(new GetDatabaseQuery());
|
||||
if (SettingsService.Instance.GetSetting("SaveSuspend", true))
|
||||
{
|
||||
await Mediator.Send(new SaveDatabaseCommand());
|
||||
|
@@ -9,7 +9,7 @@ namespace ModernKeePass.Common
|
||||
{
|
||||
public static class ToastNotificationHelper
|
||||
{
|
||||
public static void ShowMovedToast(IPwEntity entity, string action, string text)
|
||||
public static void ShowMovedToast(IVmEntity entity, string action, string text)
|
||||
{
|
||||
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
|
||||
var toastElements = notificationXml.GetElementsByTagName("text");
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using ModernKeePass.ViewModels;
|
||||
using ModernKeePass.Application.Group.Models;
|
||||
|
||||
namespace ModernKeePass.Events
|
||||
{
|
||||
|
@@ -1,17 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using ModernKeePass.ViewModels;
|
||||
|
||||
namespace ModernKeePass.Interfaces
|
||||
{
|
||||
public interface IPwEntity
|
||||
public interface IVmEntity
|
||||
{
|
||||
GroupVm ParentGroup { get; }
|
||||
GroupVm PreviousGroup { get; }
|
||||
int IconId { get; }
|
||||
string Id { get; }
|
||||
string Name { get; set; }
|
||||
IEnumerable<IPwEntity> BreadCrumb { get; }
|
||||
IEnumerable<IVmEntity> BreadCrumb { get; }
|
||||
bool IsEditMode { get; }
|
||||
bool IsRecycleOnDelete { get; }
|
||||
|
||||
@@ -31,10 +32,10 @@ namespace ModernKeePass.Interfaces
|
||||
/// <summary>
|
||||
/// Delete from Model
|
||||
/// </summary>
|
||||
void CommitDelete();
|
||||
Task CommitDelete();
|
||||
/// <summary>
|
||||
/// Delete from ViewModel
|
||||
/// </summary>
|
||||
void MarkForDelete(string recycleBinTitle);
|
||||
Task MarkForDelete(string recycleBinTitle);
|
||||
}
|
||||
}
|
@@ -99,7 +99,7 @@ namespace ModernKeePass.ViewModels
|
||||
set { SetProperty(ref _keyFileText, value); }
|
||||
}
|
||||
|
||||
public GroupVm RootGroup { get; set; }
|
||||
public Application.Group.Models.GroupVm RootGroup { get; set; }
|
||||
|
||||
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace ModernKeePass.ViewModels
|
||||
try
|
||||
{
|
||||
_isOpening = true;
|
||||
OnPropertyChanged("IsValid");;
|
||||
OnPropertyChanged("IsValid");
|
||||
var fileInfo = new FileInfo
|
||||
{
|
||||
Name = databaseFile.DisplayName,
|
||||
@@ -137,7 +137,7 @@ namespace ModernKeePass.ViewModels
|
||||
};
|
||||
|
||||
var database = await _mediator.Send(new OpenDatabaseQuery { FileInfo = fileInfo, Credentials = CreateCredentials()});
|
||||
await Task.Run(() => RootGroup = new GroupVm(database.RootGroup));
|
||||
await Task.Run(() => RootGroup = database.RootGroup);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
|
@@ -13,7 +13,7 @@ using ModernKeePassLib.Cryptography;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
{
|
||||
public class EntryVm : INotifyPropertyChanged, IPwEntity, ISelectableModel
|
||||
public class EntryVm : INotifyPropertyChanged, IVmEntity, ISelectableModel
|
||||
{
|
||||
public GroupVm ParentGroup { get; private set; }
|
||||
public GroupVm PreviousGroup { get; private set; }
|
||||
@@ -32,7 +32,7 @@ namespace ModernKeePass.ViewModels
|
||||
public PwUuid IdUuid => _pwEntry?.Uuid;
|
||||
public string Id => _pwEntry?.Uuid.ToHexString();
|
||||
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !ParentGroup.IsSelected;
|
||||
public IEnumerable<IPwEntity> BreadCrumb => new List<IPwEntity>(ParentGroup.BreadCrumb) {ParentGroup};
|
||||
public IEnumerable<IVmEntity> BreadCrumb => new List<IVmEntity>(ParentGroup.BreadCrumb) {ParentGroup};
|
||||
/// <summary>
|
||||
/// Determines if the Entry is current or from history
|
||||
/// </summary>
|
||||
@@ -160,7 +160,7 @@ namespace ModernKeePass.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IPwEntity> History
|
||||
public IEnumerable<IVmEntity> History
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@@ -5,14 +5,17 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||
using ModernKeePass.Common;
|
||||
using ModernKeePass.Domain.Enums;
|
||||
using ModernKeePass.Interfaces;
|
||||
using ModernKeePass.Services;
|
||||
using ModernKeePassLib;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
{
|
||||
public class GroupVm : NotifyPropertyChangedBase, IPwEntity, ISelectableModel
|
||||
public class GroupVm : NotifyPropertyChangedBase, IVmEntity, ISelectableModel
|
||||
{
|
||||
public GroupVm ParentGroup { get; private set; }
|
||||
public GroupVm PreviousGroup { get; private set; }
|
||||
@@ -40,23 +43,22 @@ namespace ModernKeePass.ViewModels
|
||||
|
||||
public ObservableCollection<GroupVm> Groups { get; set; } = new ObservableCollection<GroupVm>();
|
||||
|
||||
public PwUuid IdUuid => _pwGroup?.Uuid;
|
||||
public string Id => IdUuid?.ToHexString();
|
||||
public string Id => _group.Id;
|
||||
public bool IsNotRoot => ParentGroup != null;
|
||||
|
||||
public bool ShowRestore => IsNotRoot && ParentGroup.IsSelected;
|
||||
|
||||
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !IsSelected && !ParentGroup.IsSelected;
|
||||
public bool IsRecycleOnDelete => IsRecycleBinEnabled().GetAwaiter().GetResult() && !IsSelected && !ParentGroup.IsSelected;
|
||||
|
||||
/// <summary>
|
||||
/// Is the Group the database Recycle Bin?
|
||||
/// </summary>
|
||||
public bool IsSelected
|
||||
{
|
||||
get { return _database != null && _database.RecycleBinEnabled && _database.RecycleBin?.Id == Id; }
|
||||
get { return IsRecycleBinEnabled().GetAwaiter().GetResult() && _database.RecycleBin?.Id == Id; }
|
||||
set
|
||||
{
|
||||
if (value && _pwGroup != null) _database.RecycleBin = this;
|
||||
if (value && _group != null) _database.RecycleBin = this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,18 +69,18 @@ namespace ModernKeePass.ViewModels
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _pwGroup == null ? string.Empty : _pwGroup.Name; }
|
||||
set { _pwGroup.Name = value; }
|
||||
get { return _group == null ? string.Empty : _group.Title; }
|
||||
set { _group.Title = value; }
|
||||
}
|
||||
|
||||
public int IconId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pwGroup?.IconId != null) return (int) _pwGroup?.IconId;
|
||||
if (_group?.Icon != null) return (int) _group?.Icon;
|
||||
return -1;
|
||||
}
|
||||
set { _pwGroup.IconId = (PwIcon)value; }
|
||||
set { _group.Icon = (Icon)value; }
|
||||
}
|
||||
|
||||
public bool IsEditMode
|
||||
@@ -98,7 +100,7 @@ namespace ModernKeePass.ViewModels
|
||||
set { SetProperty(ref _isMenuClosed, value); }
|
||||
}
|
||||
|
||||
public IEnumerable<IPwEntity> BreadCrumb
|
||||
public IEnumerable<IVmEntity> BreadCrumb
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -119,36 +121,35 @@ namespace ModernKeePass.ViewModels
|
||||
public ICommand SortGroupsCommand { get; }
|
||||
public ICommand UndoDeleteCommand { get; }
|
||||
|
||||
private readonly PwGroup _pwGroup;
|
||||
private readonly IDatabaseService _database;
|
||||
private readonly Application.Group.Models.GroupVm _group;
|
||||
private readonly IMediator _mediator;
|
||||
private bool _isEditMode;
|
||||
private PwEntry _reorderedEntry;
|
||||
private Application.Entry.Models.EntryVm _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)
|
||||
internal GroupVm(Application.Group.Models.GroupVm group, GroupVm parent, string recycleBinId = null) : this(group, parent, App.Mediator, recycleBinId)
|
||||
{ }
|
||||
|
||||
public GroupVm(PwGroup pwGroup, GroupVm parent, IDatabaseService database, PwUuid recycleBinId = null)
|
||||
public GroupVm(Application.Group.Models.GroupVm group, GroupVm parent, IMediator mediator, string recycleBinId = null)
|
||||
{
|
||||
_pwGroup = pwGroup;
|
||||
_database = database;
|
||||
_group = group;
|
||||
_mediator = mediator;
|
||||
ParentGroup = parent;
|
||||
|
||||
SaveCommand = new RelayCommand(() => _database.Save());
|
||||
SaveCommand = new RelayCommand(async () => await _mediator.Send(new SaveDatabaseCommand()));
|
||||
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)));
|
||||
if (recycleBinId != null && _group.Id.Equals(recycleBinId)) _database.RecycleBin = this;
|
||||
Entries = new ObservableCollection<EntryVm>(group.Entries.Select(e => new EntryVm(e, this)));
|
||||
Entries.CollectionChanged += Entries_CollectionChanged;
|
||||
Groups = new ObservableCollection<GroupVm>(pwGroup.Groups.Select(g => new GroupVm(g, this, recycleBinId)));
|
||||
Groups = new ObservableCollection<GroupVm>(group.SubGroups.Select(g => new GroupVm(g, this, recycleBinId)));
|
||||
}
|
||||
|
||||
private void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
@@ -157,12 +158,12 @@ namespace ModernKeePass.ViewModels
|
||||
{
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
var oldIndex = (uint) e.OldStartingIndex;
|
||||
_reorderedEntry = _pwGroup.Entries.GetAt(oldIndex);
|
||||
_pwGroup.Entries.RemoveAt(oldIndex);
|
||||
_reorderedEntry = _group.Entries.GetAt(oldIndex);
|
||||
_group.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);
|
||||
if (_reorderedEntry == null) _group.AddEntry(((EntryVm) e.NewItems[0]).GetPwEntry(), true);
|
||||
else _group.Entries.Insert((uint)e.NewStartingIndex, _reorderedEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -170,7 +171,7 @@ namespace ModernKeePass.ViewModels
|
||||
public GroupVm AddNewGroup(string name = "")
|
||||
{
|
||||
var pwGroup = new PwGroup(true, true, name, PwIcon.Folder);
|
||||
_pwGroup.AddGroup(pwGroup, true);
|
||||
_group.AddGroup(pwGroup, true);
|
||||
var newGroup = new GroupVm(pwGroup, this) {Name = name, IsEditMode = string.IsNullOrEmpty(name)};
|
||||
Groups.Add(newGroup);
|
||||
return newGroup;
|
||||
@@ -185,11 +186,12 @@ namespace ModernKeePass.ViewModels
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
public void MarkForDelete(string recycleBinTitle)
|
||||
public async Task MarkForDelete(string recycleBinTitle)
|
||||
{
|
||||
if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
|
||||
var isRecycleBinEnabled = await IsRecycleBinEnabled();
|
||||
if (isRecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
|
||||
_database.CreateRecycleBin(recycleBinTitle);
|
||||
Move(_database.RecycleBinEnabled && !IsSelected ? _database.RecycleBin : null);
|
||||
Move(isRecycleBinEnabled && !IsSelected ? _database.RecycleBin : null);
|
||||
((RelayCommand)UndoDeleteCommand).RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
@@ -202,7 +204,7 @@ namespace ModernKeePass.ViewModels
|
||||
{
|
||||
PreviousGroup = ParentGroup;
|
||||
PreviousGroup.Groups.Remove(this);
|
||||
PreviousGroup._pwGroup.Groups.Remove(_pwGroup);
|
||||
PreviousGroup._group.SubGroups.Remove(_group);
|
||||
if (destination == null)
|
||||
{
|
||||
_database.AddDeletedItem(IdUuid);
|
||||
@@ -210,13 +212,13 @@ namespace ModernKeePass.ViewModels
|
||||
}
|
||||
ParentGroup = destination;
|
||||
ParentGroup.Groups.Add(this);
|
||||
ParentGroup._pwGroup.AddGroup(_pwGroup, true);
|
||||
ParentGroup._group.AddGroup(_group, true);
|
||||
}
|
||||
|
||||
public void CommitDelete()
|
||||
public async Task CommitDelete()
|
||||
{
|
||||
_pwGroup.ParentGroup.Groups.Remove(_pwGroup);
|
||||
if (_database.RecycleBinEnabled && !PreviousGroup.IsSelected) _database.RecycleBin._pwGroup.AddGroup(_pwGroup, true);
|
||||
_group.ParentGroup.Groups.Remove(_group);
|
||||
if (await IsRecycleBinEnabled() && !PreviousGroup.IsSelected) _database.RecycleBin._group.AddGroup(_group, true);
|
||||
else _database.AddDeletedItem(IdUuid);
|
||||
}
|
||||
|
||||
@@ -230,7 +232,7 @@ namespace ModernKeePass.ViewModels
|
||||
var comparer = new PwEntryComparer(PwDefs.TitleField, true, false);
|
||||
try
|
||||
{
|
||||
_pwGroup.Entries.Sort(comparer);
|
||||
_group.Entries.Sort(comparer);
|
||||
Entries = new ObservableCollection<EntryVm>(Entries.OrderBy(e => e.Name));
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -243,8 +245,8 @@ namespace ModernKeePass.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
_pwGroup.SortSubGroups(false);
|
||||
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Name).ThenBy(g => g._pwGroup == null));
|
||||
_group.SortSubGroups(false);
|
||||
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Name).ThenBy(g => g._group == null));
|
||||
OnPropertyChanged("Groups");
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -253,5 +255,10 @@ namespace ModernKeePass.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsRecycleBinEnabled()
|
||||
{
|
||||
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||
return database.IsRecycleBinEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ namespace ModernKeePass.Views
|
||||
{
|
||||
NavigationHelper.OnNavigatedTo(e);
|
||||
|
||||
var args = e.Parameter as PasswordEventArgs;
|
||||
/*var args = e.Parameter as PasswordEventArgs;
|
||||
if (args != null)
|
||||
DataContext = args.RootGroup;
|
||||
else
|
||||
@@ -55,7 +55,9 @@ namespace ModernKeePass.Views
|
||||
var vm = e.Parameter as GroupVm;
|
||||
if (vm != null)
|
||||
DataContext = vm;
|
||||
}
|
||||
}*/
|
||||
var args = e.Parameter as Application.Group.Models.GroupVm;
|
||||
if (args != null) DataContext = new GroupVm(args);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
@@ -13,17 +13,17 @@ namespace ModernKeePass.Views.UserControls
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public IEnumerable<IPwEntity> ItemsSource
|
||||
public IEnumerable<IVmEntity> ItemsSource
|
||||
{
|
||||
get { return (IEnumerable<IPwEntity>)GetValue(ItemsSourceProperty); }
|
||||
get { return (IEnumerable<IVmEntity>)GetValue(ItemsSourceProperty); }
|
||||
set { SetValue(ItemsSourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty =
|
||||
DependencyProperty.Register(
|
||||
"ItemsSource",
|
||||
typeof(IEnumerable<IPwEntity>),
|
||||
typeof(IEnumerable<IVmEntity>),
|
||||
typeof(BreadCrumbUserControl),
|
||||
new PropertyMetadata(new Stack<IPwEntity>(), (o, args) => { }));
|
||||
new PropertyMetadata(new Stack<IVmEntity>(), (o, args) => { }));
|
||||
}
|
||||
}
|
||||
|
@@ -75,18 +75,18 @@ namespace ModernKeePass.Views.UserControls
|
||||
typeof(HamburgerMenuUserControl),
|
||||
new PropertyMetadata(Visibility.Collapsed, (o, args) => { }));
|
||||
|
||||
public IEnumerable<IPwEntity> ItemsSource
|
||||
public IEnumerable<IVmEntity> ItemsSource
|
||||
{
|
||||
get { return (IEnumerable<IPwEntity>)GetValue(ItemsSourceProperty); }
|
||||
get { return (IEnumerable<IVmEntity>)GetValue(ItemsSourceProperty); }
|
||||
set { SetValue(ItemsSourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty =
|
||||
DependencyProperty.Register(
|
||||
"ItemsSource",
|
||||
typeof(IEnumerable<IPwEntity>),
|
||||
typeof(IEnumerable<IVmEntity>),
|
||||
typeof(HamburgerMenuUserControl),
|
||||
new PropertyMetadata(new List<IPwEntity>(), (o, args) => { }));
|
||||
new PropertyMetadata(new List<IVmEntity>(), (o, args) => { }));
|
||||
|
||||
public object SelectedItem
|
||||
{
|
||||
|
@@ -192,7 +192,7 @@
|
||||
<Compile Include="Converters\TextToWidthConverter.cs" />
|
||||
<Compile Include="Events\PasswordEventArgs.cs" />
|
||||
<Compile Include="Interfaces\IIsEnabled.cs" />
|
||||
<Compile Include="Interfaces\IPwEntity.cs" />
|
||||
<Compile Include="Interfaces\IVmEntity.cs" />
|
||||
<Compile Include="Views\MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
Reference in New Issue
Block a user