mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
added a dialog to prompt for action when decrypting a connection file fails
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
@@ -19,7 +18,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
public void Setup(string confCons, string password)
|
||||
{
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString);
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -9,35 +10,31 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
{
|
||||
public class PasswordAuthenticatorTests
|
||||
{
|
||||
private PasswordAuthenticator _authenticator;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
private string _cipherText;
|
||||
private readonly SecureString _correctPassword = "9theCorrectPass#5".ConvertToSecureString();
|
||||
private readonly SecureString _wrongPassword = "wrongPassword".ConvertToSecureString();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
const string cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
_authenticator = new PasswordAuthenticator(cryptoProvider, cipherText);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_authenticator = null;
|
||||
_cryptographyProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
_cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithCorrectPasswordReturnsTrue()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_correctPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithWrongPasswordReturnsFalse()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -45,12 +42,15 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorIsCalledWhenInitialPasswordIsWrong()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(wasCalled);
|
||||
}
|
||||
|
||||
@@ -58,28 +58,30 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorNotCalledWhenInitialPasswordIsCorrect()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_correctPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(!wasCalled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvidingCorrectPasswordToTheAuthenticationRequestorReturnsTrue()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => _correctPassword;
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => _correctPassword);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticationFailsWhenAuthenticationRequestorGivenEmptyPassword()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => new SecureString();
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => new SecureString());
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -87,27 +89,34 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticatorRespectsMaxAttempts()
|
||||
{
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == _authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatorRespectsMaxAttemptsCustomValue()
|
||||
{
|
||||
const int customMaxAttempts = 5;
|
||||
_authenticator.MaxAttempts = customMaxAttempts;
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator =
|
||||
new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor)
|
||||
{
|
||||
MaxAttempts = customMaxAttempts
|
||||
};
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == customMaxAttempts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Security;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
@@ -20,7 +19,7 @@ using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Runtime
|
||||
public static class Runtime
|
||||
{
|
||||
public static bool IsPortableEdition
|
||||
{
|
||||
@@ -93,18 +92,6 @@ namespace mRemoteNG.App
|
||||
{
|
||||
ConnectionsService.LastSqlUpdate = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connectionFileName == ConnectionsService.GetDefaultStartupConnectionFileName())
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = true;
|
||||
Settings.Default.CustomConsPath = connectionFileName;
|
||||
}
|
||||
}
|
||||
|
||||
// re-enable sql update checking after updates are loaded
|
||||
ConnectionsService.RemoteConnectionsSyncronizer?.Enable();
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using System.IO;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class XmlConnectionsLoader
|
||||
public class XmlConnectionsLoader
|
||||
{
|
||||
private readonly string _connectionFilePath;
|
||||
|
||||
@@ -32,7 +31,7 @@ namespace mRemoteNG.Config.Connections
|
||||
return deserializer.Deserialize(xmlString);
|
||||
}
|
||||
|
||||
private SecureString PromptForPassword()
|
||||
private Optional<SecureString> PromptForPassword()
|
||||
{
|
||||
var password = MiscTools.PasswordDialog("", false);
|
||||
return password;
|
||||
|
||||
@@ -13,6 +13,7 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Forms;
|
||||
@@ -20,7 +21,7 @@ using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
{
|
||||
private XmlDocument _xmlDocument;
|
||||
private double _confVersion;
|
||||
@@ -29,9 +30,9 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
private const double MaxSupportedConfVersion = 2.8;
|
||||
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public XmlConnectionsDeserializer(Func<SecureString> authenticationRequestor = null)
|
||||
public XmlConnectionsDeserializer(Func<Optional<SecureString>> authenticationRequestor = null)
|
||||
{
|
||||
AuthenticationRequestor = authenticationRequestor;
|
||||
}
|
||||
@@ -47,8 +48,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
LoadXmlConnectionData(xml);
|
||||
ValidateConnectionFileVersion();
|
||||
if (!import)
|
||||
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
|
||||
|
||||
var rootXmlElement = _xmlDocument.DocumentElement;
|
||||
InitializeRootNode(rootXmlElement);
|
||||
@@ -62,8 +61,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
|
||||
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
|
||||
{
|
||||
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
|
||||
mRemoteNG.Settings.Default.CustomConsPath = "";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
@@ -13,7 +14,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly RootNodeInfo _rootNodeInfo;
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public int KeyDerivationIterations
|
||||
{
|
||||
@@ -91,16 +92,14 @@ namespace mRemoteNG.Config.Serializers
|
||||
|
||||
private bool Authenticate(string cipherText, SecureString password)
|
||||
{
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText)
|
||||
{
|
||||
AuthenticationRequestor = AuthenticationRequestor
|
||||
};
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
var authenticated = authenticator.Authenticate(password);
|
||||
|
||||
if (!authenticated) return authenticated;
|
||||
if (!authenticated)
|
||||
return false;
|
||||
|
||||
_rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString();
|
||||
return authenticated;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
@@ -51,9 +52,8 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
var newConnectionsModel = new ConnectionTreeModel();
|
||||
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename);
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
|
||||
LoadConnections(false, false, filename);
|
||||
UpdateCustomConsPathSetting(filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -101,16 +101,25 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="import"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
{
|
||||
var oldConnectionTreeModel = ConnectionTreeModel;
|
||||
var oldIsUsingDatabaseValue = UsingDatabase;
|
||||
|
||||
var newConnectionTreeModel =
|
||||
(useDatabase
|
||||
? new SqlConnectionsLoader().Load()
|
||||
: new XmlConnectionsLoader(connectionFileName).Load())
|
||||
?? new ConnectionTreeModel();
|
||||
var newConnectionTreeModel = useDatabase
|
||||
? new SqlConnectionsLoader().Load()
|
||||
: new XmlConnectionsLoader(connectionFileName).Load();
|
||||
|
||||
if (newConnectionTreeModel == null)
|
||||
{
|
||||
//IsConnectionsFileLoaded = false;
|
||||
DialogFactory.BuildLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
|
||||
if (!import)
|
||||
{
|
||||
@@ -118,12 +127,9 @@ namespace mRemoteNG.Connection
|
||||
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
ConnectionTreeModel = newConnectionTreeModel;
|
||||
UpdateCustomConsPathSetting(connectionFileName);
|
||||
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName);
|
||||
return newConnectionTreeModel;
|
||||
}
|
||||
|
||||
public void BeginBatchingSaves()
|
||||
@@ -158,12 +164,13 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="saveFilter"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName)
|
||||
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false)
|
||||
{
|
||||
if (connectionTreeModel == null)
|
||||
return;
|
||||
|
||||
if (!IsConnectionsFileLoaded)
|
||||
if (!forceSave && !IsConnectionsFileLoaded)
|
||||
return;
|
||||
|
||||
if (_batchingSaves)
|
||||
@@ -223,12 +230,16 @@ namespace mRemoteNG.Connection
|
||||
|
||||
public string GetStartupConnectionFileName()
|
||||
{
|
||||
return Settings.Default.LoadConsFromCustomLocation == false ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath;
|
||||
return Settings.Default.LoadConsFromCustomLocation == false
|
||||
? GetDefaultStartupConnectionFileName()
|
||||
: Settings.Default.CustomConsPath;
|
||||
}
|
||||
|
||||
public string GetDefaultStartupConnectionFileName()
|
||||
{
|
||||
return Runtime.IsPortableEdition ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
return Runtime.IsPortableEdition
|
||||
? GetDefaultStartupConnectionFileNamePortableEdition()
|
||||
: GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
}
|
||||
|
||||
private void UpdateCustomConsPathSetting(string filename)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Security.Authentication
|
||||
{
|
||||
@@ -7,15 +9,16 @@ namespace mRemoteNG.Security.Authentication
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly string _cipherText;
|
||||
private readonly Func<Optional<SecureString>> _authenticationRequestor;
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public int MaxAttempts { get; set; } = 3;
|
||||
public SecureString LastAuthenticatedPassword { get; private set; }
|
||||
|
||||
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText)
|
||||
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText, Func<Optional<SecureString>> authenticationRequestor)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
_cipherText = cipherText;
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_cipherText = cipherText.ThrowIfNullOrEmpty(nameof(cipherText));
|
||||
_authenticationRequestor = authenticationRequestor.ThrowIfNull(nameof(authenticationRequestor));
|
||||
}
|
||||
|
||||
public bool Authenticate(SecureString password)
|
||||
@@ -32,7 +35,11 @@ namespace mRemoteNG.Security.Authentication
|
||||
}
|
||||
catch
|
||||
{
|
||||
password = AuthenticationRequestor?.Invoke();
|
||||
var providedPassword = _authenticationRequestor();
|
||||
if (!providedPassword.Any())
|
||||
return false;
|
||||
|
||||
password = providedPassword.First();
|
||||
if (password == null || password.Length == 0) break;
|
||||
}
|
||||
attempts++;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Security
|
||||
{
|
||||
public interface IKeyProvider
|
||||
{
|
||||
SecureString GetKey();
|
||||
Optional<SecureString> GetKey();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ using static System.String;
|
||||
|
||||
namespace mRemoteNG.Tools
|
||||
{
|
||||
public static class MiscTools
|
||||
public static class MiscTools
|
||||
{
|
||||
public static Icon GetIconFromFile(string FileName)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace mRemoteNG.Tools
|
||||
}
|
||||
}
|
||||
|
||||
public static SecureString PasswordDialog(string passwordName = null, bool verify = true)
|
||||
public static Optional<SecureString> PasswordDialog(string passwordName = null, bool verify = true)
|
||||
{
|
||||
var passwordForm = new PasswordForm(passwordName, verify);
|
||||
return passwordForm.GetKey();
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using System.Windows.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.UI
|
||||
{
|
||||
@@ -15,5 +20,74 @@ namespace mRemoteNG.UI
|
||||
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
|
||||
};
|
||||
}
|
||||
|
||||
public static void BuildLoadConnectionsFailedDialog(string connectionFileName, string messageText, bool showCancelButton)
|
||||
{
|
||||
var commandButtons = new List<string>
|
||||
{
|
||||
Language.ConfigurationCreateNew,
|
||||
Language.strOpenADifferentFile,
|
||||
Language.strMenuExit
|
||||
};
|
||||
|
||||
if (showCancelButton)
|
||||
commandButtons.Add(Language.strButtonCancel);
|
||||
|
||||
var answered = false;
|
||||
while (!answered)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTaskDialog.ShowTaskDialogBox(
|
||||
GeneralAppInfo.ProductName,
|
||||
messageText,
|
||||
"", "", "", "", "",
|
||||
string.Join(" | ", commandButtons),
|
||||
ETaskDialogButtons.None,
|
||||
ESysIcons.Question,
|
||||
ESysIcons.Question);
|
||||
|
||||
switch (CTaskDialog.CommandButtonResult)
|
||||
{
|
||||
case 0: // New
|
||||
var saveAsDialog = ConnectionsSaveAsDialog();
|
||||
saveAsDialog.ShowDialog();
|
||||
Runtime.ConnectionsService.NewConnectionsFile(saveAsDialog.FileName);
|
||||
answered = true;
|
||||
break;
|
||||
case 1: // Load
|
||||
Runtime.LoadConnections(true);
|
||||
answered = true;
|
||||
break;
|
||||
case 2: // Exit
|
||||
Application.Exit();
|
||||
answered = true;
|
||||
break;
|
||||
case 3: // Cancel
|
||||
answered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(
|
||||
string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName),
|
||||
exception,
|
||||
MessageClass.WarningMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SaveFileDialog ConnectionsSaveAsDialog()
|
||||
{
|
||||
return new SaveFileDialog
|
||||
{
|
||||
CheckPathExists = true,
|
||||
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
|
||||
FileName = ConnectionsFileInfo.DefaultConnectionsFile,
|
||||
OverwritePrompt = true,
|
||||
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Security;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.UI.Forms
|
||||
{
|
||||
@@ -19,12 +20,12 @@ namespace mRemoteNG.UI.Forms
|
||||
Verify = verify;
|
||||
}
|
||||
|
||||
public SecureString GetKey()
|
||||
public Optional<SecureString> GetKey()
|
||||
{
|
||||
var dialog = ShowDialog();
|
||||
return dialog == DialogResult.OK
|
||||
? _password
|
||||
: new SecureString();
|
||||
: Optional<SecureString>.Empty;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
@@ -24,7 +24,7 @@ using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
namespace mRemoteNG.UI.Window
|
||||
{
|
||||
public class ConfigWindow : BaseWindow
|
||||
public class ConfigWindow : BaseWindow
|
||||
{
|
||||
private bool _originalPropertyGridToolStripItemCountValid;
|
||||
private int _originalPropertyGridToolStripItemCount;
|
||||
@@ -745,29 +745,32 @@ namespace mRemoteNG.UI.Window
|
||||
private void UpdateRootInfoNode(PropertyValueChangedEventArgs e)
|
||||
{
|
||||
var rootInfo = _pGrid.SelectedObject as RootNodeInfo;
|
||||
if (rootInfo == null) return;
|
||||
if (e.ChangedItem.PropertyDescriptor == null) return;
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (e.ChangedItem.PropertyDescriptor.Name)
|
||||
{
|
||||
case "Password":
|
||||
if (rootInfo.Password)
|
||||
{
|
||||
var passwordName = Settings.Default.UseSQLServer ? Language.strSQLServer.TrimEnd(':') : Path.GetFileName(Runtime.ConnectionsService.GetStartupConnectionFileName());
|
||||
if (rootInfo == null)
|
||||
return;
|
||||
|
||||
var password = MiscTools.PasswordDialog(passwordName);
|
||||
if (password.Length == 0)
|
||||
rootInfo.Password = false;
|
||||
else
|
||||
rootInfo.PasswordString = password.ConvertToUnsecureString();
|
||||
}
|
||||
else
|
||||
{
|
||||
rootInfo.PasswordString = "";
|
||||
}
|
||||
break;
|
||||
case "Name":
|
||||
break;
|
||||
if (e.ChangedItem.PropertyDescriptor?.Name != "Password")
|
||||
return;
|
||||
|
||||
if (rootInfo.Password)
|
||||
{
|
||||
var passwordName = Settings.Default.UseSQLServer
|
||||
? Language.strSQLServer.TrimEnd(':')
|
||||
: Path.GetFileName(Runtime.ConnectionsService.GetStartupConnectionFileName());
|
||||
|
||||
var password = MiscTools.PasswordDialog(passwordName);
|
||||
|
||||
// operation cancelled, dont set a password
|
||||
if (!password.Any() || password.First().Length == 0)
|
||||
{
|
||||
rootInfo.Password = false;
|
||||
return;
|
||||
}
|
||||
|
||||
rootInfo.PasswordString = password.First().ConvertToUnsecureString();
|
||||
}
|
||||
else
|
||||
{
|
||||
rootInfo.PasswordString = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user