some more deserialization refactoring

This commit is contained in:
David Sparer
2019-01-21 17:52:18 -06:00
parent 739112a3ff
commit f78ca1e9fd
16 changed files with 136 additions and 114 deletions

View File

@@ -1,11 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNG.Tools;
using mRemoteNGTests.Properties;
using NUnit.Framework;
@@ -14,50 +15,40 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public class XmlConnectionsDeserializerTests
{
private XmlConnectionsDeserializer _xmlConnectionsDeserializer;
private ConnectionTreeModel _connectionTreeModel;
private SerializationResult _serializationResult;
public void Setup(string confCons, string password)
{
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
_serializationResult = _xmlConnectionsDeserializer.Deserialize(confCons);
}
[TearDown]
public void Teardown()
{
_xmlConnectionsDeserializer = null;
_connectionTreeModel = null;
_serializationResult = null;
}
[TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))]
public void DeserializingCreatesRootNode(Datagram testData)
public void RootHasThreeChildren(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
Assert.That(_connectionTreeModel.RootNodes, Is.Not.Empty);
}
[TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))]
public void RootNodeHasThreeChildren(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
Assert.That(connectionRoot.Children.Count, Is.EqualTo(3));
Assert.That(_serializationResult.ConnectionRecords.Count, Is.EqualTo(3));
}
[TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))]
public void RootContainsFolder1(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
Assert.That(ContainsNodeNamed("Folder1", connectionRoot.Children), Is.True);
Assert.That(ContainsNodeNamed("Folder1", _serializationResult.ConnectionRecords), Is.True);
}
[TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))]
public void Folder1ContainsThreeConnections(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
var folder1 = GetFolderNamed("Folder1", connectionRoot.Children);
var folder1 = GetFolderNamed("Folder1", _serializationResult.ConnectionRecords);
var folder1ConnectionCount = folder1?.Children.Count(node => !(node is ContainerInfo));
Assert.That(folder1ConnectionCount, Is.EqualTo(3));
}
@@ -66,9 +57,8 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Folder2ContainsThreeNodes(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
var folder2 = GetFolderNamed("Folder2", connectionRoot.Children);
var folder1Count = folder2?.Children.Count();
var folder2 = GetFolderNamed("Folder2", _serializationResult.ConnectionRecords);
var folder1Count = folder2?.Children.Count;
Assert.That(folder1Count, Is.EqualTo(3));
}
@@ -76,8 +66,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Folder21HasTwoNodes(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
var folder2 = GetFolderNamed("Folder2", connectionRoot.Children);
var folder2 = GetFolderNamed("Folder2", _serializationResult.ConnectionRecords);
var folder21 = GetFolderNamed("Folder2.1", folder2.Children);
Assert.That(folder21.Children.Count, Is.EqualTo(2));
}
@@ -86,8 +75,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Folder211HasOneConnection(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
var folder2 = GetFolderNamed("Folder2", connectionRoot.Children);
var folder2 = GetFolderNamed("Folder2", _serializationResult.ConnectionRecords);
var folder21 = GetFolderNamed("Folder2.1", folder2.Children);
var folder211 = GetFolderNamed("Folder2.1.1", folder21.Children);
var connectionCount = folder211.Children.Count(node => !(node is ContainerInfo));
@@ -98,8 +86,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Folder22InheritsUsername(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var connectionRoot = _connectionTreeModel.RootNodes[0];
var folder2 = GetFolderNamed("Folder2", connectionRoot.Children);
var folder2 = GetFolderNamed("Folder2", _serializationResult.ConnectionRecords);
var folder22 = GetFolderNamed("Folder2.2", folder2.Children);
Assert.That(folder22.Inheritance.Username, Is.True);
}
@@ -108,7 +95,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void ExpandedPropertyGetsDeserialized(Datagram testData)
{
Setup(testData.ConfCons, testData.Password);
var folder1 = GetFolderNamed("Folder1", _connectionTreeModel.GetRecursiveChildList());
var folder1 = GetFolderNamed("Folder1", _serializationResult.ConnectionRecords.FlattenConnectionTree());
Assert.That(folder1.IsExpanded, Is.True);
}

View File

@@ -5,6 +5,7 @@ using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers;
using NUnit.Framework;

View File

@@ -10,6 +10,7 @@ using NUnit.Framework;
using System;
using System.Linq;
using System.Text;
using mRemoteNG.Tools;
namespace mRemoteNGTests.IntegrationTests
@@ -45,7 +46,7 @@ namespace mRemoteNGTests.IntegrationTests
{
var serializedContent = _serializer.Serialize(_originalModel);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromDeserializedModel = deserializedModel.ConnectionRecords.FlattenConnectionTree().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
}
@@ -56,7 +57,7 @@ namespace mRemoteNGTests.IntegrationTests
_serializer.UseFullEncryption = true;
var serializedContent = _serializer.Serialize(_originalModel);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromDeserializedModel = deserializedModel.ConnectionRecords.FlattenConnectionTree().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
}
@@ -67,7 +68,7 @@ namespace mRemoteNGTests.IntegrationTests
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" };
var serializedContent = _serializer.Serialize(originalConnectionInfo);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
var deserializedConnectionInfo = deserializedModel.ConnectionRecords.FlattenConnectionTree().First(node => node.Name == originalConnectionInfo.Name);
Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description));
}
@@ -84,7 +85,7 @@ namespace mRemoteNGTests.IntegrationTests
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
var serializedContent = _serializer.Serialize(_originalModel);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromDeserializedModel = deserializedModel.ConnectionRecords.FlattenConnectionTree().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
}
@@ -99,7 +100,7 @@ namespace mRemoteNGTests.IntegrationTests
serializedContent = serializedContent.Replace(originalConnectionInfo.ConstantID, "");
var deserializedModel = _deserializer.Deserialize(serializedContent);
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
var deserializedConnectionInfo = deserializedModel.ConnectionRecords.FlattenConnectionTree().First(node => node.Name == originalConnectionInfo.Name);
Assert.That(Guid.TryParse(deserializedConnectionInfo.ConstantID, out var guid));
}
@@ -111,7 +112,8 @@ namespace mRemoteNGTests.IntegrationTests
var serializedContent = _serializer.Serialize(originalConnectionInfo);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var deserializedConnectionInfo = deserializedModel
.GetRecursiveChildList()
.ConnectionRecords
.FlattenConnectionTree()
.First(info => info.GetTreeNodeType() == TreeNodeType.Connection);
var sb = new StringBuilder();
@@ -139,7 +141,8 @@ namespace mRemoteNGTests.IntegrationTests
var serializedContent = _serializer.Serialize(container);
var deserializedModel = _deserializer.Deserialize(serializedContent);
var deserializedConnectionInfo = deserializedModel
.GetRecursiveChildList()
.ConnectionRecords
.FlattenConnectionTree()
.First(info => info.GetTreeNodeType() == TreeNodeType.Connection);
var sb = new StringBuilder();

