simplified some of the credential management classes

This commit is contained in:
David Sparer
2018-12-28 11:45:03 -06:00
parent 29d44d103d
commit e0486bec7d
37 changed files with 459 additions and 329 deletions

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using mRemoteNG.Config;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using NSubstitute;
using NUnit.Framework;
// ReSharper disable ObjectCreationAsStatement
@@ -10,7 +11,7 @@ namespace mRemoteNGTests.Credential
{
public class CredentialServiceFacadeTests
{
private CredentialServiceFacade _credentialService;
private CredentialService _credentialService;
private ICredentialRepositoryList _credentialRepositoryList;
private ILoader<IEnumerable<ICredentialRepository>> _loader;
private ISaver<IEnumerable<ICredentialRepository>> _saver;
@@ -21,25 +22,31 @@ namespace mRemoteNGTests.Credential
_credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
_loader = Substitute.For<ILoader<IEnumerable<ICredentialRepository>>>();
_saver = Substitute.For<ISaver<IEnumerable<ICredentialRepository>>>();
_credentialService = new CredentialServiceFacade(_credentialRepositoryList, _loader, _saver);
_credentialService = new CredentialService(_credentialRepositoryList, new List<ICredentialRepositoryFactory>(), _loader, _saver);
}
[Test]
public void CantProvideNullRepoListToCtor()
{
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(null, _loader, _saver));
Assert.Throws<ArgumentNullException>(() => new CredentialService(null, new List<ICredentialRepositoryFactory>(), _loader, _saver));
}
[Test]
public void CantProvideNullFactoryListToCtor()
{
Assert.Throws<ArgumentNullException>(() => new CredentialService(_credentialRepositoryList, null, _loader, _saver));
}
[Test]
public void CantProvideNullRepoLoaderToCtor()
{
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(_credentialRepositoryList, null, _saver));
Assert.Throws<ArgumentNullException>(() => new CredentialService(_credentialRepositoryList, new List<ICredentialRepositoryFactory>(), null, _saver));
}
[Test]
public void CantProvideNullRepoSaverToCtor()
{
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(_credentialRepositoryList, _loader, null));
Assert.Throws<ArgumentNullException>(() => new CredentialService(_credentialRepositoryList, new List<ICredentialRepositoryFactory>(), _loader, null));
}
[Test]

View File

@@ -86,7 +86,7 @@ namespace mRemoteNG.App
serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer);
break;
case SaveFormat.mRCSV:
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog);
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialService.RepositoryList);
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);

View File

