0
0
mirror of https://github.com/keepassxreboot/keepassxc.git synced 2024-09-20 04:12:15 +02:00

FdoSecrets: add unit tests

This commit is contained in:
Aetf 2019-12-16 16:49:58 -05:00
parent af6493b07b
commit 44779bc862
23 changed files with 1579 additions and 31 deletions

View File

@ -31,7 +31,8 @@
using FdoSecrets::Service;
FdoSecretsPlugin::FdoSecretsPlugin(DatabaseTabWidget* tabWidget)
: m_dbTabs(tabWidget)
: QObject(tabWidget)
, m_dbTabs(tabWidget)
{
FdoSecrets::registerDBusTypes();
}

View File

@ -75,6 +75,8 @@ namespace FdoSecrets
m_registered = false;
}
Q_ASSERT(m_backend);
// make sure we have updated copy of the filepath, which is used to identify the database.
m_backendPath = m_backend->database()->filePath();
@ -310,13 +312,13 @@ namespace FdoSecrets
QString itemPath;
StringStringMap attributes;
// check existing item using attributes
auto iterAttr = properties.find(QStringLiteral(DBUS_INTERFACE_SECRET_ITEM ".Attributes"));
if (iterAttr != properties.end()) {
attributes = qdbus_cast<StringStringMap>(iterAttr.value().value<QDBusArgument>());
attributes = iterAttr.value().value<StringStringMap>();
itemPath = attributes.value(ItemAttributes::PathKey);
// check existing item using attributes
auto existings = searchItems(attributes);
if (existings.isError()) {
return existings;
@ -614,6 +616,11 @@ namespace FdoSecrets
void Collection::doDelete()
{
if (!m_backend) {
// I'm already deleted
return;
}
emit collectionAboutToDelete();
unregisterCurrentPath();
@ -623,7 +630,11 @@ namespace FdoSecrets
removeAlias(a).okOrDie();
}
// cleanup connection on Database
cleanupConnections();
// cleanup connection on Backend itself
m_backend->disconnect(this);
parent()->disconnect(this);
m_exposedGroup = nullptr;

View File

@ -59,9 +59,9 @@ namespace FdoSecrets
createItem(const QVariantMap& properties, const SecretStruct& secret, bool replace, PromptBase*& prompt);
signals:
void itemCreated(const Item* item);
void itemDeleted(const Item* item);
void itemChanged(const Item* item);
void itemCreated(Item* item);
void itemDeleted(Item* item);
void itemChanged(Item* item);
void collectionChanged();
void collectionAboutToDelete();

View File

@ -51,6 +51,11 @@ namespace FdoSecrets
return m_objectPath;
}
QDBusAbstractAdaptor& dbusAdaptor() const
{
return *m_dbusAdaptor;
}
protected:
void registerWithPath(const QString& path, QDBusAbstractAdaptor* adaptor);
@ -74,11 +79,6 @@ namespace FdoSecrets
QString callingPeerName() const;
template <typename Adaptor> Adaptor& dbusAdaptor() const
{
return *static_cast<Adaptor*>(m_dbusAdaptor);
}
DBusObject* p() const
{
return qobject_cast<DBusObject*>(parent());

View File

@ -35,6 +35,16 @@ namespace FdoSecrets
qRegisterMetaType<ObjectPathSecretMap>();
qDBusRegisterMetaType<ObjectPathSecretMap>();
QMetaType::registerConverter<QDBusArgument, StringStringMap>([](const QDBusArgument& arg) {
if (arg.currentSignature() != "a{ss}") {
return StringStringMap{};
}
// QDBusArgument is COW and qdbus_cast modifies it by detaching even it is const.
// we don't want to modify the instance (arg) stored in the qvariant so we create a copy
const auto copy = arg; // NOLINT(performance-unnecessary-copy-initialization)
return qdbus_cast<StringStringMap>(copy);
});
// NOTE: this is already registered by Qt in qtextratypes.h
// qRegisterMetaType<QList<QDBusObjectPath > >();
// qDBusRegisterMetaType<QList<QDBusObjectPath> >();

View File

@ -26,6 +26,7 @@
#include "core/Entry.h"
#include "core/EntryAttributes.h"
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
#include <QMimeDatabase>
@ -274,8 +275,8 @@ namespace FdoSecrets
return ret;
}
auto attributes = qdbus_cast<StringStringMap>(
properties.value(QStringLiteral(DBUS_INTERFACE_SECRET_ITEM ".Attributes")).value<QDBusArgument>());
auto attributes =
properties.value(QStringLiteral(DBUS_INTERFACE_SECRET_ITEM ".Attributes")).value<StringStringMap>();
ret = setAttributes(attributes);
if (ret.isError()) {
return ret;
@ -350,6 +351,13 @@ namespace FdoSecrets
return pathComponents.join('/');
}
bool Item::isDeletePermanent() const
{
auto recycleBin = backend()->database()->metadata()->recycleBin();
return (recycleBin && recycleBin->findEntryByUuid(backend()->uuid()))
|| !backend()->database()->metadata()->recycleBinEnabled();
}
void setEntrySecret(Entry* entry, const QByteArray& data, const QString& contentType)
{
auto mimeName = contentType.split(';').takeFirst().trimmed();
@ -369,7 +377,8 @@ namespace FdoSecrets
}
if (!mimeType.isValid() || !mimeType.inherits(QStringLiteral("text/plain")) || !codec) {
// we can't handle this content type, save the data as attachment
// we can't handle this content type, save the data as attachment, and clear the password field
entry->setPassword("");
entry->attachments()->set(FDO_SECRETS_DATA, data);
entry->attributes()->set(FDO_SECRETS_CONTENT_TYPE, contentType);
return;
@ -393,8 +402,13 @@ namespace FdoSecrets
if (entry->attachments()->hasKey(FDO_SECRETS_DATA)) {
ss.value = entry->attachments()->value(FDO_SECRETS_DATA);
Q_ASSERT(entry->attributes()->hasKey(FDO_SECRETS_CONTENT_TYPE));
ss.contentType = entry->attributes()->value(FDO_SECRETS_CONTENT_TYPE);
if (entry->attributes()->hasKey(FDO_SECRETS_CONTENT_TYPE)) {
ss.contentType = entry->attributes()->value(FDO_SECRETS_CONTENT_TYPE);
} else {
// the entry is somehow corrupted, maybe the user deleted it.
// set to binary and hope for the best...
ss.contentType = QStringLiteral("application/octet-stream");
}
return ss;
}

View File

@ -79,6 +79,14 @@ namespace FdoSecrets
*/
QString path() const;
/**
* If the containing db does not have recycle bin enabled,
* or the entry is already in the recycle bin (not possible for item, though),
* the delete is permanent
* @return true if delete is permanent
*/
bool isDeletePermanent() const;
public slots:
void doDelete();

View File

@ -68,9 +68,9 @@ namespace FdoSecrets
incomplete = false;
std::unique_ptr<CipherPair> cipher{};
if (algorithm == QLatin1Literal("plain")) {
if (algorithm == QLatin1String(PlainCipher::Algorithm)) {
cipher.reset(new PlainCipher);
} else if (algorithm == QLatin1Literal("dh-ietf1024-sha256-aes128-cbc-pkcs7")) {
} else if (algorithm == QLatin1String(DhIetf1024Sha256Aes128CbcPkcs7::Algorithm)) {
QByteArray clientPublicKey = input.toByteArray();
cipher.reset(new DhIetf1024Sha256Aes128CbcPkcs7(clientPublicKey));
} else {

View File

@ -43,6 +43,9 @@ namespace
namespace FdoSecrets
{
// XXX: remove the redundant definitions once we are at C++17
constexpr char PlainCipher::Algorithm[];
constexpr char DhIetf1024Sha256Aes128CbcPkcs7::Algorithm[];
DhIetf1024Sha256Aes128CbcPkcs7::DhIetf1024Sha256Aes128CbcPkcs7(const QByteArray& clientPublicKeyBytes)
: m_valid(false)
@ -51,13 +54,24 @@ namespace FdoSecrets
auto clientPub = MpiFromBytes(clientPublicKeyBytes, false);
// generate server side private, 128 bytes
GcryptMPI serverPrivate(gcry_mpi_snew(KEY_SIZE_BYTES * 8));
gcry_mpi_randomize(serverPrivate.get(), KEY_SIZE_BYTES * 8, GCRY_STRONG_RANDOM);
GcryptMPI serverPrivate = nullptr;
if (NextPrivKey) {
serverPrivate = std::move(NextPrivKey);
} else {
serverPrivate.reset(gcry_mpi_snew(KEY_SIZE_BYTES * 8));
gcry_mpi_randomize(serverPrivate.get(), KEY_SIZE_BYTES * 8, GCRY_STRONG_RANDOM);
}
// generate server side public key
GcryptMPI serverPublic(gcry_mpi_snew(KEY_SIZE_BYTES * 8));
// the generator of Second Oakley Group is 2
gcry_mpi_powm(serverPublic.get(), GCRYMPI_CONST_TWO, serverPrivate.get(), IETF1024_SECOND_OAKLEY_GROUP_P.get());
GcryptMPI serverPublic = nullptr;
if (NextPubKey) {
serverPublic = std::move(NextPubKey);
} else {
serverPublic.reset(gcry_mpi_snew(KEY_SIZE_BYTES * 8));
// the generator of Second Oakley Group is 2
gcry_mpi_powm(
serverPublic.get(), GCRYMPI_CONST_TWO, serverPrivate.get(), IETF1024_SECOND_OAKLEY_GROUP_P.get());
}
initialize(std::move(clientPub), std::move(serverPublic), std::move(serverPrivate));
}
@ -216,4 +230,13 @@ namespace FdoSecrets
return m_publicKey;
}
void DhIetf1024Sha256Aes128CbcPkcs7::fixNextServerKeys(GcryptMPI priv, GcryptMPI pub)
{
NextPrivKey = std::move(priv);
NextPubKey = std::move(pub);
}
GcryptMPI DhIetf1024Sha256Aes128CbcPkcs7::NextPrivKey = nullptr;
GcryptMPI DhIetf1024Sha256Aes128CbcPkcs7::NextPubKey = nullptr;
} // namespace FdoSecrets

View File

@ -22,6 +22,7 @@
#include "fdosecrets/objects/Session.h"
class TestFdoSecrets;
class TestGuiFdoSecrets;
namespace FdoSecrets
{
@ -42,6 +43,8 @@ namespace FdoSecrets
{
Q_DISABLE_COPY(PlainCipher)
public:
static constexpr const char Algorithm[] = "plain";
PlainCipher() = default;
SecretStruct encrypt(const SecretStruct& input) override
{
@ -113,6 +116,8 @@ namespace FdoSecrets
}
public:
static constexpr const char Algorithm[] = "dh-ietf1024-sha256-aes128-cbc-pkcs7";
explicit DhIetf1024Sha256Aes128CbcPkcs7(const QByteArray& clientPublicKeyBytes);
SecretStruct encrypt(const SecretStruct& input) override;
@ -123,9 +128,18 @@ namespace FdoSecrets
QVariant negotiationOutput() const override;
private:
/**
* For test only, fix the server side private and public key.
*/
static void fixNextServerKeys(GcryptMPI priv, GcryptMPI pub);
static GcryptMPI NextPrivKey;
static GcryptMPI NextPubKey;
private:
Q_DISABLE_COPY(DhIetf1024Sha256Aes128CbcPkcs7);
friend class ::TestFdoSecrets;
friend class ::TestGuiFdoSecrets;
};
} // namespace FdoSecrets

View File

@ -335,9 +335,7 @@ namespace FdoSecrets
{
switch (role) {
case Qt::EditRole: {
auto v = QVariant::fromValue(sess);
qDebug() << v << v.type() << v.userType();
return v;
return QVariant::fromValue(sess);
}
default:
return {};

View File

@ -49,7 +49,7 @@ DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
: QTabWidget(parent)
, m_dbWidgetStateSync(new DatabaseWidgetStateSync(this))
, m_dbWidgetPendingLock(nullptr)
, m_databaseOpenDialog(new DatabaseOpenDialog())
, m_databaseOpenDialog(new DatabaseOpenDialog(this))
{
auto* tabBar = new DragTabBar(this);
setTabBar(tabBar);

View File

@ -108,7 +108,7 @@ private:
QPointer<DatabaseWidgetStateSync> m_dbWidgetStateSync;
QPointer<DatabaseWidget> m_dbWidgetPendingLock;
QScopedPointer<DatabaseOpenDialog> m_databaseOpenDialog;
QPointer<DatabaseOpenDialog> m_databaseOpenDialog;
};
#endif // KEEPASSX_DATABASETABWIDGET_H

View File

@ -57,8 +57,9 @@ macro(parse_arguments prefix arg_names option_names)
endmacro(parse_arguments)
macro(add_unit_test)
parse_arguments(TEST "NAME;SOURCES;LIBS" "" ${ARGN})
parse_arguments(TEST "NAME;SOURCES;LIBS;LAUNCHER" "" ${ARGN})
set(_test_NAME ${TEST_NAME})
set(_test_LAUNCHER ${TEST_LAUNCHER})
set(_srcList ${TEST_SOURCES})
add_executable(${_test_NAME} ${_srcList})
target_link_libraries(${_test_NAME} ${TEST_LIBS})
@ -69,9 +70,9 @@ macro(add_unit_test)
set(TEST_OUTPUT ${TEST_OUTPUT} CACHE STRING "The output to generate when running the QTest unit tests")
if(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME} -xml -o ${_test_NAME}.tml)
add_test(${_test_NAME} ${_test_LAUNCHER} ${_test_NAME} -xml -o ${_test_NAME}.tml)
else(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME})
add_test(${_test_NAME} ${_test_LAUNCHER} ${_test_NAME})
endif(KDE4_TEST_OUTPUT STREQUAL "xml")
if(NOT MSVC_IDE) #not needed for the ide

View File

@ -0,0 +1,33 @@
<interface name="org.freedesktop.Secret.Collection">
<property name="Items" type="ao" access="read"/>
<property name="Label" type="s" access="readwrite"/>
<property name="Locked" type="b" access="read"/>
<property name="Created" type="t" access="read"/>
<property name="Modified" type="t" access="read"/>
<signal name="ItemCreated">
<arg name="item" type="o" direction="out"/>
</signal>
<signal name="ItemDeleted">
<arg name="item" type="o" direction="out"/>
</signal>
<signal name="ItemChanged">
<arg name="item" type="o" direction="out"/>
</signal>
<method name="Delete">
<arg type="o" direction="out"/>
</method>
<method name="SearchItems">
<arg type="ao" direction="out"/>
<arg name="attributes" type="a{ss}" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StringStringMap"/>
</method>
<method name="CreateItem">
<arg type="o" direction="out"/>
<arg name="properties" type="a{sv}" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
<arg name="secret" type="(oayays)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="FdoSecrets::SecretStruct"/>
<arg name="replace" type="b" direction="in"/>
<arg name="prompt" type="o" direction="out"/>
</method>
</interface>

View File

@ -0,0 +1,21 @@
<interface name="org.freedesktop.Secret.Item">
<property name="Locked" type="b" access="read"/>
<property name="Attributes" type="a{ss}" access="readwrite">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="StringStringMap"/>
</property>
<property name="Label" type="s" access="readwrite"/>
<property name="Created" type="t" access="read"/>
<property name="Modified" type="t" access="read"/>
<method name="Delete">
<arg type="o" direction="out"/>
</method>
<method name="GetSecret">
<arg type="(oayays)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FdoSecrets::SecretStruct"/>
<arg name="session" type="o" direction="in"/>
</method>
<method name="SetSecret">
<arg name="secret" type="(oayays)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FdoSecrets::SecretStruct"/>
</method>
</interface>

View File

@ -0,0 +1,11 @@
<interface name="org.freedesktop.Secret.Prompt">
<signal name="Completed">
<arg name="dismissed" type="b" direction="out"/>
<arg name="result" type="v" direction="out"/>
</signal>
<method name="Prompt">
<arg name="windowId" type="s" direction="in"/>
</method>
<method name="Dismiss">
</method>
</interface>

View File

@ -0,0 +1,55 @@
<interface name="org.freedesktop.Secret.Service">
<property name="Collections" type="ao" access="read"/>
<signal name="CollectionCreated">
<arg name="collection" type="o" direction="out"/>
</signal>
<signal name="CollectionDeleted">
<arg name="collection" type="o" direction="out"/>
</signal>
<signal name="CollectionChanged">
<arg name="collection" type="o" direction="out"/>
</signal>
<method name="OpenSession">
<arg type="v" direction="out"/>
<arg name="algorithm" type="s" direction="in"/>
<arg name="input" type="v" direction="in"/>
<arg name="result" type="o" direction="out"/>
</method>
<method name="CreateCollection">
<arg type="o" direction="out"/>
<arg name="properties" type="a{sv}" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
<arg name="alias" type="s" direction="in"/>
<arg name="prompt" type="o" direction="out"/>
</method>
<method name="SearchItems">
<arg type="ao" direction="out"/>
<arg name="attributes" type="a{ss}" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StringStringMap"/>
<arg name="locked" type="ao" direction="out"/>
</method>
<method name="Unlock">
<arg type="ao" direction="out"/>
<arg name="paths" type="ao" direction="in"/>
<arg name="prompt" type="o" direction="out"/>
</method>
<method name="Lock">
<arg type="ao" direction="out"/>
<arg name="paths" type="ao" direction="in"/>
<arg name="prompt" type="o" direction="out"/>
</method>
<method name="GetSecrets">
<arg type="a{o(oayays)}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObjectPathSecretMap"/>
<arg name="items" type="ao" direction="in"/>
<arg name="session" type="o" direction="in"/>
</method>
<method name="ReadAlias">
<arg type="o" direction="out"/>
<arg name="name" type="s" direction="in"/>
</method>
<method name="SetAlias">
<arg name="name" type="s" direction="in"/>
<arg name="collection" type="o" direction="in"/>
</method>
</interface>

View File

@ -0,0 +1,4 @@
<interface name="org.freedesktop.Secret.Session">
<method name="Close">
</method>
</interface>

View File

@ -0,0 +1,39 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<type>session</type>
<keep_umask/>
<listen>unix:tmpdir=/tmp</listen>
<auth>EXTERNAL</auth>
<standard_session_servicedirs />
<policy context="default">
<allow send_destination="*" eavesdrop="true"/>
<allow eavesdrop="true"/>
<allow own="*"/>
</policy>
<include ignore_missing="yes">/etc/dbus-1/session.conf</include>
<includedir>session.d</includedir>
<includedir>/etc/dbus-1/session.d</includedir>
<include ignore_missing="yes">/etc/dbus-1/session-local.conf</include>
<include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
<limit name="max_incoming_bytes">1000000000</limit>
<limit name="max_incoming_unix_fds">250000000</limit>
<limit name="max_outgoing_bytes">1000000000</limit>
<limit name="max_outgoing_unix_fds">250000000</limit>
<limit name="max_message_size">1000000000</limit>
<limit name="auth_timeout">240000</limit>
<limit name="pending_fd_timeout">150000</limit>
<limit name="max_completed_connections">100000</limit>
<limit name="max_incomplete_connections">10000</limit>
<limit name="max_connections_per_user">100000</limit>
<limit name="max_pending_service_starts">10000</limit>
<limit name="max_names_per_connection">50000</limit>
<limit name="max_match_rules_per_connection">50000</limit>
<limit name="max_replies_per_connection">50000</limit>
<!-- The above is copied from session bus conf.
Our only intent here is to set a low service_start_timeout,
such that ctest can exit sooner when dbus-run-session is used
to launch tests and some service fails to start.
-->
<limit name="service_start_timeout">500</limit>
</busconfig>

View File

@ -21,3 +21,12 @@ add_unit_test(NAME testguipixmaps SOURCES TestGuiPixmaps.cpp LIBS ${TEST_LIBRARI
if(WITH_XC_BROWSER)
add_unit_test(NAME testguibrowser SOURCES TestGuiBrowser.cpp ../util/TemporaryFile.cpp LIBS ${TEST_LIBRARIES})
endif()
if(WITH_XC_FDOSECRETS)
add_unit_test(NAME testguifdosecrets
SOURCES TestGuiFdoSecrets.cpp ../util/TemporaryFile.cpp
LIBS ${TEST_LIBRARIES}
# The following doesn't work because dbus-run-session expects execname to be in PATH
# dbus-run-session -- execname
LAUNCHER dbus-run-session --config-file ${CMAKE_CURRENT_SOURCE_DIR}/../data/dbus/session.conf -- sh -c "exec ./$0")
endif()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2019 Aetf <aetf@unlimitedcodeworks.xyz>
*
* 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
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_TESTGUIFDOSECRETS_H
#define KEEPASSXC_TESTGUIFDOSECRETS_H
#include <QByteArray>
#include <QObject>
#include <QPointer>
#include <QScopedPointer>
#include <QSharedPointer>
#include <QString>
#include "fdosecrets/GcryptMPI.h"
#include "fdosecrets/objects/DBusTypes.h"
class MainWindow;
class Database;
class DatabaseTabWidget;
class DatabaseWidget;
class TemporaryFile;
class FdoSecretsPlugin;
namespace FdoSecrets
{
class Service;
class Session;
class Collection;
class Item;
class Prompt;
class DhIetf1024Sha256Aes128CbcPkcs7;
} // namespace FdoSecrets
class QAbstractItemView;
class TestGuiFdoSecrets : public QObject
{
Q_OBJECT
public:
~TestGuiFdoSecrets() override;
private slots:
void initTestCase();
void init();
void cleanup();
void cleanupTestCase();
void testDBusSpec();
void testServiceEnable();
void testServiceEnableNoExposedDatabase();
void testServiceSearch();
void testServiceUnlock();
void testServiceLock();
void testSessionOpen();
void testSessionClose();
void testCollectionCreate();
void testCollectionDelete();
void testItemCreate();
void testItemReplace();
void testItemSecret();
void testItemDelete();
void testAlias();
void testDefaultAliasAlwaysPresent();
void testExposeSubgroup();
void testModifiyingExposedGroup();
protected slots:
void createDatabaseCallback();
private:
void lockDatabaseInBackend();
void unlockDatabaseInBackend();
QPointer<FdoSecrets::Service> enableService();
QPointer<FdoSecrets::Session> openSession(FdoSecrets::Service* service, const QString& algo);
QPointer<FdoSecrets::Collection> getDefaultCollection(FdoSecrets::Service* service);
QPointer<FdoSecrets::Item> getFirstItem(FdoSecrets::Collection* coll);
QPointer<FdoSecrets::Item> createItem(FdoSecrets::Session* sess,
FdoSecrets::Collection* coll,
const QString& label,
const QString& pass,
const StringStringMap& attr,
bool replace);
private:
QScopedPointer<MainWindow> m_mainWindow;
QPointer<DatabaseTabWidget> m_tabWidget;
QPointer<DatabaseWidget> m_dbWidget;
QSharedPointer<Database> m_db;
QPointer<FdoSecretsPlugin> m_plugin;
// For DH session tests
GcryptMPI m_serverPrivate;
GcryptMPI m_serverPublic;
std::unique_ptr<FdoSecrets::DhIetf1024Sha256Aes128CbcPkcs7> m_cipher;
QByteArray m_dbData;
QScopedPointer<TemporaryFile> m_dbFile;
};
#endif // KEEPASSXC_TESTGUIFDOSECRETS_H