View File

@@ -128,19 +128,5 @@ namespace mRemoteNGTests.TestHelpers
var values = Enum.GetValues(typeof(T));
return (T)values.GetValue(_random.Next(values.Length));
}
internal static IEnumerable<ConnectionInfo> FlattenConnectionTree(this IEnumerable<ConnectionInfo> connections)
{
foreach (var item in connections)
{
yield return item;
if (!(item is ContainerInfo container))
continue;
foreach (var child in FlattenConnectionTree(container.Children))
yield return child;
}
}
}
}

View File

@@ -88,7 +88,7 @@ namespace mRemoteNG.App
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
}
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, connectionFileName);
if (Settings.Default.UseSQLServer)
{

View File

@@ -34,7 +34,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
private void Load(object sender, ConnectionsUpdateAvailableEventArgs args)
{
Runtime.ConnectionsService.LoadConnections(true, false, "");
Runtime.ConnectionsService.LoadConnections(true, "");
args.Handled = true;
}

View File

@@ -48,9 +48,9 @@ namespace mRemoteNG.Config.Connections
ConnectionDeserializer = new XmlConnectionsDeserializer(PromptForPassword)
};
var connectionTreeModel = deserializer.Deserialize(xmlString);
var serializationResult = deserializer.Deserialize(xmlString);
return new SerializationResult(connectionTreeModel.RootNodes.Cast<ConnectionInfo>().ToList(), new ConnectionToCredentialMap());
return serializationResult;
}
private Optional<SecureString> PromptForPassword()

