FdoSecrets: refactor DBus registration error handling

This commit is contained in:
Aetf 2020-11-02 22:58:54 -05:00
parent f8f2271f33
commit 000e1823ac
15 changed files with 281 additions and 76 deletions

View file

@ -26,8 +26,6 @@
#include <QFile> #include <QFile>
#include <utility>
using FdoSecrets::Service; using FdoSecrets::Service;
// TODO: Only used for testing. Need to split service functions away from settings page. // TODO: Only used for testing. Need to split service functions away from settings page.
@ -65,12 +63,8 @@ void FdoSecretsPlugin::updateServiceState()
{ {
if (FdoSecrets::settings()->isEnabled()) { if (FdoSecrets::settings()->isEnabled()) {
if (!m_secretService && m_dbTabs) { if (!m_secretService && m_dbTabs) {
m_secretService.reset(new Service(this, m_dbTabs)); m_secretService = Service::Create(this, m_dbTabs);
connect(m_secretService.data(), &Service::error, this, [this](const QString& msg) { if (!m_secretService) {
emit error(tr("<b>Fdo Secret Service:</b> %1").arg(msg));
});
if (!m_secretService->initialize()) {
m_secretService.reset();
FdoSecrets::settings()->setEnabled(false); FdoSecrets::settings()->setEnabled(false);
return; return;
} }
@ -86,7 +80,7 @@ void FdoSecretsPlugin::updateServiceState()
Service* FdoSecretsPlugin::serviceInstance() const Service* FdoSecretsPlugin::serviceInstance() const
{ {
return m_secretService.data(); return m_secretService.get();
} }
DatabaseTabWidget* FdoSecretsPlugin::dbTabs() const DatabaseTabWidget* FdoSecretsPlugin::dbTabs() const
@ -107,6 +101,11 @@ void FdoSecretsPlugin::emitRequestShowNotification(const QString& msg, const QSt
emit requestShowNotification(msg, title, 10000); emit requestShowNotification(msg, title, 10000);
} }
void FdoSecretsPlugin::emitError(const QString& msg)
{
emit error(tr("<b>Fdo Secret Service:</b> %1").arg(msg));
}
QString FdoSecretsPlugin::reportExistingService() const QString FdoSecretsPlugin::reportExistingService() const
{ {
auto pidStr = tr("Unknown", "Unknown PID"); auto pidStr = tr("Unknown", "Unknown PID");

View file

@ -22,7 +22,8 @@
#include "gui/Icons.h" #include "gui/Icons.h"
#include <QPointer> #include <QPointer>
#include <QScopedPointer>
#include <memory>
class DatabaseTabWidget; class DatabaseTabWidget;
@ -77,6 +78,12 @@ public slots:
void emitRequestSwitchToDatabases(); void emitRequestSwitchToDatabases();
void emitRequestShowNotification(const QString& msg, const QString& title = {}); void emitRequestShowNotification(const QString& msg, const QString& title = {});
/**
* @brief Show error in the GUI
* @param msg
*/
void emitError(const QString& msg);
signals: signals:
void error(const QString& msg); void error(const QString& msg);
void requestSwitchToDatabases(); void requestSwitchToDatabases();
@ -86,7 +93,7 @@ signals:
private: private:
QPointer<DatabaseTabWidget> m_dbTabs; QPointer<DatabaseTabWidget> m_dbTabs;
QScopedPointer<FdoSecrets::Service> m_secretService; std::unique_ptr<FdoSecrets::Service> m_secretService;
}; };
#endif // KEEPASSXC_FDOSECRETSPLUGIN_H #endif // KEEPASSXC_FDOSECRETSPLUGIN_H

View file

@ -17,6 +17,7 @@
#include "Collection.h" #include "Collection.h"
#include "fdosecrets/FdoSecretsPlugin.h"
#include "fdosecrets/FdoSecretsSettings.h" #include "fdosecrets/FdoSecretsSettings.h"
#include "fdosecrets/objects/Item.h" #include "fdosecrets/objects/Item.h"
#include "fdosecrets/objects/Prompt.h" #include "fdosecrets/objects/Prompt.h"
@ -34,6 +35,18 @@
namespace FdoSecrets namespace FdoSecrets
{ {
Collection* Collection::Create(Service* parent, DatabaseWidget* backend)
{
std::unique_ptr<Collection> coll{new Collection(parent, backend)};
if (!coll->reloadBackend()) {
return nullptr;
}
if (!coll->backend()) {
// no exposed group on this db
return nullptr;
}
return coll.release();
}
Collection::Collection(Service* parent, DatabaseWidget* backend) Collection::Collection(Service* parent, DatabaseWidget* backend)
: DBusObject(parent) : DBusObject(parent)
@ -56,11 +69,9 @@ namespace FdoSecrets
} }
emit doneUnlockCollection(accepted); emit doneUnlockCollection(accepted);
}); });
reloadBackend();
} }
void Collection::reloadBackend() bool Collection::reloadBackend()
{ {
if (m_registered) { if (m_registered) {
// delete all items // delete all items
@ -83,9 +94,11 @@ namespace FdoSecrets
// the database may not have a name (derived from filePath) yet, which may happen if it's newly created. // the database may not have a name (derived from filePath) yet, which may happen if it's newly created.
// defer the registration to next time a file path change happens. // defer the registration to next time a file path change happens.
if (!name().isEmpty()) { if (!name().isEmpty()) {
registerWithPath( auto path = QStringLiteral(DBUS_PATH_TEMPLATE_COLLECTION).arg(p()->objectPath().path(), encodePath(name()));
QStringLiteral(DBUS_PATH_TEMPLATE_COLLECTION).arg(p()->objectPath().path(), encodePath(name())), if (!registerWithPath(path, new CollectionAdaptor(this))) {
new CollectionAdaptor(this)); service()->plugin()->emitError(tr("Failed to register database on DBus under the name '%1'").arg(name()));
return false;
}
m_registered = true; m_registered = true;
} }
@ -95,6 +108,8 @@ namespace FdoSecrets
} else { } else {
cleanupConnections(); cleanupConnections();
} }
return true;
} }
DBusReturn<void> Collection::ensureBackend() const DBusReturn<void> Collection::ensureBackend() const
@ -197,7 +212,11 @@ namespace FdoSecrets
} }
// Delete means close database // Delete means close database
auto prompt = new DeleteCollectionPrompt(service(), this); auto dpret = DeleteCollectionPrompt::Create(service(), this);
if (dpret.isError()) {
return dpret;
}
auto prompt = dpret.value();
if (backendLocked()) { if (backendLocked()) {
// this won't raise a dialog, immediate execute // this won't raise a dialog, immediate execute
auto pret = prompt->prompt({}); auto pret = prompt->prompt({});
@ -405,6 +424,8 @@ namespace FdoSecrets
if (ok) { if (ok) {
m_aliases.insert(alias); m_aliases.insert(alias);
emit aliasAdded(alias); emit aliasAdded(alias);
} else {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
} }
return {}; return {};
@ -558,7 +579,7 @@ namespace FdoSecrets
return; return;
} }
auto item = new Item(this, entry); auto item = Item::Create(this, entry);
m_items << item; m_items << item;
m_entryToItem[entry] = item; m_entryToItem[entry] = item;

