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

Support multiple URLs in a single entry #1769

Closed
wants to merge 3 commits into from
Closed
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
32 changes: 30 additions & 2 deletions src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,14 @@ QList<Entry*> BrowserService::searchEntries(QSharedPointer<Database> db, const Q
return entries;
}

for (Entry* entry : EntrySearcher().search(baseDomain(hostname), rootGroup)) {
// XXX: will this include disabled entries or ones in recycle bin?
// TODO: check if this is compatible with https://github.com/keepassxreboot/keepassxc/pull/2253
for (Entry* entry : rootGroup->entriesRecursive()) {
if (matchAdditionalURLs(entry, hostname, url)) {
entries.append(entry);
continue;
}

QString entryUrl = entry->url();
QUrl entryQUrl(entryUrl);
QString entryScheme = entryQUrl.scheme();
Expand All @@ -405,13 +412,34 @@ QList<Entry*> BrowserService::searchEntries(QSharedPointer<Database> db, const Q
// Filter to match hostname in URL field
if ((!entryUrl.isEmpty() && hostname.contains(entryUrl))
|| (matchUrlScheme(entryUrl) && hostname.endsWith(entryQUrl.host()))) {
entries.append(entry);
entries.append(entry);
}
}

return entries;
}

bool BrowserService::matchAdditionalURLs(const Entry* entry, const QString& hostname, const QString& url)
{
for (QString altURL : entry->altURLs()) {
// TODO: match port and scheme
if (matchUrlScheme(altURL) && hostname.endsWith(QUrl(altURL).host())) {
return true;
}
}

for (QString regExURL : entry->regExURLs()) {
// XXX: does allowing arbitrary URLs bring security issues
QRegularExpression rx(regExURL);
auto match = rx.match(url);
if (match.hasMatch()) {
return true;
}
}

return false;
}

QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPairList& keyList)
{
// Get the list of databases to search
Expand Down
1 change: 1 addition & 0 deletions src/browser/BrowserService.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public slots:
int
sortPriority(const Entry* entry, const QString& host, const QString& submitUrl, const QString& baseSubmitUrl) const;
bool matchUrlScheme(const QString& url);
bool matchAdditionalURLs(const Entry* entry, const QString& hostname, const QString& url);
bool removeFirstDomain(QString& hostname);
QString baseDomain(const QString& url) const;
QSharedPointer<Database> getDatabase();
Expand Down
36 changes: 36 additions & 0 deletions src/core/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "core/Metadata.h"
#include "totp/totp.h"

#include <QDebug>
#include <QDir>
#include <QRegularExpression>
#include <utility>
Expand Down Expand Up @@ -394,6 +395,41 @@ QSharedPointer<Totp::Settings> Entry::totpSettings() const
return m_data.totpSettings;
}

QStringList Entry::additionalURLs(QString key) const
{
QStringList urlList;

if (m_attributes->hasKey(key)) {
urlList = m_attributes->value(key).split('\n', QString::SkipEmptyParts);
}

return urlList;
}

void Entry::migrateAttributes()
{
renameAttribute("altURLs", "URL_ALT");
renameAttribute("regExURLs", "URL_REGEX");
}

void Entry::renameAttribute(const QString& from, const QString& to)
{
if (m_attributes->hasKey(from)) {
qDebug() << "Migrate the attribute" << from << " in entry" << title() << "to" << to;
m_attributes->rename(from, to);
}
}

QStringList Entry::altURLs() const
{
return additionalURLs("URL_ALT");
}

QStringList Entry::regExURLs() const
{
return additionalURLs("URL_REGEX");
}

void Entry::setUuid(const QUuid& uuid)
{
Q_ASSERT(!uuid.isNull());
Expand Down
6 changes: 6 additions & 0 deletions src/core/Entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class Entry : public QObject
QString notes() const;
QString totp() const;
QSharedPointer<Totp::Settings> totpSettings() const;
QStringList altURLs() const;
QStringList regExURLs() const;

bool hasTotp() const;
bool isExpired() const;
Expand Down Expand Up @@ -218,6 +220,8 @@ class Entry : public QObject
bool canUpdateTimeinfo() const;
void setUpdateTimeinfo(bool value);

void migrateAttributes();

signals:
/**
* Emitted when a default attribute has been changed.
Expand All @@ -240,6 +244,8 @@ private slots:
static EntryReferenceType referenceType(const QString& referenceStr);

template <class T> bool set(T& property, const T& value);
QStringList additionalURLs(QString key) const;
void renameAttribute(const QString& from, const QString& to);

QUuid m_uuid;
EntryData m_data;
Expand Down
4 changes: 4 additions & 0 deletions src/format/KdbxXmlWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ void KdbxXmlWriter::writeRoot()

m_xml.writeStartElement("Root");

for (Entry* entry : m_db->rootGroup()->entriesRecursive()) {
entry->migrateAttributes();
}

writeGroup(m_db->rootGroup());
writeDeletedObjects();

Expand Down