Merge PR #341: Add an API keys provider plugin mechanism
This commit is contained in:
commit
c956988f32
1
debian/control
vendored
1
debian/control
vendored
@ -75,6 +75,7 @@ Recommends: nymea-cli,
|
|||||||
nymea-update-plugin-impl,
|
nymea-update-plugin-impl,
|
||||||
nymea-system-plugin-impl,
|
nymea-system-plugin-impl,
|
||||||
nymea-zeroconf-plugin-impl,
|
nymea-zeroconf-plugin-impl,
|
||||||
|
nymea-apikeysprovider-plugin-impl,
|
||||||
Replaces: guhd
|
Replaces: guhd
|
||||||
Description: An open source IoT server - daemon
|
Description: An open source IoT server - daemon
|
||||||
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
||||||
|
|||||||
77
libnymea-core/integrations/apikeysprovidersloader.cpp
Normal file
77
libnymea-core/integrations/apikeysprovidersloader.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "apikeysprovidersloader.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QPluginLoader>
|
||||||
|
|
||||||
|
ApiKeysProvidersLoader::ApiKeysProvidersLoader(QObject *parent):
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (const QString &path, pluginSearchDirs()) {
|
||||||
|
QDir dir(path);
|
||||||
|
qCDebug(dcApiKeys()) << "Loading API keys provider plugins from:" << dir.absolutePath();
|
||||||
|
foreach (const QString &entry, dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
|
QFileInfo fi(path + "/" + entry);
|
||||||
|
if (fi.isFile()) {
|
||||||
|
if (entry.startsWith("libnymea_apikeysproviderplugin") && entry.endsWith(".so")) {
|
||||||
|
loadPlugin(path + "/" + entry);
|
||||||
|
}
|
||||||
|
} else if (fi.isDir()) {
|
||||||
|
if (QFileInfo::exists(path + "/" + entry + "/libnymea_apikeysproviderplugin" + entry + ".so")) {
|
||||||
|
loadPlugin(path + "/" + entry + "/libnymea_apikeysproviderplugin" + entry + ".so");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, ApiKey> ApiKeysProvidersLoader::allApiKeys() const
|
||||||
|
{
|
||||||
|
QHash<QString, ApiKey> ret;
|
||||||
|
foreach (ApiKeysProvider *provider, m_providers) {
|
||||||
|
foreach (const QString &name, provider->apiKeys().keys()) {
|
||||||
|
ret.insert(name, provider->apiKeys().value(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ApiKeysProvidersLoader::pluginSearchDirs() const
|
||||||
|
{
|
||||||
|
QStringList searchDirs;
|
||||||
|
QByteArray envPath = qgetenv("NYMEA_APIKEYS_PLUGINS_PATH");
|
||||||
|
if (!envPath.isEmpty()) {
|
||||||
|
searchDirs << QString(envPath).split(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (QString libraryPath, QCoreApplication::libraryPaths()) {
|
||||||
|
searchDirs << libraryPath.replace("qt5", "nymea").replace("plugins", "apikeysproviders");
|
||||||
|
}
|
||||||
|
searchDirs << QDir(QCoreApplication::applicationDirPath() + "/../lib/nymea/apikeysproviders/").absolutePath();
|
||||||
|
searchDirs << QDir(QCoreApplication::applicationDirPath() + "/../apikeysproviders/").absolutePath();
|
||||||
|
searchDirs << QDir(QCoreApplication::applicationDirPath() + "/../../../apikeysproviders/").absolutePath();
|
||||||
|
searchDirs.removeDuplicates();
|
||||||
|
return searchDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiKeysProvidersLoader::loadPlugin(const QString &file)
|
||||||
|
{
|
||||||
|
QPluginLoader loader;
|
||||||
|
loader.setFileName(file);
|
||||||
|
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint);
|
||||||
|
if (!loader.load()) {
|
||||||
|
qCWarning(dcApiKeys()) << loader.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApiKeysProvider *provider = qobject_cast<ApiKeysProvider*>(loader.instance());
|
||||||
|
if (!provider) {
|
||||||
|
qCWarning(dcApiKeys()) << "Could not get plugin instance of" << loader.fileName();
|
||||||
|
loader.unload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCDebug(dcApiKeys()) << "Loaded API keys provider plugin:" << loader.fileName();
|
||||||
|
provider->setParent(this);
|
||||||
|
m_providers.append(provider);
|
||||||
|
|
||||||
|
}
|
||||||
24
libnymea-core/integrations/apikeysprovidersloader.h
Normal file
24
libnymea-core/integrations/apikeysprovidersloader.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef APIKEYSPROVIDERSLOADER_H
|
||||||
|
#define APIKEYSPROVIDERSLOADER_H
|
||||||
|
|
||||||
|
#include "network/apikeys/apikeysprovider.h"
|
||||||
|
|
||||||
|
class ApiKeysProvidersLoader: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ApiKeysProvidersLoader(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QList<ApiKeysProvider*> providers() const;
|
||||||
|
|
||||||
|
QHash<QString, ApiKey> allApiKeys() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList pluginSearchDirs() const;
|
||||||
|
void loadPlugin(const QString &file);
|
||||||
|
|
||||||
|
QList<ApiKeysProvider*> m_providers;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APIKEYSPROVIDERSLOADER_H
|
||||||
@ -52,6 +52,8 @@
|
|||||||
#include "integrations/browseractioninfo.h"
|
#include "integrations/browseractioninfo.h"
|
||||||
#include "integrations/browseritemactioninfo.h"
|
#include "integrations/browseritemactioninfo.h"
|
||||||
|
|
||||||
|
#include "apikeysprovidersloader.h"
|
||||||
|
|
||||||
//#include "unistd.h"
|
//#include "unistd.h"
|
||||||
|
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
@ -86,6 +88,8 @@ ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardware
|
|||||||
oldStateFile.copy(settingsPath + "/thingstates.conf");
|
oldStateFile.copy(settingsPath + "/thingstates.conf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_apiKeysProvidersLoader = new ApiKeysProvidersLoader(this);
|
||||||
|
|
||||||
// Give hardware a chance to start up before loading plugins etc.
|
// Give hardware a chance to start up before loading plugins etc.
|
||||||
QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection);
|
||||||
QMetaObject::invokeMethod(this, "loadConfiguredThings", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "loadConfiguredThings", Qt::QueuedConnection);
|
||||||
@ -1319,8 +1323,28 @@ void ThingManagerImplementation::loadPlugins()
|
|||||||
|
|
||||||
void ThingManagerImplementation::loadPlugin(IntegrationPlugin *pluginIface)
|
void ThingManagerImplementation::loadPlugin(IntegrationPlugin *pluginIface)
|
||||||
{
|
{
|
||||||
|
// Populate the API storage for the plugin.
|
||||||
|
// NOTE:
|
||||||
|
// Right now we grant access to every api key requested in the JSON file. This means, an attacker could just
|
||||||
|
// write a plugin requesting a certain key and load it. This is not an actual problem right now as
|
||||||
|
// deployments that allow loading random plugins don't ship any high security keys. Once nymea supports
|
||||||
|
// a "plugin store" and allows loading 3rd party plugins along with a more sensitive api key provider,
|
||||||
|
// the plugins JSON needs to be reviewd by the store owner and signed with a store key. Only signed plugins
|
||||||
|
// should be granted access to their requested keys.
|
||||||
|
ApiKeyStorage *apiKeyStorage = new ApiKeyStorage(pluginIface);
|
||||||
|
QStringList requestedKeys = pluginIface->metadata().apiKeys();
|
||||||
|
foreach (const QString &apiKeyName, pluginIface->metadata().apiKeys()) {
|
||||||
|
if (m_apiKeysProvidersLoader->allApiKeys().contains(apiKeyName)) {
|
||||||
|
ApiKey apiKey = m_apiKeysProvidersLoader->allApiKeys().value(apiKeyName);
|
||||||
|
apiKeyStorage->insertKey(apiKeyName, apiKey);
|
||||||
|
requestedKeys.removeAll(apiKeyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!requestedKeys.isEmpty()) {
|
||||||
|
qCWarning(dcThingManager()).nospace() << "Unable to load API keys for plugin " << pluginIface->metadata().pluginName() << ": " << requestedKeys;
|
||||||
|
}
|
||||||
pluginIface->setParent(this);
|
pluginIface->setParent(this);
|
||||||
pluginIface->initPlugin(this, m_hardwareManager);
|
pluginIface->initPlugin(this, m_hardwareManager, apiKeyStorage);
|
||||||
|
|
||||||
qCDebug(dcThingManager) << "**** Loaded plugin" << pluginIface->pluginName();
|
qCDebug(dcThingManager) << "**** Loaded plugin" << pluginIface->pluginName();
|
||||||
foreach (const Vendor &vendor, pluginIface->supportedVendors()) {
|
foreach (const Vendor &vendor, pluginIface->supportedVendors()) {
|
||||||
|
|||||||
@ -59,6 +59,7 @@ class IntegrationPlugin;
|
|||||||
class ThingPairingInfo;
|
class ThingPairingInfo;
|
||||||
class HardwareManager;
|
class HardwareManager;
|
||||||
class Translator;
|
class Translator;
|
||||||
|
class ApiKeysProvidersLoader;
|
||||||
|
|
||||||
class ThingManagerImplementation: public ThingManager
|
class ThingManagerImplementation: public ThingManager
|
||||||
{
|
{
|
||||||
@ -192,6 +193,8 @@ private:
|
|||||||
QHash<PairingTransactionId, PairingContext> m_pendingPairings;
|
QHash<PairingTransactionId, PairingContext> m_pendingPairings;
|
||||||
|
|
||||||
QHash<IOConnectionId, IOConnection> m_ioConnections;
|
QHash<IOConnectionId, IOConnection> m_ioConnections;
|
||||||
|
|
||||||
|
ApiKeysProvidersLoader *m_apiKeysProvidersLoader = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // THINGMANAGERIMPLEMENTATION_H
|
#endif // THINGMANAGERIMPLEMENTATION_H
|
||||||
|
|||||||
@ -36,6 +36,7 @@ RESOURCES += $$top_srcdir/icons.qrc \
|
|||||||
|
|
||||||
|
|
||||||
HEADERS += nymeacore.h \
|
HEADERS += nymeacore.h \
|
||||||
|
integrations/apikeysprovidersloader.h \
|
||||||
integrations/plugininfocache.h \
|
integrations/plugininfocache.h \
|
||||||
integrations/python/pynymealogginghandler.h \
|
integrations/python/pynymealogginghandler.h \
|
||||||
integrations/python/pynymeamodule.h \
|
integrations/python/pynymeamodule.h \
|
||||||
@ -129,6 +130,7 @@ HEADERS += nymeacore.h \
|
|||||||
|
|
||||||
|
|
||||||
SOURCES += nymeacore.cpp \
|
SOURCES += nymeacore.cpp \
|
||||||
|
integrations/apikeysprovidersloader.cpp \
|
||||||
integrations/plugininfocache.cpp \
|
integrations/plugininfocache.cpp \
|
||||||
integrations/thingmanagerimplementation.cpp \
|
integrations/thingmanagerimplementation.cpp \
|
||||||
integrations/translator.cpp \
|
integrations/translator.cpp \
|
||||||
|
|||||||
@ -374,10 +374,11 @@ ParamTypes IntegrationPlugin::configurationDescription() const
|
|||||||
return m_metaData.pluginSettings();
|
return m_metaData.pluginSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPlugin::initPlugin(ThingManager *thingManager, HardwareManager *hardwareManager)
|
void IntegrationPlugin::initPlugin(ThingManager *thingManager, HardwareManager *hardwareManager, ApiKeyStorage *apiKeyStorage)
|
||||||
{
|
{
|
||||||
m_thingManager = thingManager;
|
m_thingManager = thingManager;
|
||||||
m_hardwareManager = hardwareManager;
|
m_hardwareManager = hardwareManager;
|
||||||
|
m_apiKeyStorage = apiKeyStorage;
|
||||||
m_storage = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId().toString().remove(QRegExp("[{}]")) + ".conf", QSettings::IniFormat, this);
|
m_storage = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId().toString().remove(QRegExp("[{}]")) + ".conf", QSettings::IniFormat, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,6 +479,15 @@ QSettings* IntegrationPlugin::pluginStorage() const
|
|||||||
return m_storage;
|
return m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief IntegrationPlugin::apiKeyStorage
|
||||||
|
* \return Returns the api key storage for this plugin. A plugin needs to list required API keys in the plugins JSON file.
|
||||||
|
*/
|
||||||
|
ApiKeyStorage *IntegrationPlugin::apiKeyStorage() const
|
||||||
|
{
|
||||||
|
return m_apiKeyStorage;
|
||||||
|
}
|
||||||
|
|
||||||
void IntegrationPlugin::setMetaData(const PluginMetadata &metaData)
|
void IntegrationPlugin::setMetaData(const PluginMetadata &metaData)
|
||||||
{
|
{
|
||||||
m_metaData = metaData;
|
m_metaData = metaData;
|
||||||
|
|||||||
@ -49,6 +49,8 @@
|
|||||||
|
|
||||||
#include "hardwaremanager.h"
|
#include "hardwaremanager.h"
|
||||||
|
|
||||||
|
#include "network/apikeys/apikeystorage.h"
|
||||||
|
|
||||||
#include "thingdiscoveryinfo.h"
|
#include "thingdiscoveryinfo.h"
|
||||||
#include "thingpairinginfo.h"
|
#include "thingpairinginfo.h"
|
||||||
#include "thingsetupinfo.h"
|
#include "thingsetupinfo.h"
|
||||||
@ -125,6 +127,7 @@ protected:
|
|||||||
Things myThings() const;
|
Things myThings() const;
|
||||||
HardwareManager *hardwareManager() const;
|
HardwareManager *hardwareManager() const;
|
||||||
QSettings *pluginStorage() const;
|
QSettings *pluginStorage() const;
|
||||||
|
ApiKeyStorage *apiKeyStorage() const;
|
||||||
|
|
||||||
void setMetaData(const PluginMetadata &metaData);
|
void setMetaData(const PluginMetadata &metaData);
|
||||||
|
|
||||||
@ -132,12 +135,13 @@ private:
|
|||||||
friend class ThingManager;
|
friend class ThingManager;
|
||||||
friend class ThingManagerImplementation;
|
friend class ThingManagerImplementation;
|
||||||
|
|
||||||
void initPlugin(ThingManager *thingManager, HardwareManager *hardwareManager);
|
void initPlugin(ThingManager *thingManager, HardwareManager *hardwareManager, ApiKeyStorage *apiKeyStorage);
|
||||||
|
|
||||||
PluginMetadata m_metaData;
|
PluginMetadata m_metaData;
|
||||||
ThingManager *m_thingManager = nullptr;
|
ThingManager *m_thingManager = nullptr;
|
||||||
HardwareManager *m_hardwareManager = nullptr;
|
HardwareManager *m_hardwareManager = nullptr;
|
||||||
QSettings *m_storage = nullptr;
|
QSettings *m_storage = nullptr;
|
||||||
|
ApiKeyStorage *m_apiKeyStorage;
|
||||||
|
|
||||||
ParamList m_config;
|
ParamList m_config;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -84,6 +84,11 @@ bool PluginMetadata::isBuiltIn() const
|
|||||||
return m_isBuiltIn;
|
return m_isBuiltIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList PluginMetadata::apiKeys() const
|
||||||
|
{
|
||||||
|
return m_apiKeys;
|
||||||
|
}
|
||||||
|
|
||||||
ParamTypes PluginMetadata::pluginSettings() const
|
ParamTypes PluginMetadata::pluginSettings() const
|
||||||
{
|
{
|
||||||
return m_pluginSettings;
|
return m_pluginSettings;
|
||||||
@ -110,7 +115,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject)
|
|||||||
|
|
||||||
// General plugin info
|
// General plugin info
|
||||||
QStringList pluginMandatoryJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors";
|
QStringList pluginMandatoryJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors";
|
||||||
QStringList pluginJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors" << "paramTypes" << "builtIn";
|
QStringList pluginJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors" << "paramTypes" << "builtIn" << "apiKeys";
|
||||||
QPair<QStringList, QStringList> verificationResult = verifyFields(pluginJsonProperties, pluginMandatoryJsonProperties, jsonObject);
|
QPair<QStringList, QStringList> verificationResult = verifyFields(pluginJsonProperties, pluginMandatoryJsonProperties, jsonObject);
|
||||||
if (!verificationResult.first.isEmpty()) {
|
if (!verificationResult.first.isEmpty()) {
|
||||||
m_validationErrors.append("Plugin metadata has missing fields: " + verificationResult.first.join(", "));
|
m_validationErrors.append("Plugin metadata has missing fields: " + verificationResult.first.join(", "));
|
||||||
@ -122,6 +127,9 @@ void PluginMetadata::parse(const QJsonObject &jsonObject)
|
|||||||
m_pluginId = PluginId(jsonObject.value("id").toString());
|
m_pluginId = PluginId(jsonObject.value("id").toString());
|
||||||
m_pluginName = jsonObject.value("name").toString();
|
m_pluginName = jsonObject.value("name").toString();
|
||||||
m_pluginDisplayName = jsonObject.value("displayName").toString();
|
m_pluginDisplayName = jsonObject.value("displayName").toString();
|
||||||
|
foreach (const QVariant &apiKeyVariant, jsonObject.value("apiKeys").toArray().toVariantList()) {
|
||||||
|
m_apiKeys.append(apiKeyVariant.toString());
|
||||||
|
}
|
||||||
|
|
||||||
if (!verificationResult.second.isEmpty()) {
|
if (!verificationResult.second.isEmpty()) {
|
||||||
m_validationErrors.append("Plugin \"" + m_pluginName + "\" has unknown fields: \"" + verificationResult.second.join("\", \"") + "\"");
|
m_validationErrors.append("Plugin \"" + m_pluginName + "\" has unknown fields: \"" + verificationResult.second.join("\", \"") + "\"");
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public:
|
|||||||
QString pluginName() const;
|
QString pluginName() const;
|
||||||
QString pluginDisplayName() const;
|
QString pluginDisplayName() const;
|
||||||
bool isBuiltIn() const;
|
bool isBuiltIn() const;
|
||||||
|
QStringList apiKeys() const;
|
||||||
|
|
||||||
ParamTypes pluginSettings() const;
|
ParamTypes pluginSettings() const;
|
||||||
|
|
||||||
@ -76,6 +77,7 @@ private:
|
|||||||
ParamTypes m_pluginSettings;
|
ParamTypes m_pluginSettings;
|
||||||
Vendors m_vendors;
|
Vendors m_vendors;
|
||||||
ThingClasses m_thingClasses;
|
ThingClasses m_thingClasses;
|
||||||
|
QStringList m_apiKeys;
|
||||||
|
|
||||||
QList<QUuid> m_allUuids;
|
QList<QUuid> m_allUuids;
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,9 @@ HEADERS += \
|
|||||||
jsonrpc/jsonreply.h \
|
jsonrpc/jsonreply.h \
|
||||||
jsonrpc/jsonrpcserver.h \
|
jsonrpc/jsonrpcserver.h \
|
||||||
libnymea.h \
|
libnymea.h \
|
||||||
|
network/apikeys/apikey.h \
|
||||||
|
network/apikeys/apikeysprovider.h \
|
||||||
|
network/apikeys/apikeystorage.h \
|
||||||
platform/package.h \
|
platform/package.h \
|
||||||
platform/repository.h \
|
platform/repository.h \
|
||||||
types/browseritem.h \
|
types/browseritem.h \
|
||||||
@ -119,6 +122,9 @@ SOURCES += \
|
|||||||
jsonrpc/jsonreply.cpp \
|
jsonrpc/jsonreply.cpp \
|
||||||
jsonrpc/jsonrpcserver.cpp \
|
jsonrpc/jsonrpcserver.cpp \
|
||||||
loggingcategories.cpp \
|
loggingcategories.cpp \
|
||||||
|
network/apikeys/apikey.cpp \
|
||||||
|
network/apikeys/apikeysprovider.cpp \
|
||||||
|
network/apikeys/apikeystorage.cpp \
|
||||||
nymeasettings.cpp \
|
nymeasettings.cpp \
|
||||||
platform/package.cpp \
|
platform/package.cpp \
|
||||||
platform/repository.cpp \
|
platform/repository.cpp \
|
||||||
|
|||||||
32
libnymea/network/apikeys/apikey.cpp
Normal file
32
libnymea/network/apikeys/apikey.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "apikey.h"
|
||||||
|
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
NYMEA_LOGGING_CATEGORY(dcApiKeys, "ApiKeys")
|
||||||
|
|
||||||
|
ApiKey::ApiKey()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ApiKey::data
|
||||||
|
* \param key
|
||||||
|
* \return Retrns the data for key. For example data("key") or data("clientId")
|
||||||
|
* An ApiKey can have multiple properties, like appid, clientsecret, scope information etc.
|
||||||
|
*/
|
||||||
|
QByteArray ApiKey::data(const QString &key) const
|
||||||
|
{
|
||||||
|
return m_data.value(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ApiKey::insert
|
||||||
|
* Insert a key value pair in the this api key. For example insert("appid", "...").
|
||||||
|
* An ApiKey can have multiple properties, like appid, clientsecret, scope information etc.
|
||||||
|
* \param key
|
||||||
|
* \param data
|
||||||
|
*/
|
||||||
|
void ApiKey::insert(const QString &key, const QByteArray &data)
|
||||||
|
{
|
||||||
|
m_data.insert(key, data);
|
||||||
|
}
|
||||||
22
libnymea/network/apikeys/apikey.h
Normal file
22
libnymea/network/apikeys/apikey.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef APIKEY_H
|
||||||
|
#define APIKEY_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcApiKeys)
|
||||||
|
|
||||||
|
class ApiKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApiKey();
|
||||||
|
|
||||||
|
QByteArray data(const QString &key) const;
|
||||||
|
void insert(const QString &key, const QByteArray &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, QByteArray> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APIKEY_H
|
||||||
7
libnymea/network/apikeys/apikeysprovider.cpp
Normal file
7
libnymea/network/apikeys/apikeysprovider.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "apikeysprovider.h"
|
||||||
|
|
||||||
|
ApiKeysProvider::ApiKeysProvider(QObject *parent):
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
21
libnymea/network/apikeys/apikeysprovider.h
Normal file
21
libnymea/network/apikeys/apikeysprovider.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef APIKEYSPROVIDER_H
|
||||||
|
#define APIKEYSPROVIDER_H
|
||||||
|
|
||||||
|
#include "apikey.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class ApiKeysProvider: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ApiKeysProvider(QObject *parent = nullptr);
|
||||||
|
virtual ~ApiKeysProvider() = default;
|
||||||
|
|
||||||
|
virtual QHash<QString, ApiKey> apiKeys() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_INTERFACE(ApiKeysProvider, "io.nymea.ApiKeysProvider")
|
||||||
|
|
||||||
|
#endif // APIKEYSPROVIDER_H
|
||||||
26
libnymea/network/apikeys/apikeystorage.cpp
Normal file
26
libnymea/network/apikeys/apikeystorage.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "apikeystorage.h"
|
||||||
|
|
||||||
|
ApiKeyStorage::ApiKeyStorage(QObject *parent):
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiKey ApiKeyStorage::requestKey(const QString &name) const
|
||||||
|
{
|
||||||
|
if (!m_keys.contains(name)) {
|
||||||
|
qCWarning(dcApiKeys) << "API key not found for" << name;
|
||||||
|
}
|
||||||
|
return m_keys.value(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiKeyStorage::insertKey(const QString &name, const ApiKey &key)
|
||||||
|
{
|
||||||
|
if (m_keys.contains(name)) {
|
||||||
|
m_keys[name] = key;
|
||||||
|
emit keyUpdated(name, key);
|
||||||
|
} else {
|
||||||
|
m_keys.insert(name, key);
|
||||||
|
emit keyAdded(name, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
libnymea/network/apikeys/apikeystorage.h
Normal file
25
libnymea/network/apikeys/apikeystorage.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef APIKEYSTORAGE_H
|
||||||
|
#define APIKEYSTORAGE_H
|
||||||
|
|
||||||
|
#include "apikey.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class ApiKeyStorage: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ApiKeyStorage(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
ApiKey requestKey(const QString &name) const;
|
||||||
|
void insertKey(const QString &name, const ApiKey &key);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void keyAdded(const QString &name, const ApiKey &key);
|
||||||
|
void keyUpdated(const QString &name, const ApiKey &key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, ApiKey> m_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APIKEYSTORAGE_H
|
||||||
Reference in New Issue
Block a user