diff --git a/mRemoteNGTests/Config/Serializers/CsvConnectionsSerializerMremotengFormatTests.cs b/mRemoteNGTests/Config/Serializers/CsvConnectionsSerializerMremotengFormatTests.cs new file mode 100644 index 00000000..1bdd88d2 --- /dev/null +++ b/mRemoteNGTests/Config/Serializers/CsvConnectionsSerializerMremotengFormatTests.cs @@ -0,0 +1,87 @@ +using System; +using mRemoteNG.Config.Serializers; +using mRemoteNG.Connection; +using mRemoteNG.Credential; +using mRemoteNG.Security; +using mRemoteNG.Tree; +using NSubstitute; +using NUnit.Framework; + +namespace mRemoteNGTests.Config.Serializers +{ + public class CsvConnectionsSerializerMremotengFormatTests + { + private const string ConnectionName = "myconnection"; + private const string Username = "myuser"; + private const string Domain = "mydomain"; + private const string Password = "mypass123"; + + [TestCase(Username)] + [TestCase(Domain)] + [TestCase(Password)] + [TestCase("InheritColors")] + public void CreatesCsv(string valueThatShouldExist) + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter()); + var connectionInfo = BuildConnectionInfo(); + var csv = serializer.Serialize(connectionInfo); + Assert.That(csv, Does.Match(valueThatShouldExist)); + } + + [TestCase(Username)] + [TestCase(Domain)] + [TestCase(Password)] + [TestCase("InheritColors")] + public void SerializerRespectsSaveFilterSettings(string valueThatShouldntExist) + { + var saveFilter = new SaveFilter(true); + var serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter); + var connectionInfo = BuildConnectionInfo(); + var csv = serializer.Serialize(connectionInfo); + Assert.That(csv, Does.Not.Match(valueThatShouldntExist)); + } + + [Test] + public void CanSerializeEmptyConnectionInfo() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter()); + var connectionInfo = new ConnectionInfo(); + var csv = serializer.Serialize(connectionInfo); + Assert.That(csv, Is.Not.Empty); + } + + [Test] + public void CantPassNullToConstructor() + { + Assert.Throws(() => new CsvConnectionsSerializerMremotengFormat(null)); + } + + [Test] + public void CantPassNullToSerializeConnectionInfo() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter()); + Assert.Throws(() => serializer.Serialize((ConnectionInfo)null)); + } + + [Test] + public void CantPassNullToSerializeConnectionTreeModel() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter()); + Assert.Throws(() => serializer.Serialize((ConnectionTreeModel)null)); + } + + private ConnectionInfo BuildConnectionInfo() + { + var credRecord = Substitute.For(); + credRecord.Username.Returns(Username); + credRecord.Domain.Returns(Domain); + credRecord.Password.Returns(Password.ConvertToSecureString()); + return new ConnectionInfo + { + Name = ConnectionName, + CredentialRecord = credRecord, + Inheritance = {Colors = true} + }; + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index c8562e2a..c6cd6673 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -113,6 +113,7 @@ + diff --git a/mRemoteV1/App/Export.cs b/mRemoteV1/App/Export.cs index bc8d4127..560e982e 100644 --- a/mRemoteV1/App/Export.cs +++ b/mRemoteV1/App/Export.cs @@ -84,10 +84,7 @@ namespace mRemoteNG.App serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer); break; case ConnectionsSaver.Format.mRCSV: - serializer = new CsvConnectionsSerializerMremotengFormat - { - SaveFilter = saveFilter - }; + serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter); break; default: throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null); diff --git a/mRemoteV1/Config/Connections/ConnectionsSaver.cs b/mRemoteV1/Config/Connections/ConnectionsSaver.cs index 2f456881..4904166a 100644 --- a/mRemoteV1/Config/Connections/ConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/ConnectionsSaver.cs @@ -264,7 +264,7 @@ namespace mRemoteNG.Config.Connections private void SaveToMremotengFormattedCsv() { - var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat { SaveFilter = SaveFilter }; + var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(SaveFilter); var dataProvider = new FileDataProvider(ConnectionFileName); var csvContent = csvConnectionsSerializer.Serialize(ConnectionTreeModel); dataProvider.Save(csvContent); diff --git a/mRemoteV1/Config/Serializers/CsvConnectionsSerializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/CsvConnectionsSerializerMremotengFormat.cs index 2f4b53bd..425b0d75 100644 --- a/mRemoteV1/Config/Serializers/CsvConnectionsSerializerMremotengFormat.cs +++ b/mRemoteV1/Config/Serializers/CsvConnectionsSerializerMremotengFormat.cs @@ -12,17 +12,30 @@ namespace mRemoteNG.Config.Serializers { private string _csv = ""; private ConnectionInfo _serializationTarget; + private readonly SaveFilter _saveFilter; - public SaveFilter SaveFilter { get; set; } + + public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter) + { + if (saveFilter == null) + throw new ArgumentNullException(nameof(saveFilter)); + _saveFilter = saveFilter; + } public string Serialize(ConnectionTreeModel connectionTreeModel) { + if (connectionTreeModel == null) + throw new ArgumentNullException(nameof(connectionTreeModel)); + var rootNode = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo); return Serialize(rootNode); } public string Serialize(ConnectionInfo serializationTarget) { + if (serializationTarget == null) + throw new ArgumentNullException(nameof(serializationTarget)); + _csv = ""; _serializationTarget = serializationTarget; WriteCsvHeader(); @@ -34,14 +47,14 @@ namespace mRemoteNG.Config.Serializers { var csvHeader = string.Empty; csvHeader += "Name;Folder;Description;Icon;Panel;"; - if (SaveFilter.SaveUsername) + if (_saveFilter.SaveUsername) csvHeader += "Username;"; - if (SaveFilter.SavePassword) + if (_saveFilter.SavePassword) csvHeader += "Password;"; - if (SaveFilter.SaveDomain) + if (_saveFilter.SaveDomain) csvHeader += "Domain;"; csvHeader += "Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;"; - if (SaveFilter.SaveInheritance) + if (_saveFilter.SaveInheritance) csvHeader += "InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain"; _csv += csvHeader; } @@ -70,18 +83,64 @@ namespace mRemoteNG.Config.Serializers csvLine += con.Name + ";" + GetNodePath(con) + ";" + con.Description + ";" + con.Icon + ";" + con.Panel + ";"; - if (SaveFilter.SaveUsername) - csvLine += con.Username + ";"; + if (_saveFilter.SaveUsername) + csvLine += con.CredentialRecord?.Username + ";"; - if (SaveFilter.SavePassword) - csvLine += con.Password + ";"; + if (_saveFilter.SavePassword) + csvLine += con.CredentialRecord?.Password.ConvertToUnsecureString() + ";"; - if (SaveFilter.SaveDomain) - csvLine += con.Domain + ";"; + if (_saveFilter.SaveDomain) + csvLine += con.CredentialRecord?.Domain + ";"; - csvLine += con.Hostname + ";" + con.Protocol + ";" + con.PuttySession + ";" + Convert.ToString(con.Port) + ";" + Convert.ToString(con.UseConsoleSession) + ";" + Convert.ToString(con.UseCredSsp) + ";" + con.RenderingEngine + ";" + con.ICAEncryptionStrength + ";" + con.RDPAuthenticationLevel + ";" + con.LoadBalanceInfo + ";" + con.Colors + ";" + con.Resolution + ";" + Convert.ToString(con.AutomaticResize) + ";" + Convert.ToString(con.DisplayWallpaper) + ";" + Convert.ToString(con.DisplayThemes) + ";" + Convert.ToString(con.EnableFontSmoothing) + ";" + Convert.ToString(con.EnableDesktopComposition) + ";" + Convert.ToString(con.CacheBitmaps) + ";" + Convert.ToString(con.RedirectDiskDrives) + ";" + Convert.ToString(con.RedirectPorts) + ";" + Convert.ToString(con.RedirectPrinters) + ";" + Convert.ToString(con.RedirectSmartCards) + ";" + con.RedirectSound + ";" + Convert.ToString(con.RedirectKeys) + ";" + con.PreExtApp + ";" + con.PostExtApp + ";" + con.MacAddress + ";" + con.UserField + ";" + con.ExtApp + ";" + con.VNCCompression + ";" + con.VNCEncoding + ";" + con.VNCAuthMode + ";" + con.VNCProxyType + ";" + con.VNCProxyIP + ";" + Convert.ToString(con.VNCProxyPort) + ";" + con.VNCProxyUsername + ";" + con.VNCProxyPassword + ";" + con.VNCColors + ";" + con.VNCSmartSizeMode + ";" + Convert.ToString(con.VNCViewOnly) + ";"; + csvLine += con.Hostname + ";" + + con.Protocol + ";" + + con.PuttySession + ";" + + Convert.ToString(con.Port) + ";" + + Convert.ToString(con.UseConsoleSession) + ";" + + Convert.ToString(con.UseCredSsp) + ";" + + con.RenderingEngine + ";" + + con.ICAEncryptionStrength + ";" + + con.RDPAuthenticationLevel + ";" + + con.LoadBalanceInfo + ";" + + con.Colors + ";" + + con.Resolution + ";" + + Convert.ToString(con.AutomaticResize) + ";" + + Convert.ToString(con.DisplayWallpaper) + ";" + + Convert.ToString(con.DisplayThemes) + ";" + + Convert.ToString(con.EnableFontSmoothing) + ";" + + Convert.ToString(con.EnableDesktopComposition) + ";" + + Convert.ToString(con.CacheBitmaps) + ";" + + Convert.ToString(con.RedirectDiskDrives) + ";" + + Convert.ToString(con.RedirectPorts) + ";" + + Convert.ToString(con.RedirectPrinters) + ";" + + Convert.ToString(con.RedirectSmartCards) + ";" + + con.RedirectSound + ";" + + Convert.ToString(con.RedirectKeys) + ";" + + con.PreExtApp + ";" + + con.PostExtApp + ";" + + con.MacAddress + ";" + + con.UserField + ";" + + con.ExtApp + ";" + + con.VNCCompression + ";" + + con.VNCEncoding + ";" + + con.VNCAuthMode + ";" + + con.VNCProxyType + ";" + + con.VNCProxyIP + ";" + + Convert.ToString(con.VNCProxyPort) + ";" + + con.VNCProxyUsername + ";" + + con.VNCProxyPassword + ";" + + con.VNCColors + ";" + + con.VNCSmartSizeMode + ";" + + Convert.ToString(con.VNCViewOnly) + ";" + + con.RDGatewayUsageMethod + ";" + + con.RDGatewayHostname + ";" + + con.RDGatewayUseConnectionCredentials + ";" + + con.RDGatewayUsername + ";" + + con.RDGatewayPassword + ";" + + con.RDGatewayDomain + ";"; - if (SaveFilter.SaveInheritance) + + if (_saveFilter.SaveInheritance) { csvLine += con.Inheritance.CacheBitmaps + ";" + con.Inheritance.Colors + ";" + @@ -127,7 +186,13 @@ namespace mRemoteNG.Config.Serializers con.Inheritance.VNCProxyPassword + ";" + con.Inheritance.VNCColors + ";" + con.Inheritance.VNCSmartSizeMode + ";" + - con.Inheritance.VNCViewOnly; + con.Inheritance.VNCViewOnly + + con.Inheritance.RDGatewayUsageMethod + ";" + + con.Inheritance.RDGatewayHostname + ";" + + con.Inheritance.RDGatewayUseConnectionCredentials + ";" + + con.Inheritance.RDGatewayUsername + ";" + + con.Inheritance.RDGatewayPassword + ";" + + con.Inheritance.RDGatewayDomain + ";"; } _csv += csvLine; @@ -137,6 +202,7 @@ namespace mRemoteNG.Config.Serializers { var nodePath = ""; var container = connectionInfo.Parent; + if (container == null) return nodePath; while (container != _serializationTarget) { container = container.Parent;