private static int SanitizeSeeds(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } int i = 0; foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true)) { KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } otp.OTPSeed = otp.OTPSeed; if (otp.SanitizeChanged) { i++; pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); } } return(i); }
public override void PerformCellAction(string strColumnName, PwEntry pe) { //Copy OTP to clipboard if (strColumnName == null) { return; } if (KeePassOTPExt.CopyOTP(pe) || OTPDAO.OTPDefined(pe) != OTPDAO.OTPDefinition.None) { return; } //Show 2FA setup instructions if available if (!Config.CheckTFA) { return; } string url = pe.Strings.ReadSafe(PwDefs.UrlField); string target = TFASites.GetTFAUrl(url); PluginDebug.AddInfo("Show 2FA instructions", 0, "URL: " + target); try { System.Diagnostics.Process.Start(target); } catch { } }
public override void Terminate() { if (m_host == null) { return; } PTHotKeyManager.HotKeyPressed -= PTHotKeyManager_HotKeyPressed; OTPDAO.Cleanup(); m_host.MainWindow.FileOpened -= MainWindow_FileOpened; SprEngine.FilterCompile -= SprEngine_FilterCompile; SprEngine.FilterPlaceholderHints.Remove(Config.Placeholder); m_columnOTP.StopTimer(); m_host.ColumnProviderPool.Remove(m_columnOTP); Config.Cleanup(); RemoveTray(); RemoveMenu(); PluginDebug.SaveOrShow(); m_host = null; }
private void SprEngine_FilterCompile(object sender, SprEventArgs e) { if ((e.Context.Flags & SprCompileFlags.ExtActive) != SprCompileFlags.ExtActive) { return; } if (e.Text.IndexOf(Config.Placeholder, StringComparison.InvariantCultureIgnoreCase) >= 0) { OTPDAO.EnsureOTPUsagePossible(e.Context.Entry); KPOTP myOTP = OTPDAO.GetOTP(e.Context.Entry); if (!myOTP.Valid) { PluginDebug.AddError("Auto-Type OTP failed", 0, "Uuid: " + e.Context.Entry.Uuid.ToHexString()); } else { PluginDebug.AddInfo("Auto-Type OTP success", 0, "Uuid: " + e.Context.Entry.Uuid.ToHexString()); } e.Text = StrUtil.ReplaceCaseInsensitive(e.Text, Config.Placeholder, myOTP.GetOTP(false, true)); if (myOTP.Valid && (myOTP.Type == KPOTPType.HOTP)) { var newOTP = myOTP.Clone(); newOTP.HOTPCounter++; OTPDAO.SaveOTP(newOTP, e.Context.Entry); } } }
internal static void UseDBForOTPSeeds(this PwDatabase db, bool value) { if (db == null) { return; } bool bUse = true; //default if (db.CustomData.Exists(DBUsage)) { bUse = StrUtil.StringToBool(db.CustomData.Get(DBUsage)); } //Explicitly set value, even if it's the default value db.CustomData.Set(DBUsage, StrUtil.BoolToString(value)); if (bUse == value) { return; } db.Modified = true; db.SettingsChanged = DateTime.UtcNow; Program.MainForm.UpdateUI(false, null, false, null, false, null, Program.MainForm.ActiveDatabase == db); OTPDAO.InitEntries(db); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); }
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); }
/// Calculate time offset for all relevant entries /// Do NOT use Task.Run as this requires .NET 4.5 which will cause issues on Mono /// Mono reports .NET 4.0.3 being installed despite higher versions can be used /// This results in KeePass refusing to compile the plgx public static /*async*/ void GetTimingsAsync(KeePassLib.PwDatabase db) { //Don't use TraverseTree as db content might change during processing //and this will result in an exception since TraverseTree uses 'foreach' //Don't use Task at all (https://github.com/Rookiestyle/KeePassOTP/issues/31) KeePassLib.Delegates.GAction <object> act = new KeePassLib.Delegates.GAction <object>((object o) => { DateTime dtStart = DateTime.Now; IEnumerable <string> lURL = db.RootGroup.GetEntries(true). Where(e => OTPDAO.OTPDefined(e) != OTPDAO.OTPDefinition.None). //We're not interested in sites without OTP being set up Select(e => e.Strings.ReadSafe(KeePassLib.PwDefs.UrlField)).Distinct(); //We're not interested in duplicate URLs foreach (string url in lURL) { if (m_timeCorrectionUrls.ContainsKey(url)) { continue; } GetTimeCorrection(url); System.Threading.Thread.Sleep(100); } ; DateTime dtEnd = DateTime.Now; PluginDebug.AddInfo("Calculated OTP time corrections", 0, "Start: " + dtStart.ToLongTimeString(), "End: " + dtEnd.ToLongTimeString()); }); System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(act)); }
/// Calculate time offset for all relevant entries /// Do NOT use Task.Run as this requires .NET 4.5 which will cause issues on Mono /// Mono reports .NET 4.0.3 being installed despite higher versions can be used /// This results in KeePass refusing to compile the plgx public static /*async*/ void GetTimingsAsync(KeePassLib.PwDatabase db) { //Don't use TraverseTree as db content might change during processing //and this will result in an exception since TraverseTree uses 'foreach' //await - Don't use, see comment above method definition System.Threading.Tasks.Task.Factory.StartNew(() => //System.Threading.Tasks.Task.Run(() => { DateTime dtStart = DateTime.Now; IEnumerable <string> lURL = db.RootGroup.GetEntries(true). Where(e => OTPDAO.OTPDefined(e) != OTPDAO.OTPDefinition.None). //We're not interested in sites without OTP being set up Select(e => e.Strings.ReadSafe(KeePassLib.PwDefs.UrlField)).Distinct(); //We're not interested in duplicate URLs foreach (string url in lURL) { if (m_timeCorrectionUrls.ContainsKey(url)) { continue; } GetTimeCorrection(url); System.Threading.Thread.Sleep(100); } ; DateTime dtEnd = DateTime.Now; PluginDebug.AddInfo("Calculated OTP time corrections", 0, "Start: " + dtStart.ToLongTimeString(), "End: " + dtEnd.ToLongTimeString()); } ); }
public override string GetCellData(string strColumnName, PwEntry pe) { if (strColumnName == null) { return(string.Empty); } if (pe == null) { return(string.Empty); } Random r = new Random(); string otp = string.Empty; bool bForUsage = new System.Diagnostics.StackTrace().GetFrames().FirstOrDefault(x => x.GetMethod().Name == "OnPwListItemDrag") != null; if (bForUsage) { otp = OTPDAO.GetOTP(pe).GetOTP(); } else { otp = OTPDAO.GetReadableOTP(pe); } if (!string.IsNullOrEmpty(otp)) { if (bForUsage || strColumnName == OTPColumn_Verbose) { return(otp); } return(PluginTranslation.PluginTranslate.TFADefined); } if (!Config.CheckTFA) { return(string.Empty); } string url = pe.Strings.ReadSafe(PwDefs.UrlField); if (string.IsNullOrEmpty(url)) { return(string.Empty); } TFASites.TFAPossible TFAPossible = TFASites.IsTFAPossible(url); if (TFAPossible == TFASites.TFAPossible.Yes) { return(PluginTranslation.PluginTranslate.SetupTFA); } else if (TFAPossible == TFASites.TFAPossible.Unknown) { return("Checking 2FA"); } else { return(string.Empty); } }
private PwDatabase OTPDB_Load() { List <string> lMsg = new List <string>(); try { OTPDB_Init(true); KeySources_Clear(); byte[] bOTPDB = GetOTPDBData(); // ConvertFromCustomData(DB.CustomData.Get(DBNAME)); if (bOTPDB == null) { return(null); } AceKeyAssoc aka_old = null; for (int i = 0; i < Program.Config.Security.MasterKeyTries; i++) { bool bCancel = false; if (Program.Config.Defaults.RememberKeySources && (i == 0)) { aka_old = KeySources_Load(); } CompositeKey ck = OTPDB_RequestPassword(false, out bCancel); if (bCancel) { lMsg.Add("Masterkey input cancelled by user"); break; } OTPDB.MasterKey = ck; try { OTPDB_Synchronize(OTPDB, m_FFP, bOTPDB, PluginTranslate.OTPDB_Opening); lMsg.Add("Masterkey valid, attempt: " + (i + 1).ToString()); Program.Config.Defaults.SetKeySources(EmptyIOC, OTPDB.MasterKey); AceKeyAssoc aka_new = Program.Config.Defaults.GetKeySources(EmptyIOC); KeySources_Clear(); if (!KeySources_Equal(aka_old, aka_new)) { KeySources_Save(aka_new); } KeySources_Clear(); OTPDAO.InitEntries(DB); UpdateDBHeader(); if (OTPDB_Opened && CheckAndMigrate(DB)) { FlagChanged(false); } return(OTPDB); } catch { lMsg.Add("Masterkey invalid, attempt: " + (i + 1).ToString()); } } KeySources_Clear(); OTPDB_Init(false); return(OTPDB); } finally { PluginDebug.AddInfo("OTP DB - Load", 0, lMsg.ToArray()); } }
public override bool Initialize(IPluginHost host) { Terminate(); if (host == null) { return(false); } m_host = host; PluginTranslate.Init(this, Program.Translation.Properties.Iso6391Code); Tools.DefaultCaption = PluginTranslate.PluginName; Tools.PluginURL = "https://github.com/rookiestyle/keepassotp/"; var t = typeof(Program).Assembly.GetType("KeePass.Native.NativeMethods"); try { m_miSetForegroundWindowEx = t.GetMethod("SetForegroundWindowEx", BindingFlags.Static | BindingFlags.NonPublic); } catch { } if (m_miSetForegroundWindowEx == null) { PluginDebug.AddError("Could not locate method 'SetForegroundEx'", 0); } try { m_miGetForegroundWindowHandle = t.GetMethod("GetForegroundWindowHandle", BindingFlags.Static | BindingFlags.NonPublic); } catch { } if (m_miGetForegroundWindowHandle == null) { PluginDebug.AddError("Could not locate method 'GetForegroundWindowHandle'", 0); } m_miAutoType = m_host.MainWindow.GetType().GetMethod("ExecuteGlobalAutoType", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null); if (m_miSetForegroundWindowEx == null) { PluginDebug.AddError("Could not locate method 'ExecuteGlobalAutoType'", 0); } CreateMenu(); AddTray(); Config.Init(); m_columnOTP = new KeePassOTPColumnProvider(); m_host.ColumnProviderPool.Add(m_columnOTP); m_columnOTP.StartTimer(); SprEngine.FilterCompile += SprEngine_FilterCompile; SprEngine.FilterPlaceholderHints.Add(Config.Placeholder); TFASites.Init(false); OTPDAO.Init(); PTHotKeyManager.HotKeyPressed += PTHotKeyManager_HotKeyPressed; m_host.MainWindow.FileOpened += MainWindow_FileOpened; GlobalWindowManager.WindowAdded += GlobalWindowManager_WindowAdded; return(true); }
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 OnEntryContextMenuOpening(object sender, EventArgs e) { m_ContextMenuCopy.ShortcutKeys = m_MainMenuCopy.ShortcutKeys = Config.Hotkey; if (m_host.MainWindow.GetSelectedEntriesCount() != 1) { m_ContextMenu.Enabled = m_ContextMenuAutotype.Enabled = false; m_MainMenu.Enabled = m_MainMenuAutotype.Enabled = false; } else { KPOTP myOTP = OTPDAO.GetOTP(m_host.MainWindow.GetSelectedEntry(true)); m_ContextMenu.Enabled = m_MainMenu.Enabled = true; m_ContextMenuCopy.Enabled = m_ContextMenuAutotype.Enabled = m_ContextMenuQRCode.Enabled = myOTP.Valid; m_MainMenuCopy.Enabled = m_MainMenuAutotype.Enabled = m_MainMenuQRCode.Enabled = myOTP.Valid; } }
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); }
private static int ProcessReferences(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } if (otpdb == null || !otpdb.IsOpen) { return(-1); } int i = 0; var b = new OTPHandler_Base(); foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true)) { KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } if (!otp.Issuer.ToLowerInvariant().Contains("{ref:") && !otp.Label.ToLowerInvariant().EndsWith("{ref")) { continue; } PwEntry peMain = h is OTPHandler_DB ? (h as OTPHandler_DB).GetMainPwEntry(pe) : pe; b.InitIssuerLabel(otp, peMain); pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); i++; } return(i); }
public static async void GetTimingsAsync(KeePassLib.PwDatabase db) { //Don't use TraverseTree as db content might change during processing //and this will result in an exception since TraverseTree uses 'foreach' await System.Threading.Tasks.Task.Run(() => { IEnumerable <string> lURL = db.RootGroup.GetEntries(true). Where(e => OTPDAO.OTPDefined(e) != OTPDAO.OTPDefinition.None). //We're not interested in sites without OTP being set up Select(e => e.Strings.ReadSafe(KeePassLib.PwDefs.UrlField)).Distinct(); //We're not interested in duplicate URLs foreach (string url in lURL) { if (m_timeCorrectionUrls.ContainsKey(url)) { continue; } GetTimeCorrection(url); System.Threading.Thread.Sleep(100); } ; } ); }
private void GlobalWindowManager_WindowAdded(object sender, GwmWindowEventArgs e) { if (!m_bOTPHotkeyPressed) { return; } if (!(e.Form is AutoTypeCtxForm)) { return; } PluginDebug.AddInfo("Auto-Type entry selection window added", 0); List <AutoTypeCtx> lCtx = (List <AutoTypeCtx>)Tools.GetField("m_lCtxs", e.Form); if (lCtx == null) { return; } //Adjust sequence to show correct auto-type sequence //Remove lines that don't have KPOTP defined int PrevCount = lCtx.Count; lCtx.RemoveAll(x => OTPDAO.OTPDefined(x.Entry) == OTPDAO.OTPDefinition.None); PluginDebug.AddInfo("Removed sequences without valid OTP settings", 0, "Before: " + PrevCount.ToString(), "After: " + lCtx.Count.ToString()); //If now 0 or 1 entries remain, we need to hook the Shown event //simply to close it //We do not want to display an entry selection form with less then 2 entries if (lCtx.Count < 2) { e.Form.Shown += OnAutoTypeFormShown; } }
private void OnOTPSetup(object sender, EventArgs e) { if (m_host.MainWindow.GetSelectedEntriesCount() != 1) { return; } PwEntry pe = m_host.MainWindow.GetSelectedEntry(true); if (!OTPDAO.EnsureOTPSetupPossible(pe)) { return; } var otpSetup = new KeePassOTPSetup(); Tools.GlobalWindowManager(otpSetup); otpSetup.OTP = OTPDAO.GetOTP(pe); otpSetup.EntryUrl = pe.Strings.GetSafe(PwDefs.UrlField).ReadString(); otpSetup.InitEx(); if (otpSetup.ShowDialog(m_host.MainWindow) == DialogResult.OK) { OTPDAO.SaveOTP(otpSetup.OTP, pe); } otpSetup.Dispose(); }
internal static bool CopyOTP(PwEntry pe) { if (!OTPDAO.EnsureOTPUsagePossible(pe)) { PluginDebug.AddError("Copy OTP failed", 0, "Uuid: " + pe.Uuid.ToHexString(), "OTP db not unlocked"); return(false); } KPOTP myOTP = OTPDAO.GetOTP(pe); if (!myOTP.Valid) { PluginDebug.AddError("Copy OTP failed", 0, "Uuid: " + pe.Uuid.ToHexString()); return(false); } ClipboardUtil.CopyAndMinimize(myOTP.GetOTP(false, true), true, Program.MainForm, pe, Program.MainForm.DocumentManager.SafeFindContainerOf(pe)); Program.MainForm.StartClipboardCountdown(); PluginDebug.AddInfo("Copy OTP success", 0, "Uuid: " + pe.Uuid.ToString()); if (myOTP.Type == KPOTPType.HOTP) { myOTP.HOTPCounter++; OTPDAO.SaveOTP(myOTP, pe); } return(true); }
public static void MigrateToCustomdata(PwDatabase db, PwEntry pe) { bool bPreload = !pe.Strings.Exists(Config.DBPreload) || StrUtil.StringToBool(pe.Strings.ReadSafe(Config.DBPreload)); db.CustomData.Set(Config.DBPreload, StrUtil.BoolToString(bPreload)); bool bUseDB = !pe.Strings.Exists(Config.DBUsage) || StrUtil.StringToBool(pe.Strings.ReadSafe(Config.DBUsage)); db.CustomData.Set(Config.DBUsage, StrUtil.BoolToString(bUseDB)); db.CustomData.Remove(Config.DBKeySources); string k = pe.Strings.ReadSafe("KPOTP.KeySources"); if (!string.IsNullOrEmpty(k)) { db.CustomData.Set(Config.DBKeySources, k); } if (pe.Binaries.Get(OTPDAO.OTPHandler_DB.DBNAME + ".kdbx") != null) { ProtectedBinary pbOTPDB = pe.Binaries.Get(OTPDAO.OTPHandler_DB.DBNAME + ".kdbx"); string otpdb = OTPDAO.OTPHandler_DB.ConvertToCustomData(pbOTPDB.ReadData()); db.CustomData.Set(OTPDAO.OTPHandler_DB.DBNAME, otpdb); } bool bDeleted = false; if (db.RecycleBinEnabled) { PwGroup pgRecycleBin = db.RootGroup.FindGroup(db.RecycleBinUuid, true); if (pgRecycleBin == null) { MethodInfo miEnsureRecycleBin = Program.MainForm.GetType().GetMethod("EnsureRecycleBin", BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); if (miEnsureRecycleBin != null) { object[] p = new object[] { null, db, null }; try { miEnsureRecycleBin.Invoke(null, p); pgRecycleBin = p[0] as PwGroup; } catch { } } } if (pgRecycleBin != null) { pe.ParentGroup.Entries.Remove(pe); pgRecycleBin.AddEntry(pe, true); bDeleted = true; } } else if (!db.RecycleBinEnabled && !bUseDB) { pe.ParentGroup.Entries.Remove(pe); bDeleted = true; } if (!bDeleted) { pe.Strings.Remove(Config.DBPreload); pe.Strings.Remove(Config.DBUsage); pe.Strings.Remove(Config.DBKeySources); pe.Binaries.Remove(OTPDAO.OTPHandler_DB.DBNAME + ".kdbx"); pe.Touch(true); } db.Modified = true; db.SettingsChanged = DateTime.UtcNow; System.Threading.Thread tUpdate = new System.Threading.Thread(UpdateUI); tUpdate.Start(new object[] { bDeleted, db }); OTPDAO.InitEntries(db); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); }
/// <summary> /// Perform all kind of migrations between different KeePassOTP versions /// </summary> /// <param name="db"></param> /// <returns>true if something was migrated, false if nothing was done</returns> private static bool CheckAndMigrate(PwDatabase db, OTP_Migrations omFlags) { const string Migration_EntryDB = "KeePassOTP.MigrationStatus"; const string Migration_OTPDB = "KeePassOTPDB.MigrationStatus"; string sMigrationStatus = string.Empty; bool bMigrated = false; //Get DB to work on OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { sMigrationStatus = Migration_OTPDB; } else { sMigrationStatus = Migration_EntryDB; } OTP_Migrations omStatusOld = OTP_Migrations.None; if (!OTP_Migrations.TryParse(db.CustomData.Get(sMigrationStatus), out omStatusOld)) { omStatusOld = OTP_Migrations.None; } OTP_Migrations omStatusNew = omStatusOld; if (MigrationRequired(OTP_Migrations.Entry2CustomData, omFlags, omStatusOld)) { if (!db.UseDBForOTPSeeds() || !db.CustomData.Exists(OTPDAO.OTPHandler_DB.DBNAME)) { PwEntry pe = OTPHandler_DB.GetOTPDBEntry(db); if (pe != null) { bMigrated = true; OTPDAO.MigrateToCustomdata(db, pe); } } omStatusNew |= OTP_Migrations.Entry2CustomData; } if (MigrationRequired(OTP_Migrations.KeePassOTP2OtpAuth, omFlags, omStatusOld)) { int r = CheckOTPDataMigration(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.KeePassOTP2OtpAuth; } } if (MigrationRequired(OTP_Migrations.SanitizeSeed, omFlags, omStatusOld)) { int r = SanitizeSeeds(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.SanitizeSeed; } } if (MigrationRequired(OTP_Migrations.OTPAuthFormatCorrection, omFlags, omStatusOld)) { int r = OTPAuthFormatCorrection(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.OTPAuthFormatCorrection; } } if ((omStatusNew != omStatusOld) || bMigrated) { db.CustomData.Set(sMigrationStatus, omStatusNew.ToString()); db.SettingsChanged = DateTime.UtcNow; db.Modified = true; Program.MainForm.UpdateUI(false, null, false, null, false, null, Program.MainForm.ActiveDatabase == db); } return(bMigrated); }
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); }
private void OnOTPQRCode(object sender, EventArgs e) { if (m_host.MainWindow.GetSelectedEntriesCount() != 1) { return; } KPOTP otp = OTPDAO.GetOTP(m_host.MainWindow.GetSelectedEntry(true)); if (!otp.Valid) { return; } try { ZXing.BarcodeWriter zBW = new ZXing.BarcodeWriter(); zBW.Options.Height = 320; zBW.Options.Width = 320; zBW.Format = ZXing.BarcodeFormat.QR_CODE; Bitmap bmp = zBW.Write(otp.OTPAuthString.ReadString()); QRForm f = new QRForm(); f.FormBorderStyle = FormBorderStyle.FixedDialog; f.StartPosition = FormStartPosition.CenterParent; f.Text = PluginTranslate.PluginName; f.MinimizeBox = false; f.MaximizeBox = false; PictureBox pb = new PictureBox(); pb.Location = new Point(0, 0); pb.Image = new Bitmap(bmp, bmp.Size); //Assigning bmp directly did not work in my Ubuntu VM... pb.ClientSize = pb.Image.Size; f.ClientSize = pb.Size; f.Controls.Add(pb); if (!string.IsNullOrEmpty(otp.Issuer) && (otp.Issuer != PluginTranslate.PluginName)) { Label lIssuer = new Label(); lIssuer.Width = f.ClientSize.Width; lIssuer.Text = otp.Issuer; lIssuer.Location = new Point(0, f.ClientSize.Height + 10); f.Controls.Add(lIssuer); f.Height += lIssuer.Height + 10; } if (!string.IsNullOrEmpty(otp.Label)) { Label lLabel = new Label(); lLabel.Width = f.ClientSize.Width; lLabel.Text = otp.Label; lLabel.Location = new Point(0, f.ClientSize.Height + 10); f.Controls.Add(lLabel); f.Height += lLabel.Height + 10; } f.Height += 5; Timer tClose = new Timer(); tClose.Interval = 30000; tClose.Tick += (o, e1) => { tClose.Stop(); tClose.Dispose(); if (f != null) { f.Close(); } }; f.Shown += (o, e2) => { KeePass.UI.GlobalWindowManager.AddWindow(f, f); tClose.Start(); }; f.FormClosed += (o, e1) => { if (f != null) { KeePass.UI.GlobalWindowManager.RemoveWindow(f); } }; f.ShowDialog(KeePass.UI.GlobalWindowManager.TopWindow); pb.Image.Dispose(); f.Dispose(); bmp.Dispose(); } catch { }; }
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); }
private void OnTimerTick(object sender, EventArgs e) { if (m_bUpdateInProgress) { return; } m_bUpdateInProgress = true; //Trigger refresh of entry list if at least one relevant entry is shown //Relevant = Entry has OTP settings defined try { if (KeePass.Program.MainForm.UIIsInteractionBlocked()) { return; } if (!KeePass.Program.MainForm.Visible) { return; } if (!KeePass.Program.MainForm.ActiveDatabase.IsOpen) { return; } if (KeePass.Program.Config.MainWindow.EntryListColumns.Find(x => x.CustomName == KPOTPColumnName) == null) { return; } PwGroup pg = KeePass.Program.MainForm.GetSelectedGroup(); if (pg == null) { return; } bool bRefresh = pg.GetEntries(KeePass.Program.Config.MainWindow.ShowEntriesOfSubGroups).FirstOrDefault(x => OTPDAO.OTPDefined(x) == OTPDAO.OTPDefinition.Complete) != null; if (!bRefresh && !ForceUpdate) { return; //Update entry list if OTP DB was closed / deleted } if (ForceUpdate) { ForceUpdate = false; } bool LVPossible = LV_DirectUpdate(); if (!LVPossible) { KeePass.Program.MainForm.RefreshEntriesList(); } } finally { m_bUpdateInProgress = false; } }
private static int OTPAuthFormatCorrection(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } int i = 0; foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(Config.OTPFIELD))) { //Don't compare strings because strings are not protected and will remain in memory char[] ps = pe.Strings.Get(Config.OTPFIELD).ReadChars(); try { if (ps.Length < 15) { continue; } bool bConvert = false; foreach (char[] check in lOTPAuthStart) { if (check.Length > ps.Length) { continue; } bConvert = true; for (int j = 0; j < check.Length; j++) { if (Char.ToLowerInvariant(check[j]) != Char.ToLowerInvariant(ps[j])) { bConvert = false; break; } } if (bConvert) { break; } } if (!bConvert) { break; } KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } i++; pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); } finally { MemUtil.ZeroArray(ps); } } return(i); }
private void OnOTPQRCode(object sender, EventArgs e) { if (m_host.MainWindow.GetSelectedEntriesCount() != 1) { return; } KPOTP otp = OTPDAO.GetOTP(m_host.MainWindow.GetSelectedEntry(true)); if (!otp.Valid) { return; } try { byte[] bOTP = otp.OTPAuthString.ReadUtf8(); QRCoder.QRCodeData qrd = QRCoder.QRCodeGenerator.GenerateQrCode(bOTP, QRCoder.QRCodeGenerator.ECCLevel.Q); MemUtil.ZeroByteArray(bOTP); QRCoder.QRCode qrc = new QRCoder.QRCode(qrd); Bitmap bmp = qrc.GetGraphic(8); QRForm f = new QRForm(); f.FormBorderStyle = FormBorderStyle.FixedDialog; f.StartPosition = FormStartPosition.CenterParent; f.Text = PluginTranslate.PluginName; f.MinimizeBox = false; f.MaximizeBox = false; PictureBox pb = new PictureBox(); pb.Size = new Size(bmp.Width, bmp.Height); pb.Location = new Point(0, 0); f.ClientSize = pb.Size; pb.Image = bmp; f.Controls.Add(pb); if (!string.IsNullOrEmpty(otp.Issuer) && (otp.Issuer != PluginTranslate.PluginName)) { Label lIssuer = new Label(); lIssuer.Width = f.ClientSize.Width; lIssuer.Text = otp.Issuer; lIssuer.Location = new Point(0, f.ClientSize.Height + 10); f.Controls.Add(lIssuer); f.Height += lIssuer.Height + 10; } if (!string.IsNullOrEmpty(otp.Label)) { Label lLabel = new Label(); lLabel.Width = f.ClientSize.Width; lLabel.Text = otp.Label; lLabel.Location = new Point(0, f.ClientSize.Height + 10); f.Controls.Add(lLabel); f.Height += lLabel.Height + 10; } f.Height += 5; Timer tClose = new Timer(); tClose.Interval = 30000; tClose.Tick += (o, e1) => { tClose.Stop(); tClose.Dispose(); if (f != null) { f.Close(); } }; f.Shown += (o, e2) => { KeePass.UI.GlobalWindowManager.AddWindow(f, f); tClose.Start(); }; f.FormClosed += (o, e1) => { if (f != null) { KeePass.UI.GlobalWindowManager.RemoveWindow(f); } }; f.ShowDialog(KeePass.UI.GlobalWindowManager.TopWindow); pb.Image.Dispose(); f.Dispose(); qrc.Dispose(); qrd.Dispose(); } catch { } }