/// <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);
                }
            }
        }
Beispiel #4
0
        /// <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
                {
                }
            }
        }