@@ -9,7 +9,7 @@ namespace mRemoteNG.App.Initialization
{
public class CredsAndConsSetup
{
public void LoadCredsAndCons(ConnectionsService connectionsService, CredentialServiceFacade credentialService)
public void LoadCredsAndCons(ConnectionsService connectionsService, CredentialService credentialService)
{
new SaveConnectionsOnEdit(connectionsService);
@@ -21,7 +21,7 @@ namespace mRemoteNG.App.Initialization
Runtime.LoadConnections();
}
private void LoadDefaultConnectionCredentials(CredentialServiceFacade credentialService)
private void LoadDefaultConnectionCredentials(CredentialService credentialService)
{
var defaultCredId = Settings.Default.ConDefaultCredentialRecord;
var matchedCredentials = credentialService

View File

@@ -2,7 +2,6 @@ using mRemoteNG.App.Info;
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Messages;
using mRemoteNG.Security;
using mRemoteNG.Tools;
@@ -42,8 +41,7 @@ namespace mRemoteNG.App
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
public static CredentialServiceFacade CredentialService { get; } = new CredentialServiceFactory().Build();
public static CredentialService CredentialService { get; } = new CredentialServiceFactory().Build();
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance, CredentialService);
#region Connections Loading/Saving

View File

@@ -26,7 +26,7 @@ namespace mRemoteNG.Config.Connections
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialService.RepositoryList);
var dataProvider = new FileDataProvider(_connectionFileName);
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
dataProvider.Save(csvContent);

View File

@@ -18,9 +18,9 @@ namespace mRemoteNG.Config.Connections
private readonly string _credentialFilePath = Path.Combine(CredentialsFileInfo.CredentialsPath, CredentialsFileInfo.CredentialsFile);
private readonly string _connectionFilePath;
private readonly ConnectionsService _connectionsService;
private readonly CredentialServiceFacade _credentialService;
private readonly CredentialService _credentialService;
public XmlConnectionsLoader(string connectionFilePath, CredentialServiceFacade credentialService, ConnectionsService connectionsService)
public XmlConnectionsLoader(string connectionFilePath, CredentialService credentialService, ConnectionsService connectionsService)
{
if (string.IsNullOrEmpty(connectionFilePath))
throw new ArgumentException($"{nameof(connectionFilePath)} cannot be null or empty");

View File

@@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Credential;
namespace mRemoteNG.Config
{
public class CredentialRepositoryListLoader : ILoader<IEnumerable<ICredentialRepository>>
{
private readonly IDataProvider<string> _dataProvider;
private readonly CredentialRepositoryListDeserializer _deserializer;
public CredentialRepositoryListLoader(IDataProvider<string> dataProvider, CredentialRepositoryListDeserializer deserializer)
{
if (dataProvider == null)
throw new ArgumentNullException(nameof(dataProvider));
if (deserializer == null)
throw new ArgumentNullException(nameof(deserializer));
_dataProvider = dataProvider;
_deserializer = deserializer;
}
public IEnumerable<ICredentialRepository> Load()
{
var data = _dataProvider.Load();
return _deserializer.Deserialize(data);
}
}
}

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
namespace mRemoteNG.Config
{
public class CredentialRepositoryListPersistor : ISaver<IEnumerable<ICredentialRepository>>, ILoader<IEnumerable<ICredentialRepository>>
{
private readonly IReadOnlyCollection<ICredentialRepositoryFactory> _repositoryFactories;
private readonly IDataProvider<string> _dataProvider;
private readonly CredentialRepositoryListDeserializer _deserializer;
private readonly CredentialRepositoryListSerializer _serializer;
public CredentialRepositoryListPersistor(
IDataProvider<string> dataProvider,
IReadOnlyCollection<ICredentialRepositoryFactory> repositoryFactories)
{
_repositoryFactories = repositoryFactories.ThrowIfNull(nameof(repositoryFactories));
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
_deserializer = new CredentialRepositoryListDeserializer();
_serializer = new CredentialRepositoryListSerializer();
}
public IEnumerable<ICredentialRepository> Load()
{
var data = _dataProvider.Load();
return _deserializer.Deserialize(data, _repositoryFactories);
}
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
{
var data = _serializer.Serialize(repositories);
_dataProvider.Save(data);
}
}
}

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Credential;
namespace mRemoteNG.Config
{
public class CredentialRepositoryListSaver : ISaver<IEnumerable<ICredentialRepository>>
{
private readonly IDataProvider<string> _dataProvider;
public CredentialRepositoryListSaver(IDataProvider<string> dataProvider)
{
if (dataProvider == null)
throw new ArgumentNullException(nameof(dataProvider));
_dataProvider = dataProvider;
}
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
{
var serializer = new CredentialRepositoryListSerializer();
var data = serializer.Serialize(repositories);
_dataProvider.Save(data);
}
}
}

View File

@@ -9,27 +9,38 @@ namespace mRemoteNG.Config.Serializers.CredentialProviderSerializer
{
public class CredentialRepositoryListDeserializer
{
private readonly ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
private readonly ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
public CredentialRepositoryListDeserializer(ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer, ISecureDeserializer<string, IEnumerable<ICredentialRecord>> deserializer)
public IEnumerable<ICredentialRepository> Deserialize(string xml, IEnumerable<ICredentialRepositoryFactory> factories)
{
if (serializer == null)
throw new ArgumentNullException(nameof(serializer));
if (deserializer == null)
throw new ArgumentNullException(nameof(deserializer));
if (string.IsNullOrEmpty(xml))
return new ICredentialRepository[0];
_serializer = serializer;
_deserializer = deserializer;
}
public IEnumerable<ICredentialRepository> Deserialize(string xml)
{
if (string.IsNullOrEmpty(xml)) return new ICredentialRepository[0];
var xdoc = XDocument.Parse(xml);
var repoEntries = xdoc.Descendants("CredentialRepository");
var xmlRepoFactory = new XmlCredentialRepositoryFactory(_serializer, _deserializer);
return repoEntries.Select(xmlRepoFactory.Build);
return repoEntries
.Select(ParseConfigEntries)
.Select(config =>
factories
.FirstOrDefault(f => string.Equals(f.SupportsConfigType, config.TypeName))?
.Build(config));
}
public ICredentialRepositoryConfig ParseConfigEntries(XElement repositoryXElement)
{
var stringId = repositoryXElement.Attribute("Id")?.Value;
Guid.TryParse(stringId, out var id);
if (id.Equals(Guid.Empty))
id = Guid.NewGuid();
var config = new CredentialRepositoryConfig(id)
{
TypeName = repositoryXElement.Attribute("TypeName")?.Value,
Title = repositoryXElement.Attribute("Title")?.Value,
Source = repositoryXElement.Attribute("Source")?.Value
};
return config;
}
}
}

View File

@@ -17,7 +17,7 @@ namespace mRemoteNG.Config.Serializers.Versioning
{
public class XmlCredentialManagerUpgrader : IDeserializer<string, ConnectionTreeModel>
{
private readonly CredentialServiceFacade _credentialsService;
private readonly CredentialService _credentialsService;
private readonly IDeserializer<string, ConnectionTreeModel> _decoratedDeserializer;
private readonly SecureString _newRepoPassword;
@@ -25,7 +25,7 @@ namespace mRemoteNG.Config.Serializers.Versioning
public XmlCredentialManagerUpgrader(
CredentialServiceFacade credentialsService,
CredentialService credentialsService,
string credentialFilePath,
IDeserializer<string, ConnectionTreeModel> decoratedDeserializer,
SecureString newRepoPassword)
@@ -103,22 +103,20 @@ namespace mRemoteNG.Config.Serializers.Versioning
private ICredentialRepository BuildXmlCredentialRepo(SecureString newCredRepoKey)
{
var cryptoFromSettings = new CryptoProviderFactoryFromSettings();
var credRepoSerializer = new XmlCredentialPasswordEncryptorDecorator(
cryptoFromSettings.Build(),
new XmlCredentialRecordSerializer());
var credRepoDeserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer());
var repositoryConfig = new CredentialRepositoryConfig
{
Source = CredentialFilePath,
Title = "Converted Credentials",
TypeName = "Xml",
Key = newCredRepoKey
};
var xmlRepoFactory = _credentialsService.GetRepositoryFactoryForConfig(repositoryConfig);
var xmlRepoFactory = new XmlCredentialRepositoryFactory(credRepoSerializer, credRepoDeserializer);
var newRepo = xmlRepoFactory.Build(
new CredentialRepositoryConfig
{
Source = CredentialFilePath,
Title = "Converted Credentials",
TypeName = "Xml",
Key = newCredRepoKey
}
);
if (!xmlRepoFactory.Any())
throw new CredentialRepositoryTypeNotSupportedException(repositoryConfig.TypeName);
var newRepo = xmlRepoFactory.First().Build(repositoryConfig);
newRepo.LoadCredentials(newCredRepoKey);
return newRepo;
}

View File

@@ -189,7 +189,7 @@ namespace mRemoteNG.Connection
get
{
var credential = CredentialRecordId
.Select(guid => Runtime.CredentialProviderCatalog.GetCredentialRecord(guid))
.Select(guid => Runtime.CredentialService.RepositoryList.GetCredentialRecord(guid))
.FirstOrDefault();
return credential ?? new PlaceholderCredentialRecord(CredentialRecordId);
}

View File

@@ -30,7 +30,7 @@ namespace mRemoteNG.Connection
private bool _batchingSaves = false;
private bool _saveRequested = false;
private bool _saveAsyncRequested = false;
private readonly CredentialServiceFacade _credentialService;
private readonly CredentialService _credentialService;
public bool IsConnectionsFileLoaded { get; set; }
public bool UsingDatabase { get; private set; }
@@ -40,7 +40,7 @@ namespace mRemoteNG.Connection
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
public ConnectionsService(PuttySessionsManager puttySessionsManager, CredentialServiceFacade credentialService)
public ConnectionsService(PuttySessionsManager puttySessionsManager, CredentialService credentialService)
{
_puttySessionsManager = puttySessionsManager.ThrowIfNull(nameof(puttySessionsManager));
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));

View File

@@ -34,7 +34,7 @@ namespace mRemoteNG.Credential
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is Guid)) return base.ConvertFrom(context, culture, value);
var matchedCredentials = Runtime.CredentialProviderCatalog.GetCredentialRecords().Where(record => record.Id.Equals(value)).ToArray();
var matchedCredentials = Runtime.CredentialService.RepositoryList.GetCredentialRecords().Where(record => record.Id.Equals(value)).ToArray();
return matchedCredentials.Any() ? matchedCredentials.First() : null;
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using mRemoteNG.Config;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
using mRemoteNG.Tools.CustomCollections;
namespace mRemoteNG.Credential
{
public class CredentialService
{
private readonly List<ICredentialRepositoryFactory> _repositoryFactories;
private readonly ILoader<IEnumerable<ICredentialRepository>> _loader;
private readonly ISaver<IEnumerable<ICredentialRepository>> _saver;
public ICredentialRepositoryList RepositoryList { get; }
public IReadOnlyCollection<ICredentialRepositoryFactory> RepositoryFactories => _repositoryFactories;
public CredentialService(
ICredentialRepositoryList repositoryList,
List<ICredentialRepositoryFactory> repositoryFactories,
ILoader<IEnumerable<ICredentialRepository>> loader,
ISaver<IEnumerable<ICredentialRepository>> saver)
{
RepositoryList = repositoryList.ThrowIfNull(nameof(repositoryList));
_repositoryFactories = repositoryFactories.ThrowIfNull(nameof(repositoryFactories));
_loader = loader.ThrowIfNull(nameof(loader));
_saver = saver.ThrowIfNull(nameof(saver));
SetupEventHandlers();
}
public void SaveRepositoryList()
{
_saver.Save(RepositoryList);
}
public void LoadRepositoryList()
{
var loadedRepositories = _loader.Load();
foreach (var repository in loadedRepositories)
{
RepositoryList.AddProvider(repository);
}
}
public void AddRepository(ICredentialRepository repository)
{
RepositoryList.AddProvider(repository);
}
public void RemoveRepository(ICredentialRepository repository)
{
RepositoryList.RemoveProvider(repository);
}
public IEnumerable<ICredentialRecord> GetCredentialRecords()
{
return RepositoryList.GetCredentialRecords();
}
public ICredentialRecord GetCredentialRecord(Guid id)
{
return RepositoryList.GetCredentialRecord(id);
}
/// <summary>
/// Registers an <see cref="ICredentialRepositoryFactory"/> for
/// use throughout the application.
/// </summary>
/// <param name="factory"></param>
public void RegisterRepositoryFactory(ICredentialRepositoryFactory factory)
{
if (_repositoryFactories.Contains(factory))
return;
_repositoryFactories.Add(factory);
}
public Optional<ICredentialRepositoryFactory> GetRepositoryFactoryForConfig(ICredentialRepositoryConfig repositoryConfig)
{
return new Optional<ICredentialRepositoryFactory>(
RepositoryFactories
.FirstOrDefault(factory =>
string.Equals(factory.SupportsConfigType, repositoryConfig.TypeName)));
}
#region Setup
private void SetupEventHandlers()
{
RepositoryList.RepositoriesUpdated += HandleRepositoriesUpdatedEvent;
RepositoryList.CredentialsUpdated += HandleCredentialsUpdatedEvent;
}
private void HandleRepositoriesUpdatedEvent(object sender, CollectionUpdatedEventArgs<ICredentialRepository> collectionUpdatedEventArgs)
{
SaveRepositoryList();
}
private void HandleCredentialsUpdatedEvent(object sender, CollectionUpdatedEventArgs<ICredentialRecord> collectionUpdatedEventArgs)
{
var repo = sender as ICredentialRepository;
repo?.SaveCredentials(repo.Config.Key);
}
#endregion
}
}

