diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 0861369e5..9521a7142 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -2533,6 +2533,14 @@ Disable safe saves and try again?
Database tab name modifier
+
+
+
+
+
+
+
+
@@ -3586,6 +3594,10 @@ This may cause the affected plugins to malfunction.
+
+
+
+
EntryAttachments
@@ -5738,6 +5750,10 @@ We recommend you use the AppImage available on our downloads page.
+
+
+
+
ManageDatabase
diff --git a/src/browser/BrowserSettingsWidget.ui b/src/browser/BrowserSettingsWidget.ui
index 3444b219a..a484c2ddd 100644
--- a/src/browser/BrowserSettingsWidget.ui
+++ b/src/browser/BrowserSettingsWidget.ui
@@ -487,7 +487,7 @@
-
-
+
-
diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp
index db1542c6c..77d37dc70 100644
--- a/src/core/Entry.cpp
+++ b/src/core/Entry.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2010 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -551,6 +551,12 @@ bool Entry::hasPasskey() const
return m_attributes->hasPasskey();
}
+void Entry::removePasskey()
+{
+ m_attributes->removePasskeyAttributes();
+ removeTag(tr("Passkey"));
+}
+
QString Entry::totp() const
{
if (hasTotp()) {
diff --git a/src/core/Entry.h b/src/core/Entry.h
index 796170514..359ce7a30 100644
--- a/src/core/Entry.h
+++ b/src/core/Entry.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2010 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -120,8 +120,10 @@ public:
bool excludeFromReports() const;
void setExcludeFromReports(bool state);
- bool hasTotp() const;
bool hasPasskey() const;
+ void removePasskey();
+
+ bool hasTotp() const;
bool isExpired() const;
bool willExpireInDays(int days) const;
bool isRecycled() const;
diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp
index 49c243ec1..a14ae7dde 100644
--- a/src/core/EntryAttributes.cpp
+++ b/src/core/EntryAttributes.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2012 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -65,6 +65,16 @@ bool EntryAttributes::hasPasskey() const
return false;
}
+void EntryAttributes::removePasskeyAttributes()
+{
+ const auto keyList = keys();
+ for (const auto& key : keyList) {
+ if (isPasskeyAttribute(key)) {
+ remove(key);
+ }
+ }
+}
+
QList EntryAttributes::customKeys() const
{
QList customKeys;
diff --git a/src/core/EntryAttributes.h b/src/core/EntryAttributes.h
index fecf6a993..ee814b03d 100644
--- a/src/core/EntryAttributes.h
+++ b/src/core/EntryAttributes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2012 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -34,6 +34,7 @@ public:
QList keys() const;
bool hasKey(const QString& key) const;
bool hasPasskey() const;
+ void removePasskeyAttributes();
QList customKeys() const;
QString value(const QString& key) const;
QList values(const QList& keys) const;
diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp
index 412bc95e4..805d4eabd 100644
--- a/src/gui/DatabaseTabWidget.cpp
+++ b/src/gui/DatabaseTabWidget.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
*
* 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
@@ -565,6 +565,11 @@ void DatabaseTabWidget::importPasskeyToEntry()
{
currentDatabaseWidget()->showImportPasskeyDialog(true);
}
+
+void DatabaseTabWidget::removePasskeyFromEntry()
+{
+ currentDatabaseWidget()->removePasskeyFromEntry();
+}
#endif
bool DatabaseTabWidget::isModified(int index) const
diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h
index 5c995b536..59e555451 100644
--- a/src/gui/DatabaseTabWidget.h
+++ b/src/gui/DatabaseTabWidget.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
*
* 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
@@ -87,6 +87,7 @@ public slots:
void showPasskeys();
void importPasskey();
void importPasskeyToEntry();
+ void removePasskeyFromEntry();
#endif
void performGlobalAutoType(const QString& search);
void performBrowserUnlock();
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 04c9e337b..2146f1aea 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -1428,6 +1428,22 @@ void DatabaseWidget::showImportPasskeyDialog(bool isEntry)
passkeyImporter.importPasskey(m_db);
}
}
+
+void DatabaseWidget::removePasskeyFromEntry()
+{
+ auto currentEntry = currentSelectedEntry();
+ if (!currentEntry) {
+ return;
+ }
+
+ auto result = MessageBox::question(this,
+ tr("Remove passkey from entry"),
+ tr("Do you want to remove the passkey from this entry?"),
+ MessageBox::Remove | MessageBox::Cancel);
+ if (result == MessageBox::Remove) {
+ currentEntry->removePasskey();
+ }
+}
#endif
void DatabaseWidget::performUnlockDatabase(const QString& password, const QString& keyfile)
@@ -2020,6 +2036,14 @@ bool DatabaseWidget::currentEntryHasSshKey()
}
#endif
+#ifdef WITH_XC_BROWSER_PASSKEYS
+bool DatabaseWidget::currentEntryHasPasskey()
+{
+ auto currentEntry = m_entryView->currentEntry();
+ return currentEntry && currentEntry->hasPasskey();
+}
+#endif
+
bool DatabaseWidget::currentEntryHasNotes()
{
auto currentEntry = currentSelectedEntry();
diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h
index 681260009..0b306d91d 100644
--- a/src/gui/DatabaseWidget.h
+++ b/src/gui/DatabaseWidget.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2010 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -212,6 +212,8 @@ public slots:
#ifdef WITH_XC_BROWSER_PASSKEYS
void switchToPasskeys();
void showImportPasskeyDialog(bool isEntry = false);
+ void removePasskeyFromEntry();
+ bool currentEntryHasPasskey();
#endif
void switchToOpenDatabase();
void switchToOpenDatabase(const QString& filePath);
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index cc7673fb6..4d4f2c23a 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 KeePassXC Team
+ * Copyright (C) 2024 KeePassXC Team
* Copyright (C) 2010 Felix Geyer
*
* This program is free software: you can redistribute it and/or modify
@@ -137,6 +137,7 @@ MainWindow::MainWindow()
m_entryContextMenu->addSeparator();
#ifdef WITH_XC_BROWSER_PASSKEYS
m_entryContextMenu->addAction(m_ui->actionEntryImportPasskey);
+ m_entryContextMenu->addAction(m_ui->actionEntryRemovePasskey);
m_entryContextMenu->addSeparator();
#endif
m_entryContextMenu->addAction(m_ui->actionEntryEdit);
@@ -446,6 +447,7 @@ MainWindow::MainWindow()
m_ui->actionPasskeys->setIcon(icons()->icon("passkey"));
m_ui->actionImportPasskey->setIcon(icons()->icon("document-import"));
m_ui->actionEntryImportPasskey->setIcon(icons()->icon("document-import"));
+ m_ui->actionEntryRemovePasskey->setIcon(icons()->icon("document-close"));
#endif
m_actionMultiplexer.connect(
@@ -497,6 +499,7 @@ MainWindow::MainWindow()
connect(m_ui->actionPasskeys, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showPasskeys()));
connect(m_ui->actionImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskey()));
connect(m_ui->actionEntryImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskeyToEntry()));
+ connect(m_ui->actionEntryRemovePasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(removePasskeyFromEntry()));
#endif
connect(m_ui->actionImport, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importFile()));
connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToCsv()));
@@ -990,9 +993,11 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionExportXML->setEnabled(true);
m_ui->actionDatabaseMerge->setEnabled(m_ui->tabWidget->currentIndex() != -1);
#ifdef WITH_XC_BROWSER_PASSKEYS
+ bool singleEntryHasPasskey = singleEntrySelected && dbWidget->currentEntryHasPasskey();
m_ui->actionPasskeys->setEnabled(true);
m_ui->actionImportPasskey->setEnabled(true);
m_ui->actionEntryImportPasskey->setEnabled(singleEntrySelected);
+ m_ui->actionEntryRemovePasskey->setEnabled(singleEntryHasPasskey);
#endif
#ifdef WITH_XC_SSHAGENT
bool singleEntryHasSshKey =
@@ -1064,10 +1069,12 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionPasskeys->setEnabled(false);
m_ui->actionImportPasskey->setEnabled(false);
m_ui->actionEntryImportPasskey->setEnabled(false);
+ m_ui->actionEntryRemovePasskey->setEnabled(false);
#else
m_ui->actionPasskeys->setVisible(false);
m_ui->actionImportPasskey->setVisible(false);
m_ui->actionEntryImportPasskey->setVisible(false);
+ m_ui->actionEntryRemovePasskey->setVisible(false);
#endif
m_searchWidgetAction->setEnabled(false);
diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui
index a1dc25c58..84b4b751e 100644
--- a/src/gui/MainWindow.ui
+++ b/src/gui/MainWindow.ui
@@ -335,6 +335,7 @@
+
@@ -733,6 +734,14 @@
Import Passkey
+
+
+ false
+
+
+ Remove Passkey From Entry
+
+
false
diff --git a/src/gui/SearchHelpWidget.ui b/src/gui/SearchHelpWidget.ui
index 907b2822d..d9778fd22 100644
--- a/src/gui/SearchHelpWidget.ui
+++ b/src/gui/SearchHelpWidget.ui
@@ -388,7 +388,7 @@
-
-
+
0