Skip to content

Commit

Permalink
Add support for multiple URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
varjolintu committed Sep 21, 2019
1 parent 344198b commit 772a8af
Show file tree
Hide file tree
Showing 11 changed files with 633 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ add_subdirectory(proxy)
if(WITH_XC_BROWSER)
set(keepassxcbrowser_LIB keepassxcbrowser)
set(keepassx_SOURCES ${keepassx_SOURCES} gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp)
set(keepassx_SOURCES ${keepassx_SOURCES} gui/entry/EntryURLModel.cpp)
endif()

add_subdirectory(autotype)
Expand Down
96 changes: 68 additions & 28 deletions src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@
#include "gui/macutils/MacUtils.h"
#endif

const char BrowserService::KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
const char BrowserService::KEEPASSXCBROWSER_OLD_NAME[] = "keepassxc-browser Settings";
const char BrowserService::ASSOCIATE_KEY_PREFIX[] = "KPXC_BROWSER_";
static const char KEEPASSXCBROWSER_GROUP_NAME[] = "KeePassXC-Browser Passwords";
const QString BrowserService::KEEPASSXCBROWSER_NAME = QStringLiteral("KeePassXC-Browser Settings");
const QString BrowserService::KEEPASSXCBROWSER_OLD_NAME = QStringLiteral("keepassxc-browser Settings");
const QString BrowserService::ASSOCIATE_KEY_PREFIX = QStringLiteral("KPXC_BROWSER_");
static const QString KEEPASSXCBROWSER_GROUP_NAME = QStringLiteral("KeePassXC-Browser Passwords");
static int KEEPASSXCBROWSER_DEFAULT_ICON = 1;
// These are for the settings and password conversion
const char BrowserService::LEGACY_ASSOCIATE_KEY_PREFIX[] = "Public Key: ";
static const char KEEPASSHTTP_NAME[] = "KeePassHttp Settings";
static const char KEEPASSHTTP_GROUP_NAME[] = "KeePassHttp Passwords";
const QString BrowserService::LEGACY_ASSOCIATE_KEY_PREFIX = QStringLiteral("Public Key: ");
static const QString KEEPASSHTTP_NAME = QStringLiteral("KeePassHttp Settings");
static const QString KEEPASSHTTP_GROUP_NAME = QStringLiteral("KeePassHttp Passwords");
// Extra entry related options saved in custom data
const QString BrowserService::OPTION_SKIP_AUTO_SUBMIT = QStringLiteral("BrowserSkipAutoSubmit");
const QString BrowserService::OPTION_HIDE_ENTRY = QStringLiteral("BrowserHideEntry");

BrowserService::BrowserService(DatabaseTabWidget* parent)
: m_dbTabWidget(parent)
Expand Down Expand Up @@ -317,7 +320,7 @@ QString BrowserService::storeKey(const QString& key)
return {};
}

contains = db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
contains = db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + id);
if (contains) {
dialogResult = MessageBox::warning(nullptr,
tr("KeePassXC: Overwrite existing key?"),
Expand All @@ -330,7 +333,7 @@ QString BrowserService::storeKey(const QString& key)
} while (contains && dialogResult == MessageBox::Cancel);

hideWindow();
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key);
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + id, key);
return id;
}

Expand All @@ -341,7 +344,7 @@ QString BrowserService::getKey(const QString& id)
return {};
}

return db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
return db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + id);
}

