/// <summary> /// Enumerates the entries of the logins.json file. /// </summary> /// <param name="profilePath">Path of the profile folder</param> /// <returns></returns> private IEnumerable <EntryInfo> ReadLoginsFile(string profilePath) { var path = Path.Combine(profilePath, "logins.json"); if (File.Exists(path)) { var root = new JsonObject(new CharStream(File.ReadAllText(path))); var logins = root.Items["logins"].Value as JsonArray; foreach (var item in logins.Values.Select(v => v.Value).Cast <JsonObject>()) { EntryInfo entry; try { entry = new EntryInfo { Hostname = (item.Items["hostname"].Value as string).Trim(), Username = PK11_Decrypt(item.Items["encryptedUsername"].Value as string).Trim(), Password = PK11_Decrypt(item.Items["encryptedPassword"].Value as string), Created = DateUtils.FromUnixTimeMilliseconds((long)(item.Items["timeCreated"].Value as JsonNumber).Value), Modified = DateUtils.FromUnixTimeMilliseconds((long)(item.Items["timePasswordChanged"].Value as JsonNumber).Value) }; } catch { continue; } yield return(entry); } } }
/// <summary> /// Import credentials from the "Login Data" file. /// </summary> /// <exception cref="FileNotFoundException">Thrown when the database is not present.</exception> /// <param name="param">The parameters for the import</param> public override void ImportCredentials(ImportParameter param) { var currentProfilePath = !string.IsNullOrEmpty(param.CustomProfilePath) ? param.CustomProfilePath : !string.IsNullOrEmpty(param.Profile) ? Path.Combine(ProfilePath, param.Profile) : ProfilePath; if (!Directory.Exists(currentProfilePath)) { throw new ProfileNotFoundException(currentProfilePath); } var loginDataPath = Path.Combine(currentProfilePath, "Login Data"); if (!File.Exists(loginDataPath)) { throw new ProfileNotFoundException(loginDataPath); } try { using (var db = new DBHandler(loginDataPath)) { DataTable dt; db.Query(out dt, "SELECT origin_url, username_value, password_value, date_created FROM logins"); foreach (var row in dt.AsEnumerable()) { var date = DateUtils.FromChromiumTime((long)row["date_created"]); var entry = new EntryInfo { Hostname = row["origin_url"] as string, Username = row["username_value"] as string, Password = Encoding.UTF8.GetString(Cryptography.DecryptUserData(row["password_value"] as byte[])), Created = date, Modified = date }; param.Database.CreateWebsiteEntry( param.Group, entry, param.CreationSettings, param.Logger ); } } } catch (DbException ex) { throw new Exception(string.Format("Error while using the browsers login database. It may help to close all running instances of the browser.\n\n{0}", StrUtil.FormatException(ex)), ex); } }
/// <summary> /// Enumerates the entries of the signons.sqlite file. /// </summary> /// <param name="profilePath">Path of the profile folder</param> /// <returns></returns> private IEnumerable <EntryInfo> ReadSignonsFile(string profilePath) { using (var db = new DBHandler(Path.Combine(profilePath, "signons.sqlite"))) { DataTable dt = null; try { db.Query(out dt, "SELECT hostname, encryptedUsername, encryptedPassword, timeCreated, timePasswordChanged FROM moz_logins"); } catch { yield break; } foreach (var row in dt.AsEnumerable()) { EntryInfo entry; try { entry = new EntryInfo { Hostname = (row["hostname"] as string).Trim(), Username = PK11_Decrypt(row["encryptedUsername"] as string).Trim(), Password = PK11_Decrypt(row["encryptedPassword"] as string), Created = DateUtils.FromUnixTimeMilliseconds((long)row["timeCreated"]), Modified = DateUtils.FromUnixTimeMilliseconds((long)row["timePasswordChanged"]) }; } catch { continue; } yield return(entry); } } }
/// <summary> /// A PwDatabase extension method that creates a website entry. /// </summary> /// <param name="pd">The database to act on</param> /// <param name="group">The group to insert new entries into</param> /// <param name="host">The host</param> /// <param name="username">The username</param> /// <param name="password">The password</param> /// <param name="creationSettings">Settings used while creating the entry</param> /// <param name="logger">The logger</param> public static void CreateWebsiteEntry(this PwDatabase pd, PwGroup group, EntryInfo entry, CreationSettings creationSettings, IStatusLogger logger) { Contract.Requires(group != null); Contract.Requires(entry != null); Contract.Requires(creationSettings != null); Contract.Requires(logger != null); logger.SetText(string.Format("{0} - {1}", entry.Username, entry.Hostname), LogStatusType.Info); var pe = new PwEntry(true, true); group.AddEntry(pe, true); pe.Strings.Set(PwDefs.TitleField, new ProtectedString(pd.MemoryProtection.ProtectTitle, entry.Hostname)); pe.Strings.Set(PwDefs.UserNameField, new ProtectedString(pd.MemoryProtection.ProtectUserName, entry.Username)); pe.Strings.Set(PwDefs.PasswordField, new ProtectedString(pd.MemoryProtection.ProtectPassword, entry.Password)); pe.Strings.Set(PwDefs.UrlField, new ProtectedString(pd.MemoryProtection.ProtectUrl, entry.Hostname)); if (creationSettings.UseDates) { pe.CreationTime = entry.Created; pe.LastModificationTime = entry.Modified; } if (!string.IsNullOrEmpty(entry.Hostname) && (creationSettings.ExtractIcon || creationSettings.ExtractTitle)) { try { string content; using (var client = new WebClientEx()) { content = client.DownloadStringAwareOfEncoding(entry.Hostname); var document = new HtmlDocument(); document.LoadHtml(content); if (creationSettings.ExtractTitle) { var title = document.DocumentNode.SelectSingleNode("/html/head/title"); if (title != null) { pe.Strings.Set(PwDefs.TitleField, new ProtectedString(pd.MemoryProtection.ProtectTitle, HttpUtility.HtmlDecode(title.InnerText.Trim()))); } } if (creationSettings.ExtractIcon) { string iconUrl = null; foreach (var prio in new string[] { "shortcut icon", "apple-touch-icon", "icon" }) { //iconUrl = document.DocumentNode.SelectNodes("/html/head/link").Where(l => prio == l.Attributes["rel"]?.Value).LastOrDefault()?.Attributes["href"]?.Value; var node = document.DocumentNode.SelectNodes("/html/head/link").Where(l => l.GetAttributeValue("rel", string.Empty) == prio).LastOrDefault(); if (node != null) { iconUrl = node.GetAttributeValue("href", string.Empty); } if (!string.IsNullOrEmpty(iconUrl)) { break; } } if (!string.IsNullOrEmpty(iconUrl)) { if (!iconUrl.StartsWith("http://") && !iconUrl.StartsWith("https://")) { iconUrl = entry.Hostname.TrimEnd('/') + '/' + iconUrl.TrimStart('/'); } using (var s = client.OpenRead(iconUrl)) { var icon = Image.FromStream(s); if (icon.Width > 16 || icon.Height > 16) { icon = icon.GetThumbnailImage(16, 16, null, IntPtr.Zero); } using (var ms = new MemoryStream()) { icon.Save(ms, ImageFormat.Png); var data = ms.ToArray(); var createNewIcon = true; foreach (var item in pd.CustomIcons) { if (KeePassLib.Utility.MemUtil.ArraysEqual(data, item.ImageDataPng)) { pe.CustomIconUuid = item.Uuid; createNewIcon = false; break; } } if (createNewIcon) { var pwci = new PwCustomIcon(new PwUuid(true), data); pd.CustomIcons.Add(pwci); pe.CustomIconUuid = pwci.Uuid; } } } pd.UINeedsIconUpdate = true; } } } } catch { } } }