Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented new request type "get-logins-custom-search" to search for entries like through the search box in KeePass #233

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified KeePassHttp.plgx
Binary file not shown.
7 changes: 7 additions & 0 deletions KeePassHttp/ConfigOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class ConfigOpt
const string SearchInAllOpenedDatabasesKey = "KeePassHttp_SearchInAllOpenedDatabases";
const string MatchSchemesKey = "KeePassHttp_MatchSchemes";
const string ReturnStringFieldsKey = "KeePassHttp_ReturnStringFields";
const string ReturnStringFieldsWithKphOnlyKey = "KeePassHttp_ReturnStringFieldsWithKphOnly";
const string SortResultByUsernameKey = "KeePassHttp_SortResultByUsername";
const string ListenerPortKey = "KeePassHttp_ListenerPort";
const string ListenerHostKey = "KeePassHttp_ListenerHost";
Expand Down Expand Up @@ -70,6 +71,12 @@ public bool ReturnStringFields
set { _config.SetBool(ReturnStringFieldsKey, value); }
}

public bool ReturnStringFieldsWithKphOnly
{
get { return _config.GetBool(ReturnStringFieldsWithKphOnlyKey, true); }
set { _config.SetBool(ReturnStringFieldsWithKphOnlyKey, value); }
}

public bool SortResultByUsername
{
get { return _config.GetBool(SortResultByUsernameKey, true); }
Expand Down
200 changes: 197 additions & 3 deletions KeePassHttp/Handlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,145 @@ private void GetAllLoginsHandler(Request r, Response resp, Aes aes)
}
}

private void GetLoginsCustomSearchHandler(Request r, Response resp, Aes aes)
{
if (!VerifyRequest(r, aes))
return;

string clientId = r.Id;

string searchString = null;
if (r.SearchString != null)
searchString = CryptoTransform(r.SearchString, true, false, aes, CMode.DECRYPT);

var items = FindMatchingEntriesLikeSearchbox(r, aes);
if (items.ToList().Count > 0)
{
Func<PwEntry, bool> filter = delegate (PwEntry e)
{
var c = GetEntryConfig(e);
if (c != null)
{
return !c.Allow.Contains(clientId);
}
return true;
};

var configOpt = new ConfigOpt(this.host.CustomConfig);
var config = GetConfigEntry(true);
var autoAllowS = config.Strings.ReadSafe("Auto Allow");
var autoAllow = autoAllowS != null && autoAllowS.Trim() != "";
autoAllow = autoAllow || configOpt.AlwaysAllowAccess;
var needPrompting = from e in items where filter(e.entry) select e;

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

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

var itemsList = items.ToList();

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

ulong lowestDistance = itemsList[0].entry.UsageCount;

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, 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();
}

foreach (var entryDatabase in itemsList)
{
var e = PrepareElementForResponseEntries(configOpt, entryDatabase);
resp.Entries.Add(e);
}

if (itemsList.Count > 0)
{
var names = (from e in resp.Entries select e.Name).Distinct<string>();
var n = String.Join("\n ", names.ToArray<string>());

if (configOpt.ReceiveCredentialNotification)
ShowNotification(String.Format("{0}: is receiving credentials for:\n {1}", r.Id, n));
}

resp.Success = true;
resp.Id = r.Id;
SetResponseVerifier(resp, aes);

foreach (var entry in resp.Entries)
{
entry.Name = CryptoTransform(entry.Name, false, true, aes, CMode.ENCRYPT);
entry.Login = CryptoTransform(entry.Login, false, true, aes, CMode.ENCRYPT);
entry.Uuid = CryptoTransform(entry.Uuid, false, true, aes, CMode.ENCRYPT);
entry.Password = CryptoTransform(entry.Password, false, true, aes, CMode.ENCRYPT);

if (entry.StringFields != null)
{
foreach (var sf in entry.StringFields)
{
sf.Key = CryptoTransform(sf.Key, false, true, aes, CMode.ENCRYPT);
sf.Value = CryptoTransform(sf.Value, false, true, aes, CMode.ENCRYPT);
}
}
}

resp.Count = resp.Entries.Count;
}
else
{
resp.Success = true;
resp.Id = r.Id;
SetResponseVerifier(resp, aes);
}
}