View File

@@ -27,10 +27,10 @@ namespace mRemoteNG.Config.Import
var dataProvider = new FileDataProvider(fileName);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer();
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var serializationResult = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) };
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
rootImportContainer.AddChildRange(serializationResult.ConnectionRecords);
destinationContainer.AddChild(rootImportContainer);
}
}

View File

@@ -15,21 +15,23 @@ using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Security;
using System.Windows.Forms;
using System.Xml;
using mRemoteNG.Credential;
namespace mRemoteNG.Config.Serializers.Xml
{
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
public class XmlConnectionsDeserializer
{
private XmlDocument _xmlDocument;
private double _confVersion;
private XmlConnectionsDecryptor _decryptor;
private string ConnectionFileName = "";
private const double MaxSupportedConfVersion = 2.7;
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
private readonly CredentialDomainUserPasswordComparer _credentialComparer = new CredentialDomainUserPasswordComparer();
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
@@ -38,12 +40,12 @@ namespace mRemoteNG.Config.Serializers.Xml
AuthenticationRequestor = authenticationRequestor;
}
public ConnectionTreeModel Deserialize(string xml)
public SerializationResult Deserialize(string xml)
{
return Deserialize(xml, false);
}
public ConnectionTreeModel Deserialize(string xml, bool import)
public SerializationResult Deserialize(string xml, bool import)
{
try
{
@@ -51,16 +53,13 @@ namespace mRemoteNG.Config.Serializers.Xml
ValidateConnectionFileVersion();
var rootXmlElement = _xmlDocument.DocumentElement;
InitializeRootNode(rootXmlElement);
CreateDecryptor(_rootNodeInfo, rootXmlElement);
var connectionTreeModel = new ConnectionTreeModel();
connectionTreeModel.AddRootNode(_rootNodeInfo);
var rootNodeInfo = InitializeRootNode(rootXmlElement);
_decryptor = CreateDecryptor(rootNodeInfo, rootXmlElement);
if (_confVersion > 1.3)
{
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, rootNodeInfo.PasswordString.ConvertToSecureString()))
{
return null;
}
@@ -76,12 +75,11 @@ namespace mRemoteNG.Config.Serializers.Xml
}
}
AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo);
var credentialMap = new ConnectionToCredentialMap();
var rootNodes = AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, credentialMap);
var serializationResult = new SerializationResult(rootNodes, credentialMap);
if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel;
return serializationResult;
}
catch (Exception ex)
{
@@ -93,8 +91,8 @@ namespace mRemoteNG.Config.Serializers.Xml
private void LoadXmlConnectionData(string connections)
{
CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
connections = _decryptor.LegacyFullFileDecrypt(connections);
var legacyDecryptor = CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
connections = legacyDecryptor.LegacyFullFileDecrypt(connections);
_xmlDocument = new XmlDocument();
if (connections != "")
_xmlDocument.LoadXml(connections);
@@ -130,13 +128,16 @@ namespace mRemoteNG.Config.Serializers.Xml
);
}
private void InitializeRootNode(XmlElement connectionsRootElement)
private RootNodeInfo InitializeRootNode(XmlElement connectionsRootElement)
{
var rootNodeName = connectionsRootElement?.Attributes["Name"].Value.Trim();
_rootNodeInfo.Name = rootNodeName;
return new RootNodeInfo(RootNodeType.Connection)
{
Name = rootNodeName
};
}
private void CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
private XmlConnectionsDecryptor CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
{
if (_confVersion >= 2.6)
{
@@ -144,23 +145,27 @@ namespace mRemoteNG.Config.Serializers.Xml
var mode = connectionsRootElement.GetAttributeAsEnum<BlockCipherModes>("BlockCipherMode");
var keyDerivationIterations = connectionsRootElement.GetAttributeAsInt("KdfIterations");
_decryptor = new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
return new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
{
AuthenticationRequestor = AuthenticationRequestor,
KeyDerivationIterations = keyDerivationIterations
};
}
else
return new XmlConnectionsDecryptor(rootNodeInfo)
{
_decryptor = new XmlConnectionsDecryptor(_rootNodeInfo) { AuthenticationRequestor = AuthenticationRequestor };
}
AuthenticationRequestor = AuthenticationRequestor
};
}
private void AddNodesFromXmlRecursive(XmlNode parentXmlNode, ContainerInfo parentContainer)
private List<ConnectionInfo> AddNodesFromXmlRecursive(XmlNode parentXmlNode, ConnectionToCredentialMap credentialMap)
{
try
{
if (!parentXmlNode.HasChildNodes) return;
if (!parentXmlNode.HasChildNodes)
return new List<ConnectionInfo>();
var children = new List<ConnectionInfo>();
foreach (XmlNode xmlNode in parentXmlNode.ChildNodes)
{
var nodeType = xmlNode.GetAttributeAsEnum("Type", TreeNodeType.Connection);
@@ -169,24 +174,27 @@ namespace mRemoteNG.Config.Serializers.Xml
switch (nodeType)
{
case TreeNodeType.Connection:
var connectionInfo = GetConnectionInfoFromXml(xmlNode);
parentContainer.AddChild(connectionInfo);
var connectionInfo = GetConnectionInfoFromXml(xmlNode, credentialMap);
children.Add(connectionInfo);
break;
case TreeNodeType.Container:
var containerInfo = new ContainerInfo();
if (_confVersion >= 0.9)
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode));
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode, credentialMap));
if (_confVersion >= 0.8)
{
containerInfo.IsExpanded = xmlNode.GetAttributeAsBool("Expanded");
}
parentContainer.AddChild(containerInfo);
AddNodesFromXmlRecursive(xmlNode, containerInfo);
var subChildren = AddNodesFromXmlRecursive(xmlNode, credentialMap);
subChildren.ForEach(info => containerInfo.AddChild(info));
children.Add(containerInfo);
break;
}
}
return children;
}
catch (Exception ex)
{
@@ -195,7 +203,7 @@ namespace mRemoteNG.Config.Serializers.Xml
}
}
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode)
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode, ConnectionToCredentialMap credentialMap)
{
if (xmlnode?.Attributes == null)
return null;
@@ -225,10 +233,19 @@ namespace mRemoteNG.Config.Serializers.Xml
if (_confVersion <= 2.6) // 0.2 - 2.6
{
// TODO: harvest
connectionInfo.Username = xmlnode.GetAttributeAsString("Username");
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
connectionInfo.Domain = xmlnode.GetAttributeAsString("Domain");
var username = xmlnode.GetAttributeAsString("Username");
var domain = xmlnode.GetAttributeAsString("Domain");
var cred = new CredentialRecord
{
Title = domain.Length > 0 ? $"{domain}\\{username}" : username,
Username = username,
Domain = domain,
Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password")).ConvertToSecureString()
};
if (!_credentialComparer.Equals(cred, new NullCredentialRecord()))
connectionInfo.CredentialRecordId = cred.Id;
}
}
@@ -502,7 +519,7 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.RedirectClipboard = xmlnode.GetAttributeAsBool("RedirectClipboard");
connectionInfo.Inheritance.RedirectClipboard = xmlnode.GetAttributeAsBool("InheritRedirectClipboard");
connectionInfo.CredentialRecordId = Guid.TryParse(xmlnode.Attributes["CredentialId"]?.Value, out var credId)
connectionInfo.CredentialRecordId = Guid.TryParse(xmlnode.Attributes?["CredentialId"]?.Value, out var credId)
? credId
: Optional<Guid>.Empty;

