mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-13 08:19:50 -05:00
Add delete-entry command to Browser Integration API
This commit is contained in:
parent
e3c7b570ae
commit
4c10e516c3
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "BrowserShared.h"
|
#include "BrowserShared.h"
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
|
#include "core/Tools.h"
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@ -51,7 +52,8 @@ namespace
|
|||||||
ERROR_KEEPASS_NO_URL_PROVIDED = 14,
|
ERROR_KEEPASS_NO_URL_PROVIDED = 14,
|
||||||
ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
|
ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
|
||||||
ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
|
ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
|
||||||
ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17
|
ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17,
|
||||||
|
ERROR_KEEPASS_NO_VALID_UUID_PROVIDED = 18
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +114,8 @@ QJsonObject BrowserAction::handleAction(const QJsonObject& json)
|
|||||||
return handleCreateNewGroup(json, action);
|
return handleCreateNewGroup(json, action);
|
||||||
} else if (action.compare("get-totp", Qt::CaseSensitive) == 0) {
|
} else if (action.compare("get-totp", Qt::CaseSensitive) == 0) {
|
||||||
return handleGetTotp(json, action);
|
return handleGetTotp(json, action);
|
||||||
|
} else if (action.compare("delete-entry", Qt::CaseSensitive) == 0) {
|
||||||
|
return handleDeleteEntry(json, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action was not recognized
|
// Action was not recognized
|
||||||
@ -360,6 +364,10 @@ QJsonObject BrowserAction::handleSetLogin(const QJsonObject& json, const QString
|
|||||||
if (uuid.isEmpty()) {
|
if (uuid.isEmpty()) {
|
||||||
browserService()->addEntry(id, login, password, url, submitUrl, realm, group, groupUuid);
|
browserService()->addEntry(id, login, password, url, submitUrl, realm, group, groupUuid);
|
||||||
} else {
|
} else {
|
||||||
|
if (!Tools::isValidUuid(uuid)) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_NO_VALID_UUID_PROVIDED);
|
||||||
|
}
|
||||||
|
|
||||||
result = browserService()->updateEntry(id, uuid, login, password, url, submitUrl);
|
result = browserService()->updateEntry(id, uuid, login, password, url, submitUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +498,9 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString uuid = decrypted.value("uuid").toString();
|
const QString uuid = decrypted.value("uuid").toString();
|
||||||
|
if (!Tools::isValidUuid(uuid)) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_NO_VALID_UUID_PROVIDED);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current TOTP
|
// Get the current TOTP
|
||||||
const auto totp = browserService()->getCurrentTotp(uuid);
|
const auto totp = browserService()->getCurrentTotp(uuid);
|
||||||
@ -501,6 +512,39 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
|
|||||||
return buildResponse(action, message, newNonce);
|
return buildResponse(action, message, newNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject BrowserAction::handleDeleteEntry(const QJsonObject& json, const QString& action)
|
||||||
|
{
|
||||||
|
const QString nonce = json.value("nonce").toString();
|
||||||
|
const QString encrypted = json.value("message").toString();
|
||||||
|
|
||||||
|
if (!m_associated) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_ASSOCIATION_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QJsonObject decrypted = decryptMessage(encrypted, nonce);
|
||||||
|
if (decrypted.isEmpty()) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString command = decrypted.value("action").toString();
|
||||||
|
if (command.isEmpty() || command.compare("delete-entry", Qt::CaseSensitive) != 0) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto uuid = decrypted.value("uuid").toString();
|
||||||
|
if (!Tools::isValidUuid(uuid)) {
|
||||||
|
return getErrorReply(action, ERROR_KEEPASS_NO_VALID_UUID_PROVIDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = browserService()->deleteEntry(uuid);
|
||||||
|
|
||||||
|
const QString newNonce = incrementNonce(nonce);
|
||||||
|
QJsonObject message = buildMessage(newNonce);
|
||||||
|
message["success"] = result ? TRUE_STR : FALSE_STR;
|
||||||
|
|
||||||
|
return buildResponse(action, message, newNonce);
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
|
QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
|
||||||
{
|
{
|
||||||
QJsonObject response;
|
QJsonObject response;
|
||||||
@ -564,6 +608,8 @@ QString BrowserAction::getErrorMessage(const int errorCode) const
|
|||||||
return QObject::tr("No groups found");
|
return QObject::tr("No groups found");
|
||||||
case ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP:
|
case ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP:
|
||||||
return QObject::tr("Cannot create new group");
|
return QObject::tr("Cannot create new group");
|
||||||
|
case ERROR_KEEPASS_NO_VALID_UUID_PROVIDED:
|
||||||
|
return QObject::tr("No valid UUID provided");
|
||||||
default:
|
default:
|
||||||
return QObject::tr("Unknown error");
|
return QObject::tr("Unknown error");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -43,6 +43,7 @@ private:
|
|||||||
QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action);
|
QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action);
|
QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGetTotp(const QJsonObject& json, const QString& action);
|
QJsonObject handleGetTotp(const QJsonObject& json, const QString& action);
|
||||||
|
QJsonObject handleDeleteEntry(const QJsonObject& json, const QString& action);
|
||||||
|
|
||||||
QJsonObject buildMessage(const QString& nonce) const;
|
QJsonObject buildMessage(const QString& nonce) const;
|
||||||
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
|
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Francois Ferrand
|
* Copyright (C) 2013 Francois Ferrand
|
||||||
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||||
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -578,6 +578,32 @@ bool BrowserService::updateEntry(const QString& dbid,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowserService::deleteEntry(const QString& uuid)
|
||||||
|
{
|
||||||
|
auto db = selectedDatabase();
|
||||||
|
if (!db) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* entry = db->rootGroup()->findEntryByUuid(Tools::hexToUuid(uuid));
|
||||||
|
if (!entry) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dialogResult = MessageBox::warning(nullptr,
|
||||||
|
tr("KeePassXC: Delete entry"),
|
||||||
|
tr("A request for deleting entry \"%1\" has been received.\n"
|
||||||
|
"Do you want to delete the entry?\n")
|
||||||
|
.arg(entry->title()),
|
||||||
|
MessageBox::Yes | MessageBox::No);
|
||||||
|
if (dialogResult != MessageBox::Yes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
db->recycleEntry(entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QList<Entry*>
|
QList<Entry*>
|
||||||
BrowserService::searchEntries(const QSharedPointer<Database>& db, const QString& siteUrlStr, const QString& formUrlStr)
|
BrowserService::searchEntries(const QSharedPointer<Database>& db, const QString& siteUrlStr, const QString& formUrlStr)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Francois Ferrand
|
* Copyright (C) 2013 Francois Ferrand
|
||||||
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||||
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -71,6 +71,7 @@ public:
|
|||||||
const QString& password,
|
const QString& password,
|
||||||
const QString& siteUrlStr,
|
const QString& siteUrlStr,
|
||||||
const QString& formUrlStr);
|
const QString& formUrlStr);
|
||||||
|
bool deleteEntry(const QString& uuid);
|
||||||
|
|
||||||
QJsonArray findMatchingEntries(const QString& dbid,
|
QJsonArray findMatchingEntries(const QString& dbid,
|
||||||
const QString& siteUrlStr,
|
const QString& siteUrlStr,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
|
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
|
||||||
* Copyright (C) 2017 Lennart Glauer <mail@lennart-glauer.de>
|
* Copyright (C) 2017 Lennart Glauer <mail@lennart-glauer.de>
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -317,6 +317,20 @@ namespace Tools
|
|||||||
return QUuid::fromRfc4122(QByteArray::fromHex(uuid.toLatin1()));
|
return QUuid::fromRfc4122(QByteArray::fromHex(uuid.toLatin1()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidUuid(const QString& uuidStr)
|
||||||
|
{
|
||||||
|
if (uuidStr.isEmpty() || uuidStr.length() != 32 || !isHex(uuidStr.toLatin1())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto uuid = hexToUuid(uuidStr);
|
||||||
|
if (uuid.isNull() || uuid.version() == QUuid::VerUnknown) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QString envSubstitute(const QString& filepath, QProcessEnvironment environment)
|
QString envSubstitute(const QString& filepath, QProcessEnvironment environment)
|
||||||
{
|
{
|
||||||
QString subbed = filepath;
|
QString subbed = filepath;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
|
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -40,6 +40,7 @@ namespace Tools
|
|||||||
bool checkUrlValid(const QString& urlField);
|
bool checkUrlValid(const QString& urlField);
|
||||||
QString uuidToHex(const QUuid& uuid);
|
QString uuidToHex(const QUuid& uuid);
|
||||||
QUuid hexToUuid(const QString& uuid);
|
QUuid hexToUuid(const QString& uuid);
|
||||||
|
bool isValidUuid(const QString& uuidStr);
|
||||||
QRegularExpression convertToRegex(const QString& string,
|
QRegularExpression convertToRegex(const QString& string,
|
||||||
bool useWildcards = false,
|
bool useWildcards = false,
|
||||||
bool exactMatch = false,
|
bool exactMatch = false,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -88,3 +88,20 @@ void TestTools::testEnvSubstitute()
|
|||||||
QCOMPARE(Tools::envSubstitute("start/$EMPTY$$EMPTY$HOME/end", environment), QString("start/$/home/user/end"));
|
QCOMPARE(Tools::envSubstitute("start/$EMPTY$$EMPTY$HOME/end", environment), QString("start/$/home/user/end"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestTools::testValidUuid()
|
||||||
|
{
|
||||||
|
auto validUuid = Tools::uuidToHex(QUuid::createUuid());
|
||||||
|
auto nonValidUuid = "1234567890abcdef1234567890abcdef";
|
||||||
|
auto emptyUuid = QString();
|
||||||
|
auto shortUuid = validUuid.left(10);
|
||||||
|
auto longUuid = validUuid + "baddata";
|
||||||
|
auto nonHexUuid = Tools::uuidToHex(QUuid::createUuid()).replace(0, 1, 'p');
|
||||||
|
|
||||||
|
QVERIFY(Tools::isValidUuid(validUuid));
|
||||||
|
QVERIFY(not Tools::isValidUuid(nonValidUuid));
|
||||||
|
QVERIFY(not Tools::isValidUuid(emptyUuid));
|
||||||
|
QVERIFY(not Tools::isValidUuid(shortUuid));
|
||||||
|
QVERIFY(not Tools::isValidUuid(longUuid));
|
||||||
|
QVERIFY(not Tools::isValidUuid(nonHexUuid));
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -28,6 +28,7 @@ private slots:
|
|||||||
void testIsHex();
|
void testIsHex();
|
||||||
void testIsBase64();
|
void testIsBase64();
|
||||||
void testEnvSubstitute();
|
void testEnvSubstitute();
|
||||||
|
void testValidUuid();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_TESTTOOLS_H
|
#endif // KEEPASSX_TESTTOOLS_H
|
||||||
|
Loading…
Reference in New Issue
Block a user