mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
some more deserialization refactoring
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user