mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
simplified some of the credential management classes
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
mRemoteV1/Config/CredentialRepositoryListPersistor.cs
Normal file
39
mRemoteV1/Config/CredentialRepositoryListPersistor.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
110
mRemoteV1/Credential/CredentialService.cs
Normal file
110
mRemoteV1/Credential/CredentialService.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
1
mRemoteV1/UI/Forms/frmMain.Designer.cs
generated
1
mRemoteV1/UI/Forms/frmMain.Designer.cs
generated
@@ -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";
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user