View file

@ -39,8 +39,19 @@ namespace FdoSecrets
class Collection : public DBusObject class Collection : public DBusObject
{ {
Q_OBJECT Q_OBJECT
public:
explicit Collection(Service* parent, DatabaseWidget* backend); explicit Collection(Service* parent, DatabaseWidget* backend);
public:
/**
* @brief Create a new instance of `Collection`
* @param parent the owning Service
* @param backend the widget containing the database
* @return pointer to created instance, or nullptr when error happens.
* This may be caused by
* - DBus path registration error
* - database has no exposed group
*/
static Collection* Create(Service* parent, DatabaseWidget* backend);
DBusReturn<const QList<Item*>> items() const; DBusReturn<const QList<Item*>> items() const;
@ -101,7 +112,7 @@ namespace FdoSecrets
static EntrySearcher::SearchTerm attributeToTerm(const QString& key, const QString& value); static EntrySearcher::SearchTerm attributeToTerm(const QString& key, const QString& value);
public slots: public slots:
// expose some methods for Prmopt to use // expose some methods for Prompt to use
bool doLock(); bool doLock();
void doUnlock(); void doUnlock();
// will remove self // will remove self
@ -114,7 +125,7 @@ namespace FdoSecrets
void onDatabaseLockChanged(); void onDatabaseLockChanged();
void onDatabaseExposedGroupChanged(); void onDatabaseExposedGroupChanged();
// force reload info from backend, potentially delete self // force reload info from backend, potentially delete self
void reloadBackend(); bool reloadBackend();
private: private:
friend class DeleteCollectionPrompt; friend class DeleteCollectionPrompt;

View file

@ -31,17 +31,18 @@ namespace FdoSecrets
DBusObject::DBusObject(DBusObject* parent) DBusObject::DBusObject(DBusObject* parent)
: QObject(parent) : QObject(parent)
, m_dbusAdaptor(nullptr)
{ {
} }
void DBusObject::registerWithPath(const QString& path, QDBusAbstractAdaptor* adaptor) bool DBusObject::registerWithPath(const QString& path, QDBusAbstractAdaptor* adaptor)
{ {
Q_ASSERT(!m_dbusAdaptor);
m_objectPath.setPath(path); m_objectPath.setPath(path);
m_dbusAdaptor = adaptor; m_dbusAdaptor = adaptor;
adaptor->setParent(this); adaptor->setParent(this);
auto ok = QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this); return QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this);
Q_UNUSED(ok);
Q_ASSERT(ok);
} }
QString DBusObject::callingPeerName() const QString DBusObject::callingPeerName() const

