diff --git a/libnymea-core/jsonrpc/integrationshandler.cpp b/libnymea-core/jsonrpc/integrationshandler.cpp index 66976424..eef33a47 100644 --- a/libnymea-core/jsonrpc/integrationshandler.cpp +++ b/libnymea-core/jsonrpc/integrationshandler.cpp @@ -38,6 +38,9 @@ #include "integrations/browseritemresult.h" #include "ruleengine/ruleengine.h" +#include "nymeacore.h" +#include "usermanager/usermanager.h" + #include #include #include @@ -769,29 +772,65 @@ JsonReply* IntegrationsHandler::GetThings(const QVariantMap ¶ms, const JsonC { QVariantMap returns; QVariantList things; - if (params.contains("thingId")) { - Thing *thing = m_thingManager->findConfiguredThing(ThingId(params.value("thingId").toString())); - if (!thing) { - returns.insert("thingError", enumValueName(Thing::ThingErrorThingNotFound)); - return createReply(returns); - } else { - QVariantMap packedThing = pack(thing).toMap(); - QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); - if (!translatedSetupStatus.isEmpty()) { - packedThing["setupDisplayMessage"] = translatedSetupStatus; + + + if (NymeaCore::instance()->userManager()->restrictedThingAccess(context.token())) { + QList allowedThingIds = NymeaCore::instance()->userManager()->allowedThingIds(context.token()); + if (params.contains("thingId")) { + ThingId thingId(params.value("thingId").toString()); + Thing *thing = m_thingManager->findConfiguredThing(thingId); + if (!thing || !allowedThingIds.contains(thingId)) { + returns.insert("thingError", enumValueName(Thing::ThingErrorThingNotFound)); + return createReply(returns); + } else { + QVariantMap packedThing = pack(thing).toMap(); + QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); + if (!translatedSetupStatus.isEmpty()) { + packedThing["setupDisplayMessage"] = translatedSetupStatus; + } + things.append(packedThing); + } + } else { + foreach (Thing *thing, m_thingManager->configuredThings()) { + if (!allowedThingIds.contains(thing->id())) + continue; + + + QVariantMap packedThing = pack(thing).toMap(); + QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); + if (!translatedSetupStatus.isEmpty()) { + packedThing["setupDisplayMessage"] = translatedSetupStatus; + } + things.append(packedThing); } - things.append(packedThing); } } else { - foreach (Thing *thing, m_thingManager->configuredThings()) { - QVariantMap packedThing = pack(thing).toMap(); - QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); - if (!translatedSetupStatus.isEmpty()) { - packedThing["setupDisplayMessage"] = translatedSetupStatus; + // Unrestricted things access + if (params.contains("thingId")) { + Thing *thing = m_thingManager->findConfiguredThing(ThingId(params.value("thingId").toString())); + if (!thing) { + returns.insert("thingError", enumValueName(Thing::ThingErrorThingNotFound)); + return createReply(returns); + } else { + QVariantMap packedThing = pack(thing).toMap(); + QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); + if (!translatedSetupStatus.isEmpty()) { + packedThing["setupDisplayMessage"] = translatedSetupStatus; + } + things.append(packedThing); + } + } else { + foreach (Thing *thing, m_thingManager->configuredThings()) { + QVariantMap packedThing = pack(thing).toMap(); + QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale()); + if (!translatedSetupStatus.isEmpty()) { + packedThing["setupDisplayMessage"] = translatedSetupStatus; + } + things.append(packedThing); } - things.append(packedThing); } } + returns.insert("thingError", enumValueName(Thing::ThingErrorNoError)); returns.insert("things", things); return createReply(returns); diff --git a/libnymea-core/jsonrpc/usershandler.cpp b/libnymea-core/jsonrpc/usershandler.cpp index 95abdd09..1f72026e 100644 --- a/libnymea-core/jsonrpc/usershandler.cpp +++ b/libnymea-core/jsonrpc/usershandler.cpp @@ -42,12 +42,13 @@ UsersHandler::UsersHandler(UserManager *userManager, QObject *parent): QString description; params.clear(); returns.clear(); - description = "Create a new user in the API with the given username and password. Use scopes to define the permissions for the new user. If no scopes are given, this user will be an admin user. Call Authenticate after this to obtain a device token for this user."; + description = "Create a new user in the API with the given username and password. Use scopes to define the permissions for the new user. If the user has not the permission \"PermissionScopeAccessAllThings\", the list of things this user has access to can be defined in the \"allowedThingIds\" property. If no scopes are given, this user will be an admin user. Call Authenticate after this to obtain a device token for this user."; params.insert("username", enumValueName(String)); params.insert("password", enumValueName(String)); params.insert("o:email", enumValueName(String)); params.insert("o:displayName", enumValueName(String)); params.insert("o:scopes", flagRef()); + params.insert("o:allowedThingIds", QVariantList() << enumValueName(Uuid)); returns.insert("error", enumRef()); registerMethod("CreateUser", description, params, returns); @@ -87,9 +88,10 @@ UsersHandler::UsersHandler(UserManager *userManager, QObject *parent): registerMethod("RemoveUser", description, params, returns); params.clear(); returns.clear(); - description = "Set the permissions (scopes) for a given user."; + description = "Set the permissions (scopes) for a given user. If the user has not the permission \"PermissionScopeAccessAllThings\" the list of thing IDs this user has access to can be defined in the \"allowedThingIds\" property."; params.insert("username", enumValueName(String)); params.insert("scopes", flagRef()); + params.insert("o:allowedThingIds", QVariantList() << enumValueName(Uuid)); returns.insert("error", enumRef()); registerMethod("SetUserScopes", description, params, returns); diff --git a/libnymea-core/usermanager/userinfo.cpp b/libnymea-core/usermanager/userinfo.cpp index d23df318..dae0e3fc 100644 --- a/libnymea-core/usermanager/userinfo.cpp +++ b/libnymea-core/usermanager/userinfo.cpp @@ -79,6 +79,16 @@ void UserInfo::setScopes(Types::PermissionScopes scopes) m_scopes = scopes; } +void UserInfo::setAllowedThingIds(const QList &allowedThingIds) +{ + m_allowedThingIds = allowedThingIds; +} + +QList UserInfo::allowedThingIds() const +{ + return m_allowedThingIds; +} + QVariant UserInfoList::get(int index) const { return QVariant::fromValue(at(index)); diff --git a/libnymea-core/usermanager/userinfo.h b/libnymea-core/usermanager/userinfo.h index 4051fd49..ca91aeca 100644 --- a/libnymea-core/usermanager/userinfo.h +++ b/libnymea-core/usermanager/userinfo.h @@ -56,11 +56,16 @@ public: Types::PermissionScopes scopes() const; void setScopes(Types::PermissionScopes scopes); + void setAllowedThingIds(const QList &allowedThingIds); + QList allowedThingIds() const; + private: QString m_username; QString m_email; QString m_displayName; Types::PermissionScopes m_scopes = Types::PermissionScopeNone; + QList m_allowedThingIds; + }; class UserInfoList: public QList diff --git a/libnymea-core/usermanager/usermanager.cpp b/libnymea-core/usermanager/usermanager.cpp index 0db89958..080f94ff 100644 --- a/libnymea-core/usermanager/usermanager.cpp +++ b/libnymea-core/usermanager/usermanager.cpp @@ -539,6 +539,18 @@ bool UserManager::verifyToken(const QByteArray &token) return true; } +bool UserManager::restrictedThingAccess(const QByteArray &token) const +{ + UserInfo ui = userInfo(tokenInfo(token).username()); + return !ui.scopes().testFlag(Types::PermissionScopeAccessAllThings); +} + +QList UserManager::allowedThingIds(const QByteArray &token) const +{ + UserInfo ui = userInfo(tokenInfo(token).username()); + return ui.allowedThingIds(); +} + bool UserManager::initDB() { m_db.close(); diff --git a/libnymea-core/usermanager/usermanager.h b/libnymea-core/usermanager/usermanager.h index a55d3837..3b313613 100644 --- a/libnymea-core/usermanager/usermanager.h +++ b/libnymea-core/usermanager/usermanager.h @@ -74,9 +74,11 @@ public: UserError removeToken(const QUuid &tokenId); - bool verifyToken(const QByteArray &token); + bool restrictedThingAccess(const QByteArray &token) const; + QList allowedThingIds(const QByteArray &token) const; + signals: void userAdded(const QString &username); void userRemoved(const QString &username); @@ -102,7 +104,9 @@ private: QPair m_pushButtonTransaction; }; + } + Q_DECLARE_METATYPE(nymeaserver::UserManager::UserError) #endif // USERMANAGER_H diff --git a/libnymea/integrations/thing.h b/libnymea/integrations/thing.h index b7ecbf7e..3c862213 100644 --- a/libnymea/integrations/thing.h +++ b/libnymea/integrations/thing.h @@ -87,7 +87,7 @@ public: ThingErrorItemNotFound, ThingErrorItemNotExecutable, ThingErrorUnsupportedFeature, - ThingErrorTimeout, + ThingErrorTimeout }; Q_ENUM(ThingError) diff --git a/libnymea/typeutils.h b/libnymea/typeutils.h index b8d9387b..10a25377 100644 --- a/libnymea/typeutils.h +++ b/libnymea/typeutils.h @@ -202,6 +202,7 @@ public: PermissionScopeNone = 0x0000, PermissionScopeControlThings = 0x0001, PermissionScopeConfigureThings = 0x0003, + PermissionScopeAccessAllThings = 0x0004, PermissionScopeExecuteRules = 0x0010, PermissionScopeConfigureRules = 0x0030, PermissionScopeAdmin = 0xFFFF,