Пример #1
0
 public OptionsForm(ConfigOpt config)
 {
     _host   = NativeMessagingHost.GetHost();
     _config = config;
     InitializeComponent();
     lblVersion.Text = string.Format("KeePassNatMsg v{0}", AssemblyVersion);
 }
Пример #2
0
        public Response ProcessRequest(Request req)
        {
            var handler = GetHandler(req.Action);

            if (handler != null)
            {
                if (handler != ChangePublicKeys)
                {
                    lock (_unlockLock)
                    {
                        var config = new ConfigOpt(_host.CustomConfig);
                        if (!_host.Database.IsOpen && config.UnlockDatabaseRequest)
                        {
                            if (KeePass.UI.GlobalWindowManager.WindowCount == 0)
                            {
                                _host.MainWindow.Invoke(new System.Action(() => _host.MainWindow.OpenDatabase(_host.MainWindow.DocumentManager.ActiveDocument.LockedIoc, null, false)));
                            }
                        }
                        if (!_host.Database.IsOpen)
                        {
                            return(new ErrorResponse(req, ErrorType.DatabaseNotOpened));
                        }
                    }
                }

                return(handler.Invoke(req));
            }
            return(new ErrorResponse(req, ErrorType.IncorrectAction));
        }
Пример #3
0
        private PwEntryDatabase FindEntry(string uuid)
        {
            PwUuid id = new PwUuid(MemUtil.HexStringToByteArray(uuid));

            var configOpt = new ConfigOpt(_host.CustomConfig);

            if (configOpt.SearchInAllOpenedDatabases)
            {
                foreach (var doc in _host.MainWindow.DocumentManager.Documents)
                {
                    if (doc.Database.IsOpen)
                    {
                        var entry = doc.Database.RootGroup.FindEntry(id, true);
                        if (entry != null)
                        {
                            return(new PwEntryDatabase(entry, doc.Database));
                        }
                    }
                }
            }
            else
            {
                var entry = _host.Database.RootGroup.FindEntry(id, true);
                if (entry != null)
                {
                    return(new PwEntryDatabase(entry, _host.Database));
                }
            }

            return(null);
        }
Пример #4
0
        private bool UnlockDatabase(bool triggerUnlock)
        {
            lock (_unlockLock)
            {
                var config = new ConfigOpt(_host.CustomConfig);
                if (!_host.Database.IsOpen && config.UnlockDatabaseRequest && KeePass.UI.GlobalWindowManager.WindowCount == 0 && triggerUnlock)
                {
                    _host.MainWindow.Invoke(new System.Action(() => _host.MainWindow.OpenDatabase(_host.MainWindow.DocumentManager.ActiveDocument.LockedIoc, null, false)));
                }

                return(_host.Database.IsOpen);
            }
        }
Пример #5
0
        private static IEnumerable <KeyValuePair <string, string> > GetFields(ConfigOpt configOpt, PwEntryDatabase entryDatabase)
        {
            SprContext ctx = new SprContext(entryDatabase.entry, entryDatabase.database, SprCompileFlags.All, false, false);

            List <KeyValuePair <string, string> > fields = null;

            if (configOpt.ReturnStringFields)
            {
                fields = new List <KeyValuePair <string, string> >();
                foreach (var sf in entryDatabase.entry.Strings)
                {
                    var sfValue = entryDatabase.entry.Strings.ReadSafe(sf.Key);

                    // follow references
                    sfValue = SprEngine.Compile(sfValue, ctx);

                    // KeeOtp support through keepassxc-browser
                    // KeeOtp stores the TOTP config in a string field "otp" and provides a placeholder "{TOTP}"
                    // KeeTrayTOTP uses by default a "TOTP Seed" string field, and the {TOTP} placeholder.
                    // keepassxc-browser needs the value in a string field named "KPH: {TOTP}"
                    if (sf.Key == "otp" || sf.Key.Equals("TOTP Seed", StringComparison.InvariantCultureIgnoreCase))
                    {
                        fields.Add(new KeyValuePair <string, string>("KPH: {TOTP}", SprEngine.Compile("{TOTP}", ctx)));
                    }
                    else if (configOpt.ReturnStringFieldsWithKphOnly)
                    {
                        if (sf.Key.StartsWith("KPH: "))
                        {
                            fields.Add(new KeyValuePair <string, string>(sf.Key.Substring(5), sfValue));
                        }
                    }
                    else
                    {
                        fields.Add(new KeyValuePair <string, string>(sf.Key, sfValue));
                    }
                }

                if (fields.Count > 0)
                {
                    var sorted = from e2 in fields orderby e2.Key ascending select e2;
                    fields = sorted.ToList();
                }
                else
                {
                    fields = null;
                }
            }

            return(fields);
        }
