private void bCreateOpen_Click(object sender, EventArgs e) { cbUseDBForSeeds.Checked = true; PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; RefreshHandler(db); if (!m_handler.OTPDB_Exists) { m_handler.OTPDB_Create(); if (m_handler.OTPDB_Exists) { bDBSettings_Click(sender, e); } } else if (!m_handler.OTPDB_Opened) { m_handler.SetDB(db, true); } if (m_handler.OTPDB_Opened) { cbUseDBForSeeds.Checked = true; Config.UseDBForOTPSeeds(db, true); OTPDAO.GetOTPHandler(db); OTPDAO.InitEntries(db); } lbDB_SelectedIndexChanged(sender, e); }
private void RefreshHandler(PwDatabase db) { Config.UseDBForOTPSeeds(db, cbUseDBForSeeds.Checked); Config.PreloadOTPDB(db, cbPreloadOTP.Checked); m_handler = OTPDAO.GetOTPHandler(db) as OTPDAO.OTPHandler_DB; if (m_handler == null) { m_handler = new OTPDAO.OTPHandler_DB(); m_handler.SetDB(db, false); } }
private void bMigrate_Click(object sender, EventArgs e) { PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; bool bToKeePassOTP = cbMigrate.SelectedItem.ToString().EndsWith("KeePassOTP"); string sPlugin = PluginTranslate.PluginName; MigrationBase mBase = null; string sel = cbMigrate.SelectedItem.ToString(); foreach (KeyValuePair <string, MigrationBase> kvp in m_dMigration) { if (sel.Contains(kvp.Key)) { mBase = kvp.Value; if (bToKeePassOTP) { sPlugin = kvp.Key; } break; } } if (mBase == null) { return; } bool bRemove = Tools.AskYesNo(string.Format(PluginTranslate.MigrateOtherPlugins_Delete, sPlugin)) == DialogResult.Yes; int EntriesOverall; int EntriesMigrated; mBase.SetDB(db); if (bToKeePassOTP) { mBase.MigrateToKeePassOTP(bRemove, out EntriesOverall, out EntriesMigrated); } else { mBase.MigrateFromKeePassOTP(bRemove, out EntriesOverall, out EntriesMigrated); } if ((EntriesMigrated != -1) && (EntriesOverall != -1)) { OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(db) as OTPDAO.OTPHandler_DB; if (h != null) { h.OTPDB_SaveAfterMigration(); } Tools.ShowInfo(string.Format(PluginTranslate.MigrateOtherPlugins_Result, EntriesMigrated, EntriesOverall)); } }
private void bCreateOpen_Click(object sender, EventArgs e) { cbUseDBForSeeds.Checked = true; PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; RefreshHandler(db); DBAction dba = cbDBAction.SelectedItem as DBAction; if (dba == null) { return; } if ((dba.Action == ACTION_CREATE) || !m_handler.OTPDB_Exists) { m_handler.OTPDB_Create(); if (m_handler.OTPDB_Exists) { bDBSettings_Click(sender, e); } } else if (dba.Action == ACTION_OPEN) { m_handler.SetDB(db, true); } else if (dba.Action == ACTION_CLOSE) { m_handler.OTPDB_Close(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.GetOTPHandler(db); OTPDAO.InitEntries(db); KeePassOTPColumnProvider.ForceUpdate = true; } else if (dba.Action == ACTION_DELETE) { m_handler.OTPDB_Remove(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.InitEntries(db); KeePassOTPColumnProvider.ForceUpdate = true; } if (m_handler.OTPDB_Opened) { cbUseDBForSeeds.Checked = true; Config.UseDBForOTPSeeds(db, true); OTPDAO.GetOTPHandler(db); OTPDAO.InitEntries(db); } lbDB_SelectedIndexChanged(sender, e); }
private void cbUseDBForSeeds_CheckedChanged(object sender, EventArgs e) { PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; if (!cbUseDBForSeeds.Checked) { OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(db); if ((h != null) && h.OTPDB_Exists) { DialogResult dr = DialogResult.None; if (!h.HasEntries()) { dr = DialogResult.Yes; } else { dr = MessageBox.Show(string.Format(PluginTranslate.ConfirmOTPDBDelete, DialogResult.Yes.ToString(), DialogResult.No.ToString()), PluginTranslate.PluginName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } if (dr == DialogResult.Cancel) { cbUseDBForSeeds.CheckedChanged -= cbUseDBForSeeds_CheckedChanged; cbUseDBForSeeds.Checked = true; cbUseDBForSeeds.CheckedChanged += cbUseDBForSeeds_CheckedChanged; return; } if (dr == DialogResult.Yes) { h.OTPDB_Remove(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.InitEntries(db); } else if (dr == DialogResult.No) { h.OTPDB_Close(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.InitEntries(db); } } } m_dDB[db].UseOTPDB = cbUseDBForSeeds.Checked; cbPreloadOTP.Enabled = cbUseDBForSeeds.Checked; DBAction_Init(db); }
public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; List <PwEntry> lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists("TOTP Seed")).ToList(); EntriesOverall = lEntries.Count; if (lEntries.Count == 0) { return; } if (!OTPDAO.EnsureOTPSetupPossible(lEntries[0])) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries[0]); InitLogger("KeeTrayTOTP -> KeePassOTP", lEntries.Count); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); string seed = pe.Strings.ReadSafe("TOTP Seed"); string settings = pe.Strings.ReadSafe("TOTP Settings"); if (string.IsNullOrEmpty(settings)) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: not defined"); continue; } var parameters = settings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (parameters.Count() < 2) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + settings); continue; } var otp = OTPDAO.GetOTP(pe); otp.OTPSeed = new ProtectedString(true, MigrateString(seed)); otp.TOTPTimestep = MigrateInt(parameters[0], 30); int l = MigrateInt(parameters[1], -1); if (l == -1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + settings); continue; } otp.Length = l; if ((parameters.Count() > 2) && !string.IsNullOrEmpty(parameters[2])) { otp.TimeCorrectionUrl = parameters[2]; } if (otp.Valid) { EntriesMigrated++; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } if (bRemove) { pe.Strings.Remove("TOTP Seed"); pe.Strings.Remove("TOTP Settings"); } } else { string s = string.Empty; for (int i = 0; i < parameters.Count(); i++) { if (parameters[i].ToLowerInvariant().StartsWith("key=")) { s += "key=<secret>"; } else { s += parameters[i]; } if (i < parameters.Count() - 1) { s += "&"; } } PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + s); } } } finally { EndLogger(); } MigratePlaceholder(OtherPluginPlaceholder, Config.Placeholder, false); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeTrayTOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Encoding != KPOTPEncoding.BASE32) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Encoding not supported: " + otp.Encoding.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } if (otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } string settings = otp.TOTPTimestep.ToString() + ";" + otp.Length.ToString(); if (otp.TimeCorrectionUrlOwn) { settings += ";" + pe.Strings.ReadSafe(PwDefs.UrlField); } else if (!string.IsNullOrEmpty(otp.TimeCorrectionUrl)) { settings += ";" + otp.TimeCorrectionUrl; } pe.Strings.Set("TOTP Seed", otp.OTPSeed); pe.Strings.Set("TOTP Settings", new ProtectedString(false, settings)); EntriesMigrated++; if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Encoding != KPOTPEncoding.BASE32) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Encoding not supported: " + otp.Encoding.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } if (otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } string s = "key=" + otp.OTPSeed.ReadString(); if (otp.Length != 6) { s += "&size=" + otp.Length.ToString(); } if (otp.Type == KPOTPType.HOTP) { s += "&type=hotp"; if (otp.HOTPCounter > 0) { s += "&counter=" + otp.HOTPCounter.ToString(); } } if ((otp.Type == KPOTPType.TOTP) && (otp.TOTPTimestep != 30)) { s += "&step=" + otp.TOTPTimestep.ToString(); } pe.Strings.Set("otp", new ProtectedString(true, s)); if (pe.Strings.Exists("otp")) { EntriesMigrated++; } if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); }
public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; List <PwEntry> lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists("otp")).ToList(); EntriesOverall = lEntries.Count; if (lEntries.Count == 0) { return; } if (!OTPDAO.EnsureOTPSetupPossible(lEntries[0])) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries[0]); InitLogger("KeeOTP -> KeePassOTP", lEntries.Count); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); string old = pe.Strings.ReadSafe("otp"); if (string.IsNullOrEmpty(old)) { continue; } var parameters = old.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); var otp = OTPDAO.GetOTP(pe); foreach (var parameter in parameters) { var kvp = parameter.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries); if (kvp.Length != 2) { continue; } switch (kvp[0].ToLowerInvariant()) { case "key": otp.OTPSeed = new ProtectedString(true, MigrateString(kvp[1])); break; case "type": otp.Type = kvp[1].ToLower() != "hotp" ? KPOTPType.TOTP : KPOTPType.HOTP; break; case "step": otp.TOTPTimestep = MigrateInt(kvp[1], 30); break; case "counter": otp.HOTPCounter = MigrateInt(kvp[1], 0); break; case "size": otp.Length = MigrateInt(kvp[1], 6); break; default: break; } } if (otp.Valid) { EntriesMigrated++; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } pe.Touch(true); //Only remove setting if we migrated to OTP-DB //Do not remove if KeePassOTP stores OTP data within the entry if (bRemove && Config.UseDBForOTPSeeds(pe.GetDB())) { pe.Strings.Remove("otp"); } } else { string s = string.Empty; for (int i = 0; i < parameters.Count(); i++) { if (parameters[i].ToLowerInvariant().StartsWith("key=")) { s += "key=<secret>"; } else { s += parameters[i]; } if (i < parameters.Count() - 1) { s += "&"; } } PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + s); } } } finally { EndLogger(); } MigratePlaceholder(OtherPluginPlaceholder, Config.Placeholder, false); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeTrayTOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Type != KPOTPType.HOTP && otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } if (otp.Type == KPOTPType.TOTP) { if (Tools.KeePassVersion < m_vKeePass247) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString(), "Minimum required KeePass version: " + m_vKeePass247.ToString()); } foreach (var line in m_dTotpStrings) { if (line.Key == otp.Encoding) { pe.Strings.Set(line.Value, otp.OTPSeed); } else { pe.Strings.Remove(line.Value); } } if (otp.TOTPTimestep == 30) { pe.Strings.Remove(TOTPPERIOD); } else { pe.Strings.Set(TOTPPERIOD, new ProtectedString(false, otp.TOTPTimestep.ToString())); } if (otp.Length == 6) { pe.Strings.Remove(TOTPLENGTH); } else { pe.Strings.Set(TOTPLENGTH, new ProtectedString(false, otp.Length.ToString())); } if (otp.Hash == KPOTPHash.SHA1) { pe.Strings.Remove(TOTPHASH); } else if (otp.Hash == KPOTPHash.SHA256) { pe.Strings.Set(TOTPHASH, new ProtectedString(false, "HMAC-SHA-256")); } else if (otp.Hash == KPOTPHash.SHA512) { pe.Strings.Set(TOTPHASH, new ProtectedString(false, "HMAC-SHA-512")); } bool bDummy; MigratePlaceholder(Config.Placeholder, PLACEHOLDER_TOTP, pe, out bDummy); } else if (otp.Type == KPOTPType.HOTP) { if (otp.Length != 6) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Length not supported: " + otp.Length.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } foreach (var line in m_dHotpStrings) { if (line.Key == otp.Encoding) { pe.Strings.Set(line.Value, otp.OTPSeed); } else { pe.Strings.Remove(line.Value); } } pe.Strings.Set(HOTP_COUNTER, new ProtectedString(false, otp.HOTPCounter.ToString())); bool bDummy; MigratePlaceholder(Config.Placeholder, PLACEHOLDER_HOTP, pe, out bDummy); } EntriesMigrated++; if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, PLACEHOLDER_TOTP); //In case something is defined on group level (could be right, could be wrong, ...) }
private void MigrateToKeePassOTP_Totp(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = 0; Dictionary <PwEntry, KPOTPEncoding> dEntries = new Dictionary <PwEntry, KPOTPEncoding>(); foreach (KeyValuePair <KPOTPEncoding, string> kvp in m_dTotpStrings) { List <PwEntry> lHelp = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(kvp.Value)).ToList(); foreach (PwEntry pe in lHelp) { if (!dEntries.ContainsKey(pe)) { dEntries[pe] = kvp.Key; } } } EntriesOverall = dEntries.Count; if (dEntries.Count == 0) { return; } if (!OTPDAO.EnsureOTPSetupPossible(dEntries.Keys.First())) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(dEntries.Keys.First()); InitLogger("KeePass -> KeePassOTP (TOTP)", dEntries.Count); try { foreach (KeyValuePair <PwEntry, KPOTPEncoding> kvp in dEntries) { IncreaseLogger(); KPOTPEncoding enc = kvp.Value; PwEntry pe = kvp.Key; var otp = OTPDAO.GetOTP(pe); otp.Encoding = enc; otp.OTPSeed = new ProtectedString(true, MigrateString(pe.Strings.ReadSafe(m_dTotpStrings[enc]))); string hash = pe.Strings.ReadSafe(TOTPHASH).ToLowerInvariant(); if (hash.Contains("sha-512")) { otp.Hash = KPOTPHash.SHA512; } else if (hash.Contains("sha-256")) { otp.Hash = KPOTPHash.SHA256; } else { otp.Hash = KPOTPHash.SHA1; } otp.Length = MigrateInt(pe.Strings.ReadSafe(TOTPLENGTH), 6); otp.TOTPTimestep = MigrateInt(pe.Strings.ReadSafe(TOTPPERIOD), 30); otp.HOTPCounter = MigrateInt(pe.Strings.ReadSafe(HOTP_COUNTER), 0); if (otp.Valid) { EntriesMigrated++; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } if (bRemove) { pe.Strings.Remove(m_dTotpStrings[enc]); pe.Strings.Remove(TOTPHASH); pe.Strings.Remove(TOTPLENGTH); pe.Strings.Remove(TOTPPERIOD); } } else { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + m_dHotpStrings[enc]); } } } finally { EndLogger(); } MigratePlaceholder(PLACEHOLDER_TOTP, Config.Placeholder); }
private void MigrateToKeePassOTP_Hotp(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = 0; List <PwEntry> lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(HOTP_COUNTER)).ToList(); EntriesOverall = lEntries.Count; if (lEntries.Count == 0) { return; } if (!OTPDAO.EnsureOTPSetupPossible(lEntries[0])) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries[0]); InitLogger("KeePass -> KeePassOTP (HOTP)", lEntries.Count); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTPEncoding enc = KPOTPEncoding.BASE32; bool bFound = false; string seed = null; foreach (KeyValuePair <KPOTPEncoding, string> kvp in m_dHotpStrings) { if (pe.Strings.Exists(kvp.Value)) { enc = kvp.Key; seed = pe.Strings.ReadSafe(kvp.Value); bFound = true; break; } } if (!bFound) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: not defined"); continue; } var otp = OTPDAO.GetOTP(pe); otp.Type = KPOTPType.HOTP; otp.Encoding = enc; otp.OTPSeed = new ProtectedString(true, MigrateString(seed)); otp.HOTPCounter = MigrateInt(pe.Strings.ReadSafe(HOTP_COUNTER), 0); if (otp.Valid) { EntriesMigrated++; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } if (bRemove) { pe.Strings.Remove(m_dHotpStrings[enc]); pe.Strings.Remove(HOTP_COUNTER); } } else { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "OTP data: " + m_dHotpStrings[enc]); } } } finally { EndLogger(); } MigratePlaceholder(PLACEHOLDER_HOTP, Config.Placeholder); }