private void setPwEntryFromEntry(PwEntry pwe, Entry login) { bool firstPasswordFound = false; foreach (FormField kpff in login.FormFieldList) { if (kpff.Type == FormFieldType.FFTpassword && !firstPasswordFound) { pwe.Strings.Set("Password", new ProtectedString(host.Database.MemoryProtection.ProtectPassword, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "password")); firstPasswordFound = true; } else if (kpff.Type == FormFieldType.FFTpassword) { pwe.Strings.Set("KPRPC Form field " + kpff.Name + " value", new ProtectedString(host.Database.MemoryProtection.ProtectPassword, kpff.Value)); // we protect this string if user has asked to protect passwords pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "password")); } else if (kpff.Type == FormFieldType.FFTusername) { pwe.Strings.Set("UserName", new ProtectedString(host.Database.MemoryProtection.ProtectUserName, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "username")); } else if (kpff.Type == FormFieldType.FFTtext) { pwe.Strings.Set("KPRPC Form field " + kpff.Name + " value", new ProtectedString(false, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "text")); } else if (kpff.Type == FormFieldType.FFTcheckbox) { pwe.Strings.Set("KPRPC Form field " + kpff.Name + " value", new ProtectedString(false, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "checkbox")); } else if (kpff.Type == FormFieldType.FFTradio) { pwe.Strings.Set("KPRPC Form field " + kpff.Name + " value", new ProtectedString(false, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "radio")); } else if (kpff.Type == FormFieldType.FFTselect) { pwe.Strings.Set("KPRPC Form field " + kpff.Name + " value", new ProtectedString(false, kpff.Value)); pwe.Strings.Set("KPRPC Form field " + kpff.Name + " type", new ProtectedString(false, "select")); } pwe.Strings.Set("KPRPC Form field " + kpff.Name + " page", new ProtectedString(false, kpff.Page.ToString())); if (kpff.Id != null && kpff.Id.Length > 0) pwe.Strings.Set("KPRPC Form field " + kpff.Name + " id", new ProtectedString(false, kpff.Id)); } string altURLs = ""; for (int i = 0; i < login.URLs.Length; i++) { string url = login.URLs[i]; if (i == 0) pwe.Strings.Set("URL", new ProtectedString(host.Database.MemoryProtection.ProtectUrl, url ?? "")); else if (i == 1) altURLs += url; else altURLs += " " + url; } if (altURLs.Length > 0) pwe.Strings.Set("KPRPC Alternative URLs", new ProtectedString(host.Database.MemoryProtection.ProtectUrl, altURLs)); pwe.Strings.Set("Form match URL", new ProtectedString(host.Database.MemoryProtection.ProtectUrl, login.FormActionURL ?? "")); pwe.Strings.Set("KPRPC HTTP realm", new ProtectedString(host.Database.MemoryProtection.ProtectUrl, login.HTTPRealm ?? "")); // Set some of the string fields pwe.Strings.Set(PwDefs.TitleField, new ProtectedString(host.Database.MemoryProtection.ProtectTitle, login.Title ?? "")); // update the icon for this entry (in most cases we'll // just detect that it is the same standard icon as before) PwUuid customIconUUID = PwUuid.Zero; PwIcon iconId = PwIcon.Key; if (login.IconImageData != null && login.IconImageData.Length > 0 && base64ToIcon(login.IconImageData, ref customIconUUID, ref iconId)) { if (customIconUUID == PwUuid.Zero) pwe.IconId = iconId; else pwe.CustomIconUuid = customIconUUID; } }
public Entry[] FindLogins(string[] URLs, string actionURL, string httpRealm, LoginSearchType lst, bool requireFullURLMatches, string uniqueID, string dbFileName, string freeTextSearch) { List<PwDatabase> dbs = null; int count = 0; List<Entry> allEntries = new List<Entry>(); if (!string.IsNullOrEmpty(dbFileName)) { // find the database PwDatabase db = SelectDatabase(dbFileName); dbs = new List<PwDatabase>(); dbs.Add(db); } else // if DB list is not populated, look in all open DBs dbs = host.MainWindow.DocumentManager.GetOpenDatabases(); //string hostname = URLs[0]; string actionHost = actionURL; // Make sure there is an active database if (!ensureDBisOpen()) { return null; } // if uniqueID is supplied, match just that one login. if not found, move on to search the content of the logins... if (uniqueID != null && uniqueID.Length > 0) { PwUuid pwuuid = new PwUuid(KeePassLib.Utility.MemUtil.HexStringToByteArray(uniqueID)); //foreach DB... foreach (PwDatabase db in dbs) { PwEntry matchedLogin = GetRootPwGroup(db).FindEntry(pwuuid, true); if (matchedLogin == null) continue; Entry[] logins = new Entry[1]; logins[0] = (Entry)GetEntryFromPwEntry(matchedLogin, true, true, db); if (logins[0] != null) return logins; } } if (!string.IsNullOrEmpty(freeTextSearch)) { //foreach DB... foreach (PwDatabase db in dbs) { KeePassLib.Collections.PwObjectList<PwEntry> output = new KeePassLib.Collections.PwObjectList<PwEntry>(); PwGroup searchGroup = GetRootPwGroup(db); //output = searchGroup.GetEntries(true); SearchParameters sp = new SearchParameters(); sp.ComparisonMode = StringComparison.InvariantCultureIgnoreCase; sp.SearchString = freeTextSearch; sp.SearchInUserNames = true; sp.SearchInTitles = true; sp.SearchInTags = true; searchGroup.SearchEntries(sp, output, false); foreach (PwEntry pwe in output) { Entry kpe = (Entry)GetEntryFromPwEntry(pwe, true, true, db); allEntries.Add(kpe); count++; } } } // else we search for the URLs if (count == 0 && URLs.Length > 0 && !string.IsNullOrEmpty(URLs[0])) { int protocolIndex = -1; Dictionary<string, string> URLHostnames = new Dictionary<string, string>(); // make sure that hostname and actionURL always represent only the hostname portion // of the URL // It's tempting to demand that the protocol must match too (e.g. http forms won't // match a stored https login) but best not to define such a restriction in KeePassRPC // - the RPC client (e.g. KeeFox) can decide to penalise protocol mismatches, // potentially dependant on user configuration options in the client. for (int i = 0; i < URLs.Length; i++) { string URL = URLs[i]; string newURL = URL; protocolIndex = URL.IndexOf("://"); string hostAndPort = ""; if (URL.IndexOf("file://") > -1) { // the "host and port" of a file is the actual file name (i.e. just not the query string) int qsIndex = URL.IndexOf("?"); if (qsIndex > -1) newURL = URL.Substring(8, qsIndex - 8); else newURL = URL.Substring(8); } else if (protocolIndex > -1) { string URLExcludingProt = URL.Substring(protocolIndex + 3); int pathStart = URLExcludingProt.IndexOf("/", 0); if (pathStart > -1 && URLExcludingProt.Length > pathStart) { hostAndPort = URL.Substring(protocolIndex + 3, pathStart); newURL = URL.Substring(0, pathStart + protocolIndex + 3); } else if (pathStart == -1) // it's already just a hostname { hostAndPort = URLExcludingProt; } } else { // we havn't received a protocol but may still have a query string // we'd like to remove from the URL (e.g. especially if we're dealing with an unknown file:///) int qsIndex = URL.IndexOf("?"); if (qsIndex > -1) newURL = URL.Substring(1, qsIndex - 1); } URLHostnames.Add(URLs[i], hostAndPort); } protocolIndex = (actionURL == null) ? -1 : actionURL.IndexOf("://"); if (protocolIndex > -1) { string actionURLAndPort = actionURL.Substring(protocolIndex + 3); int pathStart = actionURLAndPort.IndexOf("/", 0); if (pathStart > -1 && actionURLAndPort.Length > pathStart) { actionHost = actionURL.Substring(0, pathStart + protocolIndex + 3); } } //foreach DB... foreach (PwDatabase db in dbs) { KeePassLib.Collections.PwObjectList<PwEntry> output = new KeePassLib.Collections.PwObjectList<PwEntry>(); PwGroup searchGroup = GetRootPwGroup(db); output = searchGroup.GetEntries(true); // Search every entry in the DB foreach (PwEntry pwe in output) { if (db.RecycleBinUuid.EqualsValue(pwe.ParentGroup.Uuid)) continue; // ignore if it's in the recycle bin if (pwe.Strings.Exists("Hide from KeeFox") || pwe.Strings.Exists("Hide from KPRPC") || string.IsNullOrEmpty(pwe.Strings.ReadSafe("URL"))) continue; // entries must have a standard URL entry bool allowHostnameOnlyMatch = true; if (pwe.Strings.Exists("KPRPC Block hostname-only match")) { allowHostnameOnlyMatch = false; } bool entryIsAMatch = false; bool entryIsAnExactMatch = false; string regexPatterns = null; if (pwe.Strings.Exists("KeeFox URL Regex match")) regexPatterns = pwe.Strings.ReadSafe("KeeFox URL Regex match"); if (pwe.Strings.Exists("KPRPC URL Regex match")) regexPatterns = pwe.Strings.ReadSafe("KPRPC URL Regex match"); if (!string.IsNullOrEmpty(regexPatterns)) foreach (string URL in URLs) foreach (string regexPattern in regexPatterns.Split(' ')) { if (!string.IsNullOrEmpty(regexPattern) && System.Text.RegularExpressions.Regex.IsMatch(URL, regexPattern)) { entryIsAMatch = true; break; } } foreach (string URL in URLs) { if (!entryIsAMatch && lst != LoginSearchType.LSTnoForms && matchesAnyURL(pwe, URL, URLHostnames[URL], allowHostnameOnlyMatch)) { if (pwe.Strings.Exists("Form match URL") && pwe.Strings.ReadSafe("Form match URL") == actionURL && pwe.Strings.ReadSafe("URL") == URL) { entryIsAnExactMatch = true; entryIsAMatch = true; } else if (!requireFullURLMatches) entryIsAMatch = true; } } foreach (string URL in URLs) { if (!entryIsAMatch && lst != LoginSearchType.LSTnoRealms && matchesAnyURL(pwe, URL, URLHostnames[URL], allowHostnameOnlyMatch)) { if (( (pwe.Strings.Exists("Form HTTP realm") && pwe.Strings.ReadSafe("Form HTTP realm").Length > 0 && (httpRealm == "" || pwe.Strings.ReadSafe("Form HTTP realm") == httpRealm) ) || (pwe.Strings.Exists("KPRPC HTTP realm") && pwe.Strings.ReadSafe("KPRPC HTTP realm").Length > 0 && (httpRealm == "" || pwe.Strings.ReadSafe("KPRPC HTTP realm") == httpRealm) )) && pwe.Strings.ReadSafe("URL") == URL) { entryIsAnExactMatch = true; entryIsAMatch = true; } else if (!requireFullURLMatches) entryIsAMatch = true; } } foreach (string URL in URLs) { // If we think we found a match, check it's not on a block list if (entryIsAMatch && matchesAnyBlockedURL(pwe, URL)) { entryIsAMatch = false; break; } if (entryIsAMatch && pwe.Strings.Exists("KPRPC URL Regex block")) { string patterns = pwe.Strings.ReadSafe("KPRPC URL Regex block"); foreach (string pattern in patterns.Split(' ')) { if (!string.IsNullOrEmpty(pattern) && System.Text.RegularExpressions.Regex.IsMatch(URL, pattern)) { entryIsAMatch = false; break; } } } } if (entryIsAMatch) { Entry kpe = (Entry)GetEntryFromPwEntry(pwe, entryIsAnExactMatch, true, db); allEntries.Add(kpe); count++; } } } } allEntries.Sort(delegate(Entry e1, Entry e2) { return e1.Title.CompareTo(e2.Title); }); return allEntries.ToArray(); }
public Entry AddLogin(Entry login, string parentUUID, string dbFileName) { // Make sure there is an active database if (!ensureDBisOpen()) return null; PwEntry newLogin = new PwEntry(true, true); setPwEntryFromEntry(newLogin, login); // find the database PwDatabase chosenDB = SelectDatabase(dbFileName); PwGroup parentGroup = GetRootPwGroup(chosenDB); // if in doubt we'll stick it in the root folder if (parentUUID != null && parentUUID.Length > 0) { PwUuid pwuuid = new PwUuid(KeePassLib.Utility.MemUtil.HexStringToByteArray(parentUUID)); PwGroup matchedGroup = GetRootPwGroup(chosenDB).FindGroup(pwuuid, true); if (matchedGroup != null) parentGroup = matchedGroup; } parentGroup.AddEntry(newLogin, true); host.MainWindow.BeginInvoke(new dlgSaveDB(saveDB), chosenDB); Entry output = (Entry)GetEntryFromPwEntry(newLogin, true, true, chosenDB); return output; }
private LightEntry GetEntryFromPwEntry(PwEntry pwe, bool isExactMatch, bool fullDetails, PwDatabase db) { //Debug.Indent(); //Stopwatch sw = Stopwatch.StartNew(); ArrayList formFieldList = new ArrayList(); ArrayList URLs = new ArrayList(); URLs.Add(pwe.Strings.ReadSafe("URL")); bool usernameFound = false; bool passwordFound = false; bool alwaysAutoFill = false; bool neverAutoFill = false; bool alwaysAutoSubmit = false; bool neverAutoSubmit = false; int priority = 0; string usernameName = ""; string usernameValue = ""; if (!fullDetails) { } else { foreach (System.Collections.Generic.KeyValuePair <string, KeePassLib.Security.ProtectedString> pwestring in pwe.Strings) { string pweKey = pwestring.Key; string pweValue = pwestring.Value.ReadString(); if (!fullDetails && pweValue != "username") continue; if ((pweKey.StartsWith("Form field ") || pweKey.StartsWith("KPRPC Form field ")) && pweKey.EndsWith(" type") && pweKey.Length > 16) { string fieldName = ""; if (pweKey.StartsWith("Form field ")) fieldName = pweKey.Substring(11).Substring(0, pweKey.Length - 11 - 5); else fieldName = pweKey.Substring(17).Substring(0, pweKey.Length - 17 - 5); string fieldId = ""; int fieldPage = 1; if (pwe.Strings.Exists("Form field " + fieldName + " page")) { try { fieldPage = int.Parse(GetPwEntryString(pwe, "Form field " + fieldName + " page")); } catch (Exception) { fieldPage = 1; } } else if (pwe.Strings.Exists("KPRPC Form field " + fieldName + " page")) { try { fieldPage = int.Parse(GetPwEntryString(pwe, "KPRPC Form field " + fieldName + " page")); } catch (Exception) { fieldPage = 1; } } if (pwe.Strings.Exists("Form field " + fieldName + " id")) fieldId = GetPwEntryString(pwe, "Form field " + fieldName + " id"); else if (pwe.Strings.Exists("KPRPC Form field " + fieldName + " id")) fieldId = GetPwEntryString(pwe, "KPRPC Form field " + fieldName + " id"); if (pweValue == "password") { // If there is a matching custom string for this password, use that but if not // we can just use the standard entry password. if (pwe.Strings.Exists("Form field " + fieldName + " value")) formFieldList.Add(new FormField(fieldName, "Password", GetPwEntryString(pwe, "Form field " + fieldName + " value"), FormFieldType.FFTpassword, fieldId, fieldPage)); else if (pwe.Strings.Exists("KPRPC Form field " + fieldName + " value")) formFieldList.Add(new FormField(fieldName, "Password", GetPwEntryString(pwe, "KPRPC Form field " + fieldName + " value"), FormFieldType.FFTpassword, fieldId, fieldPage)); else formFieldList.Add(new FormField(fieldName, "Password", GetPwEntryString(pwe, "Password"), FormFieldType.FFTpassword, fieldId, fieldPage)); passwordFound = true; } else if (pweValue == "username") { formFieldList.Add(new FormField(fieldName, "User name", GetPwEntryString(pwe, "UserName"), FormFieldType.FFTusername, fieldId, fieldPage)); usernameName = fieldName; usernameValue = GetPwEntryString(pwe, "UserName", fullDetails); usernameFound = true; } else if (pweValue == "text") { formFieldList.Add(new FormField(fieldName, fieldName, GetFormFieldValue(pwe, fieldName), FormFieldType.FFTtext, fieldId, fieldPage)); } else if (pweValue == "radio") { formFieldList.Add(new FormField(fieldName, fieldName, GetFormFieldValue(pwe, fieldName), FormFieldType.FFTradio, fieldId, fieldPage)); } else if (pweValue == "select") { formFieldList.Add(new FormField(fieldName, fieldName, GetFormFieldValue(pwe, fieldName), FormFieldType.FFTselect, fieldId, fieldPage)); } else if (pweValue == "checkbox") { formFieldList.Add(new FormField(fieldName, fieldName, GetFormFieldValue(pwe, fieldName), FormFieldType.FFTcheckbox, fieldId, fieldPage)); } } else if (pweKey == "Alternative URLs" || pweKey == "KPRPC Alternative URLs") { string[] urlsArray = pweValue.Split(new char[]{' '}); foreach (string altURL in urlsArray) URLs.Add(altURL); } //Debug.WriteLine("GetEntryFromPwEntry field processed: " + sw.Elapsed); } } // If we didn't find an explicit password field, we assume any value // in the KeePass "password" box is what we are looking for if (fullDetails && !passwordFound) { formFieldList.Add(new FormField("password", "Password", GetPwEntryString(pwe, "Password"), FormFieldType.FFTpassword, "password", 1)); } // If we didn't find an explicit username field, we assume any value // in the KeePass "username" box is what we are looking for if (!usernameFound) { formFieldList.Add(new FormField("username", "Username", GetPwEntryString(pwe, "UserName"), FormFieldType.FFTusername, "username", 1)); usernameName = "username"; usernameValue = GetPwEntryString(pwe, "UserName"); } string imageData = iconToBase64(pwe.CustomIconUuid, pwe.IconId); //Debug.WriteLine("GetEntryFromPwEntry icon converted: " + sw.Elapsed); if (fullDetails) { if (pwe.Strings.Exists("KeeFox Always Auto Fill") || pwe.Strings.Exists("KPRPC Always Auto Fill")) alwaysAutoFill = true; if (pwe.Strings.Exists("KeeFox Always Auto Submit") || pwe.Strings.Exists("KPRPC Always Auto Submit")) alwaysAutoSubmit = true; if (pwe.Strings.Exists("KeeFox Never Auto Fill") || pwe.Strings.Exists("KPRPC Never Auto Fill")) neverAutoFill = true; if (pwe.Strings.Exists("KeeFox Never Auto Submit") || pwe.Strings.Exists("KPRPC Never Auto Submit")) neverAutoSubmit = true; if (pwe.Strings.Exists("KeeFox Priority")) { string priorityString = pwe.Strings.ReadSafe("KeeFox Priority"); if (!string.IsNullOrEmpty(priorityString)) { try { priority = int.Parse(priorityString); } catch { } if (priority < 0 || priority > 100000) priority = 0; } } if (pwe.Strings.Exists("KPRPC Priority")) { string priorityString = pwe.Strings.ReadSafe("KPRPC Priority"); if (!string.IsNullOrEmpty(priorityString)) { try { priority = int.Parse(priorityString); } catch { } if (priority < 0 || priority > 100000) priority = 0; } } } //sw.Stop(); //Debug.WriteLine("GetEntryFromPwEntry execution time: " + sw.Elapsed); //Debug.Unindent(); if (fullDetails) { string realm = ""; try { realm = GetPwEntryString(pwe, "Form HTTP realm"); } catch (Exception) { realm = ""; } if (string.IsNullOrEmpty(realm)) { try { realm = GetPwEntryString(pwe, "KPRPC Form HTTP realm"); } catch (Exception) { realm = ""; } } if (string.IsNullOrEmpty(realm)) { try { realm = GetPwEntryString(pwe, "KPRPC HTTP realm"); } catch (Exception) { realm = ""; } } FormField[] temp = (FormField[])formFieldList.ToArray(typeof(FormField)); Entry kpe = new Entry( (string[])URLs.ToArray(typeof(string)), GetPwEntryString(pwe, "Form match URL"), realm, pwe.Strings.ReadSafe(PwDefs.TitleField), temp, KeePassLib.Utility.MemUtil.ByteArrayToHexString(pwe.Uuid.UuidBytes), alwaysAutoFill, neverAutoFill, alwaysAutoSubmit, neverAutoSubmit, priority, GetGroupFromPwGroup(pwe.ParentGroup), imageData, GetDatabaseFromPwDatabase(db, false, true)); return kpe; } else { return new LightEntry((string[])URLs.ToArray(typeof(string)), pwe.Strings.ReadSafe(PwDefs.TitleField), KeePassLib.Utility.MemUtil.ByteArrayToHexString(pwe.Uuid.UuidBytes), imageData, usernameName, usernameValue); } }
public void ModifyLogin(Entry oldLogin, Entry newLogin) { if (oldLogin == null) throw new Exception("old login must be passed to the ModifyLogin function. It wasn't"); if (newLogin == null) throw new Exception("new login must be passed to the ModifyLogin function. It wasn't"); if (oldLogin.UniqueID == null || oldLogin.UniqueID == "") throw new Exception("old login doesn't contain a uniqueID"); // Make sure there is an active database if (!ensureDBisOpen()) return; PwUuid pwuuid = new PwUuid(KeePassLib.Utility.MemUtil.HexStringToByteArray(oldLogin.UniqueID)); PwEntry modificationTarget = GetRootPwGroup(host.Database).FindEntry(pwuuid, true); if (modificationTarget == null) throw new Exception("Could not find correct entry to modify. No changes made to KeePass database."); setPwEntryFromEntry(modificationTarget, newLogin); host.MainWindow.BeginInvoke(new dlgSaveDB(saveDB), host.Database); }
public Entry[] FindLogins(string[] URLs, string actionURL, string httpRealm, LoginSearchType lst, bool requireFullURLMatches, string uniqueID, string dbFileName, string freeTextSearch, string username) { List<PwDatabase> dbs = null; int count = 0; List<Entry> allEntries = new List<Entry>(); if (!string.IsNullOrEmpty(dbFileName)) { // find the database PwDatabase db = SelectDatabase(dbFileName); dbs = new List<PwDatabase>(); dbs.Add(db); } else { // if DB list is not populated, look in all open DBs dbs = host.MainWindow.DocumentManager.GetOpenDatabases(); // unless the DB is the wrong version dbs = dbs.FindAll(ConfigIsCorrectVersion); } //string hostname = URLs[0]; string actionHost = actionURL; // Make sure there is an active database if (!ensureDBisOpen()) { return null; } // if uniqueID is supplied, match just that one login. if not found, move on to search the content of the logins... if (uniqueID != null && uniqueID.Length > 0) { PwUuid pwuuid = new PwUuid(KeePassLib.Utility.MemUtil.HexStringToByteArray(uniqueID)); //foreach DB... foreach (PwDatabase db in dbs) { PwEntry matchedLogin = GetRootPwGroup(db).FindEntry(pwuuid, true); if (matchedLogin == null) continue; Entry[] logins = new Entry[1]; logins[0] = (Entry)GetEntryFromPwEntry(matchedLogin, MatchAccuracy.Best, true, db); if (logins[0] != null) return logins; } } if (!string.IsNullOrEmpty(freeTextSearch)) { //foreach DB... foreach (PwDatabase db in dbs) { KeePassLib.Collections.PwObjectList<PwEntry> output = new KeePassLib.Collections.PwObjectList<PwEntry>(); PwGroup searchGroup = GetRootPwGroup(db); //output = searchGroup.GetEntries(true); SearchParameters sp = new SearchParameters(); sp.ComparisonMode = StringComparison.InvariantCultureIgnoreCase; sp.SearchString = freeTextSearch; sp.SearchInUserNames = true; sp.SearchInTitles = true; sp.SearchInTags = true; MethodInfo mi; // SearchEntries method signature changed in KP 2.17 so we use // reflection to enable support for both 2.17 and earlier versions try { mi = typeof(PwGroup).GetMethod("SearchEntries", new Type[] { typeof(SearchParameters), typeof(KeePassLib.Collections.PwObjectList<PwEntry>) }); mi.Invoke(searchGroup, new object[] { sp, output }); } catch (AmbiguousMatchException ex) { // can't find the 2.17 method definition so try for an earlier version mi = typeof(PwGroup).GetMethod("SearchEntries", new Type[] { typeof(SearchParameters), typeof(KeePassLib.Collections.PwObjectList<PwEntry>), typeof(bool) }); mi.Invoke(searchGroup, new object[] { sp, output, false }); // If an exception is thrown here it would be unexpected and // require a new version of the application to be released } foreach (PwEntry pwe in output) { Entry kpe = (Entry)GetEntryFromPwEntry(pwe, MatchAccuracy.None, true, db); if (kpe != null) { allEntries.Add(kpe); count++; } } } } // else we search for the URLs if (count == 0 && URLs.Length > 0 && !string.IsNullOrEmpty(URLs[0])) { int protocolIndex = -1; Dictionary<string, URLSummary> URLHostnameAndPorts = new Dictionary<string, URLSummary>(); // make sure that hostname and actionURL always represent only the hostname portion // of the URL // It's tempting to demand that the protocol must match too (e.g. http forms won't // match a stored https login) but best not to define such a restriction in KeePassRPC // - the RPC client (e.g. KeeFox) can decide to penalise protocol mismatches, // potentially dependant on user configuration options in the client. for (int i = 0; i < URLs.Length; i++) { URLHostnameAndPorts.Add(URLs[i], URLSummary.FromURL(URLs[i])); } //foreach DB... foreach (PwDatabase db in dbs) { KeePassLib.Collections.PwObjectList<PwEntry> output = new KeePassLib.Collections.PwObjectList<PwEntry>(); PwGroup searchGroup = GetRootPwGroup(db); output = searchGroup.GetEntries(true); List<string> configErrors = new List<string>(1); // Search every entry in the DB foreach (PwEntry pwe in output) { string entryUserName = pwe.Strings.ReadSafe(PwDefs.UserNameField); entryUserName = KeePassRPCPlugin.GetPwEntryStringFromDereferencableValue(pwe, entryUserName, db); if (EntryIsInRecycleBin(pwe, db)) continue; // ignore if it's in the recycle bin //if (string.IsNullOrEmpty(pwe.Strings.ReadSafe("URL"))) // continue; // entries must have a standard URL entry string json = KeePassRPCPlugin.GetPwEntryString(pwe, "KPRPC JSON", db); EntryConfig conf; if (string.IsNullOrEmpty(json)) { conf = new EntryConfig(); } else { try { conf = (EntryConfig)Jayrock.Json.Conversion.JsonConvert.Import(typeof(EntryConfig), json); } catch (Exception ex) { configErrors.Add("Username: "******". URL: " + pwe.Strings.ReadSafe("URL")); continue; } } if (conf.Hide) continue; bool entryIsAMatch = false; int bestMatchAccuracy = MatchAccuracy.None; if (conf.RegExURLs != null) foreach (string URL in URLs) foreach (string regexPattern in conf.RegExURLs) { try { if (!string.IsNullOrEmpty(regexPattern) && System.Text.RegularExpressions.Regex.IsMatch(URL, regexPattern)) { entryIsAMatch = true; bestMatchAccuracy = MatchAccuracy.Best; break; } } catch (ArgumentException) { MessageBox.Show("'" + regexPattern + "' is not a valid regular expression. This error was found in an entry in your database called '" + pwe.Strings.ReadSafe(PwDefs.TitleField) + "'. You need to fix or delete this regular expression to prevent this warning message appearing.", "Warning: Broken regular expression", MessageBoxButtons.OK, MessageBoxIcon.Warning); break; } } // Check for matching URLs for the page containing the form if (!entryIsAMatch && lst != LoginSearchType.LSTnoForms && (string.IsNullOrEmpty(username) || username == entryUserName)) { foreach (string URL in URLs) { int accuracy = bestMatchAccuracyForAnyURL(pwe, conf, URL, URLHostnameAndPorts[URL]); if (accuracy > bestMatchAccuracy) bestMatchAccuracy = accuracy; } } // Check for matching URLs for the HTTP Auth containing the form if (!entryIsAMatch && lst != LoginSearchType.LSTnoRealms && (string.IsNullOrEmpty(username) || username == entryUserName)) { foreach (string URL in URLs) { int accuracy = bestMatchAccuracyForAnyURL(pwe, conf, URL, URLHostnameAndPorts[URL]); if (accuracy > bestMatchAccuracy) bestMatchAccuracy = accuracy; } } if (bestMatchAccuracy == MatchAccuracy.Best || (!requireFullURLMatches && bestMatchAccuracy > MatchAccuracy.None)) entryIsAMatch = true; foreach (string URL in URLs) { // If we think we found a match, check it's not on a block list if (entryIsAMatch && matchesAnyBlockedURL(pwe, conf, URL)) { entryIsAMatch = false; break; } if (conf.RegExBlockedURLs != null) foreach (string pattern in conf.RegExBlockedURLs) { try { if (!string.IsNullOrEmpty(pattern) && System.Text.RegularExpressions.Regex.IsMatch(URL, pattern)) { entryIsAMatch = false; break; } } catch (ArgumentException) { MessageBox.Show("'" + pattern + "' is not a valid regular expression. This error was found in an entry in your database called '" + pwe.Strings.ReadSafe(PwDefs.TitleField) + "'. You need to fix or delete this regular expression to prevent this warning message appearing.", "Warning: Broken regular expression", MessageBoxButtons.OK, MessageBoxIcon.Warning); break; } } } if (entryIsAMatch) { Entry kpe = (Entry)GetEntryFromPwEntry(pwe, bestMatchAccuracy, true, db); if (kpe != null) { allEntries.Add(kpe); count++; } } } if (configErrors.Count > 0) MessageBox.Show("There are configuration errors in your database called '" + db.Name + "'. To fix the entries listed below and prevent this warning message appearing, please edit the value of the 'KeePassRPC JSON config' advanced string. Please ask for help on http://keefox.org/help/forum if you're not sure how to fix this. These entries are affected:" + Environment.NewLine + string.Join(Environment.NewLine, configErrors.ToArray()), "Warning: Configuration errors", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } allEntries.Sort(delegate(Entry e1, Entry e2) { return e1.Title.CompareTo(e2.Title); }); return allEntries.ToArray(); }
private void setPwEntryFromEntry(PwEntry pwe, Entry login) { bool firstPasswordFound = false; EntryConfig conf = new EntryConfig(); List<FormField> ffl = new List<FormField>(); // Go through each form field, mostly just making a copy but with occasional tweaks such as default username and password selection // by convention, we'll always have the first text field as the username when both reading and writing from the EntryConfig foreach (FormField kpff in login.FormFieldList) { if (kpff.Type == FormFieldType.FFTpassword && !firstPasswordFound) { ffl.Add(new FormField(kpff.Name, "KeePass password", "{PASSWORD}", kpff.Type, kpff.Id, kpff.Page)); pwe.Strings.Set("Password", new ProtectedString(host.Database.MemoryProtection.ProtectPassword, kpff.Value)); firstPasswordFound = true; } else if (kpff.Type == FormFieldType.FFTusername) { ffl.Add(new FormField(kpff.Name, "KeePass username", "{USERNAME}", kpff.Type, kpff.Id, kpff.Page)); pwe.Strings.Set("UserName", new ProtectedString(host.Database.MemoryProtection.ProtectUserName, kpff.Value)); } else { ffl.Add(new FormField(kpff.Name, kpff.Name, kpff.Value, kpff.Type, kpff.Id, kpff.Page)); } } conf.FormFieldList = ffl.ToArray(); List<string> altURLs = new List<string>(); for (int i = 0; i < login.URLs.Length; i++) { string url = login.URLs[i]; if (i == 0) { URLSummary urlsum = URLSummary.FromURL(url); // Require more strict default matching for entries that come // with a port configured (user can override in the rare case // that they want the loose domain-level matching) if (!string.IsNullOrEmpty(urlsum.Port)) conf.BlockDomainOnlyMatch = true; pwe.Strings.Set("URL", new ProtectedString(host.Database.MemoryProtection.ProtectUrl, url ?? "")); } else altURLs.Add(url); } conf.AltURLs = altURLs.ToArray(); conf.HTTPRealm = login.HTTPRealm; conf.Version = 1; // Set some of the string fields pwe.Strings.Set(PwDefs.TitleField, new ProtectedString(host.Database.MemoryProtection.ProtectTitle, login.Title ?? "")); // update the icon for this entry (in most cases we'll // just detect that it is the same standard icon as before) PwUuid customIconUUID = PwUuid.Zero; PwIcon iconId = PwIcon.Key; if (login.IconImageData != null && login.IconImageData.Length > 0 && base64ToIcon(login.IconImageData, ref customIconUUID, ref iconId)) { if (customIconUUID == PwUuid.Zero) pwe.IconId = iconId; else pwe.CustomIconUuid = customIconUUID; } pwe.Strings.Set("KPRPC JSON", new ProtectedString(true, Jayrock.Json.Conversion.JsonConvert.ExportToString(conf))); }
private LightEntry GetEntryFromPwEntry(PwEntry pwe, EntryConfig conf, int matchAccuracy, bool fullDetails, PwDatabase db, bool abortIfHidden) { ArrayList formFieldList = new ArrayList(); ArrayList URLs = new ArrayList(); URLs.Add(pwe.Strings.ReadSafe("URL")); bool usernameFound = false; bool passwordFound = false; bool alwaysAutoFill = false; bool neverAutoFill = false; bool alwaysAutoSubmit = false; bool neverAutoSubmit = false; int priority = 0; string usernameName = ""; string usernameValue = ""; if (abortIfHidden && conf.Hide) return null; if (!fullDetails) { } else { if (conf.FormFieldList != null) { foreach (FormField ff in conf.FormFieldList) { if (ff.Type == FormFieldType.FFTpassword) { string ffValue = KeePassRPCPlugin.GetPwEntryStringFromDereferencableValue(pwe, ff.Value, db); if (!string.IsNullOrEmpty(ffValue)) { formFieldList.Add(new FormField(ff.Name, "KeePass password", ffValue, ff.Type, ff.Id, ff.Page)); passwordFound = true; } } else if (ff.Type == FormFieldType.FFTusername) { string ffValue = KeePassRPCPlugin.GetPwEntryStringFromDereferencableValue(pwe, ff.Value, db); if (!string.IsNullOrEmpty(ffValue)) { formFieldList.Add(new FormField(ff.Name, "KeePass username", ffValue, ff.Type, ff.Id, ff.Page)); usernameFound = true; } } else formFieldList.Add(new FormField(ff.Name, ff.Name, ff.Value, ff.Type, ff.Id, ff.Page)); } } } if (conf.AltURLs != null) URLs.AddRange(conf.AltURLs); // If we didn't find an explicit password field, we assume any value // in the KeePass "password" box is what we are looking for if (fullDetails && !passwordFound) { string ffValue = KeePassRPCPlugin.GetPwEntryString(pwe, "Password", db); ffValue = KeePassRPCPlugin.GetPwEntryStringFromDereferencableValue(pwe, ffValue, db); if (!string.IsNullOrEmpty(ffValue)) { formFieldList.Add(new FormField("password", "KeePass password", ffValue, FormFieldType.FFTpassword, "password", 1)); } } // If we didn't find an explicit username field, we assume any value // in the KeePass "username" box is what we are looking for if (!usernameFound) { string ffValue = KeePassRPCPlugin.GetPwEntryString(pwe, "UserName", db); ffValue = KeePassRPCPlugin.GetPwEntryStringFromDereferencableValue(pwe, ffValue, db); if (!string.IsNullOrEmpty(ffValue)) { formFieldList.Add(new FormField("username", "KeePass username", ffValue, FormFieldType.FFTusername, "username", 1)); usernameName = "username"; usernameValue = ffValue; } } string imageData = iconToBase64(pwe.CustomIconUuid, pwe.IconId); //Debug.WriteLine("GetEntryFromPwEntry icon converted: " + sw.Elapsed); if (fullDetails) { alwaysAutoFill = conf.AlwaysAutoFill; alwaysAutoSubmit = conf.AlwaysAutoSubmit; neverAutoFill = conf.NeverAutoFill; neverAutoSubmit = conf.NeverAutoSubmit; priority = conf.Priority; } //sw.Stop(); //Debug.WriteLine("GetEntryFromPwEntry execution time: " + sw.Elapsed); //Debug.Unindent(); if (fullDetails) { string realm = ""; if (!string.IsNullOrEmpty(conf.HTTPRealm)) realm = conf.HTTPRealm; FormField[] temp = (FormField[])formFieldList.ToArray(typeof(FormField)); Entry kpe = new Entry( (string[])URLs.ToArray(typeof(string)), realm, pwe.Strings.ReadSafe(PwDefs.TitleField), temp, KeePassLib.Utility.MemUtil.ByteArrayToHexString(pwe.Uuid.UuidBytes), alwaysAutoFill, neverAutoFill, alwaysAutoSubmit, neverAutoSubmit, priority, GetGroupFromPwGroup(pwe.ParentGroup), imageData, GetDatabaseFromPwDatabase(db, false, true),matchAccuracy); return kpe; } else { return new LightEntry((string[])URLs.ToArray(typeof(string)), pwe.Strings.ReadSafe(PwDefs.TitleField), KeePassLib.Utility.MemUtil.ByteArrayToHexString(pwe.Uuid.UuidBytes), imageData, usernameName, usernameValue); } }
public Entry UpdateLogin(Entry login, string oldLoginUUID, int urlMergeMode, string dbFileName) { if (login == null) throw new ArgumentException("(new) login was not passed to the updateLogin function"); if (string.IsNullOrEmpty(oldLoginUUID)) throw new ArgumentException("oldLoginUUID was not passed to the updateLogin function"); if (string.IsNullOrEmpty(dbFileName)) throw new ArgumentException("dbFileName was not passed to the updateLogin function"); // Make sure there is an active database if (!ensureDBisOpen()) return null; // There are odd bits of the resulting new login that we don't // need but the vast majority is going to be useful PwEntry newLoginData = new PwEntry(true, true); setPwEntryFromEntry(newLoginData, login); // find the database PwDatabase chosenDB = SelectDatabase(dbFileName); PwUuid pwuuid = new PwUuid(KeePassLib.Utility.MemUtil.HexStringToByteArray(oldLoginUUID)); PwEntry entryToUpdate = GetRootPwGroup(chosenDB).FindEntry(pwuuid, true); if (entryToUpdate == null) throw new Exception("oldLoginUUID could not be resolved to an existing entry."); MergeEntries(entryToUpdate, newLoginData, urlMergeMode, chosenDB); host.MainWindow.BeginInvoke(new dlgSaveDB(saveDB), chosenDB); Entry updatedEntry = (Entry)GetEntryFromPwEntry(entryToUpdate, MatchAccuracy.Best, true, chosenDB); return updatedEntry; }