/// <summary> /// Called everytime a database is opened. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void FileOpenedHandler(object sender, FileOpenedEventArgs e) { var ioInfo = e.Database.IOConnectionInfo; if (e.Database.CustomData.Get(ProductName) == null) // If there is no CustomData in this database { // Create CustomData to save global setting to enable or disable the plugin e.Database.CustomData.Set(ProductName, "true"); e.Database.Modified = true; // Try to save the database try { e.Database.Save(null); } catch { } } // Global settings to be used in the Options Panel dbName = Library.CharChange(ioInfo.Path); database = e.Database; UWPLibrary.ck = database.MasterKey; if (e.Database.CustomData.Get(ProductName + "AT") == "true") { LockAfterAutoType = true; } else { LockAfterAutoType = false; } if (e.Database.CustomData.Get(ProductName) == "true") { enablePlugin = true; } if (e.Database.CustomData.Get(ProductName) == "false") // if plugin is disabled for the database { enablePlugin = false; return; // Don't do anything else } if (await UWPLibrary.FirstTime(dbName)) // If the database has no credentials saved { bool isHelloAvailable = await UWPLibrary.IsHelloAvailable(); if (isHelloAvailable) { // Ask the user if he/she wants to configure the plugin bool yesOrNo = MessageService.AskYesNo("Do You want to set " + WinHelloUnlockExt.ProductName + " for " + dbName + " now?", WinHelloUnlockExt.ShortProductName, true); // In case he/she wants, create the credentials if (yesOrNo) { await UWPLibrary.CreateHelloData(dbName); } } } // Set global settings back to default tries = 0; opened = true; }
/// <summary> /// Used to detect if the master key has been changed /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void OnSavedDB(Object sender, FileSavedEventArgs args) { var db = args.Database; var ioInfo = db.IOConnectionInfo; string dbPath = Library.CharChange(ioInfo.Path); if (!await UWPLibrary.FirstTime(dbPath) && await UWPLibrary.IsHelloAvailable() && !Library.CheckMasterKey(ioInfo, UWPLibrary.ck)) { await Library.HandleMasterKeyChange(ioInfo, dbPath, false); } }
/// <summary> /// Creates the data for WinHelloUnlock to work. /// 1. A Key Credential to sign a cryptographic key. /// 2. A Password vault to save the data into /// 3. A Password Credential in which to save the encrypted data (using the signed cryptographic key). /// </summary> /// <param name="dbPath">Database path. This is the identity of the database, if Database is moved or renamed, /// WinHelloUnlock will not work and new data needs to be created. /// </param> /// <returns>True if all the data was saved successfully.</returns> internal static async Task <bool> CreateHelloData(string dbPath) { bool isHelloAvailable = await UWPLibrary.IsHelloAvailable(); if (isHelloAvailable) { KeyCredentialCreationOption optionNew = KeyCredentialCreationOption.ReplaceExisting; KeyCredentialRetrievalResult retrievalResult = await UWPLibrary.CreateCredential(dbPath, optionNew); if (retrievalResult.Status == KeyCredentialStatus.Success) { KeyList keyList = Library.GetKeys(WinHelloUnlockExt.database); string resultSave = await UWPLibrary.SaveKeys(dbPath, keyList, retrievalResult); if (resultSave == "Success") { MessageService.ShowInfo("Database Keys saved successfuly"); UWPLibrary.ck = KeePass.Program.MainForm.ActiveDatabase.MasterKey; return(true); } else { if (resultSave.Substring(0, 20) == "Value cannot be null") { MessageService.ShowWarning("Error saving the composite key: MasterKey was null." + " Verify that \"Remember master password (in encrypted form) of a database while it is open\" option under Tools/Options/Security" + " is enabled, then lock and unlock the database."); } else { MessageService.ShowWarning("Error saving the composite key: " + resultSave); } } } else { WinHelloErrors(retrievalResult.Status, "Error creating the credential: "); } } else { MessageService.ShowWarning("Windows Hello is NOT Available"); } return(false); }
/// <summary> /// Creates the data for WinHelloUnlock to work. /// 1. A Key Credential to sign a cryptographic key. /// 2. A Password vault to save the data into /// 3. A Password Credential in which to save the encrypted data (using the signed cryptographic key). /// </summary> /// <param name="dbPath">Database path. This is the identity of the database, if Database is moved or renamed, /// WinHelloUnlock will not work and new data needs to be created. /// </param> /// <returns>True if all the data was saved successfully.</returns> internal static async Task <bool> CreateHelloData(string dbPath) { bool isHelloAvailable = await UWPLibrary.IsHelloAvailable(); if (isHelloAvailable) { KeyCredentialCreationOption optionNew = KeyCredentialCreationOption.ReplaceExisting; KeyCredentialRetrievalResult retrievalResult = await UWPLibrary.CreateCredential(dbPath, optionNew); if (retrievalResult.Status == KeyCredentialStatus.Success) { KeyList keyList = Library.GetKeys(WinHelloUnlockExt.database); string resultSave = await UWPLibrary.SaveKeys(dbPath, keyList, retrievalResult); if (resultSave == "Success") { MessageService.ShowInfo("Database Keys saved successfuly"); UWPLibrary.ck = KeePass.Program.MainForm.ActiveDatabase.MasterKey; return(true); } else { MessageService.ShowWarning("Error saving the composite key: " + resultSave); } } else { WinHelloErrors(retrievalResult.Status, "Error creating the credential: "); } } else { MessageService.ShowWarning("Windows Hello is NOT Available"); } return(false); }
/// <summary> /// Used to modify other form when they load. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void WindowAddedHandler(object sender, GwmWindowEventArgs e) { // If a database is attempted to be unlocked if (e.Form is KeyPromptForm keyPromptForm) { keyPromptForm.Opacity = 0; keyPromptForm.Visible = false; var mf = KeePass.Program.MainForm; isAutoTyping = (bool)mf.GetType().GetField("m_bIsAutoTyping", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mf); var fieldInfo = keyPromptForm.GetType().GetField("m_ioInfo", BindingFlags.Instance | BindingFlags.NonPublic); var ioInfo = fieldInfo.GetValue(keyPromptForm) as IOConnectionInfo; string dbName = Library.CharChange(ioInfo.Path); bool isHelloAvailable = await UWPLibrary.IsHelloAvailable(); // if the database has credentials saved and Windows Hello is available if (!await UWPLibrary.FirstTime(dbName) && isHelloAvailable) { // If there is no other Windows Hello Prompt opened if (opened) { opened = false; Library.UnlockDatabase(ioInfo, keyPromptForm); } else // If there is another Windows Hello Prompt opened, just close this regular prompt // This is usefull for when there is a double attempt to unlock the database by some plugins (ChromeIPass) { Library.CloseFormWithResult(keyPromptForm, DialogResult.Cancel); } } else if (!await UWPLibrary.FirstTime(dbName)) { MessageService.ShowInfo("This Database has credential data saved. Enable Windows Hello to use."); keyPromptForm.Opacity = 1; keyPromptForm.Visible = true; } else { keyPromptForm.Opacity = 1; keyPromptForm.Visible = true; } } // If the Options window is opened if (e.Form is OptionsForm optionsForm) { if (!host.MainWindow.ActiveDatabase.IsOpen) { return; // If there is no database opened, don't do anything } optionsForm.Shown += (object sender2, EventArgs e2) => { try { Library.AddWinHelloOptions(optionsForm); } catch (Exception ex) { MessageService.ShowWarning("WinHelloUnlock Error: " + ex.Message); } }; } // If the Update Check Window is opened. // This is used because the Update Check Window prevents the a database from being opened if (e.Form is UpdateCheckForm ucf && !opened) { WinHelloUnlockExt.updateCheckForm = ucf; } }