View File

@@ -1,83 +0,0 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Config;
using mRemoteNG.Tools.CustomCollections;
namespace mRemoteNG.Credential
{
public class CredentialServiceFacade
{
private readonly ICredentialRepositoryList _repositoryList;
private readonly ILoader<IEnumerable<ICredentialRepository>> _loader;
private readonly ISaver<IEnumerable<ICredentialRepository>> _saver;
public IEnumerable<ICredentialRepository> CredentialRepositories => _repositoryList;
public CredentialServiceFacade(ICredentialRepositoryList repositoryList, ILoader<IEnumerable<ICredentialRepository>> loader, ISaver<IEnumerable<ICredentialRepository>> saver)
{
if (repositoryList == null)
throw new ArgumentNullException(nameof(repositoryList));
if (loader == null)
throw new ArgumentNullException(nameof(loader));
if (saver == null)
throw new ArgumentNullException(nameof(saver));
_repositoryList = repositoryList;
_loader = loader;
_saver = saver;
SetupEventHandlers();
}
public void SaveRepositoryList()
{
_saver.Save(_repositoryList);
}
public void LoadRepositoryList()
{
foreach (var repository in _loader.Load())
{
_repositoryList.AddProvider(repository);
}
}
public void AddRepository(ICredentialRepository repository)
{
_repositoryList.AddProvider(repository);
}
public void RemoveRepository(ICredentialRepository repository)
{
_repositoryList.RemoveProvider(repository);
}
public IEnumerable<ICredentialRecord> GetCredentialRecords()
{
return _repositoryList.GetCredentialRecords();
}
public ICredentialRecord GetCredentialRecord(Guid id)
{
return _repositoryList.GetCredentialRecord(id);
}
#region Setup
private void SetupEventHandlers()
{
_repositoryList.RepositoriesUpdated += HandleRepositoriesUpdatedEvent;
_repositoryList.CredentialsUpdated += HandleCredentialsUpdatedEvent;
}
private void HandleRepositoriesUpdatedEvent(object sender, CollectionUpdatedEventArgs<ICredentialRepository> collectionUpdatedEventArgs)
{
SaveRepositoryList();
}
private void HandleCredentialsUpdatedEvent(object sender, CollectionUpdatedEventArgs<ICredentialRecord> collectionUpdatedEventArgs)
{
var repo = sender as ICredentialRepository;
repo?.SaveCredentials(repo.Config.Key);
}
#endregion
}
}

