diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index bf238e657f..aca288c452 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -526,7 +526,7 @@ "groups": [ { "label": "Group", - "span": 4 + "span": 5 }, { "label": "Permissions ?", @@ -540,8 +540,12 @@ "label": "Group Name" }, { - "name": "rank", - "label": "Rank" + "name": "rank_id", + "label": "Rank ID" + }, + { + "name": "rank_order", + "label": "Rank Order" }, { "name": "rank_name", @@ -605,7 +609,7 @@ "groups": [ { "label": "Group", - "span": 4 + "span": 5 }, { "label": "Permissions ?", @@ -619,8 +623,12 @@ "label": "Group Name" }, { - "name": "rank", - "label": "Rank" + "name": "rank_id", + "label": "Rank ID" + }, + { + "name": "rank_order", + "label": "Rank Order" }, { "name": "rank_name", diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 32c0eb00c9..08fe40faff 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -150,10 +150,12 @@ NodePermissions DomainGatekeeper::applyPermissionsForUser(bool isLocalUser, // if this user is a known member of a group, give them the implied permissions foreach (QUuid groupID, _server->_settingsManager.getGroupIDs()) { - int rank = _server->_settingsManager.isGroupMember(verifiedUsername, groupID); - if (rank >= 0) { - userPerms |= _server->_settingsManager.getPermissionsForGroup(groupID, rank); - qDebug() << "user-permissions: user is in group:" << groupID << " rank:" << rank << "so:" << userPerms; + QUuid rankID = _server->_settingsManager.isGroupMember(verifiedUsername, groupID); + if (rankID != QUuid()) { + userPerms |= _server->_settingsManager.getPermissionsForGroup(groupID, rankID); + + GroupRank rank = _server->_settingsManager.getGroupRank(groupID, rankID); + qDebug() << "user-permissions: user is in group:" << groupID << " rank:" << rank.name << "so:" << userPerms; } } @@ -161,12 +163,14 @@ NodePermissions DomainGatekeeper::applyPermissionsForUser(bool isLocalUser, qDebug() << "------------------ checking blacklists ----------------------"; qDebug() << _server->_settingsManager.getBlacklistGroupIDs(); foreach (QUuid groupID, _server->_settingsManager.getBlacklistGroupIDs()) { - if (_server->_settingsManager.isGroupMember(verifiedUsername, groupID)) { - int rank = _server->_settingsManager.isGroupMember(verifiedUsername, groupID); - qDebug() << groupID << verifiedUsername << "is member with rank" << rank; - if (rank >= 0) { - userPerms &= ~_server->_settingsManager.getForbiddensForGroup(groupID, rank); - qDebug() << "user-permissions: user is in blacklist group:" << groupID << " rank:" << rank + QUuid rankID = _server->_settingsManager.isGroupMember(verifiedUsername, groupID); + if (rankID != QUuid()) { + QUuid rankID = _server->_settingsManager.isGroupMember(verifiedUsername, groupID); + if (rankID != QUuid()) { + userPerms &= ~_server->_settingsManager.getForbiddensForGroup(groupID, rankID); + + GroupRank rank = _server->_settingsManager.getGroupRank(groupID, rankID); + qDebug() << "user-permissions: user is in blacklist group:" << groupID << " rank:" << rank.name << "so:" << userPerms; } } else { @@ -197,6 +201,7 @@ void DomainGatekeeper::updateNodePermissions() { if (node->getPermissions().isAssignment) { // this node is an assignment-client userPerms.isAssignment = true; + userPerms.permissions |= NodePermissions::Permission::canConnectToDomain; userPerms.permissions |= NodePermissions::Permission::canAdjustLocks; userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities; userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities; @@ -263,9 +268,10 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo // cleanup the PendingAssignedNodeData for this assignment now that it's connecting _pendingAssignedNodes.erase(it); - // always allow assignment clients to create and destroy entities NodePermissions userPerms; userPerms.isAssignment = true; + userPerms.permissions |= NodePermissions::Permission::canConnectToDomain; + // always allow assignment clients to create and destroy entities userPerms.permissions |= NodePermissions::Permission::canAdjustLocks; userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities; userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities; @@ -701,33 +707,63 @@ void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer } } +// void DomainGatekeeper::getGroupMemberships(const QString& username) { +// // loop through the groups mentioned on the settings page and ask if this user is in each. The replies +// // will be received asynchronously and permissions will be updated as the answers come in. +// QList groupIDs = _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlacklistGroupIDs(); +// // TODO -- use alternative that allows checking entire group list in one call +// foreach (QUuid groupID, groupIDs) { +// if (groupID.isNull()) { +// continue; +// } +// getIsGroupMember(username, groupID); +// } +// } + +// void DomainGatekeeper::getIsGroupMember(const QString& username, const QUuid groupID) { +// JSONCallbackParameters callbackParams; +// callbackParams.jsonCallbackReceiver = this; +// callbackParams.jsonCallbackMethod = "getIsGroupMemberJSONCallback"; +// callbackParams.errorCallbackReceiver = this; +// callbackParams.errorCallbackMethod = "getIsGroupMemberErrorCallback"; + +// const QString GET_IS_GROUP_MEMBER_PATH = "api/v1/groups/%1/members/%2"; +// QString groupIDStr = groupID.toString().mid(1,36); +// DependencyManager::get()->sendRequest(GET_IS_GROUP_MEMBER_PATH.arg(groupIDStr).arg(username), +// AccountManagerAuth::Required, +// QNetworkAccessManager::GetOperation, callbackParams); +// } + + + void DomainGatekeeper::getGroupMemberships(const QString& username) { // loop through the groups mentioned on the settings page and ask if this user is in each. The replies // will be received asynchronously and permissions will be updated as the answers come in. - QList groupIDs = _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlacklistGroupIDs(); - // TODO -- use alternative that allows checking entire group list in one call - foreach (QUuid groupID, groupIDs) { - if (groupID.isNull()) { - continue; - } - getIsGroupMember(username, groupID); - } -} -void DomainGatekeeper::getIsGroupMember(const QString& username, const QUuid groupID) { + QJsonObject json; + QSet groupIDSet; + foreach (QUuid groupID, _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlacklistGroupIDs()) { + groupIDSet += groupID.toString().mid(1,36); + } + QJsonArray groupIDs = QJsonArray::fromStringList(groupIDSet.toList()); + json["groups"] = groupIDs; + JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackMethod = "getIsGroupMemberJSONCallback"; callbackParams.errorCallbackReceiver = this; callbackParams.errorCallbackMethod = "getIsGroupMemberErrorCallback"; - const QString GET_IS_GROUP_MEMBER_PATH = "api/v1/groups/%1/members/%2"; - QString groupIDStr = groupID.toString().mid(1,36); - DependencyManager::get()->sendRequest(GET_IS_GROUP_MEMBER_PATH.arg(groupIDStr).arg(username), + const QString GET_IS_GROUP_MEMBER_PATH = "api/v1/groups/members/%2"; + DependencyManager::get()->sendRequest(GET_IS_GROUP_MEMBER_PATH.arg(username), AccountManagerAuth::Required, - QNetworkAccessManager::GetOperation, callbackParams); + QNetworkAccessManager::PostOperation, callbackParams, + QJsonDocument(json).toJson()); + } + + void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply) { // { // "data":{ @@ -746,8 +782,6 @@ void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply) // } - - QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); qDebug() << "********* getIsGroupMember api call returned:" << QJsonDocument(jsonObject).toJson(QJsonDocument::Compact); @@ -760,8 +794,9 @@ void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply) _server->_settingsManager.clearGroupMemberships(username); foreach (auto groupID, groups.keys()) { QJsonObject group = groups[groupID].toObject(); - int order = group["order"].toInt(); - _server->_settingsManager.recordGroupMembership(username, groupID, order); + QJsonObject rank = group["rank"].toObject(); + QUuid rankID = QUuid(rank["id"].toString()); + _server->_settingsManager.recordGroupMembership(username, groupID, rankID); } } else { qDebug() << "getIsGroupMember api call returned:" << QJsonDocument(jsonObject).toJson(QJsonDocument::Compact); diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index a5ff5d90a7..a18554338a 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -107,7 +107,7 @@ private: NodePermissions applyPermissionsForUser(bool isLocalUser, NodePermissions userPerms, QString verifiedUsername); void getGroupMemberships(const QString& username); - void getIsGroupMember(const QString& username, const QUuid groupID); + // void getIsGroupMember(const QString& username, const QUuid groupID); void getDomainOwnerFriendsList(); }; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 53b90551c1..bd429029ed 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -347,11 +347,31 @@ void DomainServerSettingsManager::packPermissionsForMap(QString mapName, // convert details for each member of the subsection QVariantList* permissionsList = reinterpret_cast(permissions); (*permissionsList).clear(); - foreach (NodePermissionsKey userKey, agentPermissions.keys()) { + QList permissionsKeys = agentPermissions.keys(); + + // when a group is added from the domain-server settings page, the config map has a group-name with + // no ID or rank. We need to leave that there until we get a valid response back from the api. + // once we have the ranks and IDs, we need to delete the original entry so that it doesn't show + // up in the settings-page with undefined's after it. + QHash groupNamesWithRanks; + // note which groups have rank/ID information + foreach (NodePermissionsKey userKey, permissionsKeys) { + NodePermissionsPointer perms = agentPermissions[userKey]; + if (perms->getRankID() != QUuid()) { + groupNamesWithRanks[userKey.first] = true; + } + } + + // convert each group-name / rank-id pair to a variant-map + foreach (NodePermissionsKey userKey, permissionsKeys) { NodePermissionsPointer perms = agentPermissions[userKey]; if (perms->isGroup()) { - QVector rankNames = _groupRanks[perms->getGroupID()]; - *permissionsList += perms->toVariant(rankNames); + if (perms->getRankID() == QUuid() && groupNamesWithRanks.contains(userKey.first)) { + // skip over the entry that was created when the user added the group. + continue; + } + QHash& groupRanks = _groupRanks[perms->getGroupID()]; + *permissionsList += perms->toVariant(groupRanks); } else { *permissionsList += perms->toVariant(); } @@ -462,7 +482,7 @@ void DomainServerSettingsManager::unpackPermissions() { } if (perms->isGroup()) { // the group-id was cached. hook-up the uuid in the uuid->group hash - _groupPermissionsByUUID[GroupByUUIDKey(perms->getGroupID(), perms->getRank())] = _groupPermissions[idKey]; + _groupPermissionsByUUID[GroupByUUIDKey(perms->getGroupID(), perms->getRankID())] = _groupPermissions[idKey]; needPack |= setGroupID(perms->getID(), perms->getGroupID()); } } @@ -481,7 +501,7 @@ void DomainServerSettingsManager::unpackPermissions() { } if (perms->isGroup()) { // the group-id was cached. hook-up the uuid in the uuid->group hash - _groupForbiddensByUUID[GroupByUUIDKey(perms->getGroupID(), perms->getRank())] = _groupForbiddens[idKey]; + _groupForbiddensByUUID[GroupByUUIDKey(perms->getGroupID(), perms->getRankID())] = _groupForbiddens[idKey]; needPack |= setGroupID(perms->getID(), perms->getGroupID()); } } @@ -541,10 +561,10 @@ bool DomainServerSettingsManager::ensurePermissionsForGroupRanks() { QList permissionGroupIDs = getGroupIDs(); foreach (QUuid groupID, permissionGroupIDs) { QString groupName = _groupNames[groupID]; - int rankCountForGroup = _groupRanks[groupID].size(); - for (int rank = 0; rank < rankCountForGroup; rank++) { - NodePermissionsKey nameKey = NodePermissionsKey(groupName, rank); - GroupByUUIDKey idKey = GroupByUUIDKey(groupID, rank); + QHash& ranksForGroup = _groupRanks[groupID]; + foreach (QUuid rankID, ranksForGroup.keys()) { + NodePermissionsKey nameKey = NodePermissionsKey(groupName, rankID); + GroupByUUIDKey idKey = GroupByUUIDKey(groupID, rankID); NodePermissionsPointer perms; if (_groupPermissions.contains(nameKey)) { perms = _groupPermissions[nameKey]; @@ -561,10 +581,10 @@ bool DomainServerSettingsManager::ensurePermissionsForGroupRanks() { QList forbiddenGroupIDs = getBlacklistGroupIDs(); foreach (QUuid groupID, forbiddenGroupIDs) { QString groupName = _groupNames[groupID]; - int rankCountForGroup = _groupRanks[groupID].size(); - for (int rank = 0; rank < rankCountForGroup; rank++) { - NodePermissionsKey nameKey = NodePermissionsKey(groupName, rank); - GroupByUUIDKey idKey = GroupByUUIDKey(groupID, rank); + QHash& ranksForGroup = _groupRanks[groupID]; + foreach (QUuid rankID, ranksForGroup.keys()) { + NodePermissionsKey nameKey = NodePermissionsKey(groupName, rankID); + GroupByUUIDKey idKey = GroupByUUIDKey(groupID, rankID); NodePermissionsPointer perms; if (_groupForbiddens.contains(nameKey)) { perms = _groupForbiddens[nameKey]; @@ -610,8 +630,8 @@ NodePermissions DomainServerSettingsManager::getPermissionsForName(const QString return nullPermissions; } -NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, int rank) const { - NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rank); +NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, QUuid rankID) const { + NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID); if (_groupPermissions.contains(groupRankKey)) { return *(_groupPermissions[groupRankKey].get()); } @@ -620,8 +640,8 @@ NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QStrin return nullPermissions; } -NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QUuid& groupID, int rank) const { - GroupByUUIDKey byUUIDKey = GroupByUUIDKey(groupID, rank); +NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QUuid& groupID, QUuid rankID) const { + GroupByUUIDKey byUUIDKey = GroupByUUIDKey(groupID, rankID); if (!_groupPermissionsByUUID.contains(byUUIDKey)) { NodePermissions nullPermissions; nullPermissions.setAll(false); @@ -631,8 +651,8 @@ NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QUuid& return getPermissionsForGroup(groupKey.first, groupKey.second); } -NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QString& groupName, int rank) const { - NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rank); +NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QString& groupName, QUuid rankID) const { + NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID); if (_groupForbiddens.contains(groupRankKey)) { return *(_groupForbiddens[groupRankKey].get()); } @@ -642,8 +662,8 @@ NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QString return nullForbiddens; } -NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QUuid& groupID, int rank) const { - GroupByUUIDKey byUUIDKey = GroupByUUIDKey(groupID, rank); +NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QUuid& groupID, QUuid rankID) const { + GroupByUUIDKey byUUIDKey = GroupByUUIDKey(groupID, rankID); if (!_groupForbiddensByUUID.contains(byUUIDKey)) { NodePermissions nullForbiddens; // XXX should this be setAll(true) ? @@ -1042,9 +1062,14 @@ bool permissionVariantLessThan(const QVariant &v1, const QVariant &v2) { return v1.toString() < v2.toString(); } - if (m1.contains("rank_name") && m2.contains("rank_name") && + // if (m1.contains("rank_name") && m2.contains("rank_name") && + // m1["permissions_id"].toString() == m2["permissions_id"].toString()) { + // return m1["rank_name"].toString() < m2["rank_name"].toString(); + // } + + if (m1.contains("rank_order") && m2.contains("rank_order") && m1["permissions_id"].toString() == m2["permissions_id"].toString()) { - return m1["rank_name"].toString() < m2["rank_name"].toString(); + return m1["rank_order"].toInt() < m2["rank_order"].toInt(); } return m1["permissions_id"].toString() < m2["permissions_id"].toString(); @@ -1062,6 +1087,16 @@ void DomainServerSettingsManager::sortPermissions() { QList* permissionsList = reinterpret_cast(permissions); std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); } + QVariant* groupPermissions = valueForKeyPath(_configMap.getUserConfig(), GROUP_PERMISSIONS_KEYPATH); + if (groupPermissions && groupPermissions->canConvert(QMetaType::QVariantList)) { + QList* permissionsList = reinterpret_cast(groupPermissions); + std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); + } + QVariant* forbiddenPermissions = valueForKeyPath(_configMap.getUserConfig(), GROUP_FORBIDDENS_KEYPATH); + if (forbiddenPermissions && forbiddenPermissions->canConvert(QMetaType::QVariantList)) { + QList* permissionsList = reinterpret_cast(forbiddenPermissions); + std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); + } } void DomainServerSettingsManager::persistToFile() { @@ -1138,10 +1173,15 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() { return; } + bool changed = false; + QStringList groupNames = getAllKnownGroupNames(); foreach (QString groupName, groupNames) { - if (_groupIDs.contains(groupName.toLower())) { - // we already know about this one + QString lowerGroupName = groupName.toLower(); + if (_groupIDs.contains(lowerGroupName)) { + // we already know about this one. recall setGroupID in case the group has been + // added to another section (the same group is found in both groups and blacklists). + changed = setGroupID(groupName, _groupIDs[lowerGroupName]); continue; } apiGetGroupID(groupName); @@ -1151,6 +1191,12 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() { apiGetGroupRanks(groupID); } + changed |= ensurePermissionsForGroupRanks(); + + if (changed) { + packPermissions(); + } + unpackPermissions(); } @@ -1222,8 +1268,6 @@ void DomainServerSettingsManager::apiGetGroupIDErrorCallback(QNetworkReply& requ } void DomainServerSettingsManager::apiGetGroupRanks(const QUuid& groupID) { - _groupRanksLastFetched[groupID] = usecTimestampNow(); - JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackMethod = "apiGetGroupRanksJSONCallback"; @@ -1278,18 +1322,32 @@ void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply& re foreach (auto groupID, groups.keys()) { QJsonObject group = groups[groupID].toObject(); QJsonArray ranks = group["ranks"].toArray(); + + QHash& ranksForGroup = _groupRanks[groupID]; + QHash idsFromThisUpdate; + for (int rankIndex = 0; rankIndex < ranks.size(); rankIndex++) { QJsonObject rank = ranks.at(rankIndex).toObject(); - QString rankName = rank["name"].toString(); + + QUuid rankID = QUuid(rank["id"].toString()); int rankOrder = rank["order"].toInt(); - QVector& ranksForGroup = _groupRanks[groupID]; - if (ranksForGroup.size() < rankOrder + 1) { - ranksForGroup.resize(rankOrder + 1); + QString rankName = rank["name"].toString(); + int rankMembersCount = rank["members_count"].toInt(); + + GroupRank groupRank(rankID, rankOrder, rankName, rankMembersCount); + + if (ranksForGroup[rankID] != groupRank) { + ranksForGroup[rankID] = groupRank; changed = true; } - if (ranksForGroup[rankOrder] != rankName) { - ranksForGroup[rankOrder] = rankName; - changed = true; + + idsFromThisUpdate[rankID] = true; + } + + // clean up any that went away + foreach (QUuid rankID, ranksForGroup.keys()) { + if (!idsFromThisUpdate.contains(rankID)) { + ranksForGroup.remove(rankID); } } } @@ -1307,20 +1365,20 @@ void DomainServerSettingsManager::apiGetGroupRanksErrorCallback(QNetworkReply& r qDebug() << "******************** getGroupRanks api call failed:" << requestReply.error(); } -void DomainServerSettingsManager::recordGroupMembership(const QString& name, const QUuid groupID, int rank) { - if (rank >= 0) { - _groupMembership[name][groupID] = rank; +void DomainServerSettingsManager::recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID) { + if (rankID != QUuid()) { + _groupMembership[name][groupID] = rankID; } else { _groupMembership[name].remove(groupID); } } -int DomainServerSettingsManager::isGroupMember(const QString& name, const QUuid& groupID) { - const QHash& groupsForName = _groupMembership[name]; +QUuid DomainServerSettingsManager::isGroupMember(const QString& name, const QUuid& groupID) { + const QHash& groupsForName = _groupMembership[name]; if (groupsForName.contains(groupID)) { return groupsForName[groupID]; } - return -1; + return QUuid(); } QList DomainServerSettingsManager::getGroupIDs() { @@ -1370,9 +1428,10 @@ void DomainServerSettingsManager::debugDumpGroupsState() { qDebug() << "_groupRanks:"; foreach (QUuid groupID, _groupRanks.keys()) { - QVector& ranksForGroup = _groupRanks[groupID]; + QHash& ranksForGroup = _groupRanks[groupID]; QString readableRanks; - foreach (QString rankName, ranksForGroup) { + foreach (QUuid rankID, ranksForGroup.keys()) { + QString rankName = ranksForGroup[rankID].name; if (readableRanks == "") { readableRanks = rankName; } else { @@ -1381,4 +1440,14 @@ void DomainServerSettingsManager::debugDumpGroupsState() { } qDebug() << "| " << groupID << "==>" << readableRanks; } + + qDebug() << "_groupMembership"; + foreach (QString userName, _groupMembership.keys()) { + QHash& groupsForUser = _groupMembership[userName]; + QString line = ""; + foreach (QUuid groupID, groupsForUser.keys()) { + line += " g=" + groupID.toString() + ",r=" + groupsForUser[groupID].toString(); + } + qDebug() << "| " << userName << line; + } } diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index f59d76bd1e..c4d70baf21 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -30,7 +30,8 @@ const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions"; const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions"; const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens"; -using GroupByUUIDKey = QPair; +using GroupByUUIDKey = QPair; // groupID, rankID + class DomainServerSettingsManager : public QObject { Q_OBJECT @@ -58,32 +59,34 @@ public: QStringList getAllNames() const; // these give access to permissions for specific groups from the domain-server settings page - bool havePermissionsForGroup(const QString& groupName, int rank) const { - return _groupPermissions.contains(groupName, rank); + bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const { + return _groupPermissions.contains(groupName, rankID); } - NodePermissions getPermissionsForGroup(const QString& groupName, int rank) const; - NodePermissions getPermissionsForGroup(const QUuid& groupID, int rank) const; + NodePermissions getPermissionsForGroup(const QString& groupName, QUuid rankID) const; + NodePermissions getPermissionsForGroup(const QUuid& groupID, QUuid rankID) const; // these remove permissions from users in certain groups - bool haveForbiddensForGroup(const QString& groupName, int rank) const { return _groupForbiddens.contains(groupName, rank); } - NodePermissions getForbiddensForGroup(const QString& groupName, int rank) const; - NodePermissions getForbiddensForGroup(const QUuid& groupID, int rank) const; + bool haveForbiddensForGroup(const QString& groupName, QUuid rankID) const { + return _groupForbiddens.contains(groupName, rankID); + } + NodePermissions getForbiddensForGroup(const QString& groupName, QUuid rankID) const; + NodePermissions getForbiddensForGroup(const QUuid& groupID, QUuid rankID) const; QStringList getAllKnownGroupNames(); bool setGroupID(const QString& groupName, const QUuid& groupID); + GroupRank getGroupRank(QUuid groupID, QUuid rankID) { return _groupRanks[groupID][rankID]; } QList getGroupIDs(); QList getBlacklistGroupIDs(); // these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api void clearGroupMemberships(const QString& name) { _groupMembership[name].clear(); } - void recordGroupMembership(const QString& name, const QUuid groupID, int rank); - int isGroupMember(const QString& name, const QUuid& groupID); // returns rank or -1 if not a member + void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID); + QUuid isGroupMember(const QString& name, const QUuid& groupID); // returns rank or -1 if not a member // calls http api to refresh group information void apiRefreshGroupInformation(); - signals: void updateNodePermissions(); @@ -138,11 +141,10 @@ private: QHash _groupNames; // keep track of group-id to group-name mappings // remember the responses to api/v1/groups/%1/ranks - QHash> _groupRanks; // QHash> - QHash _groupRanksLastFetched; // when did we last update _groupRanks + QHash> _groupRanks; // QHash> // keep track of answers to api queries about which users are in which groups - QHash> _groupMembership; // QHash> + QHash> _groupMembership; // QHash> void debugDumpGroupsState(); diff --git a/libraries/networking/src/GroupRank.h b/libraries/networking/src/GroupRank.h new file mode 100644 index 0000000000..89675684d8 --- /dev/null +++ b/libraries/networking/src/GroupRank.h @@ -0,0 +1,36 @@ +// +// GroupRank.h +// libraries/networking/src/ +// +// Created by Seth Alves on 2016-7-21. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GroupRank_h +#define hifi_GroupRank_h + +class GroupRank { +public: + GroupRank() : id(QUuid()), order(-1), name(""), membersCount(-1) {} + GroupRank(QUuid id, unsigned int order, QString name, unsigned int membersCount) : + id(id), order(order), name(name), membersCount(membersCount) {} + + QUuid id; + int order; + QString name; + int membersCount; +}; + +inline bool operator==(const GroupRank& lhs, const GroupRank& rhs) { + return + lhs.id == rhs.id && + lhs.order == rhs.order && + lhs.name == rhs.name && + lhs.membersCount == rhs.membersCount; +} +inline bool operator!=(const GroupRank& lhs, const GroupRank& rhs) { return !(lhs == rhs); } + +#endif // hifi_GroupRank_h diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index 29b05fc837..c73ca122ff 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -32,8 +32,8 @@ NodePermissions::NodePermissions(QMap perms) { _groupIDSet = true; } } - if (perms.contains("rank")) { - _rank = perms["rank"].toInt(); + if (perms.contains("rank_id")) { + _rankID = QUuid(perms["rank_id"].toString()); } permissions = NodePermissions::Permissions(); @@ -46,14 +46,15 @@ NodePermissions::NodePermissions(QMap perms) { Permission::canConnectPastMaxCapacity : Permission::none; } -QVariant NodePermissions::toVariant(QVector rankNames) { +QVariant NodePermissions::toVariant(QHash groupRanks) { QMap values; values["permissions_id"] = _id; if (_groupIDSet) { values["group_id"] = _groupID; - values["rank"] = _rank; - if (rankNames.size() > _rank) { - values["rank_name"] = rankNames[_rank]; + if (groupRanks.contains(_rankID)) { + values["rank_id"] = _rankID; + values["rank_name"] = groupRanks[_rankID].name; + values["rank_order"] = groupRanks[_rankID].order; } } values["id_can_connect"] = can(Permission::canConnectToDomain); @@ -147,7 +148,7 @@ QDataStream& operator>>(QDataStream& in, NodePermissions& perms) { QDebug operator<<(QDebug debug, const NodePermissions& perms) { debug.nospace() << "[permissions: " << perms.getID() << "/" << perms.getVerifiedUserName() << " -- "; - debug.nospace() << "rank=" << perms.getRank() + debug.nospace() << "rank=" << perms.getRankID() << ", groupID=" << perms.getGroupID() << "/" << (perms.isGroup() ? "y" : "n"); if (perms.can(NodePermissions::Permission::canConnectToDomain)) { debug << " connect"; diff --git a/libraries/networking/src/NodePermissions.h b/libraries/networking/src/NodePermissions.h index 541f90aee8..6d12c4cf7e 100644 --- a/libraries/networking/src/NodePermissions.h +++ b/libraries/networking/src/NodePermissions.h @@ -18,21 +18,24 @@ #include #include +#include "GroupRank.h" + class NodePermissions; using NodePermissionsPointer = std::shared_ptr; -using NodePermissionsKey = QPair; -using NodePermissionsKeyList = QList>; +using NodePermissionsKey = QPair; // name, rankID +using NodePermissionsKeyList = QList>; + class NodePermissions { public: - NodePermissions() { _id = QUuid::createUuid().toString(); _rank = 0; } - NodePermissions(const QString& name) { _id = name.toLower(); _rank = 0; } - NodePermissions(const NodePermissionsKey& key) { _id = key.first.toLower(); _rank = key.second; } + NodePermissions() { _id = QUuid::createUuid().toString(); _rankID = QUuid(); } + NodePermissions(const QString& name) { _id = name.toLower(); _rankID = QUuid(); } + NodePermissions(const NodePermissionsKey& key) { _id = key.first.toLower(); _rankID = key.second; } NodePermissions(QMap perms); QString getID() const { return _id; } // a user-name or a group-name, not verified - int getRank() const { return _rank; } - NodePermissionsKey getKey() const { return NodePermissionsKey(_id, _rank); } + QUuid getRankID() const { return _rankID; } + NodePermissionsKey getKey() const { return NodePermissionsKey(_id, _rankID); } // the _id member isn't authenticated/verified and _username is. void setVerifiedUserName(QString userName) { _verifiedUserName = userName.toLower(); } @@ -63,7 +66,7 @@ public: Q_DECLARE_FLAGS(Permissions, Permission) Permissions permissions; - QVariant toVariant(QVector rankNames = QVector()); + QVariant toVariant(QHash groupRanks = QHash()); void setAll(bool value); @@ -81,7 +84,7 @@ public: protected: QString _id; - int _rank { 0 }; // 0 unless this is for a group + QUuid _rankID { QUuid() }; // 0 unless this is for a group QString _verifiedUserName; bool _groupIDSet { false }; @@ -107,7 +110,7 @@ public: bool contains(const NodePermissionsKey& key) const { return _data.contains(NodePermissionsKey(key.first.toLower(), key.second)); } - bool contains(const QString& keyFirst, int keySecond) const { + bool contains(const QString& keyFirst, QUuid keySecond) const { return _data.contains(NodePermissionsKey(keyFirst.toLower(), keySecond)); } QList keys() const { return _data.keys(); }