Пример #6
0
        public string GenerateFromUuid(string uuid)
        {
            PwEntry entry = null;
            PwUuid  id    = new PwUuid(MemUtil.HexStringToByteArray(uuid));

            var configOpt = new ConfigOpt(_host.CustomConfig);

            if (configOpt.SearchInAllOpenedDatabases)
            {
                foreach (PwDocument doc in _host.MainWindow.DocumentManager.Documents)
                {
                    if (doc.Database.IsOpen)
                    {
                        entry = doc.Database.RootGroup.FindEntry(id, true);
                        if (entry != null)
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                entry = _host.Database.RootGroup.FindEntry(id, true);
            }

            if (entry == null)
            {
                return(string.Empty);
            }

            string TotpSettings = _ext.GetTotpSettings(entry);

            if (TotpSettings == null)
            {
                return(string.Empty);
            }

            try
            {
                return(Totp.Generate(TotpSettings));
            }
            catch (Exception)
            {
                return(string.Empty);
            }
        }
Пример #7
0
        private IEnumerable <KeyValuePair <string, string> > GetFields(ConfigOpt configOpt, PwEntryDatabase entryDatabase)
        {
            SprContext ctx = new SprContext(entryDatabase.entry, entryDatabase.database, SprCompileFlags.All, false, false);

            List <KeyValuePair <string, string> > fields = null;

            if (configOpt.ReturnStringFields)
            {
                fields = new List <KeyValuePair <string, string> >();
                foreach (var sf in entryDatabase.entry.Strings)
                {
                    var sfValue = entryDatabase.entry.Strings.ReadSafe(sf.Key);

                    // follow references
                    sfValue = SprEngine.Compile(sfValue, ctx);

                    if (configOpt.ReturnStringFieldsWithKphOnly)
                    {
                        if (sf.Key.StartsWith("KPH: "))
                        {
                            fields.Add(new KeyValuePair <string, string>(sf.Key.Substring(5), sfValue));
                        }
                    }
                    else
                    {
                        fields.Add(new KeyValuePair <string, string>(sf.Key, sfValue));
                    }
                }

                if (fields.Count > 0)
                {
                    var sorted = from e2 in fields orderby e2.Key ascending select e2;
                    fields = sorted.ToList();
                }
                else
                {
                    fields = null;
                }
            }

            return(fields);
        }
Пример #8
0
        public bool UpdateEntry(string uuid, string username, string password, string formHost)
        {
            PwEntry    entry     = null;
            PwUuid     id        = new PwUuid(MemUtil.HexStringToByteArray(uuid));
            PwDatabase db        = null;
            var        configOpt = new ConfigOpt(_host.CustomConfig);

            if (configOpt.SearchInAllOpenedDatabases)
            {
                foreach (PwDocument doc in _host.MainWindow.DocumentManager.Documents)
                {
                    if (doc.Database.IsOpen)
                    {
                        entry = doc.Database.RootGroup.FindEntry(id, true);
                        if (entry != null)
                        {
                            db = doc.Database;
                            break;
                        }
                    }
                }
            }
            else
            {
                entry = _host.Database.RootGroup.FindEntry(id, true);
                db    = _host.Database;
            }

            if (entry == null)
            {
                return(false);
            }

            string[] up = _ext.GetUserPass(entry);
            var      u  = up[0];
            var      p  = up[1];

            if (u != username || p != password)
            {
                bool allowUpdate = configOpt.AlwaysAllowUpdates;

                if (!allowUpdate)
                {
                    _host.MainWindow.Activate();

                    DialogResult result;
                    if (_host.MainWindow.IsTrayed())
                    {
                        result = MessageBox.Show(
                            String.Format("Do you want to update the information in {0} - {1}?", formHost, u),
                            "Update Entry", MessageBoxButtons.YesNo,
                            MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
                    }
                    else
                    {
                        result = MessageBox.Show(
                            _host.MainWindow,
                            String.Format("Do you want to update the information in {0} - {1}?", formHost, u),
                            "Update Entry", MessageBoxButtons.YesNo,
                            MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                    }


                    if (result == DialogResult.Yes)
                    {
                        allowUpdate = true;
                    }
                }

                if (allowUpdate)
                {
                    PwObjectList <PwEntry> m_vHistory = entry.History.CloneDeep();
                    entry.History = m_vHistory;
                    entry.CreateBackup(null);

                    entry.Strings.Set(PwDefs.UserNameField, new ProtectedString(false, username));
                    entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(true, password));
                    entry.Touch(true, false);
                    _ext.UpdateUI(entry.ParentGroup);

                    AutoSaveIfRequired(db);

                    return(true);
                }
            }

            return(false);
        }
Пример #9
0
        private IEnumerable <PwEntryDatabase> FindMatchingEntries(string url, string realm)
        {
            var listResult = new List <PwEntryDatabase>();
            var hostUri    = new Uri(url);

            var formHost       = hostUri.Host;
            var searchHost     = hostUri.Host;
            var origSearchHost = hostUri.Host;
            var parms          = MakeSearchParameters();

            List <PwDatabase> listDatabases = new List <PwDatabase>();

            var configOpt = new ConfigOpt(_host.CustomConfig);

            if (configOpt.SearchInAllOpenedDatabases)
            {
                foreach (PwDocument doc in _host.MainWindow.DocumentManager.Documents)
                {
                    if (doc.Database.IsOpen)
                    {
                        listDatabases.Add(doc.Database);
                    }
                }
            }
            else
            {
                listDatabases.Add(_host.Database);
            }

            int listCount = 0;

            foreach (PwDatabase db in listDatabases)
            {
                searchHost = origSearchHost;
                //get all possible entries for given host-name
                while (listResult.Count == listCount && (origSearchHost == searchHost || searchHost.IndexOf(".") != -1))
                {
                    parms.SearchString = String.Format("^{0}$|/{0}/?", searchHost);
                    var listEntries = new PwObjectList <PwEntry>();
                    db.RootGroup.SearchEntries(parms, listEntries);
                    foreach (var le in listEntries)
                    {
                        listResult.Add(new PwEntryDatabase(le, db));
                    }
                    searchHost = searchHost.Substring(searchHost.IndexOf(".") + 1);

                    //searchHost contains no dot --> prevent possible infinite loop
                    if (searchHost == origSearchHost)
                    {
                        break;
                    }
                }
                listCount = listResult.Count;
            }

            var searchUrls = configOpt.SearchUrls;

            bool filter(PwEntry e)
            {
                var title    = e.Strings.ReadSafe(PwDefs.TitleField);
                var entryUrl = e.Strings.ReadSafe(PwDefs.UrlField);
                var c        = _ext.GetEntryConfig(e);

                if (c != null)
                {
                    if (c.Allow.Contains(formHost))
                    {
                        return(true);
                    }
                    if (c.Deny.Contains(formHost))
                    {
                        return(false);
                    }
                    if (!string.IsNullOrEmpty(realm) && c.Realm != realm)
                    {
                        return(false);
                    }
                }

                if (IsValidUrl(entryUrl, formHost))
                {
                    return(true);
                }

                if (IsValidUrl(title, formHost))
                {
                    return(true);
                }

                if (searchUrls)
                {
                    foreach (var sf in e.Strings.Where(s => s.Key.StartsWith("URL", StringComparison.InvariantCultureIgnoreCase)))
                    {
                        var sfv = e.Strings.ReadSafe(sf.Key);

                        if (sf.Key.IndexOf("regex", StringComparison.OrdinalIgnoreCase) >= 0 &&
                            System.Text.RegularExpressions.Regex.IsMatch(formHost, sfv))
                        {
                            return(true);
                        }

                        if (IsValidUrl(sfv, formHost))
                        {
                            return(true);
                        }
                    }
                }

                return(formHost.Contains(title) || (!string.IsNullOrEmpty(entryUrl) && formHost.Contains(entryUrl)));
            }

            bool filterSchemes(PwEntry e)
            {
                var title    = e.Strings.ReadSafe(PwDefs.TitleField);
                var entryUrl = e.Strings.ReadSafe(PwDefs.UrlField);

                if (entryUrl != null && Uri.TryCreate(entryUrl, UriKind.Absolute, out var entryUri) && entryUri.Scheme == hostUri.Scheme)
                {
                    return(true);
                }

                if (Uri.TryCreate(title, UriKind.Absolute, out var titleUri) && titleUri.Scheme == hostUri.Scheme)
                {
                    return(true);
                }

                return(false);
            }

            var result = listResult.Where(e => filter(e.entry));

            if (configOpt.MatchSchemes)
            {
                result = result.Where(e => filterSchemes(e.entry));
            }

            if (configOpt.HideExpired)
            {
                result = result.Where(x => !(x.entry.Expires && x.entry.ExpiryTime <= DateTime.UtcNow));
            }

            return(result);
        }
Пример #10
0
        internal Response GetLoginsHandler(Request req)
        {
            if (!req.TryDecrypt())
            {
                return(new ErrorResponse(req, ErrorType.CannotDecryptMessage));
            }

            var msg       = req.Message;
            var id        = msg.GetString("id");
            var url       = msg.GetString("url");
            var submitUrl = msg.GetString("submitUrl");

            Uri hostUri;
            Uri submitUri;

            if (!string.IsNullOrEmpty(url))
            {
                hostUri = new Uri(url);
            }
            else
            {
                return(new ErrorResponse(req, ErrorType.NoUrlProvided));
            }

            if (!string.IsNullOrEmpty(submitUrl))
            {
                submitUri = new Uri(submitUrl);
            }
            else
            {
                submitUri = hostUri;
            }

            var resp = req.GetResponse();

            resp.Message.Add("id", id);

            var items = FindMatchingEntries(url, null);

            if (items.ToList().Count > 0)
            {
                bool filter(PwEntry e)
                {
                    var c = _ext.GetEntryConfig(e);

                    var title    = e.Strings.ReadSafe(PwDefs.TitleField);
                    var entryUrl = e.Strings.ReadSafe(PwDefs.UrlField);

                    if (c != null)
                    {
                        return((title != hostUri.Host && entryUrl != hostUri.Host && !c.Allow.Contains(hostUri.Host)) || (submitUri.Host != null && !c.Allow.Contains(submitUri.Host) && submitUri.Host != title && submitUri.Host != entryUrl));
                    }
                    return((title != hostUri.Host && entryUrl != hostUri.Host) || (submitUri.Host != null && title != submitUri.Host && entryUrl != submitUri.Host));
                }

                var configOpt  = new ConfigOpt(_host.CustomConfig);
                var config     = _ext.GetConfigEntry(true);
                var autoAllowS = config.Strings.ReadSafe("Auto Allow");
                var autoAllow  = !string.IsNullOrWhiteSpace(autoAllowS);
                autoAllow = autoAllow || configOpt.AlwaysAllowAccess;
                var needPrompting = from e in items where filter(e.entry) select e;

                if (needPrompting.ToList().Count > 0 && !autoAllow)
                {
                    var win = _host.MainWindow;

                    using (var f = new AccessControlForm())
                    {
                        win.Invoke((MethodInvoker) delegate
                        {
                            f.Icon    = win.Icon;
                            f.Plugin  = _ext;
                            f.Entries = (from e in items where filter(e.entry) select e.entry).ToList();
                            //f.Entries = needPrompting.ToList();
                            f.Host  = submitUri.Host ?? hostUri.Host;
                            f.Load += delegate { f.Activate(); };
                            f.ShowDialog(win);
                            if (f.Remember && (f.Allowed || f.Denied))
                            {
                                foreach (var e in needPrompting)
                                {
                                    var c   = _ext.GetEntryConfig(e.entry) ?? new EntryConfig();
                                    var set = f.Allowed ? c.Allow : c.Deny;
                                    set.Add(hostUri.Host);
                                    if (submitUri.Host != null && submitUri.Host != hostUri.Host)
                                    {
                                        set.Add(submitUri.Host);
                                    }
                                    _ext.SetEntryConfig(e.entry, c);
                                }
                            }
                            if (!f.Allowed)
                            {
                                items = items.Except(needPrompting);
                            }
                        });
                    }
                }

                foreach (var entryDatabase in items)
                {
                    string entryUrl = String.Copy(entryDatabase.entry.Strings.ReadSafe(PwDefs.UrlField));
                    if (String.IsNullOrEmpty(entryUrl))
                    {
                        entryUrl = entryDatabase.entry.Strings.ReadSafe(PwDefs.TitleField);
                    }

                    entryUrl = entryUrl.ToLower();

                    entryDatabase.entry.UsageCount = (ulong)LevenshteinDistance(submitUri.ToString().ToLower(), entryUrl);
                }

                var itemsList = items.ToList();

                if (configOpt.SpecificMatchingOnly)
                {
                    itemsList = (from e in itemsList
                                 orderby e.entry.UsageCount ascending
                                 select e).ToList();

                    ulong lowestDistance = itemsList.Count > 0 ?
                                           itemsList[0].entry.UsageCount :
                                           0;

                    itemsList = (from e in itemsList
                                 where e.entry.UsageCount == lowestDistance
                                 orderby e.entry.UsageCount
                                 select e).ToList();
                }

                if (configOpt.SortResultByUsername)
                {
                    var items2 = from e in itemsList orderby e.entry.UsageCount ascending, _ext.GetUserPass(e)[0] ascending select e;
                    itemsList = items2.ToList();
                }
                else
                {
                    var items2 = from e in itemsList orderby e.entry.UsageCount ascending, e.entry.Strings.ReadSafe(PwDefs.TitleField) ascending select e;
                    itemsList = items2.ToList();
                }

                var entries = new JArray(itemsList.Select(item =>
                {
                    var up           = _ext.GetUserPass(item);
                    var TotpSettings = _ext.GetTotpSettings(item.entry);
                    JArray fldArr    = null;
                    var fields       = GetFields(configOpt, item);
                    if (fields != null)
                    {
                        fldArr = new JArray(fields.Select(f => new JObject {
                            { f.Key, f.Value }
                        }));
                    }
                    string fldTotp = null;
                    if (TotpSettings != null)
                    {
                        fldTotp = Totp.Generate(TotpSettings);
                    }
                    return(new JObject {
                        { "name", item.entry.Strings.ReadSafe(PwDefs.TitleField) },
                        { "login", up[0] },
                        { "password", up[1] },
                        { "uuid", item.entry.Uuid.ToHexString() },
                        { "totp", fldTotp },
                        { "stringFields", fldArr }
                    });
                }));

                resp.Message.Add("count", itemsList.Count);
                resp.Message.Add("entries", entries);

                if (itemsList.Count > 0)
                {
                    var names = (from e in itemsList select e.entry.Strings.ReadSafe(PwDefs.TitleField)).Distinct();
                    var n     = String.Join("\n    ", names);

                    if (configOpt.ReceiveCredentialNotification)
                    {
                        _ext.ShowNotification(String.Format("{0}: {1} is receiving credentials for:\n    {2}", req.GetString("id"), hostUri.Host, n));
                    }
                }

                return(resp);
            }

            resp.Message.Add("count", 0);
            resp.Message.Add("entries", new JArray());

            return(resp);
        }
Пример #11
0
 public OptionsForm(ConfigOpt config)
 {
     _host   = NativeMessagingHost.GetHost();
     _config = config;
     InitializeComponent();
 }
Пример #12
0
        private IEnumerable <PwEntryDatabase> FindMatchingEntries(string url, string submitUrl, string realm)
        {
            string submitHost = null;
            var    listResult = new List <PwEntryDatabase>();
            var    hostUri    = new Uri(url);

            var formHost       = hostUri.Host;
            var searchHost     = hostUri.Host;
            var origSearchHost = hostUri.Host;
            var parms          = MakeSearchParameters();

            List <PwDatabase> listDatabases = new List <PwDatabase>();

            var configOpt = new ConfigOpt(_host.CustomConfig);

            if (configOpt.SearchInAllOpenedDatabases)
            {
                foreach (PwDocument doc in _host.MainWindow.DocumentManager.Documents)
                {
                    if (doc.Database.IsOpen)
                    {
                        listDatabases.Add(doc.Database);
                    }
                }
            }
            else
            {
                listDatabases.Add(_host.Database);
            }

            int listCount = 0;

            foreach (PwDatabase db in listDatabases)
            {
                searchHost = origSearchHost;
                //get all possible entries for given host-name
                while (listResult.Count == listCount && (origSearchHost == searchHost || searchHost.IndexOf(".") != -1))
                {
                    parms.SearchString = String.Format("^{0}$|/{0}/?", searchHost);
                    var listEntries = new PwObjectList <PwEntry>();
                    db.RootGroup.SearchEntries(parms, listEntries);
                    foreach (var le in listEntries)
                    {
                        listResult.Add(new PwEntryDatabase(le, db));
                    }
                    searchHost = searchHost.Substring(searchHost.IndexOf(".") + 1);

                    //searchHost contains no dot --> prevent possible infinite loop
                    if (searchHost == origSearchHost)
                    {
                        break;
                    }
                }
                listCount = listResult.Count;
            }


            Func <PwEntry, bool> filter = delegate(PwEntry e)
            {
                var title    = e.Strings.ReadSafe(PwDefs.TitleField);
                var entryUrl = e.Strings.ReadSafe(PwDefs.UrlField);
                var c        = _ext.GetEntryConfig(e);
                if (c != null)
                {
                    if (c.Allow.Contains(formHost) && (submitHost == null || c.Allow.Contains(submitHost)))
                    {
                        return(true);
                    }
                    if (c.Deny.Contains(formHost) || (submitHost != null && c.Deny.Contains(submitHost)))
                    {
                        return(false);
                    }
                    if (realm != null && c.Realm != realm)
                    {
                        return(false);
                    }
                }

                if (entryUrl != null && (entryUrl.StartsWith("http://") || entryUrl.StartsWith("https://") || title.StartsWith("ftp://") || title.StartsWith("sftp://")))
                {
                    var uHost = new Uri(entryUrl);
                    if (formHost.EndsWith(uHost.Host))
                    {
                        return(true);
                    }
                }

                if (title.StartsWith("http://") || title.StartsWith("https://") || title.StartsWith("ftp://") || title.StartsWith("sftp://"))
                {
                    var uHost = new Uri(title);
                    if (formHost.EndsWith(uHost.Host))
                    {
                        return(true);
                    }
                }
                return(formHost.Contains(title) || (entryUrl != null && formHost.Contains(entryUrl)));
            };

            Func <PwEntry, bool> filterSchemes = delegate(PwEntry e)
            {
                var title    = e.Strings.ReadSafe(PwDefs.TitleField);
                var entryUrl = e.Strings.ReadSafe(PwDefs.UrlField);

                if (entryUrl != null)
                {
                    if (Uri.TryCreate(entryUrl, UriKind.Absolute, out var entryUri) && entryUri.Scheme == hostUri.Scheme)
                    {
                        return(true);
                    }
                }

                if (Uri.TryCreate(title, UriKind.Absolute, out var titleUri) && titleUri.Scheme == hostUri.Scheme)
                {
                    return(true);
                }

                return(false);
            };

            var result = from e in listResult where filter(e.entry) select e;

            if (configOpt.MatchSchemes)
            {
                result = from e in result where filterSchemes(e.entry) select e;
            }

            Func <PwEntry, bool> hideExpired = delegate(PwEntry e)
            {
                DateTime dtNow = DateTime.UtcNow;

                if (e.Expires && (e.ExpiryTime <= dtNow))
                {
                    return(false);
                }

                return(true);
            };

            if (configOpt.HideExpired)
            {
                result = from e in result where hideExpired(e.entry) select e;
            }

            return(result);
        }
Пример #13
0
        internal Response GetLoginsHandler(Request req)
        {
            if (!req.TryDecrypt())
            {
                return(new ErrorResponse(req, ErrorType.CannotDecryptMessage));
            }

            var msg       = req.Message;
            var id        = msg.GetString("id");
            var url       = msg.GetString("url");
            var submitUrl = msg.GetString("submitUrl");

            Uri hostUri;
            Uri submitUri = null;

            if (!string.IsNullOrEmpty(url))
            {
                hostUri = new Uri(url);
            }
            else
            {
                return(new ErrorResponse(req, ErrorType.NoUrlProvided));
            }

            if (!string.IsNullOrEmpty(submitUrl))
            {
                submitUri = new Uri(submitUrl);
            }

            var resp = req.GetResponse();

            resp.Message.Add("id", id);

            var items = FindMatchingEntries(url, null);

            if (items.ToList().Count > 0)
            {
                var filter = new GFunc <PwEntry, bool>((PwEntry e) =>
                {
                    var c = _ext.GetEntryConfig(e);

                    return(c == null || (!c.Allow.Contains(hostUri.Authority)) || (submitUri != null && submitUri.Authority != null && !c.Allow.Contains(submitUri.Authority)));
                });

                var configOpt     = new ConfigOpt(_host.CustomConfig);
                var needPrompting = items.Where(e => filter(e.entry)).ToList();

                if (needPrompting.Count > 0 && !configOpt.AlwaysAllowAccess)
                {
                    var win = _host.MainWindow;

                    using (var f = new AccessControlForm())
                    {
                        win.Invoke((MethodInvoker) delegate
                        {
                            f.Icon          = win.Icon;
                            f.Plugin        = _ext;
                            f.StartPosition = win.Visible ? FormStartPosition.CenterParent : FormStartPosition.CenterScreen;
                            f.Entries       = needPrompting.Select(e => e.entry).ToList();
                            f.Host          = submitUri != null ? submitUri.Authority : hostUri.Authority;
                            f.Load         += delegate { f.Activate(); };
                            f.ShowDialog(win);
                            if (f.Remember && (f.Allowed || f.Denied))
                            {
                                foreach (var e in needPrompting)
                                {
                                    var c   = _ext.GetEntryConfig(e.entry) ?? new EntryConfig();
                                    var set = f.Allowed ? c.Allow : c.Deny;
                                    set.Add(hostUri.Authority);
                                    if (submitUri != null && submitUri.Authority != null && submitUri.Authority != hostUri.Authority)
                                    {
                                        set.Add(submitUri.Authority);
                                    }
                                    _ext.SetEntryConfig(e.entry, c);
                                }
                            }
                            if (!f.Allowed)
                            {
                                items = items.Except(needPrompting);
                            }
                        });
                    }
                }

                var uri = submitUri != null ? submitUri : hostUri;

                foreach (var entryDatabase in items)
                {
                    string entryUrl = string.Copy(entryDatabase.entry.Strings.ReadSafe(PwDefs.UrlField));
                    if (string.IsNullOrEmpty(entryUrl))
                    {
                        entryUrl = entryDatabase.entry.Strings.ReadSafe(PwDefs.TitleField);
                    }

                    entryUrl = entryUrl.ToLower();

                    entryDatabase.entry.UsageCount = (ulong)LevenshteinDistance(uri.ToString().ToLower(), entryUrl);
                }

                var itemsList = items.ToList();

                if (configOpt.SpecificMatchingOnly)
                {
                    itemsList = (from e in itemsList
                                 orderby e.entry.UsageCount ascending
                                 select e).ToList();

                    ulong lowestDistance = itemsList.Count > 0 ?
                                           itemsList[0].entry.UsageCount :
                                           0;

                    itemsList = (from e in itemsList
                                 where e.entry.UsageCount == lowestDistance
                                 orderby e.entry.UsageCount
                                 select e).ToList();
                }

                if (configOpt.SortResultByUsername)
                {
                    var items2 = from e in itemsList orderby e.entry.UsageCount ascending, _ext.GetUserPass(e)[0] ascending select e;
                    itemsList = items2.ToList();
                }
                else
                {
                    var items2 = from e in itemsList orderby e.entry.UsageCount ascending, e.entry.Strings.ReadSafe(PwDefs.TitleField) ascending select e;
                    itemsList = items2.ToList();
                }

                var entries = new JArray(itemsList.Select(item =>
                {
                    var up        = _ext.GetUserPass(item);
                    JArray fldArr = null;
                    var fields    = GetFields(configOpt, item);
                    if (fields != null)
                    {
                        fldArr = new JArray(fields.Select(f => new JObject {
                            { f.Key, f.Value }
                        }));
                    }
                    var jobj = new JObject {
                        { "name", item.entry.Strings.ReadSafe(PwDefs.TitleField) },
                        { "login", up[0] },
                        { "password", up[1] },
                        { "uuid", item.entry.Uuid.ToHexString() },
                        { "stringFields", fldArr },
                    };

                    CheckTotp(item, jobj);

                    return(jobj);
                }));

                resp.Message.Add("count", itemsList.Count);
                resp.Message.Add("entries", entries);

                if (itemsList.Count > 0)
                {
                    var names = (from e in itemsList select e.entry.Strings.ReadSafe(PwDefs.TitleField)).Distinct();
                    var n     = String.Join("\n    ", names);

                    if (configOpt.ReceiveCredentialNotification)
                    {
                        _ext.ShowNotification(String.Format("{0}: {1} is receiving credentials for:\n    {2}", req.GetString("id"), hostUri.Host, n));
                    }
                }

                return(resp);
            }

            resp.Message.Add("count", 0);
            resp.Message.Add("entries", new JArray());

            return(resp);
        }