diff --git a/src/KeePassOTPExt.cs b/src/KeePassOTPExt.cs index f11d64b..90e7233 100644 --- a/src/KeePassOTPExt.cs +++ b/src/KeePassOTPExt.cs @@ -438,7 +438,7 @@ private void MigratePlacholderInOpenDatabases(string sOldPlaceholder, string pla if (!doc.Database.IsOpen) m_host.MainWindow.OpenDatabase(doc.LockedIoc, null, doc.LockedIoc.IsLocalFile()); if (!doc.Database.IsOpen) continue; m.SetDB(doc.Database); - if (m.MigratePlaceholder(sOldPlaceholder, Config.Placeholder, false)) + if (m.MigratePlaceholder(sOldPlaceholder, Config.Placeholder)) { doc.Database.Modified = true; bChanged = true; diff --git a/src/Migration.cs b/src/Migration.cs index a77b280..c6354e3 100644 --- a/src/Migration.cs +++ b/src/Migration.cs @@ -45,7 +45,7 @@ public virtual void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, EntriesOverall = EntriesMigrated = -1; } - public bool MigratePlaceholder(string from, string to, bool bTouchEntries) + public bool MigratePlaceholder(string from, string to) { bool bChanged = false; if (!m_bInitialized) return bChanged; @@ -64,20 +64,44 @@ public bool MigratePlaceholder(string from, string to, bool bTouchEntries) EntryHandler eh = delegate (PwEntry pe) { if (pe == null) { return true; } + bool bBackupRequired = true; foreach (var a in pe.AutoType.Associations) { if (a.Sequence.Contains(from)) { + if (bBackupRequired) + { + bBackupRequired = false; + pe.CreateBackup(m_db); + } a.Sequence = a.Sequence.Replace(from, to); bChanged = true; } } if (pe.AutoType.DefaultSequence.Contains(from)) { + if (bBackupRequired) + { + bBackupRequired = false; + pe.CreateBackup(m_db); + } pe.AutoType.DefaultSequence = pe.AutoType.DefaultSequence.Replace(from, to); bChanged = true; } - if (bTouchEntries) pe.Touch(true); + foreach (var s in pe.Strings.GetKeys()) + { + ProtectedString ps = pe.Strings.Get(s); + if (!ps.Contains(from)) continue; + if (bBackupRequired) + { + bBackupRequired = false; + pe.CreateBackup(m_db); + } + ps = ps.Replace(from, to); + pe.Strings.Set(s, ps); + bChanged = true; + } + pe.Touch(true, false); return true; }; @@ -212,7 +236,7 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o } } finally { EndLogger(); } - MigratePlaceholder(OtherPluginPlaceholder, Config.Placeholder, false); + MigratePlaceholder(OtherPluginPlaceholder, Config.Placeholder); } public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) @@ -289,7 +313,7 @@ public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, { EndLogger(); } - MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); + MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder); } } @@ -395,7 +419,7 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o { EndLogger(); } - MigratePlaceholder(m_OtherPluginPlaceholder, Config.Placeholder, false); + MigratePlaceholder(m_OtherPluginPlaceholder, Config.Placeholder); } public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) @@ -462,7 +486,7 @@ public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, } } finally { EndLogger(); } - MigratePlaceholder(Config.Placeholder, m_OtherPluginPlaceholder, false); + MigratePlaceholder(Config.Placeholder, m_OtherPluginPlaceholder); } } } diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs index efe6c29..4152ed4 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/src/Properties/AssemblyInfo.cs @@ -30,5 +30,5 @@ // 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("0.21")] -[assembly: AssemblyFileVersion("0.21")] \ No newline at end of file +[assembly: AssemblyVersion("0.22")] +[assembly: AssemblyFileVersion("0.22")] \ No newline at end of file diff --git a/src/Util.cs b/src/Util.cs index 3e9dbcc..9ff2127 100644 --- a/src/Util.cs +++ b/src/Util.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Reflection; using System.Windows.Forms; @@ -618,4 +619,74 @@ public static List GetEventHandlers(this object obj, string EventName) return result; } } + + internal static class PSExtensions + { + internal static bool Contains(this ProtectedString ps, string search) + { + return Contains(ps, new ProtectedString(false, search)); + } + + internal static bool Contains(this ProtectedString ps, ProtectedString search) + { + return IndexOfSubString(ps, search) > 0; + } + + internal static ProtectedString Replace(this ProtectedString ps, string search, string replace) + { + return Replace(ps, new ProtectedString(true, StrUtil.Utf8.GetBytes(search)), new ProtectedString(true, StrUtil.Utf8.GetBytes(replace))); + } + + internal static ProtectedString Replace(this ProtectedString ps, ProtectedString search, ProtectedString replace) + { + ProtectedString result = ps; + int i = IndexOfSubString(result, search); + while (i >= 0) + { + var psAfter = result.Remove(0, i + search.Length); + var psBefore = result.Remove(i, result.Length - i); + result = psBefore + replace + psAfter; + i = IndexOfSubString(result, search); + } + return result; + } + + private static int IndexOfSubString(ProtectedString ps, ProtectedString search) + { + if (ps == null || ps.IsEmpty || search == null || search.IsEmpty) return -1; + int i = 0; + int max = ps.Length - search.Length; + if (max < 0) return -1; + var haystack = ps.ReadChars(); + var needle = search.ReadChars(); + char[] slice = null; + try + { + while (i <= max) + { + slice = haystack.Slice(i, search.Length); + if (needle.SequenceEqual(slice)) return i; + i++; + } + return -1; + } + catch + { + return -1; + } + finally + { + MemUtil.ZeroArray(haystack); + MemUtil.ZeroArray(needle); + if (slice != null) MemUtil.ZeroArray(slice); + } + } + + internal static T[] Slice(this T[] data, int index, int length) + { + T[] result = new T[length]; + Array.Copy(data, index, result, 0, length); + return result; + } + } } diff --git a/src/Utilities/Tools_UI.cs b/src/Utilities/Tools_UI.cs index 7eac8ed..bd9c678 100644 --- a/src/Utilities/Tools_UI.cs +++ b/src/Utilities/Tools_UI.cs @@ -10,10 +10,10 @@ public static bool PreserveEntriesShown public static void RefreshEntriesList(bool bSetModified) { - UpdateUIAndRefreshEntriesList(false, null, false, null, false, null, bSetModified); + UpdateUI(false, null, false, null, false, null, bSetModified); } - public static void UpdateUIAndRefreshEntriesList(bool bRecreateTabBar, KeePass.UI.PwDocument dsSelect, + public static void UpdateUI(bool bRecreateTabBar, KeePass.UI.PwDocument dsSelect, bool bUpdateGroupList, KeePassLib.PwGroup pgSelect, bool bUpdateEntryList, KeePassLib.PwGroup pgEntrySource, bool bSetModified) { diff --git a/version.info b/version.info index 7975e35..9366f28 100644 --- a/version.info +++ b/version.info @@ -1,5 +1,5 @@ : -KeePassOTP:0.21 +KeePassOTP:0.22 KeePassOTP!de:11 KeePassOTP!fr:3 :