private IEnumerable<PwEntryDatabase> FindMatchingEntries(Request r, Aes aes)
{
string submitHost = null;
Expand Down Expand Up @@ -237,6 +376,54 @@ private IEnumerable<PwEntryDatabase> FindMatchingEntries(Request r, Aes aes)
return result;
}

private IEnumerable<PwEntryDatabase> FindMatchingEntriesLikeSearchbox(Request r, Aes aes)
{
string searchString = null;
string realm = null;
var listResult = new List<PwEntryDatabase>();
if (r.SearchString != null)
{
searchString = CryptoTransform(r.SearchString, true, false, aes, CMode.DECRYPT);
}

if (r.Realm != null)
realm = CryptoTransform(r.Realm, true, false, aes, CMode.DECRYPT);

var parms = MakeSearchParametersLikeSearchBox();

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

var configOpt = new ConfigOpt(this.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)
{
parms.SearchString = searchString;
var listEntries = new PwObjectList<PwEntry>();
db.RootGroup.SearchEntries(parms, listEntries);
foreach (var le in listEntries)
{
listResult.Add(new PwEntryDatabase(le, db));
}
}

return listResult;
}

private void GetLoginsCountHandler(Request r, Response resp, Aes aes)
{
if (!VerifyRequest(r, aes))
Expand Down Expand Up @@ -470,10 +657,17 @@ private ResponseEntry PrepareElementForResponseEntries(ConfigOpt configOpt, PwEn
fields = new List<ResponseStringField>();
foreach (var sf in entryDatabase.entry.Strings)
{
if (sf.Key.StartsWith("KPH: "))
var sfValue = entryDatabase.entry.Strings.ReadSafe(sf.Key);
if (configOpt.ReturnStringFieldsWithKphOnly)
{
if (sf.Key.StartsWith("KPH: "))
{
fields.Add(new ResponseStringField(sf.Key.Substring(5), sfValue));
}
}
else
{
var sfValue = entryDatabase.entry.Strings.ReadSafe(sf.Key);
fields.Add(new ResponseStringField(sf.Key.Substring(5), sfValue));
fields.Add(new ResponseStringField(sf.Key, sfValue));
}
}

Expand Down
17 changes: 17 additions & 0 deletions KeePassHttp/KeePassHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ private SearchParameters MakeSearchParameters()
return p;
}

private SearchParameters MakeSearchParametersLikeSearchBox()
{
var p = new SearchParameters();
p.SearchInTitles = true;
p.RegularExpression = false;
p.SearchInGroupNames = true;
p.SearchInNotes = true;
p.SearchInOther = true;
p.SearchInPasswords = true;
p.SearchInTags = true;
p.SearchInUrls = true;
p.SearchInUserNames = true;
p.SearchInUuids = true;
return p;
}

private string CryptoTransform(string input, bool base64in, bool base64out, Aes cipher, CMode mode)
{
byte[] bytes;
Expand Down Expand Up @@ -192,6 +208,7 @@ public override bool Initialize(IPluginHost host)
handlers.Add(Request.TEST_ASSOCIATE, TestAssociateHandler);
handlers.Add(Request.ASSOCIATE, AssociateHandler);
handlers.Add(Request.GET_LOGINS, GetLoginsHandler);
handlers.Add(Request.GET_LOGINS_CUSTOM_SEARCH, GetLoginsCustomSearchHandler);
handlers.Add(Request.GET_LOGINS_COUNT, GetLoginsCountHandler);
handlers.Add(Request.GET_ALL_LOGINS, GetAllLoginsHandler);
handlers.Add(Request.SET_LOGIN, SetLoginHandler);
Expand Down
Loading