View file

@ -57,7 +57,7 @@ namespace FdoSecrets
} }
protected: protected:
void registerWithPath(const QString& path, QDBusAbstractAdaptor* adaptor); bool registerWithPath(const QString& path, QDBusAbstractAdaptor* adaptor);
void unregisterCurrentPath() void unregisterCurrentPath()
{ {

View file

@ -43,6 +43,7 @@
#define DBUS_PATH_TEMPLATE_SESSION "%1/session/%2" #define DBUS_PATH_TEMPLATE_SESSION "%1/session/%2"
#define DBUS_PATH_TEMPLATE_COLLECTION "%1/collection/%2" #define DBUS_PATH_TEMPLATE_COLLECTION "%1/collection/%2"
#define DBUS_PATH_TEMPLATE_ITEM "%1/%2" #define DBUS_PATH_TEMPLATE_ITEM "%1/%2"
#define DBUS_PATH_TEMPLATE_PROMPT "%1/prompt/%2"
namespace FdoSecrets namespace FdoSecrets
{ {

View file

@ -48,18 +48,36 @@ namespace FdoSecrets
constexpr auto FDO_SECRETS_CONTENT_TYPE = "FDO_SECRETS_CONTENT_TYPE"; constexpr auto FDO_SECRETS_CONTENT_TYPE = "FDO_SECRETS_CONTENT_TYPE";
} // namespace } // namespace
Item* Item::Create(Collection* parent, Entry* backend)
{
std::unique_ptr<Item> res{new Item(parent, backend)};
if (!res->registerSelf()) {
return nullptr;
}
return res.release();
}
Item::Item(Collection* parent, Entry* backend) Item::Item(Collection* parent, Entry* backend)
: DBusObject(parent) : DBusObject(parent)
, m_backend(backend) , m_backend(backend)
{ {
Q_ASSERT(!p()->objectPath().path().isEmpty()); Q_ASSERT(!p()->objectPath().path().isEmpty());
registerWithPath(QStringLiteral(DBUS_PATH_TEMPLATE_ITEM).arg(p()->objectPath().path(), m_backend->uuidToHex()),
new ItemAdaptor(this));
connect(m_backend.data(), &Entry::entryModified, this, &Item::itemChanged); connect(m_backend.data(), &Entry::entryModified, this, &Item::itemChanged);
} }
bool Item::registerSelf()
{
auto path = QStringLiteral(DBUS_PATH_TEMPLATE_ITEM).arg(p()->objectPath().path(), m_backend->uuidToHex());
bool ok = registerWithPath(path, new ItemAdaptor(this));
if (!ok) {
service()->plugin()->emitError(tr("Failed to register item on DBus at path '%1'").arg(path));
}
return ok;
}
DBusReturn<bool> Item::locked() const DBusReturn<bool> Item::locked() const
{ {
auto ret = ensureBackend(); auto ret = ensureBackend();
@ -206,8 +224,8 @@ namespace FdoSecrets
if (ret.isError()) { if (ret.isError()) {
return ret; return ret;
} }
auto prompt = new DeleteItemPrompt(service(), this); auto prompt = DeleteItemPrompt::Create(service(), this);
return prompt; return prompt.value();
} }
DBusReturn<SecretStruct> Item::getSecret(Session* session) DBusReturn<SecretStruct> Item::getSecret(Session* session)

View file

@ -41,8 +41,18 @@ namespace FdoSecrets
class Item : public DBusObject class Item : public DBusObject
{ {
Q_OBJECT Q_OBJECT
public:
explicit Item(Collection* parent, Entry* backend); explicit Item(Collection* parent, Entry* backend);
public:
/**
* @brief Create a new instance of `Item`.
* @param parent the owning `Collection`
* @param backend the `Entry` containing the data
* @return pointer to newly created Item, or nullptr if error
* This may be caused by
* - DBus path registration error
*/
static Item* Create(Collection* parent, Entry* backend);
DBusReturn<bool> locked() const; DBusReturn<bool> locked() const;
@ -91,6 +101,12 @@ namespace FdoSecrets
void doDelete(); void doDelete();
private: private:
/**
* @brief Register self on DBus
* @return
*/
bool registerSelf();
/** /**
* Check if the backend is a valid object, send error reply if not. * Check if the backend is a valid object, send error reply if not.
* @return No error if the backend is valid. * @return No error if the backend is valid.

View file

@ -17,6 +17,7 @@
#include "Prompt.h" #include "Prompt.h"
#include "fdosecrets/FdoSecretsPlugin.h"
#include "fdosecrets/FdoSecretsSettings.h" #include "fdosecrets/FdoSecretsSettings.h"
#include "fdosecrets/objects/Collection.h" #include "fdosecrets/objects/Collection.h"
#include "fdosecrets/objects/Item.h" #include "fdosecrets/objects/Item.h"
@ -35,13 +36,19 @@ namespace FdoSecrets
PromptBase::PromptBase(Service* parent) PromptBase::PromptBase(Service* parent)
: DBusObject(parent) : DBusObject(parent)
{ {
registerWithPath(
QStringLiteral("%1/prompt/%2").arg(p()->objectPath().path(), Tools::uuidToHex(QUuid::createUuid())),
new PromptAdaptor(this));
connect(this, &PromptBase::completed, this, &PromptBase::deleteLater); connect(this, &PromptBase::completed, this, &PromptBase::deleteLater);
} }
bool PromptBase::registerSelf()
{
auto path = QStringLiteral(DBUS_PATH_TEMPLATE_PROMPT).arg(p()->objectPath().path(), Tools::uuidToHex(QUuid::createUuid()));
bool ok = registerWithPath(path, new PromptAdaptor(this));
if (!ok) {
service()->plugin()->emitError(tr("Failed to register item on DBus at path '%1'").arg(path));
}
return ok;
}
QWindow* PromptBase::findWindow(const QString& windowId) QWindow* PromptBase::findWindow(const QString& windowId)
{ {
// find parent window, or nullptr if not found // find parent window, or nullptr if not found
@ -69,6 +76,15 @@ namespace FdoSecrets
return {}; return {};
} }
DBusReturn<DeleteCollectionPrompt*> DeleteCollectionPrompt::Create(Service* parent, Collection* coll)
{
std::unique_ptr<DeleteCollectionPrompt> res{new DeleteCollectionPrompt(parent, coll)};
if (!res->registerSelf()) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
return res.release();
}
DeleteCollectionPrompt::DeleteCollectionPrompt(Service* parent, Collection* coll) DeleteCollectionPrompt::DeleteCollectionPrompt(Service* parent, Collection* coll)
: PromptBase(parent) : PromptBase(parent)
, m_collection(coll) , m_collection(coll)
@ -100,6 +116,15 @@ namespace FdoSecrets
return {}; return {};
} }
DBusReturn<CreateCollectionPrompt*> CreateCollectionPrompt::Create(Service* parent)
{
std::unique_ptr<CreateCollectionPrompt> res{new CreateCollectionPrompt(parent)};
if (!res->registerSelf()) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
return res.release();
}
CreateCollectionPrompt::CreateCollectionPrompt(Service* parent) CreateCollectionPrompt::CreateCollectionPrompt(Service* parent)
: PromptBase(parent) : PromptBase(parent)
{ {
@ -136,6 +161,15 @@ namespace FdoSecrets
return {}; return {};
} }
DBusReturn<LockCollectionsPrompt*> LockCollectionsPrompt::Create(Service* parent, const QList<Collection*>& colls)
{
std::unique_ptr<LockCollectionsPrompt> res{new LockCollectionsPrompt(parent, colls)};
if (!res->registerSelf()) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
return res.release();
}
LockCollectionsPrompt::LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls) LockCollectionsPrompt::LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls)
: PromptBase(parent) : PromptBase(parent)
{ {
@ -179,6 +213,15 @@ namespace FdoSecrets
return {}; return {};
} }
DBusReturn<UnlockCollectionsPrompt*> UnlockCollectionsPrompt::Create(Service* parent, const QList<Collection*>& coll)
{
std::unique_ptr<UnlockCollectionsPrompt> res{new UnlockCollectionsPrompt(parent, coll)};
if (!res->registerSelf()) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
return res.release();
}
UnlockCollectionsPrompt::UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& colls) UnlockCollectionsPrompt::UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& colls)
: PromptBase(parent) : PromptBase(parent)
{ {
@ -246,6 +289,15 @@ namespace FdoSecrets
return {}; return {};
} }
DBusReturn<DeleteItemPrompt*> DeleteItemPrompt::Create(Service* parent, Item* item)
{
std::unique_ptr<DeleteItemPrompt> res{new DeleteItemPrompt(parent, item)};
if (!res->registerSelf()) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
return res.release();
}
DeleteItemPrompt::DeleteItemPrompt(Service* parent, Item* item) DeleteItemPrompt::DeleteItemPrompt(Service* parent, Item* item)
: PromptBase(parent) : PromptBase(parent)
, m_item(item) , m_item(item)

View file

@ -36,8 +36,6 @@ namespace FdoSecrets
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit PromptBase(Service* parent);
virtual DBusReturn<void> prompt(const QString& windowId) = 0; virtual DBusReturn<void> prompt(const QString& windowId) = 0;
virtual DBusReturn<void> dismiss(); virtual DBusReturn<void> dismiss();
@ -46,6 +44,9 @@ namespace FdoSecrets
void completed(bool dismissed, const QVariant& result); void completed(bool dismissed, const QVariant& result);
protected: protected:
explicit PromptBase(Service* parent);
bool registerSelf();
QWindow* findWindow(const QString& windowId); QWindow* findWindow(const QString& windowId);
Service* service() const; Service* service() const;
}; };
@ -56,8 +57,9 @@ namespace FdoSecrets
{ {
Q_OBJECT Q_OBJECT
public:
explicit DeleteCollectionPrompt(Service* parent, Collection* coll); explicit DeleteCollectionPrompt(Service* parent, Collection* coll);
public:
static DBusReturn<DeleteCollectionPrompt*> Create(Service* parent, Collection* coll);
DBusReturn<void> prompt(const QString& windowId) override; DBusReturn<void> prompt(const QString& windowId) override;
@ -69,8 +71,9 @@ namespace FdoSecrets
{ {
Q_OBJECT Q_OBJECT
public:
explicit CreateCollectionPrompt(Service* parent); explicit CreateCollectionPrompt(Service* parent);
public:
static DBusReturn<CreateCollectionPrompt*> Create(Service* parent);
DBusReturn<void> prompt(const QString& windowId) override; DBusReturn<void> prompt(const QString& windowId) override;
DBusReturn<void> dismiss() override; DBusReturn<void> dismiss() override;
@ -82,8 +85,10 @@ namespace FdoSecrets
class LockCollectionsPrompt : public PromptBase class LockCollectionsPrompt : public PromptBase
{ {
Q_OBJECT Q_OBJECT
public:
explicit LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls); explicit LockCollectionsPrompt(Service* parent, const QList<Collection*>& colls);
public:
static DBusReturn<LockCollectionsPrompt*> Create(Service* parent, const QList<Collection*>& colls);
DBusReturn<void> prompt(const QString& windowId) override; DBusReturn<void> prompt(const QString& windowId) override;
DBusReturn<void> dismiss() override; DBusReturn<void> dismiss() override;
@ -96,8 +101,10 @@ namespace FdoSecrets
class UnlockCollectionsPrompt : public PromptBase class UnlockCollectionsPrompt : public PromptBase
{ {
Q_OBJECT Q_OBJECT
public:
explicit UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& coll); explicit UnlockCollectionsPrompt(Service* parent, const QList<Collection*>& coll);
public:
static DBusReturn<UnlockCollectionsPrompt*> Create(Service* parent, const QList<Collection*>& coll);
DBusReturn<void> prompt(const QString& windowId) override; DBusReturn<void> prompt(const QString& windowId) override;
DBusReturn<void> dismiss() override; DBusReturn<void> dismiss() override;
@ -116,8 +123,9 @@ namespace FdoSecrets
{ {
Q_OBJECT Q_OBJECT
public:
explicit DeleteItemPrompt(Service* parent, Item* item); explicit DeleteItemPrompt(Service* parent, Item* item);
public:
static DBusReturn<DeleteItemPrompt*> Create(Service* parent, Item* item);
DBusReturn<void> prompt(const QString& windowId) override; DBusReturn<void> prompt(const QString& windowId) override;

View file

@ -31,6 +31,8 @@
#include <QDBusServiceWatcher> #include <QDBusServiceWatcher>
#include <QDebug> #include <QDebug>
#include <utility>
namespace namespace
{ {
constexpr auto DEFAULT_ALIAS = "default"; constexpr auto DEFAULT_ALIAS = "default";
@ -38,6 +40,14 @@ namespace
namespace FdoSecrets namespace FdoSecrets
{ {
std::unique_ptr<Service> Service::Create(FdoSecretsPlugin* plugin, QPointer<DatabaseTabWidget> dbTabs)
{
std::unique_ptr<Service> res{new Service(plugin, std::move(dbTabs))};
if (!res->initialize()) {
return {};
}
return res;
}
Service::Service(FdoSecretsPlugin* plugin, Service::Service(FdoSecretsPlugin* plugin,
QPointer<DatabaseTabWidget> dbTabs) // clazy: exclude=ctor-missing-parent-argument QPointer<DatabaseTabWidget> dbTabs) // clazy: exclude=ctor-missing-parent-argument
@ -59,16 +69,19 @@ namespace FdoSecrets
bool Service::initialize() bool Service::initialize()
{ {
if (!QDBusConnection::sessionBus().registerService(QStringLiteral(DBUS_SERVICE_SECRET))) { if (!QDBusConnection::sessionBus().registerService(QStringLiteral(DBUS_SERVICE_SECRET))) {
emit error(tr("Failed to register DBus service at %1.<br/>").arg(QLatin1String(DBUS_SERVICE_SECRET)) plugin()->emitError(tr("Failed to register DBus service at %1.<br/>").arg(QLatin1String(DBUS_SERVICE_SECRET))
+ m_plugin->reportExistingService()); + m_plugin->reportExistingService());
return false; return false;
} }
registerWithPath(QStringLiteral(DBUS_PATH_SECRETS), new ServiceAdaptor(this)); if (!registerWithPath(QStringLiteral(DBUS_PATH_SECRETS), new ServiceAdaptor(this))) {
plugin()->emitError(tr("Failed to register DBus path %1.<br/>").arg(QStringLiteral(DBUS_PATH_SECRETS)));
return false;
}
// Connect to service unregistered signal // Connect to service unregistered signal
m_serviceWatcher.reset(new QDBusServiceWatcher()); m_serviceWatcher.reset(new QDBusServiceWatcher());
connect(m_serviceWatcher.data(), connect(m_serviceWatcher.get(),
&QDBusServiceWatcher::serviceUnregistered, &QDBusServiceWatcher::serviceUnregistered,
this, this,
&Service::dbusServiceUnregistered); &Service::dbusServiceUnregistered);
@ -106,11 +119,10 @@ namespace FdoSecrets
monitorDatabaseExposedGroup(dbWidget); monitorDatabaseExposedGroup(dbWidget);
}); });
auto coll = new Collection(this, dbWidget); auto coll = Collection::Create(this, dbWidget);
// Creation may fail if the database is not exposed. if (!coll) {
// The creation may fail if the database is not exposed.
// This is okay, because we monitor the expose settings above // This is okay, because we monitor the expose settings above
if (!coll->isValid()) {
coll->deleteLater();
return; return;
} }
@ -184,8 +196,9 @@ namespace FdoSecrets
Q_ASSERT(m_serviceWatcher); Q_ASSERT(m_serviceWatcher);
auto removed = m_serviceWatcher->removeWatchedService(service); auto removed = m_serviceWatcher->removeWatchedService(service);
Q_UNUSED(removed); if (!removed) {
Q_ASSERT(removed); qDebug("FdoSecrets: Failed to remove service watcher");
}
Session::CleanupNegotiation(service); Session::CleanupNegotiation(service);
auto sess = m_peerToSession.value(service, nullptr); auto sess = m_peerToSession.value(service, nullptr);
@ -218,7 +231,10 @@ namespace FdoSecrets
if (!ciphers) { if (!ciphers) {
return DBusReturn<>::Error(QDBusError::NotSupported); return DBusReturn<>::Error(QDBusError::NotSupported);
} }
result = new Session(std::move(ciphers), callingPeerName(), this); result = Session::Create(std::move(ciphers), callingPeerName(), this);
if (!result) {
return DBusReturn<>::Error(QDBusError::InvalidObjectPath);
}
m_sessions.append(result); m_sessions.append(result);
m_peerToSession[peer] = result; m_peerToSession[peer] = result;
@ -240,12 +256,15 @@ namespace FdoSecrets
// return existing collection if alias is non-empty and exists. // return existing collection if alias is non-empty and exists.
auto collection = findCollection(alias); auto collection = findCollection(alias);
if (!collection) { if (!collection) {
auto cp = new CreateCollectionPrompt(this); auto cp = CreateCollectionPrompt::Create(this);
prompt = cp; if (cp.isError()) {
return cp;
}
prompt = cp.value();
// collection will be created when the prompt complets. // collection will be created when the prompt completes.
// once it's done, we set additional properties on the collection // once it's done, we set additional properties on the collection
connect(cp, &CreateCollectionPrompt::collectionCreated, cp, [alias, properties](Collection* coll) { connect(cp.value(), &CreateCollectionPrompt::collectionCreated, cp.value(), [alias, properties](Collection* coll) {
coll->setProperties(properties).okOrDie(); coll->setProperties(properties).okOrDie();
if (!alias.isEmpty()) { if (!alias.isEmpty()) {
coll->addAlias(alias).okOrDie(); coll->addAlias(alias).okOrDie();
@ -314,7 +333,11 @@ namespace FdoSecrets
} }
} }
if (!toUnlock.isEmpty()) { if (!toUnlock.isEmpty()) {
prompt = new UnlockCollectionsPrompt(this, toUnlock); auto up = UnlockCollectionsPrompt::Create(this, toUnlock);
if (up.isError()) {
return up;
}
prompt = up.value();
} }
return unlocked; return unlocked;
} }
@ -352,7 +375,11 @@ namespace FdoSecrets
} }
} }
if (!toLock.isEmpty()) { if (!toLock.isEmpty()) {
prompt = new LockCollectionsPrompt(this, toLock); auto lp = LockCollectionsPrompt::Create(this, toLock);
if (lp.isError()) {
return lp;
}
prompt = lp.value();
} }
return locked; return locked;
} }

View file

@ -24,9 +24,10 @@
#include <QHash> #include <QHash>
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QScopedPointer>
#include <QVariant> #include <QVariant>
#include <memory>
class QDBusServiceWatcher; class QDBusServiceWatcher;
class DatabaseTabWidget; class DatabaseTabWidget;
@ -47,11 +48,17 @@ namespace FdoSecrets
class Service : public DBusObject // clazy: exclude=ctor-missing-parent-argument class Service : public DBusObject // clazy: exclude=ctor-missing-parent-argument
{ {
Q_OBJECT Q_OBJECT
public:
explicit Service(FdoSecretsPlugin* plugin, QPointer<DatabaseTabWidget> dbTabs);
~Service() override;
bool initialize(); explicit Service(FdoSecretsPlugin* plugin, QPointer<DatabaseTabWidget> dbTabs);
public:
/**
* @brief Create a new instance of `Service`. Its parent is set to `null`
* @return pointer to newly created Service, or nullptr if error
* This may be caused by
* - failed initialization
*/
static std::unique_ptr<Service> Create(FdoSecretsPlugin* plugin, QPointer<DatabaseTabWidget> dbTabs);
~Service() override;
DBusReturn<QVariant> openSession(const QString& algorithm, const QVariant& input, Session*& result); DBusReturn<QVariant> openSession(const QString& algorithm, const QVariant& input, Session*& result);
DBusReturn<Collection*> DBusReturn<Collection*>
@ -82,12 +89,6 @@ namespace FdoSecrets
void sessionOpened(Session* sess); void sessionOpened(Session* sess);
void sessionClosed(Session* sess); void sessionClosed(Session* sess);
/**
* Report error message to the GUI
* @param msg
*/
void error(const QString& msg);
/** /**
* Finish signal for async action doUnlockDatabaseInDialog * Finish signal for async action doUnlockDatabaseInDialog
* @param accepted If false, the action is canceled by the user * @param accepted If false, the action is canceled by the user
@ -131,6 +132,8 @@ namespace FdoSecrets
void onCollectionAliasRemoved(const QString& alias); void onCollectionAliasRemoved(const QString& alias);
private: private:
bool initialize();
/** /**
* Find collection by alias name * Find collection by alias name
* @param alias * @param alias
@ -158,7 +161,7 @@ namespace FdoSecrets
bool m_insdieEnsureDefaultAlias; bool m_insdieEnsureDefaultAlias;
QScopedPointer<QDBusServiceWatcher> m_serviceWatcher; std::unique_ptr<QDBusServiceWatcher> m_serviceWatcher;
}; };
} // namespace FdoSecrets } // namespace FdoSecrets

View file

@ -16,6 +16,7 @@
*/ */
#include "Session.h" #include "Session.h"
#include "fdosecrets/FdoSecretsPlugin.h"
#include "fdosecrets/objects/SessionCipher.h" #include "fdosecrets/objects/SessionCipher.h"
#include "core/Tools.h" #include "core/Tools.h"
@ -25,14 +26,33 @@ namespace FdoSecrets
QHash<QString, QVariant> Session::negoniationState; QHash<QString, QVariant> Session::negoniationState;
Session* Session::Create(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent)
{
std::unique_ptr<Session> res{new Session(std::move(cipher), peer, parent)};
if (!res->registerSelf()) {
return nullptr;
}
return res.release();
}
Session::Session(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent) Session::Session(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent)
: DBusObject(parent) : DBusObject(parent)
, m_cipher(std::move(cipher)) , m_cipher(std::move(cipher))
, m_peer(peer) , m_peer(peer)
, m_id(QUuid::createUuid()) , m_id(QUuid::createUuid())
{ {
registerWithPath(QStringLiteral(DBUS_PATH_TEMPLATE_SESSION).arg(p()->objectPath().path(), id()), }
new SessionAdaptor(this));
bool Session::registerSelf()
{
auto path = QStringLiteral(DBUS_PATH_TEMPLATE_SESSION).arg(p()->objectPath().path(), id());
bool ok = registerWithPath(path, new SessionAdaptor(this));
if (!ok) {
service()->plugin()->emitError(tr("Failed to register session on DBus at path '%1'").arg(path));
}
return ok;
} }
void Session::CleanupNegotiation(const QString& peer) void Session::CleanupNegotiation(const QString& peer)
@ -58,6 +78,11 @@ namespace FdoSecrets
return Tools::uuidToHex(m_id); return Tools::uuidToHex(m_id);
} }
Service* Session::service() const
{
return qobject_cast<Service*>(parent());
}
std::unique_ptr<CipherPair> Session::CreateCiphers(const QString& peer, std::unique_ptr<CipherPair> Session::CreateCiphers(const QString& peer,
const QString& algorithm, const QString& algorithm,
const QVariant& input, const QVariant& input,

View file

@ -37,6 +37,8 @@ namespace FdoSecrets
class Session : public DBusObject class Session : public DBusObject
{ {
Q_OBJECT Q_OBJECT
explicit Session(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent);
public: public:
static std::unique_ptr<CipherPair> CreateCiphers(const QString& peer, static std::unique_ptr<CipherPair> CreateCiphers(const QString& peer,
const QString& algorithm, const QString& algorithm,
@ -45,7 +47,16 @@ namespace FdoSecrets
bool& incomplete); bool& incomplete);
static void CleanupNegotiation(const QString& peer); static void CleanupNegotiation(const QString& peer);
explicit Session(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent); /**
* @brief Create a new instance of `Session`.
* @param cipher the negotiated cipher
* @param peer connecting peer
* @param parent the owning Service
* @return pointer to newly created Session, or nullptr if error
* This may be caused by
* - DBus path registration error
*/
static Session* Create(std::unique_ptr<CipherPair>&& cipher, const QString& peer, Service* parent);
DBusReturn<void> close(); DBusReturn<void> close();
@ -71,6 +82,8 @@ namespace FdoSecrets
QString id() const; QString id() const;
Service* service() const;
signals: signals:
/** /**
* The session is going to be closed * The session is going to be closed
@ -78,6 +91,9 @@ namespace FdoSecrets
*/ */
void aboutToClose(); void aboutToClose();
private:
bool registerSelf();
private: private:
std::unique_ptr<CipherPair> m_cipher; std::unique_ptr<CipherPair> m_cipher;
QString m_peer; QString m_peer;