Beispiel #1
0
        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 { }
        }
Beispiel #3
0
        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;
        }
Beispiel #4
0
 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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        /// 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));
        }
Beispiel #8
0
        /// 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());
            }
                                                         );
        }
Beispiel #9
0
        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);
            }
        }
Beispiel #10
0
            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()); }
            }
Beispiel #11
0
        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);
        }
Beispiel #12
0
 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);
     }
 }
Beispiel #13
0
        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));
            }
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
 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;
     }
 }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
 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);
         }
         ;
     }
                                           );
 }
Beispiel #19
0
        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;
            }
        }
Beispiel #20
0
        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();
        }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        /// <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);
        }
Beispiel #24
0
        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);
        }
Beispiel #25
0
        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 { };
        }
Beispiel #26
0
        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);
        }
Beispiel #27
0
        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; }
 }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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 { }
        }