mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-24 14:59:44 -05:00
Merge pull request #4232 from Aetf/feature/fdo-secrets-unittests
FdoSecrets: Add unit tests for secret service integration
This commit is contained in:
commit
229a756d84
@ -21,8 +21,9 @@
|
||||
#include "core/Group.h"
|
||||
#include "core/Tools.h"
|
||||
|
||||
EntrySearcher::EntrySearcher(bool caseSensitive)
|
||||
EntrySearcher::EntrySearcher(bool caseSensitive, bool skipProtected)
|
||||
: m_caseSensitive(caseSensitive)
|
||||
, m_skipProtected(skipProtected)
|
||||
, m_termParser(R"re(([-!*+]+)?(?:(\w*):)?(?:(?=")"((?:[^"\\]|\\.)*)"|([^ ]*))( |$))re")
|
||||
// Group 1 = modifiers, Group 2 = field, Group 3 = quoted string, Group 4 = unquoted string
|
||||
{
|
||||
@ -136,7 +137,7 @@ void EntrySearcher::setCaseSensitive(bool state)
|
||||
m_caseSensitive = state;
|
||||
}
|
||||
|
||||
bool EntrySearcher::isCaseSensitive()
|
||||
bool EntrySearcher::isCaseSensitive() const
|
||||
{
|
||||
return m_caseSensitive;
|
||||
}
|
||||
@ -150,7 +151,9 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry)
|
||||
// Build a group hierarchy to allow searching for e.g. /group1/subgroup*
|
||||
auto hierarchy = entry->group()->hierarchy().join('/').prepend("/");
|
||||
|
||||
bool found;
|
||||
// By default, empty term matches every entry.
|
||||
// However when skipping protected fields, we will recject everything instead
|
||||
bool found = !m_skipProtected;
|
||||
for (const auto& term : m_searchTerms) {
|
||||
switch (term.field) {
|
||||
case Field::Title:
|
||||
@ -160,6 +163,9 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry)
|
||||
found = term.regex.match(entry->resolvePlaceholder(entry->username())).hasMatch();
|
||||
break;
|
||||
case Field::Password:
|
||||
if (m_skipProtected) {
|
||||
continue;
|
||||
}
|
||||
found = term.regex.match(entry->resolvePlaceholder(entry->password())).hasMatch();
|
||||
break;
|
||||
case Field::Url:
|
||||
@ -175,8 +181,7 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry)
|
||||
found = !attachments.filter(term.regex).empty();
|
||||
break;
|
||||
case Field::AttributeValue:
|
||||
// skip protected attributes
|
||||
if (entry->attributes()->isProtected(term.word)) {
|
||||
if (m_skipProtected && entry->attributes()->isProtected(term.word)) {
|
||||
continue;
|
||||
}
|
||||
found = entry->attributes()->contains(term.word)
|
||||
@ -198,13 +203,18 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry)
|
||||
|| term.regex.match(entry->notes()).hasMatch();
|
||||
}
|
||||
|
||||
// Short circuit if we failed to match or we matched and are excluding this term
|
||||
if ((!found && !term.exclude) || (found && term.exclude)) {
|
||||
// negate the result if exclude:
|
||||
// * if found and not excluding, the entry matches
|
||||
// * if didn't found but excluding, the entry also matches
|
||||
found = (found && !term.exclude) || (!found && term.exclude);
|
||||
|
||||
// short circuit if we failed the match
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return found;
|
||||
}
|
||||
|
||||
void EntrySearcher::parseSearchTerms(const QString& searchString)
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
bool exclude;
|
||||
};
|
||||
|
||||
explicit EntrySearcher(bool caseSensitive = false);
|
||||
explicit EntrySearcher(bool caseSensitive = false, bool skipProtected = false);
|
||||
|
||||
QList<Entry*> search(const QList<SearchTerm>& searchTerms, const Group* baseGroup, bool forceSearch = false);
|
||||
QList<Entry*> search(const QString& searchString, const Group* baseGroup, bool forceSearch = false);
|
||||
@ -62,13 +62,14 @@ public:
|
||||
QList<Entry*> repeatEntries(const QList<Entry*>& entries);
|
||||
|
||||
void setCaseSensitive(bool state);
|
||||
bool isCaseSensitive();
|
||||
bool isCaseSensitive() const;
|
||||
|
||||
private:
|
||||
bool searchEntryImpl(const Entry* entry);
|
||||
void parseSearchTerms(const QString& searchString);
|
||||
|
||||
bool m_caseSensitive;
|
||||
bool m_skipProtected;
|
||||
QRegularExpression m_termParser;
|
||||
QList<SearchTerm> m_searchTerms;
|
||||
|
||||
|
@ -31,7 +31,8 @@
|
||||
using FdoSecrets::Service;
|
||||
|
||||
FdoSecretsPlugin::FdoSecretsPlugin(DatabaseTabWidget* tabWidget)
|
||||
: m_dbTabs(tabWidget)
|
||||
: QObject(tabWidget)
|
||||
, m_dbTabs(tabWidget)
|
||||
{
|
||||
FdoSecrets::registerDBusTypes();
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
@ -245,19 +247,11 @@ namespace FdoSecrets
|
||||
|
||||
QList<EntrySearcher::SearchTerm> terms;
|
||||
for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
|
||||
if (it.key() == EntryAttributes::PasswordKey) {
|
||||
continue;
|
||||
}
|
||||
terms << attributeToTerm(it.key(), it.value());
|
||||
}
|
||||
|
||||
// empty terms causes EntrySearcher returns everything
|
||||
if (terms.isEmpty()) {
|
||||
return QList<Item*>{};
|
||||
}
|
||||
|
||||
QList<Item*> items;
|
||||
const auto foundEntries = EntrySearcher().search(terms, m_exposedGroup);
|
||||
const auto foundEntries = EntrySearcher(false, true).search(terms, m_exposedGroup);
|
||||
items.reserve(foundEntries.size());
|
||||
for (const auto& entry : foundEntries) {
|
||||
items << m_entryToItem.value(entry);
|
||||
@ -310,13 +304,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;
|
||||
@ -440,6 +434,16 @@ namespace FdoSecrets
|
||||
|
||||
QString Collection::name() const
|
||||
{
|
||||
if (m_backendPath.isEmpty()) {
|
||||
// This is a newly created db without saving to file.
|
||||
// This name is also used to register dbus path.
|
||||
// For simplicity, we don't monitor the name change.
|
||||
// So the dbus object path is not updated if the db name
|
||||
// changes. This should not be a problem because once the database
|
||||
// gets saved, the dbus path will be updated to use filename and
|
||||
// everything back to normal.
|
||||
return m_backend->database()->metadata()->name();
|
||||
}
|
||||
return QFileInfo(m_backendPath).baseName();
|
||||
}
|
||||
|
||||
@ -544,8 +548,9 @@ namespace FdoSecrets
|
||||
}
|
||||
|
||||
// repopulate
|
||||
Q_ASSERT(!backendLocked());
|
||||
populateContents();
|
||||
if (!backendLocked()) {
|
||||
populateContents();
|
||||
}
|
||||
}
|
||||
|
||||
void Collection::onEntryAdded(Entry* entry, bool emitSignal)
|
||||
@ -598,11 +603,11 @@ namespace FdoSecrets
|
||||
return qobject_cast<Service*>(parent());
|
||||
}
|
||||
|
||||
void Collection::doLock()
|
||||
bool Collection::doLock()
|
||||
{
|
||||
Q_ASSERT(m_backend);
|
||||
|
||||
m_backend->lock();
|
||||
return m_backend->lock();
|
||||
}
|
||||
|
||||
void Collection::doUnlock()
|
||||
@ -614,6 +619,11 @@ namespace FdoSecrets
|
||||
|
||||
void Collection::doDelete()
|
||||
{
|
||||
if (!m_backend) {
|
||||
// I'm already deleted
|
||||
return;
|
||||
}
|
||||
|
||||
emit collectionAboutToDelete();
|
||||
|
||||
unregisterCurrentPath();
|
||||
@ -623,7 +633,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;
|
||||
|
||||
|
@ -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();
|
||||
@ -102,7 +102,7 @@ namespace FdoSecrets
|
||||
|
||||
public slots:
|
||||
// expose some methods for Prmopt to use
|
||||
void doLock();
|
||||
bool doLock();
|
||||
void doUnlock();
|
||||
// will remove self
|
||||
void doDelete();
|
||||
|
@ -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());
|
||||
|
@ -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> >();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -65,7 +65,7 @@ namespace FdoSecrets
|
||||
|
||||
DBusReturn<void> PromptBase::dismiss()
|
||||
{
|
||||
emit completed(true, {});
|
||||
emit completed(true, "");
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ namespace FdoSecrets
|
||||
// only need to delete in backend, collection will react itself.
|
||||
auto accepted = service()->doCloseDatabase(m_collection->backend());
|
||||
|
||||
emit completed(!accepted, {});
|
||||
emit completed(!accepted, "");
|
||||
|
||||
return {};
|
||||
}
|
||||
@ -125,11 +125,17 @@ namespace FdoSecrets
|
||||
}
|
||||
|
||||
emit collectionCreated(coll);
|
||||
emit completed(false, coll->objectPath().path());
|
||||
emit completed(false, QVariant::fromValue(coll->objectPath()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
DBusReturn<void> CreateCollectionPrompt::dismiss()
|
||||
{
|
||||
emit completed(true, QVariant::fromValue(QDBusObjectPath{"/"}));
|
||||
return {};
|
||||
}
|
||||
|
||||
LockCollectionsPrompt::LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls)
|
||||
: PromptBase(parent)
|
||||
{
|
||||
@ -153,19 +159,26 @@ namespace FdoSecrets
|
||||
|
||||
MessageBox::OverrideParent override(findWindow(windowId));
|
||||
|
||||
QList<QDBusObjectPath> locked;
|
||||
for (const auto& c : asConst(m_collections)) {
|
||||
if (c) {
|
||||
c->doLock();
|
||||
locked << c->objectPath();
|
||||
if (!c->doLock()) {
|
||||
return dismiss();
|
||||
}
|
||||
m_locked << c->objectPath();
|
||||
}
|
||||
}
|
||||
|
||||
emit completed(false, QVariant::fromValue(locked));
|
||||
emit completed(false, QVariant::fromValue(m_locked));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
DBusReturn<void> LockCollectionsPrompt::dismiss()
|
||||
{
|
||||
emit completed(true, QVariant::fromValue(m_locked));
|
||||
return {};
|
||||
}
|
||||
|
||||
UnlockCollectionsPrompt::UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& colls)
|
||||
: PromptBase(parent)
|
||||
{
|
||||
@ -191,6 +204,7 @@ namespace FdoSecrets
|
||||
|
||||
for (const auto& c : asConst(m_collections)) {
|
||||
if (c) {
|
||||
// doUnlock is nonblocking
|
||||
connect(c, &Collection::doneUnlockCollection, this, &UnlockCollectionsPrompt::collectionUnlockFinished);
|
||||
c->doUnlock();
|
||||
}
|
||||
@ -226,6 +240,11 @@ namespace FdoSecrets
|
||||
emit completed(m_unlocked.isEmpty(), QVariant::fromValue(m_unlocked));
|
||||
}
|
||||
}
|
||||
DBusReturn<void> UnlockCollectionsPrompt::dismiss()
|
||||
{
|
||||
emit completed(true, QVariant::fromValue(m_unlocked));
|
||||
return {};
|
||||
}
|
||||
|
||||
DeleteItemPrompt::DeleteItemPrompt(Service* parent, Item* item)
|
||||
: PromptBase(parent)
|
||||
@ -250,14 +269,18 @@ namespace FdoSecrets
|
||||
// delete item's backend. Item will be notified after the backend is deleted.
|
||||
if (m_item) {
|
||||
if (FdoSecrets::settings()->noConfirmDeleteItem()) {
|
||||
MessageBox::setNextAnswer(MessageBox::Move);
|
||||
// based on permanent or not, different button is used
|
||||
if (m_item->isDeletePermanent()) {
|
||||
MessageBox::setNextAnswer(MessageBox::Delete);
|
||||
} else {
|
||||
MessageBox::setNextAnswer(MessageBox::Move);
|
||||
}
|
||||
}
|
||||
m_item->collection()->doDeleteEntries({m_item->backend()});
|
||||
}
|
||||
|
||||
emit completed(false, {});
|
||||
emit completed(false, "");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace FdoSecrets
|
||||
|
@ -73,6 +73,7 @@ namespace FdoSecrets
|
||||
explicit CreateCollectionPrompt(Service* parent);
|
||||
|
||||
DBusReturn<void> prompt(const QString& windowId) override;
|
||||
DBusReturn<void> dismiss() override;
|
||||
|
||||
signals:
|
||||
void collectionCreated(Collection* coll);
|
||||
@ -85,9 +86,11 @@ namespace FdoSecrets
|
||||
explicit LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls);
|
||||
|
||||
DBusReturn<void> prompt(const QString& windowId) override;
|
||||
DBusReturn<void> dismiss() override;
|
||||
|
||||
private:
|
||||
QList<QPointer<Collection>> m_collections;
|
||||
QList<QDBusObjectPath> m_locked;
|
||||
};
|
||||
|
||||
class UnlockCollectionsPrompt : public PromptBase
|
||||
@ -97,6 +100,7 @@ namespace FdoSecrets
|
||||
explicit UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& coll);
|
||||
|
||||
DBusReturn<void> prompt(const QString& windowId) override;
|
||||
DBusReturn<void> dismiss() override;
|
||||
|
||||
private slots:
|
||||
void collectionUnlockFinished(bool accepted);
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -23,6 +23,7 @@ QTEST_GUILESS_MAIN(TestEntrySearcher)
|
||||
void TestEntrySearcher::init()
|
||||
{
|
||||
m_rootGroup = new Group();
|
||||
m_entrySearcher = EntrySearcher();
|
||||
}
|
||||
|
||||
void TestEntrySearcher::cleanup()
|
||||
@ -259,6 +260,7 @@ void TestEntrySearcher::testCustomAttributesAreSearched()
|
||||
QCOMPARE(m_searchResult.count(), 2);
|
||||
|
||||
// protected attributes are ignored
|
||||
m_entrySearcher = EntrySearcher(false, true);
|
||||
m_searchResult = m_entrySearcher.search("_testAttribute:test _testProtected:testP2", m_rootGroup);
|
||||
QCOMPARE(m_searchResult.count(), 2);
|
||||
}
|
||||
@ -319,3 +321,52 @@ void TestEntrySearcher::testGroup()
|
||||
m_searchResult = m_entrySearcher.search("g:/group1 search", m_rootGroup);
|
||||
QCOMPARE(m_searchResult.count(), 1);
|
||||
}
|
||||
|
||||
void TestEntrySearcher::testSkipProtected()
|
||||
{
|
||||
QScopedPointer<Entry> e1(new Entry());
|
||||
e1->setGroup(m_rootGroup);
|
||||
|
||||
e1->attributes()->set("testAttribute", "testE1");
|
||||
e1->attributes()->set("testProtected", "apple", true);
|
||||
|
||||
QScopedPointer<Entry> e2(new Entry());
|
||||
e2->setGroup(m_rootGroup);
|
||||
e2->attributes()->set("testAttribute", "testE2");
|
||||
e2->attributes()->set("testProtected", "banana", true);
|
||||
|
||||
const QList<Entry*> expectE1{e1.data()};
|
||||
const QList<Entry*> expectE2{e2.data()};
|
||||
const QList<Entry*> expectBoth{e1.data(), e2.data()};
|
||||
|
||||
// when not skipping protected, empty term matches everything
|
||||
m_searchResult = m_entrySearcher.search("", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, expectBoth);
|
||||
|
||||
// now test the searcher with skipProtected = true
|
||||
m_entrySearcher = EntrySearcher(false, true);
|
||||
|
||||
// when skipping protected, empty term matches nothing
|
||||
m_searchResult = m_entrySearcher.search("", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, {});
|
||||
|
||||
// having a protected entry in terms should not affect the results in anyways
|
||||
m_searchResult = m_entrySearcher.search("_testProtected:apple", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, {});
|
||||
m_searchResult = m_entrySearcher.search("_testProtected:apple _testAttribute:testE2", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, expectE2);
|
||||
m_searchResult = m_entrySearcher.search("_testProtected:apple _testAttribute:testE1", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, expectE1);
|
||||
m_searchResult =
|
||||
m_entrySearcher.search("_testProtected:apple _testAttribute:testE1 _testAttribute:testE2", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, {});
|
||||
|
||||
// also move the protected term around to execurise the short-circut logic
|
||||
m_searchResult = m_entrySearcher.search("_testAttribute:testE2 _testProtected:apple", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, expectE2);
|
||||
m_searchResult = m_entrySearcher.search("_testAttribute:testE1 _testProtected:apple", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, expectE1);
|
||||
m_searchResult =
|
||||
m_entrySearcher.search("_testAttribute:testE1 _testProtected:apple _testAttribute:testE2", m_rootGroup);
|
||||
QCOMPARE(m_searchResult, {});
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ private slots:
|
||||
void testSearchTermParser();
|
||||
void testCustomAttributesAreSearched();
|
||||
void testGroup();
|
||||
void testSkipProtected();
|
||||
|
||||
private:
|
||||
Group* m_rootGroup;
|
||||
|
@ -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>
|
21
tests/data/dbus/interfaces/org.freedesktop.Secret.Item.xml
Normal file
21
tests/data/dbus/interfaces/org.freedesktop.Secret.Item.xml
Normal 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>
|
11
tests/data/dbus/interfaces/org.freedesktop.Secret.Prompt.xml
Normal file
11
tests/data/dbus/interfaces/org.freedesktop.Secret.Prompt.xml
Normal 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>
|
@ -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>
|
@ -0,0 +1,4 @@
|
||||
<interface name="org.freedesktop.Secret.Session">
|
||||
<method name="Close">
|
||||
</method>
|
||||
</interface>
|
39
tests/data/dbus/session.conf
Normal file
39
tests/data/dbus/session.conf
Normal 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>
|
@ -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()
|
||||
|
1175
tests/gui/TestGuiFdoSecrets.cpp
Normal file
1175
tests/gui/TestGuiFdoSecrets.cpp
Normal file
File diff suppressed because it is too large
Load Diff
121
tests/gui/TestGuiFdoSecrets.h
Normal file
121
tests/gui/TestGuiFdoSecrets.h
Normal 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
|
Loading…
Reference in New Issue
Block a user