From 7cb46407b72b12f20f7e4f0a3e9a4874c7134209 Mon Sep 17 00:00:00 2001 From: tiuub Date: Fri, 24 Sep 2021 14:55:42 +0200 Subject: [PATCH] Fixes #32 and #31 --- .gitignore | 1 + KeeOtp2.Tests/KeeOtp2.Tests.csproj | 89 ++++++++++++++++++++++++ KeeOtp2.Tests/KeeOtp2Migration.cs | 38 ++++++++++ KeeOtp2.Tests/Properties/AssemblyInfo.cs | 36 ++++++++++ KeeOtp2.Tests/packages.config | 11 +++ KeeOtp2.sln | 6 ++ KeeOtp2/Forms/About.cs | 29 ++++---- KeeOtp2/Forms/OtpInformation.cs | 63 +++++++++++------ KeeOtp2/Forms/Settings.cs | 75 ++++++-------------- KeeOtp2/Forms/ShowOneTimePasswords.cs | 59 +++++++++------- KeeOtp2/Forms/ShowQrCode.cs | 46 ++++++------ KeeOtp2/Forms/Troubleshooting.cs | 35 ++++++---- KeeOtp2/KeeOtp2.csproj | 2 + KeeOtp2/KeeOtp2Config.cs | 2 +- KeeOtp2/KeeOtp2Ext.cs | 21 +++--- KeeOtp2/OtpAuthUtils.cs | 13 ++++ KeeOtp2/OtpMigration.cs | 35 ++++++++++ KeeOtp2/PluginUtils.cs | 63 +++++++++++++++++ KeeOtp2Tests/KeeOtp2Migration.cs | 35 ---------- KeeOtp2Tests/KeeOtp2Tests.csproj | 36 ---------- README.md | 13 ++++ 21 files changed, 481 insertions(+), 227 deletions(-) create mode 100644 KeeOtp2.Tests/KeeOtp2.Tests.csproj create mode 100644 KeeOtp2.Tests/KeeOtp2Migration.cs create mode 100644 KeeOtp2.Tests/Properties/AssemblyInfo.cs create mode 100644 KeeOtp2.Tests/packages.config create mode 100644 KeeOtp2/OtpMigration.cs create mode 100644 KeeOtp2/PluginUtils.cs delete mode 100644 KeeOtp2Tests/KeeOtp2Migration.cs delete mode 100644 KeeOtp2Tests/KeeOtp2Tests.csproj diff --git a/.gitignore b/.gitignore index 3f2dcc6..8925f41 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ Releases/ Debug/ *.user +/packages/* \ No newline at end of file diff --git a/KeeOtp2.Tests/KeeOtp2.Tests.csproj b/KeeOtp2.Tests/KeeOtp2.Tests.csproj new file mode 100644 index 0000000..6b5ed75 --- /dev/null +++ b/KeeOtp2.Tests/KeeOtp2.Tests.csproj @@ -0,0 +1,89 @@ + + + + + + + Debug + AnyCPU + {DCB1C09A-E92C-413F-8927-79E96331F56B} + Library + Properties + KeeOtp2.Tests + KeeOtp2.Tests + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\KeePass\KeePass.exe + + + + + + + + + + + ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll + + + + + + + + + + + + + + + {6239ec51-8ea1-4aec-883f-086663f24d40} + KeeOtp2 + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/KeeOtp2.Tests/KeeOtp2Migration.cs b/KeeOtp2.Tests/KeeOtp2Migration.cs new file mode 100644 index 0000000..f2e3b9e --- /dev/null +++ b/KeeOtp2.Tests/KeeOtp2Migration.cs @@ -0,0 +1,38 @@ +using KeeOtp2; +using KeePassLib; +using KeePassLib.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace KeeOtp2.Tests +{ + public class KeeOtp2Migration + { + [Theory] + [InlineData("otp", "wroiv2p5agecswssthwzyjn2xzgdquyk", MigrationMode.KeeOtp1ToBuiltIn, true, false)] + [InlineData("otp", "wroiv2p5agecswssthwzyjn2xzgdq", MigrationMode.KeeOtp1ToBuiltIn, true, false)] + [InlineData("otp", "key=wroiv2p5agecswssthwzyjn2xzgdquyk", MigrationMode.KeeOtp1ToBuiltIn, true, true)] + [InlineData("TimeOtp-Secret-Base32", "wroi v2p5 agec swss thwz yjn2 xzgd quyk", MigrationMode.BuiltInToKeeOtp1, true, true)] + [InlineData("TimeOtp-Secret-Base32", "wroi v2p5 agec swss thwz yjn2 xzgd quyk", MigrationMode.KeeOtp1ToBuiltIn, false, true)] + [InlineData("TimeOtp-Secret-Base32", "wroiv2p5agecswssthwzyjn2xzgdquyk", MigrationMode.BuiltInToKeeOtp1, true, true)] + //[InlineData("otp", "", MigrationMode.BuiltInToKeeOtp1, false)] + //[InlineData("otp", "", MigrationMode.BuiltInToKeeOtp1, false)] + public void TestKeyFormat(string keyStringName, string keyStringValue, MigrationMode migrateMode, + bool canMigrate, bool canLoad) + { + + var pwdEntry = new PwEntry(true, true); + pwdEntry.Strings.Set(keyStringName, new ProtectedString(true, keyStringValue)); + Console.WriteLine(keyStringValue); + Assert.Equal(canMigrate, OtpAuthUtils.checkEntryMigratable(pwdEntry, migrateMode)); + if (canLoad) + Assert.NotNull(OtpAuthUtils.loadData(pwdEntry)); + else + Assert.Null(OtpAuthUtils.loadData(pwdEntry)); + } + } +} diff --git a/KeeOtp2.Tests/Properties/AssemblyInfo.cs b/KeeOtp2.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2cb1398 --- /dev/null +++ b/KeeOtp2.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KeeOtp2.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KeeOtp2.Tests")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dcb1c09a-e92c-413f-8927-79e96331f56b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/KeeOtp2.Tests/packages.config b/KeeOtp2.Tests/packages.config new file mode 100644 index 0000000..5f5d42c --- /dev/null +++ b/KeeOtp2.Tests/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/KeeOtp2.sln b/KeeOtp2.sln index f1ff1a1..424ee50 100644 --- a/KeeOtp2.sln +++ b/KeeOtp2.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28307.329 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeeOtp2", "KeeOtp2\KeeOtp2.csproj", "{6239EC51-8EA1-4AEC-883F-086663F24D40}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeeOtp2.Tests", "KeeOtp2.Tests\KeeOtp2.Tests.csproj", "{DCB1C09A-E92C-413F-8927-79E96331F56B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {6239EC51-8EA1-4AEC-883F-086663F24D40}.Debug|Any CPU.Build.0 = Debug|Any CPU {6239EC51-8EA1-4AEC-883F-086663F24D40}.Release|Any CPU.ActiveCfg = Release|Any CPU {6239EC51-8EA1-4AEC-883F-086663F24D40}.Release|Any CPU.Build.0 = Release|Any CPU + {DCB1C09A-E92C-413F-8927-79E96331F56B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCB1C09A-E92C-413F-8927-79E96331F56B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCB1C09A-E92C-413F-8927-79E96331F56B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCB1C09A-E92C-413F-8927-79E96331F56B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/KeeOtp2/Forms/About.cs b/KeeOtp2/Forms/About.cs index c2614e0..fa03690 100644 --- a/KeeOtp2/Forms/About.cs +++ b/KeeOtp2/Forms/About.cs @@ -18,6 +18,23 @@ public About(IPluginHost host) { InitializeComponent(); + this.host = host; + } + + private void About_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -25,22 +42,10 @@ public About(IPluginHost host) KeeOtp2Statics.About, KeeOtp2Statics.AboutSubline); - this.Icon = host.MainWindow.Icon; - - this.host = host; - this.TopMost = host.MainWindow.TopMost; - groupBoxDependencies.Text = KeeOtp2Statics.Dependencies; linkLabelGitHubRepository.Text = KeeOtp2Statics.GitHubRepository; linkLabelDonate.Text = KeeOtp2Statics.Doante; buttonOK.Text = KeeOtp2Statics.OK; - } - - private void About_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; - groupBoxAbout.Text = KeeOtp2Statics.About; Assembly assembly = Assembly.GetExecutingAssembly(); diff --git a/KeeOtp2/Forms/OtpInformation.cs b/KeeOtp2/Forms/OtpInformation.cs index c534bb8..ba366b5 100644 --- a/KeeOtp2/Forms/OtpInformation.cs +++ b/KeeOtp2/Forms/OtpInformation.cs @@ -7,13 +7,14 @@ using KeePass.Plugins; using OtpNet; using ZXing; +using KeePassLib; namespace KeeOtp2 { public partial class OtpInformation : Form { - private readonly KeePassLib.PwEntry entry; - private readonly IPluginHost host; + private IPluginHost host; + private PwEntry entry; private OtpAuthData data; bool scanQRMode = true; @@ -21,10 +22,29 @@ public partial class OtpInformation : Form private Dictionary comboBoxLengthIndexValue; private Dictionary comboBoxTypeIndexValue; - public OtpInformation(OtpAuthData data, KeePassLib.PwEntry entry, IPluginHost host) + public OtpInformation(IPluginHost host, PwEntry entry, OtpAuthData data) { InitializeComponent(); + this.host = host; + this.entry = entry; + this.data = data; + } + + private void OtpInformation_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -32,14 +52,6 @@ public OtpInformation(OtpAuthData data, KeePassLib.PwEntry entry, IPluginHost ho KeeOtp2Statics.OtpInformation, KeeOtp2Statics.OtpInformationSubline); - this.Icon = host.MainWindow.Icon; - - this.data = data; - this.entry = entry; - this.host = host; - - this.TopMost = host.MainWindow.TopMost; - groupBoxKey.Text = KeeOtp2Statics.OtpInformationKeyUri; linkLabelLoadUriScanQR.Text = KeeOtp2Statics.OtpInformationScanQr; checkBoxCustomSettings.Text = KeeOtp2Statics.OtpInformationCustomSettings + KeeOtp2Statics.InformationChar; @@ -74,7 +86,7 @@ public OtpInformation(OtpAuthData data, KeePassLib.PwEntry entry, IPluginHost ho toolTip.SetToolTip(checkboxOldKeeOtp, KeeOtp2Statics.ToolTipOtpInformationUseOldKeeOtpSaveMode); comboBoxLengthIndexValue = new Dictionary(); - for (int i = 5; i<=10; i++) + for (int i = 5; i <= 10; i++) { if (i == 6 || i == 8) comboBoxLengthIndexValue[comboBoxLength.Items.Add(String.Format("{0} ({1})", i, KeeOtp2Statics.CommonAbbreviation.ToLower() + KeeOtp2Statics.InformationChar))] = i; @@ -82,17 +94,12 @@ public OtpInformation(OtpAuthData data, KeePassLib.PwEntry entry, IPluginHost ho comboBoxLengthIndexValue[comboBoxLength.Items.Add(i.ToString())] = i; } comboBoxTypeIndexValue = new Dictionary(); - foreach (OtpType type in Enum.GetValues(typeof(OtpType))){ + foreach (OtpType type in Enum.GetValues(typeof(OtpType))) + { comboBoxTypeIndexValue[comboBoxType.Items.Add(type.ToString())] = type; } } - private void OtpInformation_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; - } - private void OtpInformation_Shown(object sender, EventArgs e) { loadData(); @@ -122,9 +129,10 @@ private void OtpInformation_FormClosing(object sender, FormClosingEventArgs e) } - this.entry.Touch(true); + this.entry.Touch(true, false); this.host.MainWindow.ActiveDatabase.Modified = true; this.host.MainWindow.UpdateUI(false, null, false, null, false, null, true); + this.host.MainWindow.RefreshEntriesList(); } catch (InvalidBase32FormatException ex) { @@ -540,7 +548,13 @@ private void scanQRCode() Bitmap bmpScreenshot; Graphics gfxScreenshot; - this.Hide(); + Form p = this; + while (p != null) + { + p.Hide(); + p = p.Owner; + } + foreach (Screen sc in Screen.AllScreens) { bmpScreenshot = new Bitmap(sc.Bounds.Width, sc.Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); @@ -552,7 +566,12 @@ private void scanQRCode() uri = new Uri(result.ToString()); } - this.Show(); + p = this; + while (p != null) + { + p.Show(); + p = p.Owner; + } if (uri != null) { diff --git a/KeeOtp2/Forms/Settings.cs b/KeeOtp2/Forms/Settings.cs index 3c3d6fa..31a8d41 100644 --- a/KeeOtp2/Forms/Settings.cs +++ b/KeeOtp2/Forms/Settings.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -14,40 +15,13 @@ namespace KeeOtp2 public partial class Settings : Form { private IPluginHost host; - private readonly BackgroundWorker backgroundWorkerMigrate; + private BackgroundWorker backgroundWorkerMigrate; private bool removeAfterMigration; private bool migrateAutoType; private MigrationProfile currentMigrationProfile; private bool encounteredForcedKeeOtp1Entries; - public enum MigrationMode - { - KeeOtp1ToBuiltIn, - BuiltInToKeeOtp1 - } - - public class MigrationProfile - { - public string name { get; set; } - public MigrationMode migrationMode { get; set; } - public Dictionary findPlaceholder { get; set; } - public Dictionary replacePlaceholder { get; set; } - - public MigrationProfile(string name) - { - this.name = name; - } - - public MigrationProfile(string name, MigrationMode migrationMode, Dictionary findPlaceholder, Dictionary replacePlaceholder) - { - this.name = name; - this.migrationMode = migrationMode; - this.findPlaceholder = findPlaceholder; - this.replacePlaceholder = replacePlaceholder; - } - } - private Dictionary migrateModeString = new Dictionary() { { MigrationMode.KeeOtp1ToBuiltIn, "KeeOtp(1) -> Built-In" }, @@ -66,6 +40,23 @@ public Settings(IPluginHost host) { InitializeComponent(); + this.host = host; + } + + private void Settings_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -73,15 +64,10 @@ public Settings(IPluginHost host) KeeOtp2Statics.Settings, KeeOtp2Statics.SettingsSubline); - this.Icon = host.MainWindow.Icon; - - this.host = host; - this.TopMost = host.MainWindow.TopMost; - long timeInSeconds = (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; this.numericUpDownFixedTimeOffset.Maximum = timeInSeconds; this.numericUpDownFixedTimeOffset.Minimum = -timeInSeconds; - + this.backgroundWorkerMigrate = new BackgroundWorker(); this.backgroundWorkerMigrate.DoWork += backgroundWorkerMigrate_DoWork; this.backgroundWorkerMigrate.RunWorkerCompleted += backgroundWorkerMigrate_RunWorkerCompleted; @@ -126,12 +112,6 @@ public Settings(IPluginHost host) string toolTipOverrideBuiltInTime = KeeOtp2Statics.ToolTipOverrideBuiltInTime; toolTip.SetToolTip(labelOverrideBuiltInTime, toolTipOverrideBuiltInTime); toolTip.SetToolTip(checkBoxOverrideBuiltInTime, toolTipOverrideBuiltInTime); - } - - private void Settings_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; foreach (MigrationMode migrationMode in Enum.GetValues(typeof(MigrationMode))) { @@ -308,7 +288,7 @@ private void backgroundWorkerMigrate_DoWork(object sender, DoWorkEventArgs e) { if (entry.ParentGroup.Uuid != RecycleBinUuid) { - if (checkEntryMigratable(entry, currentMigrationProfile.migrationMode)) + if (OtpAuthUtils.checkEntryMigratable(entry, currentMigrationProfile.migrationMode)) { OtpAuthData data = OtpAuthUtils.loadData(entry); if (data != null) { @@ -390,18 +370,5 @@ private void timerClock_Tick(object sender, EventArgs e) dateTime = OtpTime.getTime(); labelTime.Text = String.Format(KeeOtp2Statics.SettingsPreviewUtc, dateTime.ToLongTimeString()); } - - public static bool checkEntryMigratable(PwEntry entry, MigrationMode migrateMode) - { - switch (migrateMode) - { - case MigrationMode.KeeOtp1ToBuiltIn: - return OtpAuthUtils.checkKeeOtp1Mode(entry); - case MigrationMode.BuiltInToKeeOtp1: - return OtpAuthUtils.checkBuiltInMode(entry); - default: - return false; - } - } } } diff --git a/KeeOtp2/Forms/ShowOneTimePasswords.cs b/KeeOtp2/Forms/ShowOneTimePasswords.cs index 38d644d..54011f8 100644 --- a/KeeOtp2/Forms/ShowOneTimePasswords.cs +++ b/KeeOtp2/Forms/ShowOneTimePasswords.cs @@ -1,11 +1,11 @@ -using System; -using System.Drawing; -using System.Windows.Forms; -using KeeOtp2.Properties; +using KeeOtp2.Properties; using KeePass.Plugins; using KeePass.Util; +using KeePassLib; using KeePassLib.Security; -using OtpNet; +using System; +using System.Drawing; +using System.Windows.Forms; namespace KeeOtp2 { @@ -13,8 +13,8 @@ public partial class ShowOneTimePasswords : Form { const int reloadDataDelay = 1; // in seconds - private readonly KeePassLib.PwEntry entry; - private readonly IPluginHost host; + private IPluginHost host; + private PwEntry entry; private OtpBase otp; private OtpAuthData data; @@ -22,10 +22,28 @@ public partial class ShowOneTimePasswords : Form private bool increaseHotpAfterClosing = false; private int reloadCount = 0; - public ShowOneTimePasswords(KeePassLib.PwEntry entry, IPluginHost host) + public ShowOneTimePasswords(IPluginHost host, PwEntry entry) { InitializeComponent(); + this.host = host; + this.entry = entry; + } + + private void ShowOneTimePasswords_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -33,12 +51,6 @@ public ShowOneTimePasswords(KeePassLib.PwEntry entry, IPluginHost host) KeeOtp2Statics.ShowOtp, KeeOtp2Statics.ShowOtpSubline); - this.Icon = host.MainWindow.Icon; - this.TopMost = host.MainWindow.TopMost; - - this.host = host; - this.entry = entry; - groupboxTotp.Text = KeeOtp2Statics.TOTP; linkLabelIncorrectNext.Text = KeeOtp2Statics.ShowOtpIncorrect; buttonShowQR.Text = KeeOtp2Statics.ShowOtpShowQr + KeeOtp2Statics.InformationChar; @@ -52,12 +64,6 @@ public ShowOneTimePasswords(KeePassLib.PwEntry entry, IPluginHost host) toolTip.SetToolTip(buttonShowQR, KeeOtp2Statics.ToolTipShowQrCode); } - private void ShowOneTimePasswords_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; - } - private void ShowOneTimePasswords_Shown(object sender, EventArgs e) { loadData(); @@ -74,7 +80,8 @@ private void linkLabelIncorrectNext_LinkClicked(object sender, LinkLabelLinkClic if (data.Type == OtpType.Totp || data.Type == OtpType.Steam) { Troubleshooting troubleshooting = new Troubleshooting(this.host); - troubleshooting.ShowDialog(); + troubleshooting.InitEx(); + troubleshooting.ShowDialog(this.host.MainWindow); } else if (data.Type == OtpType.Hotp) { @@ -92,8 +99,9 @@ private void buttonShowQR_Click(object sender, EventArgs e) { if (this.data.Encoding == OtpSecretEncoding.Base32) { - ShowQrCode sqc = new ShowQrCode(this.data, this.entry, this.host); - sqc.ShowDialog(); + ShowQrCode sqc = new ShowQrCode(this.host, this.entry, this.data); + sqc.InitEx(); + sqc.ShowDialog(this); } else { @@ -124,9 +132,10 @@ private void AddEdit() this.labelOtp.Text = insertSpaceInMiddle("000000"); this.otp = null; - OtpInformation addEditForm = new OtpInformation(this.data, this.entry, this.host); + OtpInformation addEditForm = new OtpInformation(this.host, this.entry, this.data); + addEditForm.InitEx(); - var result = addEditForm.ShowDialog(); + var result = addEditForm.ShowDialog(this); if (result == DialogResult.OK) { this.data = OtpAuthUtils.loadData(this.entry); diff --git a/KeeOtp2/Forms/ShowQrCode.cs b/KeeOtp2/Forms/ShowQrCode.cs index 1c51136..094936f 100644 --- a/KeeOtp2/Forms/ShowQrCode.cs +++ b/KeeOtp2/Forms/ShowQrCode.cs @@ -24,10 +24,30 @@ public partial class ShowQrCode : Form private ToolTip copyUriToolTip; private ToolTip reloadToolTip; - public ShowQrCode(OtpAuthData data, PwEntry entry, IPluginHost host) + public ShowQrCode(IPluginHost host, PwEntry entry, OtpAuthData data) { InitializeComponent(); + this.host = host; + this.data = data; + this.uri = OtpAuthUtils.otpAuthDataToUri(entry, data); + this.entry = entry; + } + + private void ShowQrCode_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -35,14 +55,6 @@ public ShowQrCode(OtpAuthData data, PwEntry entry, IPluginHost host) KeeOtp2Statics.ShowQr, KeeOtp2Statics.ShowQrSubline); - this.Icon = host.MainWindow.Icon; - this.TopMost = host.MainWindow.TopMost; - - this.data = data; - this.uri = OtpAuthUtils.otpAuthDataToUri(entry, data); - this.entry = entry; - this.host = host; - groupBoxQRCode.Text = KeeOtp2Statics.ShowQrDisclamer; buttonOk.Text = KeeOtp2Statics.OK; @@ -60,6 +72,11 @@ public ShowQrCode(OtpAuthData data, PwEntry entry, IPluginHost host) string toolTipReload = KeeOtp2Statics.ToolTipShowQrCodeReload; reloadToolTip.SetToolTip(buttonCopyUriReload, toolTipReload); + + if (!data.Proprietary) + MessageBox.Show(KeeOtp2Statics.MessageBoxOtpNotProprietary, KeeOtp2Statics.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning); + + showQrCodeImage(); } private void showQrCodeImage() @@ -84,17 +101,6 @@ private void showQrCodeImage() timerFormTimeout.Start(); } - private void ShowQrCode_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; - - if (!data.Proprietary) - MessageBox.Show(KeeOtp2Statics.MessageBoxOtpNotProprietary, KeeOtp2Statics.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning); - - showQrCodeImage(); - } - private void buttonCopyUriReload_Click(object sender, EventArgs e) { if (sharingExpired) diff --git a/KeeOtp2/Forms/Troubleshooting.cs b/KeeOtp2/Forms/Troubleshooting.cs index 4c88814..0b5abf1 100644 --- a/KeeOtp2/Forms/Troubleshooting.cs +++ b/KeeOtp2/Forms/Troubleshooting.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Drawing; using System.Windows.Forms; using KeeOtp2.Properties; using KeePass.Plugins; @@ -9,12 +10,29 @@ namespace KeeOtp2 { public partial class Troubleshooting : Form { - IPluginHost host; + private IPluginHost host; public Troubleshooting(IPluginHost host) { InitializeComponent(); + this.host = host; + } + + private void Troubleshooting_Load(object sender, EventArgs e) + { + Point location = this.Owner.Location; + location.Offset(20, 20); + this.Location = location; + + this.Icon = this.host.MainWindow.Icon; + this.TopMost = this.host.MainWindow.TopMost; + + PluginUtils.CheckKeeTheme(this); + } + + public void InitEx() + { pictureBoxBanner.Image = KeePass.UI.BannerFactory.CreateBanner(pictureBoxBanner.Width, pictureBoxBanner.Height, KeePass.UI.BannerStyle.Default, @@ -22,11 +40,6 @@ public Troubleshooting(IPluginHost host) KeeOtp2Statics.Troubleshooting, KeeOtp2Statics.TroubleshootingSubline); - this.Icon = host.MainWindow.Icon; - this.TopMost = host.MainWindow.TopMost; - - this.host = host; - groupBoxInformation.Text = KeeOtp2Statics.Information; labelInformation.Text = KeeOtp2Statics.TroubleshootingInformation; groupBoxActions.Text = KeeOtp2Statics.Actions; @@ -49,13 +62,6 @@ public Troubleshooting(IPluginHost host) string toolTipTroubleshootingWebsite = KeeOtp2Statics.ToolTipTroubleshootingWebsite; toolTip.SetToolTip(buttonTroubleshootingWebsite, toolTipTroubleshootingWebsite); - - } - - private void Troubleshooting_Load(object sender, EventArgs e) - { - this.Left = this.host.MainWindow.Left + 20; - this.Top = this.host.MainWindow.Top + 20; } private void buttonPingGoogle_Click(object sender, EventArgs e) @@ -72,7 +78,8 @@ private void buttonPingGoogle_Click(object sender, EventArgs e) private void buttonSettings_Click(object sender, EventArgs e) { Settings settings = new Settings(this.host); - settings.ShowDialog(); + settings.InitEx(); + settings.ShowDialog(this); if (settings.DialogResult == DialogResult.OK) KeeOtp2Config.loadConfig(); diff --git a/KeeOtp2/KeeOtp2.csproj b/KeeOtp2/KeeOtp2.csproj index 4d74f1e..43c777c 100644 --- a/KeeOtp2/KeeOtp2.csproj +++ b/KeeOtp2/KeeOtp2.csproj @@ -110,10 +110,12 @@ + + True diff --git a/KeeOtp2/KeeOtp2Config.cs b/KeeOtp2/KeeOtp2Config.cs index d5e84f1..2e8a7d6 100644 --- a/KeeOtp2/KeeOtp2Config.cs +++ b/KeeOtp2/KeeOtp2Config.cs @@ -20,7 +20,7 @@ public static void loadConfig() public static void registerHotKey() { - if (handler != null) + if (handler != null && !KeePassLib.Native.NativeLib.IsUnix()) HotkeyManager.Current.AddOrReplace(HOTKEY_NAME, KeeOtp2Config.HotKeyKeys, handler); } diff --git a/KeeOtp2/KeeOtp2Ext.cs b/KeeOtp2/KeeOtp2Ext.cs index 792399f..bbb60c1 100644 --- a/KeeOtp2/KeeOtp2Ext.cs +++ b/KeeOtp2/KeeOtp2Ext.cs @@ -185,8 +185,9 @@ private void otpConfigureToolStripItem_Click(object sender, EventArgs e) if (GetSelectedSingleEntry(out entry)) { OtpAuthData data = OtpAuthUtils.loadData(entry); - OtpInformation addEditForm = new OtpInformation(data, entry, host); - addEditForm.ShowDialog(); + OtpInformation addEditForm = new OtpInformation(this.host, entry, data); + addEditForm.InitEx(); + addEditForm.ShowDialog(this.host.MainWindow); } } @@ -195,8 +196,9 @@ private void otpDialogToolStripItem_Click(object sender, EventArgs e) PwEntry entry; if (GetSelectedSingleEntry(out entry)) { - ShowOneTimePasswords form = new ShowOneTimePasswords(entry, host); - form.ShowDialog(); + ShowOneTimePasswords sotp = new ShowOneTimePasswords(this.host, entry); + sotp.InitEx(); + sotp.ShowDialog(this.host.MainWindow); } } @@ -210,8 +212,9 @@ private void otpCopyToolStripItem_Click(object sender, EventArgs e) { if (MessageBox.Show(KeeOtp2Statics.MessageBoxOtpNotConfigured, KeeOtp2Statics.PluginName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - ShowOneTimePasswords form = new ShowOneTimePasswords(entry, host); - form.ShowDialog(); + ShowOneTimePasswords sotp = new ShowOneTimePasswords(this.host, entry); + sotp.InitEx(); + sotp.ShowDialog(this.host.MainWindow); } } else @@ -235,7 +238,8 @@ private void otpCopyToolStripItem_Click(object sender, EventArgs e) private void settingsToolStripitem_Click(object sender, EventArgs e) { Settings settings = new Settings(this.host); - settings.ShowDialog(); + settings.InitEx(); + settings.ShowDialog(this.host.MainWindow); if (settings.DialogResult == DialogResult.OK) { @@ -247,7 +251,8 @@ private void settingsToolStripitem_Click(object sender, EventArgs e) private void aboutToolStripitem_Click(object sender, EventArgs e) { About about = new About(this.host); - about.ShowDialog(); + about.InitEx(); + about.ShowDialog(this.host.MainWindow); } private bool GetSelectedSingleEntry(out PwEntry entry) diff --git a/KeeOtp2/OtpAuthUtils.cs b/KeeOtp2/OtpAuthUtils.cs index d579d87..6a7c16e 100644 --- a/KeeOtp2/OtpAuthUtils.cs +++ b/KeeOtp2/OtpAuthUtils.cs @@ -291,6 +291,19 @@ public static OtpAuthData loadDataFromBuiltInOtp(PwEntry entry) return data; } + public static bool checkEntryMigratable(PwEntry entry, MigrationMode migrateMode) + { + switch (migrateMode) + { + case MigrationMode.KeeOtp1ToBuiltIn: + return checkKeeOtp1Mode(entry); + case MigrationMode.BuiltInToKeeOtp1: + return checkBuiltInMode(entry); + default: + return false; + } + } + public static PwEntry migrateToKeeOtp1String(OtpAuthData data, PwEntry entry) { NameValueCollection collection = new NameValueCollection(); diff --git a/KeeOtp2/OtpMigration.cs b/KeeOtp2/OtpMigration.cs new file mode 100644 index 0000000..5d5f60f --- /dev/null +++ b/KeeOtp2/OtpMigration.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KeeOtp2 +{ + public enum MigrationMode + { + KeeOtp1ToBuiltIn, + BuiltInToKeeOtp1 + } + + public class MigrationProfile + { + public string name { get; set; } + public MigrationMode migrationMode { get; set; } + public Dictionary findPlaceholder { get; set; } + public Dictionary replacePlaceholder { get; set; } + + public MigrationProfile(string name) + { + this.name = name; + } + + public MigrationProfile(string name, MigrationMode migrationMode, Dictionary findPlaceholder, Dictionary replacePlaceholder) + { + this.name = name; + this.migrationMode = migrationMode; + this.findPlaceholder = findPlaceholder; + this.replacePlaceholder = replacePlaceholder; + } + } +} diff --git a/KeeOtp2/PluginUtils.cs b/KeeOtp2/PluginUtils.cs new file mode 100644 index 0000000..affd595 --- /dev/null +++ b/KeeOtp2/PluginUtils.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace KeeOtp2 +{ + class PluginUtils + { + public static object GetField(string field, object obj) + { + BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic; + return GetField(field, obj, bf); + } + + public static object GetField(string field, object obj, BindingFlags bf) + { + if (obj == null) return null; + FieldInfo fi = obj.GetType().GetField(field, bf); + if (fi == null) return null; + return fi.GetValue(obj); + } + + public static object GetPluginInstance(string PluginName) + { + string comp = PluginName + "." + PluginName + "Ext"; + BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic; + try + { + var PluginManager = GetField("m_pluginManager", KeePass.Program.MainForm); + var PluginList = GetField("m_vPlugins", PluginManager); + MethodInfo IteratorMethod = PluginList.GetType().GetMethod("System.Collections.Generic.IEnumerable.GetEnumerator", bf); + IEnumerator PluginIterator = (IEnumerator)(IteratorMethod.Invoke(PluginList, null)); + while (PluginIterator.MoveNext()) + { + object result = GetField("m_pluginInterface", PluginIterator.Current); + if (comp == result.GetType().ToString()) return result; + } + } + + catch (Exception) { } + return null; + } + + public static void CheckKeeTheme(Control c) + { + KeePass.Plugins.Plugin p = (KeePass.Plugins.Plugin)PluginUtils.GetPluginInstance("KeeTheme"); + if (p == null) return; + var t = PluginUtils.GetField("_theme", p); + if (t == null) return; + bool bKeeThemeEnabled = (bool)t.GetType().GetProperty("Enabled").GetValue(t, null); + if (!bKeeThemeEnabled) return; + var v = PluginUtils.GetField("_controlVisitor", p); + if (v == null) return; + MethodInfo miVisit = v.GetType().GetMethod("Visit", new Type[] { typeof(Control) }); + if (miVisit == null) return; + miVisit.Invoke(v, new object[] { c }); + } + } +} diff --git a/KeeOtp2Tests/KeeOtp2Migration.cs b/KeeOtp2Tests/KeeOtp2Migration.cs deleted file mode 100644 index d5e9545..0000000 --- a/KeeOtp2Tests/KeeOtp2Migration.cs +++ /dev/null @@ -1,35 +0,0 @@ -using KeeOtp2; -using KeePassLib; -using KeePassLib.Security; -using System; -using System.Linq; -using Xunit; -using System.Windows.Forms; - -namespace KeeOtp2Tests -{ - public class KeeOtp2Migration - { - [Theory] - [InlineData("otp", "wroiv2p5agecswssthwzyjn2xzgdquyk", Settings.MigrateMode.KeeOtp1ToBuiltIn, true, false)] - [InlineData("otp", "wroiv2p5agecswssthwzyjn2xzgdq", Settings.MigrateMode.KeeOtp1ToBuiltIn, true, false)] - [InlineData("otp", "key=wroiv2p5agecswssthwzyjn2xzgdquyk", Settings.MigrateMode.KeeOtp1ToBuiltIn, true, true)] - [InlineData("TimeOtp-Secret-Base32", "wroi v2p5 agec swss thwz yjn2 xzgd quyk", Settings.MigrateMode.BuiltInToKeeOtp1, true, true)] - [InlineData("TimeOtp-Secret-Base32", "wroi v2p5 agec swss thwz yjn2 xzgd quyk", Settings.MigrateMode.KeeOtp1ToBuiltIn, false, true)] - [InlineData("TimeOtp-Secret-Base32", "wroiv2p5agecswssthwzyjn2xzgdquyk", Settings.MigrateMode.BuiltInToKeeOtp1, true, true)] - //[InlineData("otp", "", Settings.MigrateMode.BuiltInToKeeOtp1, false)] - //[InlineData("otp", "", Settings.MigrateMode.BuiltInToKeeOtp1, false)] - public void TestKeyFormat(string keyStringName, string keyStringValue, Settings.MigrateMode migrateMode, - bool canMigrate, bool canLoad) - { - var pwdEntry = new PwEntry(true, true); - pwdEntry.Strings.Set(keyStringName, new ProtectedString(true, keyStringValue)); - Assert.Equal(canMigrate, KeeOtp2.Settings.checkEntryMigratable(pwdEntry, migrateMode)); - if (canLoad) - Assert.NotNull(OtpAuthUtils.loadData(pwdEntry)); - else - Assert.Null(OtpAuthUtils.loadData(pwdEntry)); - } - - } -} diff --git a/KeeOtp2Tests/KeeOtp2Tests.csproj b/KeeOtp2Tests/KeeOtp2Tests.csproj deleted file mode 100644 index 6bd440b..0000000 --- a/KeeOtp2Tests/KeeOtp2Tests.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - net48 - - false - - true - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - ..\KeePass\KeePass.exe - - - - - - diff --git a/README.md b/README.md index f1e49ad..6958dcf 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,19 @@ Dependencie | Source | NuGet | Author | License **NHotkey.WindowsForms** | [source](https://github.com/thomaslevesque/NHotkey) | [NuGet](https://www.nuget.org/packages/NHotkey.WindowsForms/) | [Thomas Levesque](https://github.com/thomaslevesque) | [Apache 2.0](https://github.com/tiuub/KeeOtp2/blob/master/Dependencies/NHotkey.WindowsForms/LICENSE) +### Dependencies (KeeOtp2.Tests) + +Dependencie | Source | NuGet | Author | License +--- | --- | --- | --- | --- +**xunit** | [source](https://github.com/xunit/xunit) | [NuGet](https://www.nuget.org/packages/xunit/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit/blob/main/LICENSE) +**xunit.analyzers** | [source](https://github.com/xunit/xunit.analyzers) | [NuGet](https://www.nuget.org/packages/xunit.analyzers/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit.analyzers/blob/main/LICENSE) +**xunit.assert** | [source](https://github.com/xunit/xunit) | [NuGet](https://www.nuget.org/packages/xunit.assert/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit/blob/main/LICENSE) +**xunit.core** | [source](https://github.com/xunit/xunit) | [NuGet](https://www.nuget.org/packages/xunit.core/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit/blob/main/LICENSE) +**xunit.runner.visualstudio** | [source](https://github.com/xunit/visualstudio.xunit) | [NuGet](https://www.nuget.org/packages/xunit.runner.visualstudio/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/visualstudio.xunit/blob/main/License.txt) +**xunit.extensibility.core** | [source](https://github.com/xunit/xunit) | [NuGet](https://www.nuget.org/packages/xunit.extensibility.core/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit/blob/main/LICENSE) +**xunit.extensibility.execution** | [source](https://github.com/xunit/xunit) | [NuGet](https://www.nuget.org/packages/xunit.extensibility.execution/) | [xunit](https://github.com/xunit) | [Apache 2.0](https://github.com/xunit/xunit/blob/main/LICENSE) + + ### Icons Icon | Source | Brand | Author | License