mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
WIP Protect/Unprotect Additional Field on selection
This commit is contained in:
@@ -83,6 +83,7 @@
|
||||
<Compile Include="Common\Interfaces\IFileProxy.cs" />
|
||||
<Compile Include="Common\Interfaces\IImportFormat.cs" />
|
||||
<Compile Include="Common\Interfaces\ICredentialsProxy.cs" />
|
||||
<Compile Include="Common\Interfaces\ILogger.cs" />
|
||||
<Compile Include="Common\Interfaces\INotificationService.cs" />
|
||||
<Compile Include="Common\Interfaces\IRecentProxy.cs" />
|
||||
<Compile Include="Common\Interfaces\IResourceProxy.cs" />
|
||||
|
@@ -10,6 +10,7 @@ namespace ModernKeePass.Application.Common.Interfaces
|
||||
Task<FileInfo> CreateFile(string name, string extension, string description, bool addToRecent);
|
||||
Task<byte[]> ReadBinaryFile(string path);
|
||||
Task<IList<string>> ReadTextFile(string path);
|
||||
Task WriteToLogFile(IEnumerable<string> data);
|
||||
Task WriteBinaryContentsToFile(string path, byte[] contents);
|
||||
void ReleaseFile(string path);
|
||||
}
|
||||
|
12
ModernKeePass.Application/Common/Interfaces/ILogger.cs
Normal file
12
ModernKeePass.Application/Common/Interfaces/ILogger.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ModernKeePass.Application.Common.Interfaces
|
||||
{
|
||||
public interface ILogger
|
||||
{
|
||||
Task LogError(Exception exception);
|
||||
void LogTrace(string message, Dictionary<string, string> values);
|
||||
}
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using MediatR;
|
||||
using System.Threading.Tasks;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
@@ -14,11 +16,13 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
private readonly IFileProxy _file;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public SaveDatabaseCommandHandler(IDatabaseProxy database, IFileProxy file)
|
||||
public SaveDatabaseCommandHandler(IDatabaseProxy database, IFileProxy file, ILogger logger)
|
||||
{
|
||||
_database = database;
|
||||
_file = file;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Handle(SaveDatabaseCommand message)
|
||||
@@ -27,6 +31,7 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
||||
|
||||
try
|
||||
{
|
||||
var timeToSave = Stopwatch.StartNew();
|
||||
if (!string.IsNullOrEmpty(message.FilePath))
|
||||
{
|
||||
_database.FileAccessToken = message.FilePath;
|
||||
@@ -40,6 +45,13 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
||||
|
||||
// Transactional write to file
|
||||
await _file.WriteBinaryContentsToFile(_database.FileAccessToken, contents);
|
||||
timeToSave.Stop();
|
||||
|
||||
_logger.LogTrace("SaveCommand", new Dictionary<string, string>
|
||||
{
|
||||
{ "duration", timeToSave.ElapsedMilliseconds.ToString()},
|
||||
{ "size", _database.Size.ToString()}
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@@ -253,7 +253,8 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
case EntryFieldName.Password:
|
||||
case EntryFieldName.Notes:
|
||||
case EntryFieldName.Url:
|
||||
var unprotectedFieldValue = isProtected ? await _cryptography.UnProtect(fieldValue.ToString()) : fieldValue.ToString();
|
||||
var stringValue = fieldValue == null ? string.Empty: fieldValue.ToString();
|
||||
var unprotectedFieldValue = isProtected ? await _cryptography.UnProtect(stringValue) : stringValue;
|
||||
pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(isProtected, unprotectedFieldValue));
|
||||
break;
|
||||
case EntryFieldName.HasExpirationDate:
|
||||
@@ -272,7 +273,8 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
pwEntry.ForegroundColor = (Color)fieldValue;
|
||||
break;
|
||||
default:
|
||||
var unprotectedAdditionalFieldValue = isProtected ? await _cryptography.UnProtect(fieldValue.ToString()) : fieldValue.ToString();
|
||||
var additionalStringValue = fieldValue == null ? string.Empty: fieldValue.ToString();
|
||||
var unprotectedAdditionalFieldValue = isProtected ? await _cryptography.UnProtect(additionalStringValue) : additionalStringValue;
|
||||
pwEntry.Strings.Set(fieldName, new ProtectedString(isProtected, unprotectedAdditionalFieldValue));
|
||||
break;
|
||||
}
|
||||
|
@@ -74,6 +74,24 @@ namespace ModernKeePass.Infrastructure.UWP
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task WriteToLogFile(IEnumerable<string> data)
|
||||
{
|
||||
var local = ApplicationData.Current.LocalFolder;
|
||||
var logFile = await local.CreateFileAsync("LogFile.txt", CreationCollisionOption.OpenIfExists).AsTask();
|
||||
|
||||
if (logFile != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await FileIO.AppendLinesAsync(logFile, data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// If another option is available to the app to log error(i.e. Azure Mobile Service, etc...) then try that here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseFile(string path)
|
||||
{
|
||||
StorageApplicationPermissions.FutureAccessList.Remove(path);
|
||||
|
@@ -12,27 +12,21 @@ namespace ModernKeePass.Infrastructure.UWP
|
||||
public async Task<string> Protect(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return value;
|
||||
try
|
||||
{
|
||||
// Create a DataProtectionProvider object for the specified descriptor.
|
||||
var provider = new DataProtectionProvider("LOCAL=user");
|
||||
|
||||
// Encode the plaintext input message to a buffer.
|
||||
var buffMsg = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
|
||||
// Create a DataProtectionProvider object for the specified descriptor.
|
||||
var provider = new DataProtectionProvider("LOCAL=user");
|
||||
|
||||
// Encrypt the message.
|
||||
var buffProtected = await provider.ProtectAsync(buffMsg).AsTask().ConfigureAwait(false);
|
||||
// Encode the plaintext input message to a buffer.
|
||||
var buffMsg = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
|
||||
|
||||
// Encode buffer to Base64
|
||||
var protectedValue = CryptographicBuffer.EncodeToBase64String(buffProtected);
|
||||
// Encrypt the message.
|
||||
var buffProtected = await provider.ProtectAsync(buffMsg).AsTask().ConfigureAwait(false);
|
||||
|
||||
// Return the encrypted string.
|
||||
return protectedValue;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
// Encode buffer to Base64
|
||||
var protectedValue = CryptographicBuffer.EncodeToBase64String(buffProtected);
|
||||
|
||||
// Return the encrypted string.
|
||||
return protectedValue;
|
||||
}
|
||||
|
||||
public async Task<string> UnProtect(string value)
|
||||
|
@@ -38,10 +38,11 @@ namespace ModernKeePass
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ISettingsProxy _settings;
|
||||
private readonly INavigationService _navigation;
|
||||
private readonly IHockeyClient _hockey;
|
||||
private readonly INotificationService _notification;
|
||||
private readonly IFileProxy _file;
|
||||
private readonly IMessenger _messenger;
|
||||
private readonly ILogger _log;
|
||||
private readonly IHockeyClient _hockey;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
@@ -63,6 +64,7 @@ namespace ModernKeePass
|
||||
_settings = Services.GetService<ISettingsProxy>();
|
||||
_navigation = Services.GetService<INavigationService>();
|
||||
_notification = Services.GetService<INotificationService>();
|
||||
_log = Services.GetService<ILogger>();
|
||||
_hockey = Services.GetService<IHockeyClient>();
|
||||
_file = Services.GetService<IFileProxy>();
|
||||
_messenger = Services.GetService<IMessenger>();
|
||||
@@ -93,8 +95,7 @@ namespace ModernKeePass
|
||||
|
||||
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
_hockey.TrackException(e.Exception);
|
||||
_hockey.Flush();
|
||||
_log.LogError(e.Exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,8 +210,7 @@ namespace ModernKeePass
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_hockey.TrackException(ex);
|
||||
_hockey.Flush();
|
||||
_log.LogError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@@ -4,8 +4,10 @@ using GalaSoft.MvvmLight.Messaging;
|
||||
using GalaSoft.MvvmLight.Views;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.HockeyApp;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Common;
|
||||
using ModernKeePass.Views;
|
||||
using ModernKeePass.Log;
|
||||
|
||||
namespace ModernKeePass
|
||||
{
|
||||
@@ -37,6 +39,7 @@ namespace ModernKeePass
|
||||
#endif
|
||||
return HockeyClient.Current;
|
||||
});
|
||||
services.AddSingleton(typeof(ILogger), typeof(HockeyAppLog));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
43
ModernKeePass/Log/HockeyAppLog.cs
Normal file
43
ModernKeePass/Log/HockeyAppLog.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using Microsoft.HockeyApp;
|
||||
using ModernKeePass.Domain.Interfaces;
|
||||
|
||||
namespace ModernKeePass.Log
|
||||
{
|
||||
public class HockeyAppLog : ILogger
|
||||
{
|
||||
private readonly IHockeyClient _hockey;
|
||||
private readonly IFileProxy _file;
|
||||
private readonly IDateTime _dateTime;
|
||||
|
||||
public HockeyAppLog(IHockeyClient hockey, IFileProxy file, IDateTime dateTime)
|
||||
{
|
||||
_hockey = hockey;
|
||||
_file = file;
|
||||
_dateTime = dateTime;
|
||||
}
|
||||
|
||||
public async Task LogError(Exception exception)
|
||||
{
|
||||
_hockey.TrackException(exception);
|
||||
_hockey.Flush();
|
||||
|
||||
var time = _dateTime.Now.ToLocalTime();
|
||||
var data = new List<string>
|
||||
{
|
||||
$"{time} - {exception.Message}",
|
||||
$"{time} - {exception.StackTrace}"
|
||||
};
|
||||
await _file.WriteToLogFile(data);
|
||||
}
|
||||
|
||||
public void LogTrace(string message, Dictionary<string, string> values)
|
||||
{
|
||||
_hockey.TrackTrace(message, values);
|
||||
_hockey.Flush();
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,7 +35,6 @@ using ModernKeePass.Domain.Dtos;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
using ModernKeePass.Extensions;
|
||||
using ModernKeePass.Models;
|
||||
using ModernKeePass.ViewModels.ListItems;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
{
|
||||
@@ -108,7 +107,7 @@ namespace ModernKeePass.ViewModels
|
||||
}
|
||||
|
||||
public ObservableCollection<EntryVm> History { get; private set; }
|
||||
public ObservableCollection<EntryFieldVm> AdditionalFields { get; private set; }
|
||||
public ObservableCollection<FieldVm> AdditionalFields { get; private set; }
|
||||
public ObservableCollection<Attachment> Attachments { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -124,14 +123,8 @@ namespace ModernKeePass.ViewModels
|
||||
Set(() => SelectedItem, ref _selectedItem, value, true);
|
||||
if (value != null)
|
||||
{
|
||||
AdditionalFields =
|
||||
new ObservableCollection<EntryFieldVm>(
|
||||
SelectedItem.AdditionalFields.Select(f =>
|
||||
{
|
||||
var field = new EntryFieldVm(_cryptography);
|
||||
field.Initialize(f.Name, f.Value, f.IsProtected);
|
||||
return field;
|
||||
}));
|
||||
AdditionalFields = new ObservableCollection<FieldVm>(SelectedItem.AdditionalFields);
|
||||
|
||||
Attachments = new ObservableCollection<Attachment>(SelectedItem.Attachments.Select(f => new Attachment
|
||||
{
|
||||
Name = f.Key,
|
||||
@@ -164,6 +157,13 @@ namespace ModernKeePass.ViewModels
|
||||
{
|
||||
Set(() => AdditionalFieldSelectedIndex, ref _additionalFieldSelectedIndex, value);
|
||||
DeleteAdditionalField.RaiseCanExecuteChanged();
|
||||
if (value != -1)
|
||||
{
|
||||
var additionalField = AdditionalFields[value];
|
||||
Set(nameof(AdditionalFieldName), ref _additionalFieldName, additionalField.Name);
|
||||
Set(nameof(AdditionalFieldValue), ref _additionalFieldValue, additionalField.IsProtected ? _cryptography.UnProtect(additionalField.Value).GetAwaiter().GetResult() : additionalField.Value);
|
||||
Set(nameof(AdditionalFieldIsProtected), ref _additionalFieldIsProtected, additionalField.IsProtected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.Title.Value = value;
|
||||
SetFieldValue(nameof(Title), value, false).Wait();
|
||||
SetFieldValue(nameof(Title), value, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.Username.Value = value;
|
||||
SetFieldValue(nameof(UserName), value, false).Wait();
|
||||
SetFieldValue(nameof(UserName), value, false).ConfigureAwait(false).GetAwaiter();
|
||||
RaisePropertyChanged(nameof(UserName));
|
||||
}
|
||||
}
|
||||
@@ -193,9 +193,10 @@ namespace ModernKeePass.ViewModels
|
||||
get { return _cryptography.UnProtect(SelectedItem.Password.Value).GetAwaiter().GetResult(); }
|
||||
set
|
||||
{
|
||||
var protectedPassword = _cryptography.Protect(value).GetAwaiter().GetResult();
|
||||
// TODO: cleanup this
|
||||
var protectedPassword = _cryptography.Protect(value).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
SelectedItem.Password.Value = protectedPassword;
|
||||
SetFieldValue(nameof(Password), protectedPassword, true).Wait();
|
||||
SetFieldValue(nameof(Password), value, true).ConfigureAwait(false).GetAwaiter();
|
||||
RaisePropertyChanged(nameof(Password));
|
||||
RaisePropertyChanged(nameof(PasswordComplexityIndicator));
|
||||
}
|
||||
@@ -207,7 +208,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.Url.Value = value;
|
||||
SetFieldValue(nameof(Url), value, false).Wait();
|
||||
SetFieldValue(nameof(Url), value, false).ConfigureAwait(false).GetAwaiter();
|
||||
RaisePropertyChanged(nameof(Url));
|
||||
}
|
||||
}
|
||||
@@ -218,7 +219,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.Notes.Value = value;
|
||||
SetFieldValue(nameof(Notes), value, false).Wait();
|
||||
SetFieldValue(nameof(Notes), value, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +229,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
|
||||
SetFieldValue(nameof(Icon), SelectedItem.Icon, false).Wait();
|
||||
SetFieldValue(nameof(Icon), SelectedItem.Icon, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +241,7 @@ namespace ModernKeePass.ViewModels
|
||||
if (!HasExpirationDate) return;
|
||||
|
||||
SelectedItem.ExpirationDate = value.Date;
|
||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).Wait();
|
||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +253,7 @@ namespace ModernKeePass.ViewModels
|
||||
if (!HasExpirationDate) return;
|
||||
|
||||
SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value);
|
||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).Wait();
|
||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.HasExpirationDate = value;
|
||||
SetFieldValue(nameof(HasExpirationDate), value, false).Wait();
|
||||
SetFieldValue(nameof(HasExpirationDate), value, false).ConfigureAwait(false).GetAwaiter();
|
||||
RaisePropertyChanged(nameof(HasExpirationDate));
|
||||
}
|
||||
}
|
||||
@@ -273,7 +274,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.BackgroundColor = value.ToColor();
|
||||
SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor, false).Wait();
|
||||
SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +284,7 @@ namespace ModernKeePass.ViewModels
|
||||
set
|
||||
{
|
||||
SelectedItem.ForegroundColor = value.ToColor();
|
||||
SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor, false).Wait();
|
||||
SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor, false).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +300,41 @@ namespace ModernKeePass.ViewModels
|
||||
set { Set(() => IsRevealPassword, ref _isRevealPassword, value); }
|
||||
}
|
||||
|
||||
private string _additionalFieldName;
|
||||
private string _additionalFieldValue;
|
||||
private bool _additionalFieldIsProtected;
|
||||
|
||||
public string AdditionalFieldName
|
||||
{
|
||||
get { return _additionalFieldName; }
|
||||
set
|
||||
{
|
||||
var newName = EntryFieldName.StandardFieldNames.Contains(value) ? $"{value}_1" : value;
|
||||
UpdateFieldName(_additionalFieldName, newName, AdditionalFieldValue, AdditionalFieldIsProtected).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
public string AdditionalFieldValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return _additionalFieldValue;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetFieldValue(AdditionalFieldName, value, AdditionalFieldIsProtected).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
public bool AdditionalFieldIsProtected
|
||||
{
|
||||
get { return _additionalFieldIsProtected; }
|
||||
set
|
||||
{
|
||||
SetFieldValue(AdditionalFieldName, AdditionalFieldValue, value).ConfigureAwait(false).GetAwaiter();
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand SaveCommand { get; }
|
||||
public RelayCommand GeneratePasswordCommand { get; }
|
||||
public RelayCommand<string> MoveCommand { get; }
|
||||
@@ -307,7 +343,7 @@ namespace ModernKeePass.ViewModels
|
||||
public RelayCommand GoBackCommand { get; }
|
||||
public RelayCommand GoToParentCommand { get; set; }
|
||||
public RelayCommand AddAdditionalField { get; set; }
|
||||
public RelayCommand<EntryFieldVm> DeleteAdditionalField { get; set; }
|
||||
public RelayCommand<FieldVm> DeleteAdditionalField { get; set; }
|
||||
public RelayCommand<Attachment> OpenAttachmentCommand { get; set; }
|
||||
public RelayCommand AddAttachmentCommand { get; set; }
|
||||
public RelayCommand<Attachment> DeleteAttachmentCommand { get; set; }
|
||||
@@ -349,7 +385,7 @@ namespace ModernKeePass.ViewModels
|
||||
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
||||
GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id));
|
||||
AddAdditionalField = new RelayCommand(AddField, () => IsCurrentEntry);
|
||||
DeleteAdditionalField = new RelayCommand<EntryFieldVm>(async field => await DeleteField(field), field => field != null && IsCurrentEntry);
|
||||
DeleteAdditionalField = new RelayCommand<FieldVm>(async field => await DeleteField(field), field => field != null && IsCurrentEntry);
|
||||
OpenAttachmentCommand = new RelayCommand<Attachment>(async attachment => await OpenAttachment(attachment));
|
||||
AddAttachmentCommand = new RelayCommand(async () => await AddAttachment(), () => IsCurrentEntry);
|
||||
DeleteAttachmentCommand = new RelayCommand<Attachment>(async attachment => await DeleteAttachment(attachment), _ => IsCurrentEntry);
|
||||
@@ -412,7 +448,8 @@ namespace ModernKeePass.ViewModels
|
||||
|
||||
private async Task SetFieldValue(string fieldName, object value, bool isProtected)
|
||||
{
|
||||
await _mediator.Send(new UpsertFieldCommand { EntryId = Id, FieldName = fieldName, FieldValue = value, IsProtected = isProtected});
|
||||
var protectedValue = isProtected ? await _cryptography.Protect(value?.ToString()) : value;
|
||||
await _mediator.Send(new UpsertFieldCommand { EntryId = Id, FieldName = fieldName, FieldValue = protectedValue, IsProtected = isProtected});
|
||||
UpdateDirtyStatus(true);
|
||||
}
|
||||
|
||||
@@ -424,11 +461,11 @@ namespace ModernKeePass.ViewModels
|
||||
|
||||
private void AddField()
|
||||
{
|
||||
AdditionalFields.Add(new EntryFieldVm(_cryptography));
|
||||
AdditionalFields.Add(new FieldVm());
|
||||
AdditionalFieldSelectedIndex = AdditionalFields.Count - 1;
|
||||
}
|
||||
|
||||
private async Task DeleteField(EntryFieldVm field)
|
||||
private async Task DeleteField(FieldVm field)
|
||||
{
|
||||
AdditionalFields.Remove(field);
|
||||
if (!string.IsNullOrEmpty(field.Name))
|
||||
|
@@ -321,7 +321,6 @@
|
||||
<Flyout>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<core:DataTriggerBehavior Binding="{Binding Password}" ComparisonCondition="NotEqual" Value="" >
|
||||
<!--<actions:CloseFlyoutAction />-->
|
||||
<core:CallMethodAction MethodName="Hide" />
|
||||
</core:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
@@ -506,12 +505,12 @@
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox Grid.Row="0" Text="{Binding Name, Mode=TwoWay}" Width="350"
|
||||
<TextBox Grid.Row="0" Text="{Binding Path=DataContext.AdditionalFieldName, ElementName=Page, Mode=TwoWay}" Width="350"
|
||||
IsEnabled="{Binding Path=DataContext.IsCurrentEntry, ElementName=Page}" />
|
||||
<TextBox Grid.Row="1" AcceptsReturn="True" Height="100" TextWrapping="Wrap" Width="350" Margin="0,5,0,0"
|
||||
Text="{Binding Value, Mode=TwoWay}"
|
||||
Text="{Binding Path=DataContext.AdditionalFieldValue, ElementName=Page, Mode=TwoWay}"
|
||||
IsEnabled="{Binding Path=DataContext.IsCurrentEntry, ElementName=Page}" />
|
||||
<ToggleSwitch Grid.Row="2" x:Uid="EntryEnableFieldProtection" HorizontalAlignment="Left" IsOn="{Binding IsProtected, Mode=TwoWay}" />
|
||||
<ToggleSwitch Grid.Row="2" x:Uid="EntryEnableFieldProtection" HorizontalAlignment="Left" IsOn="{Binding Path=DataContext.AdditionalFieldIsProtected, ElementName=Page, Mode=TwoWay}" />
|
||||
<Button Grid.Row="2" x:Uid="EntryDeleteAdditionalField" HorizontalAlignment="Right" Margin="0,15,0,0" Command="{Binding Path=DataContext.DeleteAdditionalField, ElementName=Page}" CommandParameter="{Binding}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
@@ -7,8 +7,8 @@
|
||||
mc:Ignorable="d">
|
||||
<ComboBox x:Name="ComboBox"
|
||||
ItemsSource="{Binding Colors, ElementName=UserControl}"
|
||||
SelectionChanged="Selector_OnSelectionChanged"
|
||||
Loaded="ComboBox_Loaded"
|
||||
SelectedValue="{Binding SelectedColor, ElementName=UserControl, Mode=TwoWay}"
|
||||
SelectedValuePath="ColorBrush"
|
||||
IsEnabled="{Binding IsEnabled, ElementName=UserControl}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
|
@@ -46,16 +46,5 @@ namespace ModernKeePass.Views.UserControls
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ComboBox.SelectedItem = Colors.Find(c => c.ColorBrush.Color.Equals(SelectedColor.Color));
|
||||
}
|
||||
|
||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selectedItem = ComboBox.SelectedItem as Color? ?? new Color();
|
||||
SelectedColor = selectedItem.ColorBrush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -93,6 +93,7 @@
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="DependencyInjection.cs" />
|
||||
<Compile Include="Log\HockeyAppLog.cs" />
|
||||
<Compile Include="Models\NavigationItem.cs" />
|
||||
<Compile Include="ViewModels\ViewModelLocator.cs" />
|
||||
<Compile Include="Views\MainPageFrames\DonatePage.xaml.cs">
|
||||
|
@@ -32,16 +32,19 @@ namespace ModernKeePass.ViewModels.ListItems
|
||||
}
|
||||
set
|
||||
{
|
||||
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = value, IsProtected = IsProtected });
|
||||
Set(nameof(Value), ref _value, value);
|
||||
var protectedValue = IsProtected ? _cryptography.Protect(value).GetAwaiter().GetResult() : value;
|
||||
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = protectedValue, IsProtected = IsProtected });
|
||||
Set(nameof(Value), ref _value, protectedValue);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsProtected
|
||||
{
|
||||
get { return _isProtected; }
|
||||
set
|
||||
{
|
||||
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = Value, IsProtected = value });
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = Value, IsProtected = value });
|
||||
Set(nameof(IsProtected), ref _isProtected, value);
|
||||
}
|
||||
}
|
||||
|
37
WinAppCommon/ViewModels/UserControls/ColorPickerVm.cs
Normal file
37
WinAppCommon/ViewModels/UserControls/ColorPickerVm.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
{
|
||||
public class ColorPickerVm
|
||||
{
|
||||
public struct Color
|
||||
{
|
||||
public string ColorName { get; set; }
|
||||
public SolidColorBrush ColorBrush { get; set; }
|
||||
}
|
||||
|
||||
public List<Color> Colors { get; }
|
||||
|
||||
public Color SelectedItem { get; set; }
|
||||
|
||||
public ColorPickerVm()
|
||||
{
|
||||
Colors = new List<Color>();
|
||||
var type = typeof(Windows.UI.Colors);
|
||||
var properties = type.GetRuntimeProperties().ToArray();
|
||||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var color = new Color
|
||||
{
|
||||
ColorName = propertyInfo.Name,
|
||||
ColorBrush = new SolidColorBrush((Windows.UI.Color) propertyInfo.GetValue(null, null))
|
||||
};
|
||||
Colors.Add(color);
|
||||
if (color.ColorBrush.Color.Equals(SelectedColor.Color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user