Skip to content

Commit

Permalink
Merge pull request #28 from keepassxreboot/develop
Browse files Browse the repository at this point in the history
Fork Sync: Update from parent repository
  • Loading branch information
libf-de authored Nov 24, 2023
2 parents 6e730c1 + cc0530b commit 4957221
Show file tree
Hide file tree
Showing 32 changed files with 472 additions and 191 deletions.
2 changes: 1 addition & 1 deletion cmake/FindBotan.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ include(FindPackageHandleStandardArgs)

set(BOTAN_VERSIONS botan-3 botan-2)
set(BOTAN_NAMES botan-3 botan-2 botan)
set(BOTAN_NAMES_DEBUG botand-3 botand-2 botand botan)
set(BOTAN_NAMES_DEBUG botand-3 botand-2 botand botan botan-3)

find_path(
BOTAN_INCLUDE_DIR
Expand Down
39 changes: 27 additions & 12 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,15 @@ Do you want to delete the entry?
<source>%1 (Passkey)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>KeePassXC: Update Passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Entry already has a Passkey.
Do you want to overwrite the Passkey in %1 - %2?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BrowserSettingsWidget</name>
Expand Down Expand Up @@ -5993,51 +6002,51 @@ Do you want to overwrite it?
<translation type="unfinished"></translation>
</message>
<message>
<source>Do you want to import the Passkey?</source>
<source>URL: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>URL: %1</source>
<source>Username: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Username: %1</source>
<source>Group</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use default group (Imported Passkeys)</source>
<source>Database</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Group</source>
<source>Import Passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Database</source>
<source>Import</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select Database</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import Passkey</source>
<source>Import the following Passkey:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import</source>
<source>Entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<source>Import the following Passkey to this entry:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Database: %1</source>
<source>Create new entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Group:</source>
<source>Default Passkeys group (Imported Passkeys)</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down Expand Up @@ -6075,6 +6084,12 @@ Do you want to overwrite it?
<source>Cannot import Passkey file &quot;%1&quot;. Private key is missing or malformed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import Passkey file &quot;%1&quot;.
The following data is missing:
%2</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PasswordEditWidget</name>
Expand Down
2 changes: 2 additions & 0 deletions src/browser/BrowserAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ QJsonObject BrowserAction::handleGeneratePassword(QLocalSocket* socket, const QJ
errorReply["requestID"] = requestId;
}

// Show the existing password generator
browserService()->showPasswordGenerator({});
return errorReply;
}

Expand Down
59 changes: 46 additions & 13 deletions src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ const QString BrowserService::OPTION_HIDE_ENTRY = QStringLiteral("BrowserHideEnt
const QString BrowserService::OPTION_ONLY_HTTP_AUTH = QStringLiteral("BrowserOnlyHttpAuth");
const QString BrowserService::OPTION_NOT_HTTP_AUTH = QStringLiteral("BrowserNotHttpAuth");
const QString BrowserService::OPTION_OMIT_WWW = QStringLiteral("BrowserOmitWww");
// Multiple URL's
const QString BrowserService::ADDITIONAL_URL = QStringLiteral("KP2A_URL");

Q_GLOBAL_STATIC(BrowserService, s_browserService);

Expand All @@ -74,7 +72,6 @@ BrowserService::BrowserService()
, m_browserHost(new BrowserHost)
, m_dialogActive(false)
, m_bringToFrontRequested(false)
, m_passwordGeneratorRequested(false)
, m_prevWindowState(WindowState::Normal)
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
{
Expand Down Expand Up @@ -512,7 +509,7 @@ QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& entriesToConfirm,
void BrowserService::showPasswordGenerator(const KeyPairMessage& keyPairMessage)
{
if (!m_passwordGenerator) {
m_passwordGenerator.reset(PasswordGeneratorWidget::popupGenerator(m_currentDatabaseWidget));
m_passwordGenerator = PasswordGeneratorWidget::popupGenerator();

connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::closed, m_passwordGenerator.data(), [=] {
if (!m_passwordGenerator->isPasswordGenerated()) {
Expand All @@ -521,9 +518,7 @@ void BrowserService::showPasswordGenerator(const KeyPairMessage& keyPairMessage)
m_browserHost->sendClientMessage(keyPairMessage.socket, errorMessage);
}

m_passwordGenerator.reset();
hideWindow();
m_passwordGeneratorRequested = false;
QTimer::singleShot(50, this, [&] { hideWindow(); });
});

connect(m_passwordGenerator.data(),
Expand All @@ -537,19 +532,18 @@ void BrowserService::showPasswordGenerator(const KeyPairMessage& keyPairMessage)
params,
keyPairMessage.publicKey,
keyPairMessage.secretKey));
hideWindow();
});
}