QJsonArray BrowserService::findMatchingEntries(const QString& id,
Expand Down Expand Up @@ -374,7 +377,12 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id,
// Check entries for authorization
QList<Entry*> pwEntriesToConfirm;
QList<Entry*> pwEntries;
for (Entry* entry : searchEntries(url, keyList)) {
for (auto* entry : searchEntries(url, keyList)) {
if (entry->customData()->contains(BrowserService::OPTION_HIDE_ENTRY) &&
entry->customData()->value(BrowserService::OPTION_HIDE_ENTRY) == "true") {
continue;
}

// HTTP Basic Auth always needs a confirmation
if (!ignoreHttpAuth && httpAuth) {
pwEntriesToConfirm.append(entry);
Expand Down Expand Up @@ -417,7 +425,7 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id,
pwEntries = sortEntries(pwEntries, host, submitUrl);

// Fill the list
for (Entry* entry : pwEntries) {
for (auto* entry : pwEntries) {
result.append(prepareEntry(entry));
}

Expand Down Expand Up @@ -580,8 +588,7 @@ BrowserService::searchEntries(const QSharedPointer<Database>& db, const QString&
return entries;
}

for (Entry* entry : EntrySearcher().search(baseDomain(hostname), rootGroup)) {
QString entryUrl = entry->url();
auto handleURL = [&](const QString entryUrl) {
QUrl entryQUrl(entryUrl);
QString entryScheme = entryQUrl.scheme();
QUrl qUrl(url);
Expand All @@ -590,13 +597,42 @@ BrowserService::searchEntries(const QSharedPointer<Database>& db, const QString&
if ((entryQUrl.port() > 0 && entryQUrl.port() != qUrl.port())
|| (browserSettings()->matchUrlScheme() && !entryScheme.isEmpty()
&& entryScheme.compare(qUrl.scheme()) != 0)) {
continue;
return false;
}

// Filter to match hostname in URL field
if ((!entryUrl.isEmpty() && hostname.contains(entryUrl))
|| (matchUrlScheme(entryUrl) && hostname.endsWith(entryQUrl.host()))) {
entries.append(entry);
return true;
}
return false;
};

// Search host from URL fields
for (auto* entry : EntrySearcher().search(baseDomain(hostname), rootGroup)) {
if (!handleURL(entry->url())) {
continue;
}

entries.append(entry);
}

// Search for additional URL's starting with KP2A_URL
for (const auto group : rootGroup->groupsRecursive(true)) {
if (group->isRecycled() || !group->resolveSearchingEnabled()) {
continue;
}

for (auto* entry : group->entries()) {
if (entry->isRecycled() || !entry->attributes()->keys().contains("KP2A_URL")) {
continue;
}

for (const auto& key : entry->attributes()->keys()) {
if (key.contains("KP2A_URL") && handleURL(entry->attributes()->value(key))) {
entries.append(entry);
}
}
}
}

Expand All @@ -613,9 +649,9 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
if (auto* dbWidget = qobject_cast<DatabaseWidget*>(m_dbTabWidget->widget(i))) {
if (const auto& db = dbWidget->database()) {
// Check if database is connected with KeePassXC-Browser
for (const StringPair& keyPair : keyList) {
for (const auto& keyPair : keyList) {
QString key =
db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + keyPair.first);
db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + keyPair.first);
if (!key.isEmpty() && keyPair.second == key) {
databases << db;
}
Expand Down Expand Up @@ -652,7 +688,7 @@ void BrowserService::convertAttributesToCustomData(const QSharedPointer<Database

int counter = 0;
int keyCounter = 0;
for (Entry* entry : entries) {
for (auto* entry : entries) {
if (progress.wasCanceled()) {
return;
}
Expand Down Expand Up @@ -705,10 +741,10 @@ void BrowserService::convertAttributesToCustomData(const QSharedPointer<Database
return;
}

const QString keePassBrowserGroupName = QLatin1String(KEEPASSXCBROWSER_GROUP_NAME);
const QString keePassHttpGroupName = QLatin1String(KEEPASSHTTP_GROUP_NAME);
const QString keePassBrowserGroupName = QLatin1String(KEEPASSXCBROWSER_GROUP_NAME.toUtf8());
const QString keePassHttpGroupName = QLatin1String(KEEPASSHTTP_GROUP_NAME.toUtf8());

for (Group* g : rootGroup->groupsRecursive(true)) {
for (auto* g : rootGroup->groupsRecursive(true)) {
if (g->name() == keePassHttpGroupName) {
g->setName(keePassBrowserGroupName);
break;
Expand All @@ -729,7 +765,7 @@ QList<Entry*> BrowserService::sortEntries(QList<Entry*>& pwEntries, const QStrin

// Build map of prioritized entries
QMultiMap<int, Entry*> priorities;
for (Entry* entry : pwEntries) {
for (auto* entry : pwEntries) {
priorities.insert(sortPriority(entry, host, submitUrl, baseSubmitUrl), entry);
}

Expand Down Expand Up @@ -785,7 +821,7 @@ bool BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,

int res = accessControlDialog.exec();
if (accessControlDialog.remember()) {
for (Entry* entry : pwEntriesToConfirm) {
for (auto* entry : pwEntriesToConfirm) {
BrowserEntryConfig config;
config.load(entry);
if (res == QDialog::Accepted) {
Expand Down Expand Up @@ -830,10 +866,14 @@ QJsonObject BrowserService::prepareEntry(const Entry* entry)
res["expired"] = "true";
}

if (entry->customData()->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) {
res["skipAutoSubmit"] = entry->customData()->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT);
}

if (browserSettings()->supportKphFields()) {
const EntryAttributes* attr = entry->attributes();
QJsonArray stringFields;
for (const QString& key : attr->keys()) {
for (const auto& key : attr->keys()) {
if (key.startsWith(QLatin1String("KPH: "))) {
QJsonObject sField;
sField[key] = entry->resolveMultiplePlaceholders(attr->value(key));
Expand Down Expand Up @@ -879,7 +919,7 @@ Group* BrowserService::getDefaultEntryGroup(const QSharedPointer<Database>& sele
return nullptr;
}

const QString groupName = QLatin1String(KEEPASSXCBROWSER_GROUP_NAME);
const QString groupName = QLatin1String(KEEPASSXCBROWSER_GROUP_NAME.toUtf8());

for (auto* g : rootGroup->groupsRecursive(true)) {
if (g->name() == groupName && !g->isRecycled()) {
Expand Down Expand Up @@ -1060,8 +1100,8 @@ int BrowserService::moveKeysToCustomData(Entry* entry, const QSharedPointer<Data
publicKey.remove(LEGACY_ASSOCIATE_KEY_PREFIX);

// Add key to database custom data
if (db && !db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + publicKey)) {
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + publicKey,
if (db && !db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + publicKey)) {
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX.toUtf8()) + publicKey,
entry->attributes()->value(key));
++keyCounter;
}
Expand Down
10 changes: 6 additions & 4 deletions src/browser/BrowserService.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ class BrowserService : public QObject
void convertAttributesToCustomData(const QSharedPointer<Database>& currentDb = {});

public:
static const char KEEPASSXCBROWSER_NAME[];
static const char KEEPASSXCBROWSER_OLD_NAME[];
static const char ASSOCIATE_KEY_PREFIX[];
static const char LEGACY_ASSOCIATE_KEY_PREFIX[];
static const QString KEEPASSXCBROWSER_NAME;
static const QString KEEPASSXCBROWSER_OLD_NAME;
static const QString ASSOCIATE_KEY_PREFIX;
static const QString LEGACY_ASSOCIATE_KEY_PREFIX;
static const QString OPTION_SKIP_AUTO_SUBMIT;
static const QString OPTION_HIDE_ENTRY;

public slots:
QJsonArray findMatchingEntries(const QString& id,
Expand Down
Loading

0 comments on commit 772a8af

Please sign in to comment.