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

Passkeys: Register to an existing entry #10408

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
114 changes: 65 additions & 49 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,32 +871,36 @@ Please select the correct database for saving credentials.</source>
</translation>
</message>
<message>
<source>Do you want to register Passkey for:</source>
<source>Relying Party: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Existing Passkey found.
Do you want to register a new Passkey for:</source>
<source>Username: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select the existing Passkey and press Update to replace it.</source>
<source>KeePassXC - Passkey credentials</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Authenticate Passkey credentials for:</source>
<source>Add to existing entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Relying Party: %1</source>
<source>Existing passkey found.
Do you want to register a new passkey for:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Username: %1</source>
<source>Select the existing passkey and press Update to replace it.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>KeePassXC - Passkey credentials</source>
<source>Authenticate passkey credentials for:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Do you want to register a passkey for:</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down Expand Up @@ -939,11 +943,6 @@ Do you want to delete the entry?
<source>%1 (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>
<message>
<source>KeePassXC - Create a new group</source>
<translation type="unfinished"></translation>
Expand All @@ -956,10 +955,6 @@ Do you want to overwrite the Passkey in %1 - %2?</source>
<source>KeePassXC - Overwrite existing key?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>KeePassXC - Update Passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>KeePassXC - Update Entry</source>
<translation type="unfinished"></translation>
Expand All @@ -976,6 +971,27 @@ Do you want to overwrite the Passkey in %1 - %2?</source>
<source>Passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>KeePassXC - Passkey credentials</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Register a new passkey to this entry:</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>
<message>
<source>Register</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BrowserSettingsWidget</name>
Expand Down Expand Up @@ -1223,11 +1239,11 @@ Do you want to overwrite the Passkey in %1 - %2?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Allows using insecure http://localhost with Passkeys for testing purposes.</source>
<source>Allows using insecure http://localhost with passkeys for testing purposes.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Allow using localhost with Passkeys</source>
<source>Allow using localhost with passkeys</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down Expand Up @@ -6214,10 +6230,6 @@ We recommend you use the AppImage available on our downloads page.</source>
<source>KeePassXC - Passkey Export</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Export the following Passkey entries.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Filenames will be generated with title and .passkey file extension.</source>
<translation type="unfinished"></translation>
Expand All @@ -6238,6 +6250,10 @@ We recommend you use the AppImage available on our downloads page.</source>
<source>Export to folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Export the following passkey entries.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PasskeyExporter</name>
Expand Down Expand Up @@ -6295,27 +6311,27 @@ Do you want to overwrite it?
<translation type="unfinished"></translation>
</message>
<message>
<source>Import the following Passkey:</source>
<source>Entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Entry</source>
<source>Create new entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import the following Passkey to this entry:</source>
<source>Relying Party: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Create new entry</source>
<source>Import the following passkey:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Default Passkeys group (Imported Passkeys)</source>
<source>Import the following passkey to this entry:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Relying Party: %1</source>
<source>Default passkeys group (Imported Passkeys)</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand All @@ -6329,10 +6345,6 @@ Do you want to overwrite it?
<source>All files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open Passkey file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot open file</source>
<translation type="unfinished"></translation>
Expand All @@ -6342,23 +6354,27 @@ Do you want to overwrite it?
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import Passkey</source>
<source>Open passkey file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import Passkey file &quot;%1&quot;. Data is missing.</source>
<source>Cannot import passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import Passkey file &quot;%1&quot;. Private key is missing or malformed.</source>
<source>Cannot import passkey file &quot;%1&quot;. Data is missing.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import Passkey file &quot;%1&quot;.
<source>Cannot import passkey file &quot;%1&quot;.
The following data is missing:
%2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot import passkey file &quot;%1&quot;. Private key is missing or malformed.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PasswordEditWidget</name>
Expand Down Expand Up @@ -8584,10 +8600,6 @@ This option is deprecated, use --set-key-file instead.</source>
<source>Wait for timer to expire</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unknown Passkeys error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Challenge is shorter than required minimum length</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -8682,6 +8694,10 @@ This option is deprecated, use --set-key-file instead.</source>
<source>Unsupported KDF type, cannot decrypt json file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unknown passkeys error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtIOCompressor</name>
Expand Down Expand Up @@ -9008,14 +9024,6 @@ This option is deprecated, use --set-key-file instead.</source>
<source>List of entry URLs</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Please wait, list of entries with Passkeys is being updated…</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No entries with Passkeys.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Title</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -9063,6 +9071,14 @@ This option is deprecated, use --set-key-file instead.</source>
<source>The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Please wait, list of entries with passkeys is being updated…</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No entries with passkeys.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ReportsWidgetStatistics</name>
Expand Down
2 changes: 1 addition & 1 deletion src/browser/BrowserMessageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ QString BrowserMessageBuilder::getErrorMessage(const int errorCode) const
case ERROR_PASSKEYS_WAIT_FOR_LIFETIMER:
return QObject::tr("Wait for timer to expire");
case ERROR_PASSKEYS_UNKNOWN_ERROR:
return QObject::tr("Unknown Passkeys error");
return QObject::tr("Unknown passkeys error");
case ERROR_PASSKEYS_INVALID_CHALLENGE:
return QObject::tr("Challenge is shorter than required minimum length");
case ERROR_PASSKEYS_INVALID_USER_ID:
Expand Down
17 changes: 9 additions & 8 deletions src/browser/BrowserPasskeysConfirmationDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2024 KeePassXC Team <team@keepassxc.org>
*
* 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 @@ -32,7 +32,6 @@ BrowserPasskeysConfirmationDialog::BrowserPasskeysConfirmationDialog(QWidget* pa
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);

m_ui->setupUi(this);
m_ui->updateButton->setVisible(false);
m_ui->verticalLayout->setAlignment(Qt::AlignTop);

connect(m_ui->credentialsTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(accept()));
Expand All @@ -53,21 +52,22 @@ void BrowserPasskeysConfirmationDialog::registerCredential(const QString& userna
const QList<Entry*>& existingEntries,
int timeout)
{
m_ui->firstLabel->setText(tr("Do you want to register Passkey for:"));
m_ui->firstLabel->setText(tr("Do you want to register a passkey for:"));
m_ui->relyingPartyLabel->setText(tr("Relying Party: %1").arg(relyingParty));
m_ui->usernameLabel->setText(tr("Username: %1").arg(username));
m_ui->updateButton->setVisible(true);
m_ui->secondLabel->setText("");

if (!existingEntries.isEmpty()) {
droidmonkey marked this conversation as resolved.
Show resolved Hide resolved
m_ui->firstLabel->setText(tr("Existing Passkey found.\nDo you want to register a new Passkey for:"));
m_ui->secondLabel->setText(tr("Select the existing Passkey and press Update to replace it."));

m_ui->updateButton->setVisible(true);
m_ui->firstLabel->setText(tr("Existing passkey found.\nDo you want to register a new passkey for:"));
m_ui->secondLabel->setText(tr("Select the existing passkey and press Update to replace it."));
m_ui->updateButton->setText(tr("Update"));
m_ui->confirmButton->setText(tr("Register new"));
updateEntriesToTable(existingEntries);
} else {
m_ui->verticalLayout->setSizeConstraint(QLayout::SetFixedSize);
m_ui->confirmButton->setText(tr("Register"));
m_ui->updateButton->setText(tr("Add to existing entry"));
varjolintu marked this conversation as resolved.
Show resolved Hide resolved
m_ui->credentialsTable->setVisible(false);
}

Expand All @@ -78,9 +78,10 @@ void BrowserPasskeysConfirmationDialog::authenticateCredential(const QList<Entry
const QString& relyingParty,
int timeout)
{
m_ui->firstLabel->setText(tr("Authenticate Passkey credentials for:"));
m_ui->firstLabel->setText(tr("Authenticate passkey credentials for:"));
m_ui->relyingPartyLabel->setText(tr("Relying Party: %1").arg(relyingParty));
m_ui->usernameLabel->setVisible(false);
m_ui->updateButton->setVisible(false);
m_ui->secondLabel->setText("");
updateEntriesToTable(entries);
startCounter(timeout);
Expand Down
39 changes: 30 additions & 9 deletions src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "BrowserPasskeysClient.h"
#include "BrowserPasskeysConfirmationDialog.h"
#include "PasskeyUtils.h"
#include "gui/passkeys/PasskeyImporter.h"
#endif
#ifdef Q_OS_MACOS
#include "gui/osutils/macutils/MacUtils.h"
Expand Down Expand Up @@ -658,13 +659,33 @@ QJsonObject BrowserService::showPasskeysRegisterPrompt(const QJsonObject& public

const auto rpName = publicKeyOptions["rp"]["name"].toString();
if (confirmDialog.isPasskeyUpdated()) {
addPasskeyToEntry(confirmDialog.getSelectedEntry(),
rpId,
rpName,
username,
publicKeyCredentials.credentialId,
userId,
publicKeyCredentials.key);
// If no entry is selected, show the import dialog for manual entry selection
auto selectedEntry = confirmDialog.getSelectedEntry();
if (!selectedEntry) {
PasskeyImporter passkeyImporter(m_currentDatabaseWidget);
const auto result = passkeyImporter.showImportDialog(db,
nullptr,
origin,
rpId,
username,
publicKeyCredentials.credentialId,
userId,
publicKeyCredentials.key,
tr("KeePassXC - Passkey credentials"),
tr("Register a new passkey to this entry:"),
tr("Register"));
if (!result) {
return getPasskeyError(ERROR_PASSKEYS_REQUEST_CANCELED);
}
} else {
addPasskeyToEntry(selectedEntry,
rpId,
rpName,
username,
publicKeyCredentials.credentialId,
userId,
publicKeyCredentials.key);
}
} else {
addPasskeyToGroup(db,
nullptr,
Expand Down Expand Up @@ -790,8 +811,8 @@ void BrowserService::addPasskeyToEntry(Entry* entry,
// 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?")
tr("KeePassXC - Update passkey"),
tr("Entry already has a passkey.\nDo you want to overwrite the passkey in %1 - %2?")
.arg(entry->title(), passkeyUtils()->getUsernameFromEntry(entry)),
MessageBox::Overwrite | MessageBox::Cancel,
MessageBox::Cancel)
Expand Down
4 changes: 2 additions & 2 deletions src/browser/BrowserSettingsWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,10 @@
<item>
<widget class="QCheckBox" name="allowLocalhostWithPasskeys">
<property name="toolTip">
<string>Allows using insecure http://localhost with Passkeys for testing purposes.</string>
<string>Allows using insecure http://localhost with passkeys for testing purposes.</string>
</property>
<property name="text">
<string>Allow using localhost with Passkeys</string>
<string>Allow using localhost with passkeys</string>
</property>
</widget>
</item>
Expand Down