View File

@@ -1,33 +1,24 @@
using System.IO;
using mRemoteNG.App;
using System.Collections.Generic;
using System.IO;
using mRemoteNG.App.Info;
using mRemoteNG.Config;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Security.Factories;
using mRemoteNG.Credential.Repositories;
namespace mRemoteNG.Credential
{
public class CredentialServiceFactory
{
// When we get a true CompositionRoot we can move this to that class. We should only require 1 instance of this service at a time
public CredentialServiceFacade Build()
public CredentialService Build()
{
var cryptoFromSettings = new CryptoProviderFactoryFromSettings();
var credRepoSerializer = new XmlCredentialPasswordEncryptorDecorator(
cryptoFromSettings.Build(),
new XmlCredentialRecordSerializer());
var credRepoDeserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer());
var repositoryList = new CredentialRepositoryList();
var credentialRepoListPath = Path.Combine(SettingsFileInfo.SettingsPath, "credentialRepositories.xml");
var repoListDataProvider = new FileDataProvider(credentialRepoListPath);
var repoListLoader = new CredentialRepositoryListLoader(
repoListDataProvider,
new CredentialRepositoryListDeserializer(credRepoSerializer, credRepoDeserializer));
var repoListSaver = new CredentialRepositoryListSaver(repoListDataProvider);
var repositoryFactories = new List<ICredentialRepositoryFactory>();
var persistor = new CredentialRepositoryListPersistor(repoListDataProvider, repositoryFactories);
return new CredentialServiceFacade(Runtime.CredentialProviderCatalog, repoListLoader, repoListSaver);
return new CredentialService(repositoryList, repositoryFactories, persistor, persistor);
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace mRemoteNG.Credential.Repositories
{
public class CredentialRepositoryTypeNotSupportedException : Exception
{
public CredentialRepositoryTypeNotSupportedException()
{
}
public CredentialRepositoryTypeNotSupportedException(string message)
: base(message)
{
}
public CredentialRepositoryTypeNotSupportedException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@@ -0,0 +1,20 @@
namespace mRemoteNG.Credential.Repositories
{
public interface ICredentialRepositoryFactory
{
/// <summary>
/// The <see cref="ICredentialRepositoryConfig.TypeName"/> that this factory can build.
/// </summary>
string SupportsConfigType { get; }
/// <summary>
/// Builds a new <see cref="ICredentialRepositoryFactory"/> given the <see cref="ICredentialRepositoryConfig"/>
/// that describes it. The <see cref="ICredentialRepositoryConfig.TypeName"/> must match this factory's
/// <see cref="SupportsConfigType"/> property.
/// </summary>
/// <param name="config"></param>
/// <param name="isLoaded"></param>
/// <returns></returns>
ICredentialRepository Build(ICredentialRepositoryConfig config, bool isLoaded = false);
}
}

View File

@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Linq;
using System.Security;
using mRemoteNG.Config;
using mRemoteNG.Tools;
using mRemoteNG.Tools.CustomCollections;
namespace mRemoteNG.Credential.Repositories
@@ -17,21 +18,33 @@ namespace mRemoteNG.Credential.Repositories
public IList<ICredentialRecord> CredentialRecords { get; }
public bool IsLoaded { get; private set; }
public XmlCredentialRepository(ICredentialRepositoryConfig config, CredentialRecordSaver credentialRecordSaver, CredentialRecordLoader credentialRecordLoader)
/// <summary>
/// Creates a new <see cref="XmlCredentialRepository"/> instance,
/// providing access to load and save credentials stored in an XML
/// format.
/// </summary>
/// <param name="config">
/// The config representing this repository
/// </param>
/// <param name="credentialRecordSaver"></param>
/// <param name="credentialRecordLoader"></param>
/// <param name="isLoaded">
/// Does this instance represent a repository that is already loaded?
/// </param>
public XmlCredentialRepository(
ICredentialRepositoryConfig config,
CredentialRecordSaver credentialRecordSaver,
CredentialRecordLoader credentialRecordLoader,
bool isLoaded = false)
{
if (config == null)
throw new ArgumentNullException(nameof(config));
if (credentialRecordSaver == null)
throw new ArgumentNullException(nameof(credentialRecordSaver));
if (credentialRecordLoader == null)
throw new ArgumentNullException(nameof(credentialRecordLoader));
Config = config.ThrowIfNull(nameof(config));
_credentialRecordSaver = credentialRecordSaver.ThrowIfNull(nameof(credentialRecordSaver));
_credentialRecordLoader = credentialRecordLoader.ThrowIfNull(nameof(credentialRecordLoader));
IsLoaded = isLoaded;
Config = config;
CredentialRecords = new FullyObservableCollection<ICredentialRecord>();
((FullyObservableCollection<ICredentialRecord>) CredentialRecords).CollectionUpdated += RaiseCredentialsUpdatedEvent;
Config.PropertyChanged += (sender, args) => RaiseRepositoryConfigUpdatedEvent(args);
_credentialRecordSaver = credentialRecordSaver;
_credentialRecordLoader = credentialRecordLoader;
}
public void LoadCredentials(SecureString key)
@@ -39,9 +52,12 @@ namespace mRemoteNG.Credential.Repositories
var credentials = _credentialRecordLoader.Load(key);
foreach (var newCredential in credentials)
{
if (ThisIsADuplicateCredentialRecord(newCredential)) continue;
if (ThisIsADuplicateCredentialRecord(newCredential))
continue;
CredentialRecords.Add(newCredential);
}
IsLoaded = true;
Config.Key = key;
}
@@ -59,7 +75,9 @@ namespace mRemoteNG.Credential.Repositories
public void SaveCredentials(SecureString key)
{
if (!IsLoaded) return;
if (!IsLoaded)
return;
_credentialRecordSaver.Save(CredentialRecords, key);
}

View File

@@ -1,54 +1,41 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Collections.Generic;
using mRemoteNG.Config;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Tools;
namespace mRemoteNG.Credential.Repositories
{
public class XmlCredentialRepositoryFactory
public class XmlCredentialRepositoryFactory : ICredentialRepositoryFactory
{
private readonly ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
private readonly ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
public XmlCredentialRepositoryFactory(ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer, ISecureDeserializer<string, IEnumerable<ICredentialRecord>> deserializer)
public XmlCredentialRepositoryFactory(
ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer,
ISecureDeserializer<string, IEnumerable<ICredentialRecord>> deserializer)
{
if (serializer == null)
throw new ArgumentNullException(nameof(serializer));
if (deserializer == null)
throw new ArgumentNullException(nameof(deserializer));
_serializer = serializer;
_deserializer = deserializer;
_serializer = serializer.ThrowIfNull(nameof(serializer));
_deserializer = deserializer.ThrowIfNull(nameof(deserializer));
}
public ICredentialRepository Build(ICredentialRepositoryConfig config)
{
return BuildXmlRepo(config);
}
public string SupportsConfigType { get; } = "Xml";
public ICredentialRepository Build(XElement repositoryXElement)
{
var stringId = repositoryXElement.Attribute("Id")?.Value;
Guid id;
Guid.TryParse(stringId, out id);
if (id.Equals(Guid.Empty)) id = Guid.NewGuid();
var config = new CredentialRepositoryConfig(id)
{
TypeName = repositoryXElement.Attribute("TypeName")?.Value,
Title = repositoryXElement.Attribute("Title")?.Value,
Source = repositoryXElement.Attribute("Source")?.Value
};
return BuildXmlRepo(config);
}
private ICredentialRepository BuildXmlRepo(ICredentialRepositoryConfig config)
/// <summary>
/// Creates a new <see cref="XmlCredentialRepository"/> instance for
/// the given <see cref="ICredentialRepositoryConfig"/>.
/// </summary>
/// <param name="config"></param>
/// <param name="isLoaded">
/// Does this instance represent a repository that is already loaded?
/// </param>
public ICredentialRepository Build(ICredentialRepositoryConfig config, bool isLoaded = false)
{
var dataProvider = new FileDataProvider(config.Source);
var saver = new CredentialRecordSaver(dataProvider, _serializer);
var loader = new CredentialRecordLoader(dataProvider, _deserializer);
return new XmlCredentialRepository(config, saver, loader);
return new XmlCredentialRepository(config, saver, loader, isLoaded);
}
}
}

View File

@@ -17,8 +17,8 @@ namespace mRemoteNG.Tools.CustomCollections
public T this[int index]
{
get { return _list[index]; }
set { _list[index] = value; }
get => _list[index];
set => _list[index] = value;
}
public FullyObservableCollection()

View File

@@ -43,7 +43,8 @@ namespace mRemoteNG.Tools
return new Optional<T>(value);
}
public static Optional<TOut> FromNullable<TOut>(TOut? value) where TOut : struct
public static Optional<TOut> FromNullable<TOut>(TOut? value)
where TOut : struct
{
return value.HasValue
? new Optional<TOut>(value.Value)

View File

@@ -21,9 +21,7 @@ namespace mRemoteNG.UI.Controls.Adapters
_editorService = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
if (_editorService == null) return value;
var credentialManager = Runtime.CredentialProviderCatalog;
var listBox = new CredentialRecordListBox(credentialManager.GetCredentialRecords());
var listBox = new CredentialRecordListBox(Runtime.CredentialService.RepositoryList.GetCredentialRecords());
listBox.SelectedValueChanged += ListBoxOnSelectedValueChanged;
_editorService.DropDownControl(listBox);

View File

@@ -1,4 +1,6 @@
using System.Drawing;
using mRemoteNG.Credential;
using mRemoteNG.UI.Controls.PageSequence;
namespace mRemoteNG.UI.Controls
{
@@ -7,5 +9,6 @@ namespace mRemoteNG.UI.Controls
string Text { get; set; }
Image Image { get; }
T Config { get; }
SequencedControl BuildEditorPage(ICredentialRepositoryList repositoryList);
}
}

View File

@@ -60,8 +60,10 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private void buttonAccept_Click_1(object sender, EventArgs e)
{
SaveFormToCredential();
if (!_credentialRepository.CredentialRecords.Contains(_credentialRecord))
_credentialRepository.CredentialRecords.Add(_credentialRecord);
RaiseNextPageEvent();
}

View File

@@ -1,8 +1,10 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Controls.PageSequence;
using mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPages;
@@ -12,24 +14,20 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
{
public sealed partial class CredentialRepositoriesPage : SequencedControl, ICredentialManagerPage
{
private readonly ICredentialRepositoryList _providerCatalog;
private readonly CredentialService _credentialService;
private readonly UnlockerFormFactory _unlockerFactory;
public string PageName { get; } = "Sources";
public Image PageIcon { get; } = Resources.folder_key;
public CredentialRepositoriesPage(ICredentialRepositoryList providerCatalog, UnlockerFormFactory unlockerFactory)
public CredentialRepositoriesPage(CredentialService credentialService, UnlockerFormFactory unlockerFactory)
{
if (providerCatalog == null)
throw new ArgumentNullException(nameof(providerCatalog));
if (unlockerFactory == null)
throw new ArgumentNullException(nameof(unlockerFactory));
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
_unlockerFactory = unlockerFactory.ThrowIfNull(nameof(unlockerFactory));
_providerCatalog = providerCatalog;
_unlockerFactory = unlockerFactory;
InitializeComponent();
ApplyTheme();
credentialRepositoryListView.CredentialRepositoryList = providerCatalog;
credentialRepositoryListView.CredentialRepositoryList = credentialService.RepositoryList;
credentialRepositoryListView.SelectionChanged += (sender, args) => UpdateUi();
credentialRepositoryListView.DoubleClickHandler = EditRepository;
}
@@ -52,10 +50,10 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
new CredentialRepositoryTypeSelectionPage(
new ISelectionTarget<ICredentialRepositoryConfig>[]
{
new XmlCredentialRepositorySelector(),
new XmlCredentialRepositorySelector(_credentialService),
//new KeePassRepositorySelector()
},
_providerCatalog
_credentialService.RepositoryList
)
{ Dock = DockStyle.Fill },
new SequencedControl(),
@@ -67,19 +65,33 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private void buttonEdit_Click(object sender, EventArgs e)
{
var selectedRepository = credentialRepositoryListView.SelectedRepository;
if (selectedRepository == null) return;
if (selectedRepository == null)
return;
EditRepository(selectedRepository);
}
private bool EditRepository(ICredentialRepository repository)
{
if (!repository.IsLoaded) return false;
var editorPage = CredentialRepositoryPageEditorFactory.BuildXmlCredentialRepositoryEditorPage(repository.Config, _providerCatalog);
if (!repository.IsLoaded)
return false;
var repositoryFactory = _credentialService.GetRepositoryFactoryForConfig(repository.Config);
if (!repositoryFactory.Any())
throw new CredentialRepositoryTypeNotSupportedException(repository.Config.TypeName);
var editorPage = new XmlCredentialRepositoryEditorPage(repository.Config, _credentialService.RepositoryList, repositoryFactory.First())
{
Dock = DockStyle.Fill
};
var pageSequence = new PageSequence(Parent,
this,
editorPage,
this
);
RaiseNextPageEvent();
return true;
}
@@ -87,14 +99,18 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private void buttonRemove_Click(object sender, EventArgs e)
{
var selectedRepository = credentialRepositoryListView.SelectedRepository;
if (selectedRepository == null) return;
if (_providerCatalog.Contains(selectedRepository.Config))
_providerCatalog.RemoveProvider(selectedRepository);
if (selectedRepository == null)
return;
if (_credentialService.RepositoryList.Contains(selectedRepository.Config))
_credentialService.RepositoryList.RemoveProvider(selectedRepository);
}
private void UpdateLoadToggleButton(ICredentialRepository selectedRepository)
{
if (selectedRepository == null) return;
if (selectedRepository == null)
return;
buttonToggleLoad.Text = selectedRepository.IsLoaded ? "Unload" : "Load";
}

View File

@@ -7,9 +7,13 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPa
{
public class CredentialRepositoryPageEditorFactory
{
public static SequencedControl BuildXmlCredentialRepositoryEditorPage<T>(T config, ICredentialRepositoryList repositoryList) where T : ICredentialRepositoryConfig
public static SequencedControl BuildXmlCredentialRepositoryEditorPage<T>(T config, ICredentialRepositoryList repositoryList, XmlCredentialRepositoryFactory repositoryFactory)
where T : ICredentialRepositoryConfig
{
return new XmlCredentialRepositoryEditorPage(config, repositoryList) {Dock = DockStyle.Fill};
return new XmlCredentialRepositoryEditorPage(config, repositoryList, repositoryFactory)
{
Dock = DockStyle.Fill
};
}
}
}

View File

@@ -1,11 +1,8 @@
using System;
using System.Windows.Forms;
using mRemoteNG.Config;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Security.Factories;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls.PageSequence;
namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPages
@@ -14,8 +11,12 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPa
{
private readonly ICredentialRepositoryConfig _repositoryConfig;
private readonly ICredentialRepositoryList _repositoryList;
private readonly ICredentialRepositoryFactory _repositoryFactory;
public XmlCredentialRepositoryEditorPage(ICredentialRepositoryConfig repositoryConfig, ICredentialRepositoryList repositoryList)
public XmlCredentialRepositoryEditorPage(
ICredentialRepositoryConfig repositoryConfig,
ICredentialRepositoryList repositoryList,
ICredentialRepositoryFactory repositoryFactory)
{
if (repositoryConfig == null)
throw new ArgumentNullException(nameof(repositoryConfig));
@@ -24,6 +25,7 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPa
_repositoryConfig = repositoryConfig;
_repositoryList = repositoryList;
_repositoryFactory = repositoryFactory.ThrowIfNull(nameof(repositoryFactory));
InitializeComponent();
PopulateFields();
}
@@ -47,6 +49,7 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPa
{
if (!string.IsNullOrEmpty(_repositoryConfig.Source))
selectFilePathDialog.FileName = _repositoryConfig.Source;
var dialogResult = selectFilePathDialog.ShowDialog(this);
if (dialogResult == DialogResult.OK)
{
@@ -56,31 +59,24 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPa
private void buttonConfirm_Click(object sender, EventArgs e)
{
if (!AllRequiredFieldsFilledOut()) return;
if (!AllRequiredFieldsFilledOut())
return;
SaveValuesToConfig();
if (!_repositoryList.Contains(_repositoryConfig))
{
var newCredentialRepository = BuildXmlRepoFromSettings(_repositoryConfig);
_repositoryList.AddProvider(newCredentialRepository);
newCredentialRepository.SaveCredentials(_repositoryConfig.Key);
AddNewRepo();
}
RaiseNextPageEvent();
}
private ICredentialRepository BuildXmlRepoFromSettings(ICredentialRepositoryConfig config)
private void AddNewRepo()
{
var cryptoFromSettings = new CryptoProviderFactoryFromSettings();
var credRepoDataProvider = new FileDataProvider(config.Source);
var credRepoSerializer = new XmlCredentialPasswordEncryptorDecorator(
cryptoFromSettings.Build(),
new XmlCredentialRecordSerializer());
var credRepoDeserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer());
return new XmlCredentialRepository(
config,
new CredentialRecordSaver(credRepoDataProvider, credRepoSerializer),
new CredentialRecordLoader(credRepoDataProvider, credRepoDeserializer)
);
var newCredentialRepository = _repositoryFactory.Build(_repositoryConfig, true);
_repositoryList.AddProvider(newCredentialRepository);
newCredentialRepository.SaveCredentials(_repositoryConfig.Key);
}
private bool AllRequiredFieldsFilledOut()

View File

@@ -1,6 +1,8 @@
using System.Drawing;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Controls.PageSequence;
namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositorySelectors
{
@@ -9,5 +11,11 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositorySelector
public string Text { get; set; } = "KeePass";
public Image Image { get; } = Resources.keepass_32x32;
public ICredentialRepositoryConfig Config { get; } = new CredentialRepositoryConfig {TypeName = "KeePass"};
public SequencedControl BuildEditorPage(ICredentialRepositoryList repositoryList)
{
// TODO
return new SequencedControl();
}
}
}

View File

@@ -1,13 +1,39 @@
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Controls.PageSequence;
using mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPages;
namespace mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositorySelectors
{
public class XmlCredentialRepositorySelector : ISelectionTarget<ICredentialRepositoryConfig>
{
private readonly CredentialService _credentialService;
public string Text { get; set; } = "XML";
public Image Image { get; } = Resources.xml;
public ICredentialRepositoryConfig Config { get; } = new CredentialRepositoryConfig {TypeName = "Xml"};
public XmlCredentialRepositorySelector(CredentialService credentialService)
{
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
}
public SequencedControl BuildEditorPage(ICredentialRepositoryList repositoryList)
{
var repositoryFactory = _credentialService.GetRepositoryFactoryForConfig(Config);
if (!repositoryFactory.Any())
throw new CredentialRepositoryTypeNotSupportedException(Config.TypeName);
return new XmlCredentialRepositoryEditorPage(Config, repositoryList, repositoryFactory.First())
{
Dock = DockStyle.Fill
};
}
}
}

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using BrightIdeasSoftware;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Controls.PageSequence;
using mRemoteNG.UI.Forms.CredentialManagerPages.CredentialRepositoryEditorPages;
namespace mRemoteNG.UI.Forms.CredentialManagerPages
{
@@ -18,10 +17,8 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
{
if (selectionTargets == null)
throw new ArgumentNullException(nameof(selectionTargets));
if (repositoryList == null)
throw new ArgumentNullException(nameof(repositoryList));
_repositoryList = repositoryList;
_repositoryList = repositoryList.ThrowIfNull(nameof(repositoryList));
InitializeComponent();
ApplyTheme();
SetupListView(selectionTargets);
@@ -37,8 +34,9 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private object ImageGetter(object rowObject)
{
var selection = rowObject as ISelectionTarget<ICredentialRepositoryConfig>;
if (selection == null) return "";
if (!(rowObject is ISelectionTarget<ICredentialRepositoryConfig> selection))
return "";
var imgHash = selection.Image.GetHashCode().ToString();
if (!objectListView.LargeImageList.Images.ContainsKey(imgHash))
objectListView.LargeImageList.Images.Add(imgHash, selection.Image);
@@ -47,18 +45,21 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private void ObjectListViewOnMouseDoubleClick(object sender, MouseEventArgs mouseEventArgs)
{
if (mouseEventArgs.Clicks < 2) return;
OLVColumn column;
var listItem = objectListView.GetItemAt(mouseEventArgs.X, mouseEventArgs.Y, out column);
var clickedNode = listItem.RowObject as ISelectionTarget<ICredentialRepositoryConfig>;
if (clickedNode == null) return;
if (mouseEventArgs.Clicks < 2)
return;
var listItem = objectListView.GetItemAt(mouseEventArgs.X, mouseEventArgs.Y, out var column);
if (!(listItem.RowObject is ISelectionTarget<ICredentialRepositoryConfig> clickedNode))
return;
NextPage(clickedNode);
}
private void buttonContinue_Click(object sender, EventArgs e)
{
var selection = objectListView.SelectedObject as ISelectionTarget<ICredentialRepositoryConfig>;
if (selection == null) return;
if (!(objectListView.SelectedObject is ISelectionTarget<ICredentialRepositoryConfig> selection))
return;
NextPage(selection);
}
@@ -71,7 +72,7 @@ namespace mRemoteNG.UI.Forms.CredentialManagerPages
private SequencedControl BuildEditorPage(ISelectionTarget<ICredentialRepositoryConfig> selection)
{
var editorPage = CredentialRepositoryPageEditorFactory.BuildXmlCredentialRepositoryEditorPage(selection.Config, _repositoryList);
var editorPage = selection.BuildEditorPage(_repositoryList);
editorPage.Dock = DockStyle.Fill;
return editorPage;
}

View File

@@ -18,7 +18,7 @@ namespace mRemoteNG.UI.Forms
public IDeserializer<string, ConnectionTreeModel> ConnectionDeserializer { get; set; }
public ConnectionsService ConnectionsService { get; set; }
public CredentialServiceFacade CredentialService { get; set; }
public CredentialService CredentialService { get; set; }
public string ConnectionFilePath
{

View File

@@ -105,7 +105,6 @@ namespace mRemoteNG.UI.Forms
//
// toolsMenu
//
this.toolsMenu.CredentialProviderCatalog = null;
this.toolsMenu.MainForm = null;
this.toolsMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.toolsMenu.Name = "mMenTools";

View File

@@ -16,11 +16,14 @@ using mRemoteNG.Config;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Messages;
using mRemoteNG.Messages.MessageWriters;
using mRemoteNG.Security.Factories;
using mRemoteNG.Themes;
using mRemoteNG.Tools;
using mRemoteNG.UI.Menu;
@@ -157,6 +160,8 @@ namespace mRemoteNG.UI.Forms
_fpChainedWindowHandle = NativeMethods.SetClipboardViewer(Handle);
InitializeCredRepoFactories();
Runtime.WindowList = new WindowList();
if (Settings.Default.ResetPanels)
@@ -196,6 +201,18 @@ namespace mRemoteNG.UI.Forms
frmSplashScreen.Close();
}
private static void InitializeCredRepoFactories()
{
var cryptoFromSettings = new CryptoProviderFactoryFromSettings();
var credRepoSerializer = new XmlCredentialPasswordEncryptorDecorator(
cryptoFromSettings.Build(),
new XmlCredentialRecordSerializer());
var credRepoDeserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer());
var xmlRepoFactory = new XmlCredentialRepositoryFactory(credRepoSerializer, credRepoDeserializer);
Runtime.CredentialService.RegisterRepositoryFactory(xmlRepoFactory);
}
private void ApplyLanguage()
{
fileMenu.ApplyLanguage();
@@ -249,7 +266,7 @@ namespace mRemoteNG.UI.Forms
viewMenu.MainForm = this;
toolsMenu.MainForm = this;
toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog;
toolsMenu.CredentialService = Runtime.CredentialService;
toolsMenu.UnlockerFormFactory = _credRepoUnlockerFormFactory;
_quickConnectToolStrip.ConnectionInitiator = connectionInitiator;
@@ -292,7 +309,7 @@ namespace mRemoteNG.UI.Forms
{
PromptForUpdatesPreference();
CheckForUpdates();
UnlockRepositories(Runtime.CredentialProviderCatalog, this);
UnlockRepositories(Runtime.CredentialService.RepositoryList, this);
}
private void PromptForUpdatesPreference()

View File

@@ -20,7 +20,7 @@ namespace mRemoteNG.UI.Menu
private ToolStripMenuItem _credentialManagerToolStripMenuItem;
public Form MainForm { get; set; }
public ICredentialRepositoryList CredentialProviderCatalog { get; set; }
public CredentialService CredentialService { get; set; }
public UnlockerFormFactory UnlockerFormFactory { get; set; }
public ToolsMenu()
@@ -143,11 +143,11 @@ namespace mRemoteNG.UI.Menu
{
var pages = new UserControl[]
{
new CredentialListPage(CredentialProviderCatalog)
new CredentialListPage(CredentialService.RepositoryList)
{
DeletionConfirmer = new CredentialDeletionMsgBoxConfirmer(MessageBox.Show)
},
new CredentialRepositoriesPage(CredentialProviderCatalog, UnlockerFormFactory)
new CredentialRepositoriesPage(CredentialService, UnlockerFormFactory)
};
var credentialManagerForm = new CredentialManagerForm(pages);

View File

@@ -150,7 +150,7 @@
<Compile Include="Config\CredentialHarvester.cs" />
<Compile Include="Config\CredentialRecordLoader.cs" />
<Compile Include="Config\CredentialRecordSaver.cs" />
<Compile Include="Config\CredentialRepositoryListSaver.cs" />
<Compile Include="Config\CredentialRepositoryListPersistor.cs" />
<Compile Include="Config\DatabaseConnectors\ConnectionTestResult.cs" />
<Compile Include="Config\DatabaseConnectors\DatabaseConnectorFactory.cs" />
<Compile Include="Config\DatabaseConnectors\SqlDatabaseConnectionTester.cs" />
@@ -165,7 +165,6 @@
<Compile Include="Config\Serializers\ConnectionSerializers\MsSql\LocalConnectionPropertiesXmlSerializer.cs" />
<Compile Include="Config\Serializers\ConnectionSerializers\MsSql\SqlConnectionListMetaData.cs" />
<Compile Include="Config\Serializers\CredentialProviderSerializer\CredentialRepositoryListDeserializer.cs" />
<Compile Include="Config\CredentialRepositoryListLoader.cs" />
<Compile Include="Config\Serializers\CredentialSerializer\XmlCredentialPasswordDecryptorDecorator.cs" />
<Compile Include="Config\Serializers\CredentialSerializer\XmlCredentialPasswordEncryptorDecorator.cs" />
<Compile Include="Config\Serializers\ISecureDeserializer.cs" />
@@ -252,9 +251,11 @@
<Compile Include="Credential\CredentialChangedEventArgs.cs" />
<Compile Include="Credential\CredentialDeletionMsgBoxConfirmer.cs" />
<Compile Include="Credential\CredentialDomainUserComparer.cs" />
<Compile Include="Credential\Repositories\CredentialRepositoryTypeNotSupportedException.cs" />
<Compile Include="Credential\Repositories\CredentialRepoUnlockerBuilder.cs" />
<Compile Include="Credential\CredentialServiceFactory.cs" />
<Compile Include="Credential\CredentialServiceFacade.cs" />
<Compile Include="Credential\CredentialService.cs" />
<Compile Include="Credential\Repositories\ICredentialRepositoryFactory.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>