m_passwordGeneratorRequested = true;
raiseWindow();
m_passwordGenerator->show();
m_passwordGenerator->raise();
m_passwordGenerator->activateWindow();
}

bool BrowserService::isPasswordGeneratorRequested() const
{
return m_passwordGeneratorRequested;
return m_passwordGenerator && m_passwordGenerator->isVisible();
}

QString BrowserService::storeKey(const QString& key)
Expand Down Expand Up @@ -779,6 +773,20 @@ void BrowserService::addPasskeyToEntry(Entry* entry,
return;
}

// Ask confirmation if entry already contains a Passkey
if (entry->hasPasskey()) {
if (MessageBox::question(
m_currentDatabaseWidget,
tr("KeePassXC: Update Passkey"),
tr("Entry already has a Passkey.\nDo you want to overwrite the Passkey in %1 - %2?")
.arg(entry->title(), entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USERNAME)),
MessageBox::Overwrite | MessageBox::Cancel,
MessageBox::Cancel)
!= MessageBox::Overwrite) {
return;
}
}

entry->beginUpdate();

entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_USERNAME, username);
Expand Down Expand Up @@ -1088,7 +1096,13 @@ void BrowserService::denyEntry(Entry* entry, const QString& siteHost, const QStr
QJsonObject BrowserService::prepareEntry(const Entry* entry)
{
QJsonObject res;
#ifdef WITH_XC_BROWSER_PASSKEYS
// Use Passkey's username instead if found
res["login"] = entry->hasPasskey() ? entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USERNAME)
: entry->resolveMultiplePlaceholders(entry->username());
#else
res["login"] = entry->resolveMultiplePlaceholders(entry->username());
#endif
res["password"] = entry->resolveMultiplePlaceholders(entry->password());
res["name"] = entry->resolveMultiplePlaceholders(entry->title());
res["uuid"] = entry->resolveMultiplePlaceholders(entry->uuidToHex());
Expand Down Expand Up @@ -1295,8 +1309,7 @@ QList<Entry*> BrowserService::getPasskeyEntries(const QString& rpId, const Strin
{
QList<Entry*> entries;
for (const auto& entry : searchEntries(rpId, "", keyList, true)) {
if (entry->attributes()->hasKey(BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM)
&& entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY) == rpId) {
if (entry->hasPasskey() && entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY) == rpId) {
entries << entry;
}
}
Expand Down Expand Up @@ -1423,14 +1436,34 @@ bool BrowserService::handleURL(const QString& entryUrl,
return false;
}

QSharedPointer<Database> BrowserService::getDatabase()
QSharedPointer<Database> BrowserService::getDatabase(const QUuid& rootGroupUuid)
{
if (!rootGroupUuid.isNull()) {
const auto openDatabases = getOpenDatabases();
for (const auto& db : openDatabases) {
if (db->rootGroup()->uuid() == rootGroupUuid) {
return db;
}
}
}

if (m_currentDatabaseWidget) {
return m_currentDatabaseWidget->database();
}
return {};
}

QList<QSharedPointer<Database>> BrowserService::getOpenDatabases()
{
QList<QSharedPointer<Database>> databaseList;
for (auto dbWidget : getMainWindow()->getOpenDatabases()) {
if (!dbWidget->isLocked()) {
databaseList << dbWidget->database();
}
}
return databaseList;
}

QSharedPointer<Database> BrowserService::selectedDatabase()
{
QList<DatabaseWidget*> databaseWidgets;
Expand Down
7 changes: 3 additions & 4 deletions src/browser/BrowserService.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ class BrowserService : public QObject
QString getCurrentTotp(const QString& uuid);
void showPasswordGenerator(const KeyPairMessage& keyPairMessage);
bool isPasswordGeneratorRequested() const;
QSharedPointer<Database> getDatabase(const QUuid& rootGroupUuid = {});
QSharedPointer<Database> selectedDatabase();
QList<QSharedPointer<Database>> getOpenDatabases();
#ifdef WITH_XC_BROWSER_PASSKEYS
QJsonObject
showPasskeysRegisterPrompt(const QJsonObject& publicKey, const QString& origin, const StringPairList& keyList);
Expand Down Expand Up @@ -124,7 +126,6 @@ class BrowserService : public QObject
static const QString OPTION_ONLY_HTTP_AUTH;
static const QString OPTION_NOT_HTTP_AUTH;
static const QString OPTION_OMIT_WWW;
static const QString ADDITIONAL_URL;

signals:
void requestUnlock();
Expand Down Expand Up @@ -191,7 +192,6 @@ private slots:
const QString& siteUrl,
const QString& formUrl,
const bool omitWwwSubdomain = false);
QSharedPointer<Database> getDatabase();
QString getDatabaseRootUuid();
QString getDatabaseRecycleBinUuid();
bool checkLegacySettings(QSharedPointer<Database> db);
Expand All @@ -204,12 +204,11 @@ private slots:

bool m_dialogActive;
bool m_bringToFrontRequested;
bool m_passwordGeneratorRequested;
WindowState m_prevWindowState;
QUuid m_keepassBrowserUUID;

QPointer<DatabaseWidget> m_currentDatabaseWidget;
QScopedPointer<PasswordGeneratorWidget> m_passwordGenerator;
QPointer<PasswordGeneratorWidget> m_passwordGenerator;

Q_DISABLE_COPY(BrowserService);

Expand Down
8 changes: 7 additions & 1 deletion src/core/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@ QStringList Entry::getAllUrls() const
}

for (const auto& key : m_attributes->keys()) {
if (key.startsWith("KP2A_URL")) {
if (key.startsWith(EntryAttributes::AdditionalUrlAttribute)
|| key == QString("%1_RELYING_PARTY").arg(EntryAttributes::PasskeyAttribute)) {
auto additionalUrl = m_attributes->value(key);
if (!additionalUrl.isEmpty()) {
urlList << resolveMultiplePlaceholders(additionalUrl);
Expand Down Expand Up @@ -545,6 +546,11 @@ bool Entry::hasTotp() const
return !m_data.totpSettings.isNull();
}

bool Entry::hasPasskey() const
{
return m_attributes->hasPasskey();
}

QString Entry::totp() const
{
if (hasTotp()) {
Expand Down
1 change: 1 addition & 0 deletions src/core/Entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class Entry : public ModifiableObject
void setExcludeFromReports(bool state);

bool hasTotp() const;
bool hasPasskey() const;
bool isExpired() const;
bool willExpireInDays(int days) const;
bool isRecycled() const;
Expand Down
13 changes: 13 additions & 0 deletions src/core/EntryAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const QString EntryAttributes::SearchInGroupName = "SearchIn";
const QString EntryAttributes::SearchTextGroupName = "SearchText";

const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
const QString EntryAttributes::AdditionalUrlAttribute = "KP2A_URL";
const QString EntryAttributes::PasskeyAttribute = "KPEX_PASSKEY";

EntryAttributes::EntryAttributes(QObject* parent)
Expand All @@ -52,6 +53,18 @@ bool EntryAttributes::hasKey(const QString& key) const
return m_attributes.contains(key);
}

bool EntryAttributes::hasPasskey() const
{
const auto keyList = keys();
for (const auto& key : keyList) {
if (isPasskeyAttribute(key)) {
return true;
}
}

return false;
}

QList<QString> EntryAttributes::customKeys() const
{
QList<QString> customKeys;
Expand Down
4 changes: 3 additions & 1 deletion src/core/EntryAttributes.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2023 KeePassXC Team <[email protected]>
* Copyright (C) 2012 Felix Geyer <[email protected]>
* Copyright (C) 2017 KeePassXC Team <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -33,6 +33,7 @@ class EntryAttributes : public ModifiableObject
explicit EntryAttributes(QObject* parent = nullptr);
QList<QString> keys() const;
bool hasKey(const QString& key) const;
bool hasPasskey() const;
QList<QString> customKeys() const;
QString value(const QString& key) const;
QList<QString> values(const QList<QString>& keys) const;
Expand Down Expand Up @@ -61,6 +62,7 @@ class EntryAttributes : public ModifiableObject
static const QString NotesKey;
static const QStringList DefaultAttributes;
static const QString RememberCmdExecAttr;
static const QString AdditionalUrlAttribute;
static const QString PasskeyAttribute;
static bool isDefaultAttribute(const QString& key);
static bool isPasskeyAttribute(const QString& key);
Expand Down
14 changes: 14 additions & 0 deletions src/core/Tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "core/Global.h"

#include <QDateTime>
#include <QList>
#include <QProcessEnvironment>

class QIODevice;
Expand Down Expand Up @@ -100,6 +101,19 @@ namespace Tools
return version;
}

// Checks if all values are found inside the list. Returns a list of values not found.
template <typename T> QList<T> getMissingValuesFromList(const QList<T>& list, const QList<T>& required)
{
QList<T> missingValues;
for (const auto& r : required) {
if (!list.contains(r)) {
missingValues << r;
}
}

return missingValues;
}

QVariantMap qo2qvm(const QObject* object, const QStringList& ignoredProperties = {"objectName"});

QString substituteBackupFilePath(QString pattern, const QString& databasePath);
Expand Down
Loading

0 comments on commit 4957221

Please sign in to comment.