View File

@@ -11,30 +11,31 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using mRemoteNG.Config.Serializers.Xml;
namespace mRemoteNG.Config.Serializers.Versioning
{
public class XmlCredentialManagerUpgrader
{
private readonly IDeserializer<string, ConnectionTreeModel> _deserializer;
private readonly XmlConnectionsDeserializer _deserializer;
public XmlCredentialManagerUpgrader(IDeserializer<string, ConnectionTreeModel> decoratedDeserializer)
public XmlCredentialManagerUpgrader(XmlConnectionsDeserializer decoratedDeserializer)
{
_deserializer = decoratedDeserializer.ThrowIfNull(nameof(decoratedDeserializer));
}
public ConnectionTreeModel Deserialize(string serializedData, ConnectionToCredentialMap upgradeMap)
public SerializationResult Deserialize(string serializedData, ConnectionToCredentialMap upgradeMap)
{
var serializedDataAsXDoc = EnsureConnectionXmlElementsHaveIds(serializedData);
var serializedDataWithIds = $"{serializedDataAsXDoc.Declaration}{serializedDataAsXDoc}";
var connectionTreeModel = _deserializer.Deserialize(serializedDataWithIds);
var serializationResult = _deserializer.Deserialize(serializedDataWithIds);
if (upgradeMap != null)
ApplyCredentialMapping(upgradeMap, connectionTreeModel.GetRecursiveChildList());
ApplyCredentialMapping(upgradeMap, serializationResult.ConnectionRecords.FlattenConnectionTree());
return connectionTreeModel;
return serializationResult;
}
private XDocument EnsureConnectionXmlElementsHaveIds(string serializedData)

View File

@@ -348,6 +348,7 @@ namespace mRemoteNG.Connection
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUsername"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")]
[Obsolete]
public string RDGatewayUsername
{
get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim();
@@ -358,6 +359,7 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayPassword"),
LocalizedAttributes.LocalizedDescription("strPropertyNameRDGatewayPassword"),
PasswordPropertyText(true)]
[Obsolete]
public string RDGatewayPassword
{
get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword);
@@ -367,6 +369,7 @@ namespace mRemoteNG.Connection
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayDomain"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")]
[Obsolete]
public string RDGatewayDomain
{
get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim();
@@ -650,6 +653,7 @@ namespace mRemoteNG.Connection
Browsable(false),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyUsername"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")]
[Obsolete]
public string VNCProxyUsername
{
get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername);
@@ -661,6 +665,7 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyPassword"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPassword"),
PasswordPropertyText(true)]
[Obsolete]
public string VNCProxyPassword
{
get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword);

