From e2f7c2afaca8809db3658bf196cdb2e3130683e2 Mon Sep 17 00:00:00 2001 From: "kenneth.skovhede@gmail.com" Date: Sat, 15 Jan 2011 15:40:33 +0000 Subject: [PATCH] Update issue #346 Status: Fixed I have now added password verification dialogs to all password fields. git-svn-id: https://duplicati.googlecode.com/svn/trunk@674 59da171f-624f-0410-aa54-27559c288bec --- Duplicati/GUI/ApplicationSetup.cs | 7 +- .../Add backup/PasswordSettings.cs | 9 +- .../CloudFiles/CloudFilesUI.Designer.cs | 12 +- .../Backend/CloudFiles/CloudFilesUI.cs | 31 +- Duplicati/Library/Backend/FTP/FTPUI.cs | 16 +- Duplicati/Library/Backend/File/FileUI.cs | 25 +- Duplicati/Library/Backend/S3/S3UI.cs | 18 +- Duplicati/Library/Backend/SSH/SSHUI.cs | 21 +- Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs | 19 +- .../Duplicati.Winforms.Controls.csproj | 18 ++ .../PasswordConfirmationDialog.Designer.cs | 99 ++++++ .../Controls/PasswordConfirmationDialog.cs | 36 +++ .../Controls/PasswordConfirmationDialog.resx | 291 ++++++++++++++++++ .../Winforms/Controls/PasswordControl.cs | 38 +++ .../PasswordConfirmationDialog.Designer.cs | 72 +++++ .../Strings/PasswordConfirmationDialog.resx | 123 ++++++++ 16 files changed, 805 insertions(+), 30 deletions(-) create mode 100644 Duplicati/Winforms/Controls/PasswordConfirmationDialog.Designer.cs create mode 100644 Duplicati/Winforms/Controls/PasswordConfirmationDialog.cs create mode 100644 Duplicati/Winforms/Controls/PasswordConfirmationDialog.resx create mode 100644 Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.Designer.cs create mode 100644 Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.resx diff --git a/Duplicati/GUI/ApplicationSetup.cs b/Duplicati/GUI/ApplicationSetup.cs index 816761973..44020460e 100644 --- a/Duplicati/GUI/ApplicationSetup.cs +++ b/Duplicati/GUI/ApplicationSetup.cs @@ -120,7 +120,10 @@ namespace Duplicati.GUI private void OKBtn_Click(object sender, EventArgs e) { - foreach(TabPage tab in TabContainer.TabPages) + if (UseCommonPassword.Checked && !CommonPassword.VerifyPasswordIfChanged()) + return; + + foreach (TabPage tab in TabContainer.TabPages) if (tab.Tag as Library.Interface.ISettingsControl != null) { try @@ -197,7 +200,7 @@ namespace Duplicati.GUI TempPath.Text = m_settings.TempPath; UseCommonPassword.Checked = m_settings.UseCommonPassword; - CommonPassword.Text = m_settings.CommonPassword; + CommonPassword.Text = CommonPassword.InitialPassword = m_settings.CommonPassword; CommonPassword.AskToEnterNewPassword = !string.IsNullOrEmpty(CommonPassword.Text); if (EncryptionModule.Items.Count > 0) diff --git a/Duplicati/GUI/Wizard pages/Add backup/PasswordSettings.cs b/Duplicati/GUI/Wizard pages/Add backup/PasswordSettings.cs index e2c23556a..a8c9e25c3 100644 --- a/Duplicati/GUI/Wizard pages/Add backup/PasswordSettings.cs +++ b/Duplicati/GUI/Wizard pages/Add backup/PasswordSettings.cs @@ -141,6 +141,13 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup m_hasGeneratedNewPassword = false; } + if (EnablePassword.Checked && !Password.VerifyPasswordIfChanged()) + { + args.Cancel = true; + return; + } + + m_settings["Password:SettingsChanged"] = m_settingsChanged; m_settings["Password:WarnedChanged"] = m_warnedChanged; m_settings["Password:NewPasswordGenerated"] = m_hasGeneratedNewPassword; @@ -175,7 +182,7 @@ namespace Duplicati.GUI.Wizard_pages.Add_backup if (!m_valuesAutoLoaded) { EnablePassword.Checked = !string.IsNullOrEmpty(m_wrapper.BackupPassword) || (m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Add || m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.RestoreSetup || m_wrapper.PrimayAction == WizardSettingsWrapper.MainAction.Restore); - Password.Text = m_wrapper.BackupPassword; + Password.Text = Password.InitialPassword = m_wrapper.BackupPassword; Password.AskToEnterNewPassword = !string.IsNullOrEmpty(m_wrapper.BackupPassword); diff --git a/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.Designer.cs b/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.Designer.cs index 5e88b3e1d..ba5c8355e 100644 --- a/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.Designer.cs +++ b/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.Designer.cs @@ -34,7 +34,7 @@ namespace Duplicati.Library.Backend this.label3 = new System.Windows.Forms.Label(); this.Username = new System.Windows.Forms.TextBox(); this.API_KEY = new Duplicati.Winforms.Controls.PasswordControl(); - this.BucketName = new System.Windows.Forms.TextBox(); + this.ContainerName = new System.Windows.Forms.TextBox(); this.SignUpLink = new System.Windows.Forms.LinkLabel(); this.label4 = new System.Windows.Forms.Label(); this.TestConnection = new System.Windows.Forms.Button(); @@ -74,9 +74,9 @@ namespace Duplicati.Library.Backend // // BucketName // - resources.ApplyResources(this.BucketName, "BucketName"); - this.BucketName.Name = "BucketName"; - this.BucketName.TextChanged += new System.EventHandler(this.BucketName_TextChanged); + resources.ApplyResources(this.ContainerName, "BucketName"); + this.ContainerName.Name = "BucketName"; + this.ContainerName.TextChanged += new System.EventHandler(this.ContainerName_TextChanged); // // SignUpLink // @@ -112,7 +112,7 @@ namespace Duplicati.Library.Backend this.Controls.Add(this.TestConnection); this.Controls.Add(this.label4); this.Controls.Add(this.SignUpLink); - this.Controls.Add(this.BucketName); + this.Controls.Add(this.ContainerName); this.Controls.Add(this.API_KEY); this.Controls.Add(this.Username); this.Controls.Add(this.label3); @@ -132,7 +132,7 @@ namespace Duplicati.Library.Backend private System.Windows.Forms.Label label3; private System.Windows.Forms.TextBox Username; private Duplicati.Winforms.Controls.PasswordControl API_KEY; - private System.Windows.Forms.TextBox BucketName; + private System.Windows.Forms.TextBox ContainerName; private System.Windows.Forms.LinkLabel SignUpLink; private System.Windows.Forms.Label label4; private System.Windows.Forms.Button TestConnection; diff --git a/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.cs b/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.cs index 866364ba7..e42c88827 100644 --- a/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.cs +++ b/Duplicati/Library/Backend/CloudFiles/CloudFilesUI.cs @@ -33,6 +33,7 @@ namespace Duplicati.Library.Backend private const string ACCESS_KEY = "Access Key"; private const string CONTAINER_NAME = "Container name"; private const string HASTESTED = "UI: Has tested"; + private const string INITIALPASSWORD = "UI: Temp password"; private const string LOGIN_PAGE = "https://www.rackspacecloud.com/signup"; private IDictionary m_options; @@ -74,17 +75,26 @@ namespace Duplicati.Library.Backend } Save(); + + m_options.Remove(INITIALPASSWORD); + return true; } private void Save() { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + m_options.Clear(); m_options[HASTESTED] = m_hasTested.ToString(); m_options[USERNAME] = Username.Text; m_options[ACCESS_KEY] = API_KEY.Text; - m_options[CONTAINER_NAME] = BucketName.Text; + m_options[CONTAINER_NAME] = ContainerName.Text; + + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; } void CloudFilesUI_Load(object sender, EventArgs args) @@ -94,9 +104,12 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(ACCESS_KEY)) API_KEY.Text = m_options[ACCESS_KEY]; if (m_options.ContainsKey(CONTAINER_NAME)) - BucketName.Text = m_options[CONTAINER_NAME]; + ContainerName.Text = m_options[CONTAINER_NAME]; - API_KEY.AskToEnterNewPassword = !string.IsNullOrEmpty(API_KEY.Text); + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(ACCESS_KEY) ? m_options[ACCESS_KEY] : ""; + API_KEY.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + API_KEY.InitialPassword = m_options[INITIALPASSWORD]; if (!m_options.ContainsKey(HASTESTED) || !bool.TryParse(m_options[HASTESTED], out m_hasTested)) m_hasTested = false; @@ -116,12 +129,15 @@ namespace Duplicati.Library.Backend return false; } - if (BucketName.Text.Trim().Length <= 0) + if (ContainerName.Text.Trim().Length <= 0) { MessageBox.Show(this, Strings.CloudFilesUI.EmptyContainerNameError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } + if (!API_KEY.VerifyPasswordIfChanged()) + return false; + return true; } @@ -182,12 +198,7 @@ namespace Duplicati.Library.Backend m_hasTested = false; } - private void BucketName_TextChanged(object sender, EventArgs e) - { - m_hasTested = false; - } - - private void UseEuroBuckets_CheckedChanged(object sender, EventArgs e) + private void ContainerName_TextChanged(object sender, EventArgs e) { m_hasTested = false; } diff --git a/Duplicati/Library/Backend/FTP/FTPUI.cs b/Duplicati/Library/Backend/FTP/FTPUI.cs index 6d0ed9be9..24354736a 100644 --- a/Duplicati/Library/Backend/FTP/FTPUI.cs +++ b/Duplicati/Library/Backend/FTP/FTPUI.cs @@ -45,6 +45,7 @@ namespace Duplicati.Library.Backend private const string HASWARNEDPATH = "UI: HasWarnedPath"; private const string HASWARNEDUSERNAME = "UI: HasWarnedUsername"; private const string HASWARNEDPASSWORD = "UI: HasWarnedPassword"; + private const string INITIALPASSWORD = "UI: Temp password"; private bool m_warnedPassword = false; private bool m_warnedUsername = false; @@ -92,6 +93,8 @@ namespace Duplicati.Library.Backend SaveSettings(); + m_options.Remove(INITIALPASSWORD); + return true; } @@ -156,11 +159,17 @@ namespace Duplicati.Library.Backend } } + if (Password.Text.Length > 0 && !Password.VerifyPasswordIfChanged()) + return false; + return true; } private void SaveSettings() { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + m_options.Clear(); m_options[HASTESTED] = m_hasTested.ToString(); m_options[HASWARNEDPATH] = m_warnedPath.ToString(); @@ -175,6 +184,8 @@ namespace Duplicati.Library.Backend m_options[USE_SSL] = UseSSL.Checked.ToString(); m_options[ACCEPT_ANY_CERTIFICATE] = AcceptAnyHash.Checked.ToString(); m_options[ACCEPT_SPECIFIC_CERTIFICATE] = AcceptSpecifiedHash.Checked ? SpecifiedHash.Text : ""; + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; } private void LoadSettings() @@ -188,7 +199,10 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(PASSWORD)) Password.Text = m_options[PASSWORD]; - Password.AskToEnterNewPassword = !string.IsNullOrEmpty(Password.Text); + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(PASSWORD) ? m_options[PASSWORD] : ""; + Password.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + Password.InitialPassword = m_options[INITIALPASSWORD]; bool b; if (!m_options.ContainsKey(PASSIVE) || !bool.TryParse(m_options[PASSIVE], out b)) diff --git a/Duplicati/Library/Backend/File/FileUI.cs b/Duplicati/Library/Backend/File/FileUI.cs index 170a108a0..770b472a0 100644 --- a/Duplicati/Library/Backend/File/FileUI.cs +++ b/Duplicati/Library/Backend/File/FileUI.cs @@ -35,6 +35,7 @@ namespace Duplicati.Library.Backend private const string USERNAME = "Username"; private const string PASSWORD = "Password"; private const string CHECKED_EMPTY = "UI: Checked empty"; + private const string INITIALPASSWORD = "UI: Temp password"; private bool m_hasCheckedEmpty = false; @@ -51,6 +52,9 @@ namespace Duplicati.Library.Backend internal bool Save(bool validate) { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + string targetpath; if (UsePath.Checked) targetpath = TargetFolder.Text; @@ -60,10 +64,14 @@ namespace Duplicati.Library.Backend if (m_hasCheckedEmpty && m_options.ContainsKey(DESTINATION_FOLDER) && targetpath != m_options[DESTINATION_FOLDER]) m_hasCheckedEmpty = false; + m_options.Clear(); m_options[CHECKED_EMPTY] = m_hasCheckedEmpty.ToString(); m_options[DESTINATION_FOLDER] = targetpath; - + + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; + if (UseCredentials.Checked) { m_options[USERNAME] = Username.Text; @@ -76,15 +84,20 @@ namespace Duplicati.Library.Backend } if (!validate) - return false; + return false; if (UseCredentials.Checked) + { if (!Duplicati.Library.Backend.File.PreAuthenticate(targetpath, Username.Text, Password.Text)) { MessageBox.Show(this, Strings.FileUI.AuthenticationError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } + if (Password.Text.Length > 0 && !Password.VerifyPasswordIfChanged()) + return false; + } + try { if (targetpath.Trim().Length == 0) @@ -144,6 +157,8 @@ namespace Duplicati.Library.Backend return false; } + m_options.Remove(INITIALPASSWORD); + return true; } @@ -172,14 +187,16 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(DESTINATION_FOLDER)) TargetFolder.Text = m_options[DESTINATION_FOLDER]; - UseCredentials.Checked = m_options.ContainsKey(USERNAME) && !string.IsNullOrEmpty(m_options[USERNAME]); if (m_options.ContainsKey(USERNAME)) Username.Text = m_options[USERNAME]; if (m_options.ContainsKey(PASSWORD)) Password.Text = m_options[PASSWORD]; - Password.AskToEnterNewPassword = !string.IsNullOrEmpty(Password.Text); + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(PASSWORD) ? m_options[PASSWORD] : ""; + Password.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + Password.InitialPassword = m_options[INITIALPASSWORD]; if (!m_options.ContainsKey(CHECKED_EMPTY) || !bool.TryParse(m_options[CHECKED_EMPTY], out m_hasCheckedEmpty)) m_hasCheckedEmpty = false; diff --git a/Duplicati/Library/Backend/S3/S3UI.cs b/Duplicati/Library/Backend/S3/S3UI.cs index 3d9ff8338..41fdae9f3 100644 --- a/Duplicati/Library/Backend/S3/S3UI.cs +++ b/Duplicati/Library/Backend/S3/S3UI.cs @@ -42,6 +42,7 @@ namespace Duplicati.Library.Backend private const string HASSUGGESTEDPREFIX = "UI: Has suggested prefix"; private const string HASSUGGESTEDLOWERCASE = "UI: Has suggested lowercase"; private const string HASWARNEDINVALIDBUCKETNAME = "UI: Has warned invalid bucket name"; + private const string INITIALPASSWORD = "UI: Temp password"; private const string S3_PATH = "s3.amazonaws.com"; @@ -101,11 +102,16 @@ namespace Duplicati.Library.Backend tmp[AWS_ID.Text] = AWS_KEY.Text; S3CommonOptions.EncodeAccounts(tmp, m_applicationSettings); + m_options.Remove(INITIALPASSWORD); + return true; } private void Save() { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + m_options.Clear(); m_options[HASTESTED] = m_hasTested.ToString(); m_options[HASCREATEDBUCKET] = m_hasCreatedbucket.ToString(); @@ -131,9 +137,11 @@ namespace Duplicati.Library.Backend m_options[BUCKET_NAME] = bucketname; } - bucketname = m_options[BUCKET_NAME]; m_options[SUBDOMAIN] = (bucketname.ToLower() == bucketname && S3.IsValidHostname(bucketname)).ToString(); + + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; } void S3UI_Load(object sender, EventArgs args) @@ -151,7 +159,10 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(PREFIX) && !string.IsNullOrEmpty(m_options[PREFIX])) BucketName.Text += "/" + m_options[PREFIX]; - AWS_KEY.AskToEnterNewPassword = !string.IsNullOrEmpty(AWS_KEY.Text); + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(ACCESS_KEY) ? m_options[ACCESS_KEY] : ""; + AWS_KEY.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + AWS_KEY.InitialPassword = m_options[INITIALPASSWORD]; bool b; @@ -313,6 +324,9 @@ namespace Duplicati.Library.Backend m_hasWarnedInvalidBucketname = true; } + if (!AWS_KEY.VerifyPasswordIfChanged()) + return false; + if (checkForBucket) return EnsureBucketForMono(); else diff --git a/Duplicati/Library/Backend/SSH/SSHUI.cs b/Duplicati/Library/Backend/SSH/SSHUI.cs index 7767252d4..415c21436 100644 --- a/Duplicati/Library/Backend/SSH/SSHUI.cs +++ b/Duplicati/Library/Backend/SSH/SSHUI.cs @@ -42,6 +42,7 @@ namespace Duplicati.Library.Backend private const string HAS_WARNED_PATH = "UI: Has warned path"; private const string HAS_TESTED = "UI: Has tested"; private const string HAS_WARNED_NO_SFTP = "UI: Has warned SFTP"; + private const string INITIALPASSWORD = "UI: Temp password"; private bool m_warnedPath = false; private bool m_hasTested = false; @@ -87,11 +88,18 @@ namespace Duplicati.Library.Backend } Save(); + + m_options.Remove(INITIALPASSWORD); + return true; } private void Save() { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + + m_options.Clear(); m_options[HAS_TESTED] = m_hasTested.ToString(); m_options[HAS_WARNED_PATH] = m_warnedPath.ToString(); m_options[HAS_WARNED_NO_SFTP] = m_warnedNoSFTP.ToString(); @@ -105,6 +113,8 @@ namespace Duplicati.Library.Backend m_options[DEBUG_ENABLED] = GenerateDebugOutput.Checked.ToString(); m_options[USE_UNMANAGED_SSH] = UseUnmanagedSSH.Checked.ToString(); m_options[SSH_KEYFILE] = Keyfile.Text; + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; } void SSHUI_PageLoad(object sender, EventArgs args) @@ -140,8 +150,11 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(SSH_KEYFILE)) Keyfile.Text = m_options[SSH_KEYFILE]; - Password.AskToEnterNewPassword = !string.IsNullOrEmpty(Password.Text); - + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(PASSWORD) ? m_options[PASSWORD] : ""; + Password.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + Password.InitialPassword = m_options[INITIALPASSWORD]; + Port.Value = port; GenerateDebugOutput.Checked = debug; UseUnmanagedSSH.Checked = useUnmanaged; @@ -247,7 +260,6 @@ namespace Duplicati.Library.Backend catch { } return false; - } if (!m_warnedPath && Path.Text.Trim().Length == 0) @@ -297,6 +309,9 @@ namespace Duplicati.Library.Backend } } + if (UsePassword.Checked && !Password.VerifyPasswordIfChanged()) + return false; + return true; } diff --git a/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs b/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs index 191a66339..3840f6177 100644 --- a/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs +++ b/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs @@ -48,6 +48,7 @@ namespace Duplicati.Library.Backend private const string HAS_WARNED_PATH = "UI: Has warned path"; private const string HAS_WARNED_LEADING_SLASH = "UI: Has warned leading slash"; private const string HAS_TESTED = "UI: Has tested"; + private const string INITIALPASSWORD = "UI: Temp password"; private bool m_warnedPassword = false; private bool m_warnedUsername = false; @@ -95,6 +96,9 @@ namespace Duplicati.Library.Backend } Save(); + + m_options.Remove(INITIALPASSWORD); + return true; } @@ -109,7 +113,10 @@ namespace Duplicati.Library.Backend if (m_options.ContainsKey(PASSWORD)) Password.Text = m_options[PASSWORD]; - Password.AskToEnterNewPassword = !string.IsNullOrEmpty(Password.Text); + if (!m_options.ContainsKey(INITIALPASSWORD)) + m_options[INITIALPASSWORD] = m_options.ContainsKey(PASSWORD) ? m_options[PASSWORD] : ""; + Password.AskToEnterNewPassword = !string.IsNullOrEmpty(m_options[INITIALPASSWORD]); + Password.InitialPassword = m_options[INITIALPASSWORD]; int port; if (!m_options.ContainsKey(PORT) || !int.TryParse(m_options[PORT], out port)) @@ -229,6 +236,10 @@ namespace Duplicati.Library.Backend } m_warnedPassword = true; } + + if (Password.Text.Length > 0 && !Password.VerifyPasswordIfChanged()) + return false; + } if (UseSSL.Checked && AcceptSpecifiedHash.Checked) @@ -255,6 +266,9 @@ namespace Duplicati.Library.Backend private void Save() { + string initialPwd; + bool hasInitial = m_options.TryGetValue(INITIALPASSWORD, out initialPwd); + m_options.Clear(); m_options[HAS_TESTED] = m_hasTested.ToString(); m_options[HAS_WARNED_PATH] = m_warnedPath.ToString(); @@ -281,6 +295,9 @@ namespace Duplicati.Library.Backend m_options[USE_SSL] = UseSSL.Checked.ToString(); m_options[ACCEPT_ANY_CERTIFICATE] = AcceptAnyHash.Checked.ToString(); m_options[ACCEPT_SPECIFIC_CERTIFICATE] = AcceptSpecifiedHash.Checked ? SpecifiedHash.Text : ""; + + if (hasInitial) + m_options[INITIALPASSWORD] = initialPwd; } private void TestConnection_Click(object sender, EventArgs e) diff --git a/Duplicati/Winforms/Controls/Duplicati.Winforms.Controls.csproj b/Duplicati/Winforms/Controls/Duplicati.Winforms.Controls.csproj index 423615d2f..a90df1e22 100644 --- a/Duplicati/Winforms/Controls/Duplicati.Winforms.Controls.csproj +++ b/Duplicati/Winforms/Controls/Duplicati.Winforms.Controls.csproj @@ -56,6 +56,12 @@ + + Form + + + PasswordConfirmationDialog.cs + UserControl @@ -68,6 +74,11 @@ True Resources.resx + + True + True + PasswordConfirmationDialog.resx + PasswordControl.resx True @@ -76,6 +87,9 @@ + + PasswordConfirmationDialog.cs + PasswordControl.cs @@ -83,6 +97,10 @@ ResXFileCodeGenerator Resources.Designer.cs + + ResXFileCodeGenerator + PasswordConfirmationDialog.Designer.cs + ResXFileCodeGenerator PasswordControl.Designer.cs diff --git a/Duplicati/Winforms/Controls/PasswordConfirmationDialog.Designer.cs b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.Designer.cs new file mode 100644 index 000000000..30d75d5ee --- /dev/null +++ b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.Designer.cs @@ -0,0 +1,99 @@ +namespace Duplicati.Winforms.Controls +{ + partial class PasswordConfirmationDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PasswordConfirmationDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.Password = new System.Windows.Forms.TextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.OKBtn = new System.Windows.Forms.Button(); + this.CancelBtn = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // Password + // + resources.ApplyResources(this.Password, "Password"); + this.Password.Name = "Password"; + this.Password.UseSystemPasswordChar = true; + // + // panel1 + // + this.panel1.Controls.Add(this.CancelBtn); + this.panel1.Controls.Add(this.OKBtn); + resources.ApplyResources(this.panel1, "panel1"); + this.panel1.Name = "panel1"; + // + // OKBtn + // + resources.ApplyResources(this.OKBtn, "OKBtn"); + this.OKBtn.Name = "OKBtn"; + this.OKBtn.UseVisualStyleBackColor = true; + this.OKBtn.Click += new System.EventHandler(this.OKBtn_Click); + // + // CancelBtn + // + resources.ApplyResources(this.CancelBtn, "CancelBtn"); + this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelBtn.Name = "CancelBtn"; + this.CancelBtn.UseVisualStyleBackColor = true; + // + // PasswordConfirmationDialog + // + this.AcceptButton = this.OKBtn; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelBtn; + this.Controls.Add(this.panel1); + this.Controls.Add(this.Password); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "PasswordConfirmationDialog"; + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox Password; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Button CancelBtn; + private System.Windows.Forms.Button OKBtn; + } +} \ No newline at end of file diff --git a/Duplicati/Winforms/Controls/PasswordConfirmationDialog.cs b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.cs new file mode 100644 index 000000000..cf42509c9 --- /dev/null +++ b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace Duplicati.Winforms.Controls +{ + public partial class PasswordConfirmationDialog : Form + { + private string m_previousPassword; + + public PasswordConfirmationDialog(string previousPassword) + { + InitializeComponent(); + + m_previousPassword = previousPassword; + } + + private void OKBtn_Click(object sender, EventArgs e) + { + if (m_previousPassword != Password.Text) + { + MessageBox.Show(this, Strings.PasswordConfirmationDialog.PasswordDoNotMatchError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + else + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + } + } +} diff --git a/Duplicati/Winforms/Controls/PasswordConfirmationDialog.resx b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.resx new file mode 100644 index 000000000..9a3595e94 --- /dev/null +++ b/Duplicati/Winforms/Controls/PasswordConfirmationDialog.resx @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + Top + + + + 8, 8 + + + 3, 8, 3, 8 + + + 0, 0, 0, 8 + + + 53, 21 + + + 0 + + + Password + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Top + + + 8, 29 + + + 3, 0, 3, 0 + + + 309, 20 + + + 1 + + + Password + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + None + + + NoControl + + + 160, 8 + + + 75, 23 + + + 1 + + + Cancel + + + CancelBtn + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 0 + + + None + + + 72, 8 + + + 75, 23 + + + 0 + + + OK + + + OKBtn + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 1 + + + Bottom + + + 8, 55 + + + 309, 37 + + + 2 + + + panel1 + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + 325, 100 + + + 8, 8, 8, 8 + + + CenterParent + + + Please confirm the password + + + PasswordConfirmationDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Duplicati/Winforms/Controls/PasswordControl.cs b/Duplicati/Winforms/Controls/PasswordControl.cs index 9159b9e1e..a0e86d411 100644 --- a/Duplicati/Winforms/Controls/PasswordControl.cs +++ b/Duplicati/Winforms/Controls/PasswordControl.cs @@ -31,6 +31,11 @@ namespace Duplicati.Winforms.Controls /// private bool m_askToEnterNewPassword = false; + /// + /// The original password assigned to the control + /// + private string m_initialPassword = null; + /// /// An event that is raised when the password changed /// @@ -71,6 +76,18 @@ namespace Duplicati.Winforms.Controls } } + /// + /// Gets or sets the initial password, used to check if the password was changed + /// + public string InitialPassword + { + get { return m_initialPassword; } + set + { + m_initialPassword = value; + } + } + /// /// A value that determines if the user can only clear the password, /// and not reveal the original password @@ -218,5 +235,26 @@ namespace Duplicati.Winforms.Controls try { TextBox.Focus(); } catch { } } + + /// + /// A helper method that asks the user to verify the password if it was changed and is not show + /// + /// True if the password was verified, false otherwise + public bool VerifyPasswordIfChanged() + { + if (!ShowPassword.Checked && (string.IsNullOrEmpty(m_initialPassword) != string.IsNullOrEmpty(m_password) || m_initialPassword != m_password)) + { + PasswordConfirmationDialog dlg = new PasswordConfirmationDialog(m_password); + if (dlg.ShowDialog(this) == DialogResult.OK) + { + m_initialPassword = m_password; + return true; + } + else + return false; + } + else + return true; + } } } diff --git a/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.Designer.cs b/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.Designer.cs new file mode 100644 index 000000000..be9b0970b --- /dev/null +++ b/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4952 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Winforms.Controls.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class PasswordConfirmationDialog { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal PasswordConfirmationDialog() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Winforms.Controls.Strings.PasswordConfirmationDialog", typeof(PasswordConfirmationDialog).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The password that you have entered does not match the previously entered password. + /// + internal static string PasswordDoNotMatchError { + get { + return ResourceManager.GetString("PasswordDoNotMatchError", resourceCulture); + } + } + } +} diff --git a/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.resx b/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.resx new file mode 100644 index 000000000..05c0a56c9 --- /dev/null +++ b/Duplicati/Winforms/Controls/Strings/PasswordConfirmationDialog.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The password that you have entered does not match the previously entered password + + \ No newline at end of file