View File

@@ -49,6 +49,8 @@ namespace mRemoteNG.Connection
var path = SettingsFileInfo.SettingsPath;
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
_puttySessionsManager.RootPuttySessionsNodes.ForEach(node => ConnectionTreeModel.AddRootNode(node));
}
public void NewConnectionsFile(string filename)
@@ -56,10 +58,9 @@ namespace mRemoteNG.Connection
try
{
filename.ThrowIfNullOrEmpty(nameof(filename));
var newConnectionsModel = new ConnectionTreeModel();
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
LoadConnections(false, false, filename);
ConnectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(ConnectionTreeModel, false, new SaveFilter(), filename, true);
LoadConnections(false, filename);
}
catch (Exception ex)
{
@@ -112,7 +113,7 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
public void LoadConnections(bool useDatabase, string connectionFileName)
{
var oldIsUsingDatabaseValue = UsingDatabase;
@@ -135,8 +136,12 @@ namespace mRemoteNG.Connection
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
ConnectionTreeModel.RemoveRootNode(ConnectionTreeModel.RootNodes.First());
ConnectionTreeModel.AddRootNode(serializationResult.ConnectionRecords.OfType<RootNodeInfo>().First());
if (ConnectionTreeModel.RootNodes.Any())
ConnectionTreeModel.RemoveRootNode(ConnectionTreeModel.RootNodes.First());
var rootNode = new RootNodeInfo(RootNodeType.Connection);
rootNode.AddChildRange(serializationResult.ConnectionRecords);
ConnectionTreeModel.AddRootNode(rootNode);
UpdateCustomConsPathSetting(connectionFileName);
RaiseConnectionsLoadedEvent(new List<ConnectionInfo>(), new List<ConnectionInfo>(), oldIsUsingDatabaseValue, useDatabase, connectionFileName);

View File

@@ -19,7 +19,7 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
void LoadConnections(bool useDatabase, bool import, string connectionFileName);
void LoadConnections(bool useDatabase, string connectionFileName);
/// <summary>
/// When turned on, calls to <see cref="ConnectionsService.SaveConnections()"/> or

View File

@@ -2,6 +2,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
namespace mRemoteNG.Tools
{
@@ -70,5 +72,19 @@ namespace mRemoteNG.Tools
return collection;
}
}
public static IEnumerable<ConnectionInfo> FlattenConnectionTree(this IEnumerable<ConnectionInfo> connections)
{
foreach (var item in connections)
{
yield return item;
if (!(item is ContainerInfo container))
continue;
foreach (var child in FlattenConnectionTree(container.Children))
yield return child;
}
}
}
}

View File

@@ -10,6 +10,7 @@ using mRemoteNG.Config.Connections;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
@@ -19,7 +20,7 @@ using mRemoteNG.Tree;
namespace mRemoteNG.UI.Forms
{
public partial class CredentialManagerUpgradeForm : Form, IDeserializer<string, ConnectionTreeModel>
public partial class CredentialManagerUpgradeForm : Form
{
private string _connectionFilePath;
private string _newCredentialRepoPath;
@@ -28,7 +29,7 @@ namespace mRemoteNG.UI.Forms
private ConnectionToCredentialMap _credentialMap;
private readonly ThemeManager _themeManager = ThemeManager.getInstance();
public IDeserializer<string, ConnectionTreeModel> ConnectionDeserializer { get; set; }
public XmlConnectionsDeserializer ConnectionDeserializer { get; set; }
public ConnectionsService ConnectionsService { get; set; }
public CredentialService CredentialService { get; set; }
@@ -73,7 +74,7 @@ namespace mRemoteNG.UI.Forms
}
}
public ConnectionTreeModel Deserialize(string serializedData)
public SerializationResult Deserialize(string serializedData)
{
_xdoc = XDocument.Parse(serializedData);
if (!XmlCredentialManagerUpgrader.CredentialManagerUpgradeNeeded(_xdoc))
@@ -85,15 +86,15 @@ namespace mRemoteNG.UI.Forms
var result = ShowDialog();
if (result != DialogResult.OK)
return new ConnectionTreeModel();
return new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
var newRepoPassword = newRepositoryPasswordEntry.SecureString;
SaveCredentialsToNewRepository(_credentialMap.DistinctCredentialRecords, newRepoPassword, _newCredentialRepoPath);
var connectionTreeModel = _upgradingDeserializer.Deserialize(serializedData, _credentialMap);
var serializationResult = _upgradingDeserializer.Deserialize(serializedData, _credentialMap);
ConnectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
return connectionTreeModel;
return serializationResult;
}
/// <summary>

View File

@@ -81,7 +81,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
{
Runtime.ConnectionsService.RemoteConnectionsSyncronizer?.Dispose();
Runtime.ConnectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker());
Runtime.ConnectionsService.LoadConnections(true, false, "");
Runtime.ConnectionsService.LoadConnections(true, "");
}
private void DisableSql()