diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 8a560984a6..d1b84ec63c 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -92,6 +92,11 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket); _receivedPacketCount++; + + if (! sendingNode.data()->getCanEdit()) { + qDebug("node %s attempted unpermitted edit", sendingNode->getUUID().toString().toUtf8().constData()); + return; + } const unsigned char* packetData = reinterpret_cast(packet.data()); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d680bbf520..578ee5202d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -41,6 +41,11 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923; const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; + +const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; +const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors"; + + DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), @@ -638,10 +643,16 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock // we got a packetUUID we didn't recognize, just add the node nodeUUID = QUuid::createUuid(); } - - SharedNodePointer newNode = DependencyManager::get()->addOrUpdateNode(nodeUUID, nodeType, - publicSockAddr, localSockAddr); + // if this user is in the editors list (or if the editors list is empty) set the user's node's canEdit to true + const QVariant* allowedEditorsVariant = + valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH); + QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList(); + bool canEdit = allowedEditors.isEmpty() || allowedEditors.contains(username); + + SharedNodePointer newNode = + DependencyManager::get()->addOrUpdateNode(nodeUUID, nodeType, + publicSockAddr, localSockAddr, canEdit); // when the newNode is created the linked data is also created // if this was a static assignment set the UUID, set the sendingSockAddr DomainServerNodeData* nodeData = reinterpret_cast(newNode->getLinkedData()); @@ -663,7 +674,6 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock } } -const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; bool DomainServer::shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, @@ -842,6 +852,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif // always send the node their own UUID back QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); broadcastDataStream << node->getUUID(); + broadcastDataStream << node->getCanEdit(); int numBroadcastPacketLeadBytes = broadcastDataStream.device()->pos(); diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 366ee8c730..6ba4206adc 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -45,7 +45,7 @@ public: void setIsAuthenticated(bool isAuthenticated) { _isAuthenticated = isAuthenticated; } bool isAuthenticated() const { return _isAuthenticated; } - + QHash& getSessionSecretHash() { return _sessionSecretHash; } private: QJsonObject mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c247da2a8c..1bca754337 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -26,22 +26,32 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType, getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties); } + +bool EntityScriptingInterface::canEdit() { + auto nodeList = DependencyManager::get(); + return nodeList->getThisNodeCanEdit(); +} + + EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { + // The application will keep track of creatorTokenID uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID(); EntityItemID id(NEW_ENTITY, creatorTokenID, false ); - // If we have a local entity tree set, then also update it. - if (_entityTree) { - _entityTree->lockForWrite(); - _entityTree->addEntity(id, properties); - _entityTree->unlock(); - } + if (canEdit()) { + // If we have a local entity tree set, then also update it. + if (_entityTree) { + _entityTree->lockForWrite(); + _entityTree->addEntity(id, properties); + _entityTree->unlock(); + } - // queue the packet - queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + // queue the packet + queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + } return id; } @@ -94,6 +104,11 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID } EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const EntityItemProperties& properties) { + + if (! canEdit()) { + return entityID; + } + EntityItemID actualID = entityID; // if the entity is unknown, attempt to look it up if (!entityID.isKnownID) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 3585cce946..6700a86731 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -59,6 +59,8 @@ public: void setEntityTree(EntityTree* modelTree) { _entityTree = modelTree; } EntityTree* getEntityTree(EntityTree*) { return _entityTree; } + + bool canEdit(); public slots: /// adds a model with the specific properties diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 06b3b6a0db..b90551dcd0 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -411,7 +411,8 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { } SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, - const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) { + const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, + bool canEdit) { NodeHash::const_iterator it = _nodeHash.find(uuid); if (it != _nodeHash.end()) { @@ -419,11 +420,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setPublicSocket(publicSocket); matchingNode->setLocalSocket(localSocket); + matchingNode->setCanEdit(canEdit); return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canEdit); SharedNodePointer newNodePointer(newNode); _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 6e736519a0..378fa89786 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -76,6 +76,9 @@ class LimitedNodeList : public QObject, public Dependency { public: const QUuid& getSessionUUID() const { return _sessionUUID; } void setSessionUUID(const QUuid& sessionUUID); + + bool getThisNodeCanEdit() { return _thisNodeCanEdit; } + void setThisNodeCanEdit(bool canEdit) { _thisNodeCanEdit = canEdit; } void rebindNodeSocket(); QUdpSocket& getNodeSocket() { return _nodeSocket; } @@ -106,7 +109,7 @@ public: SharedNodePointer sendingNodeForPacket(const QByteArray& packet); SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, - const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canEdit); const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } @@ -201,6 +204,7 @@ protected: void handleNodeKill(const SharedNodePointer& node); QUuid _sessionUUID; + bool _thisNodeCanEdit; NodeHash _nodeHash; QReadWriteLock _nodeMutex; QUdpSocket _nodeSocket; diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 697ef99b6d..ccefc4d1d0 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -41,8 +41,9 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME; } -Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : - NetworkPeer(uuid, publicSocket, localSocket), +Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, + const HifiSockAddr& localSocket, bool canEdit) : + NetworkPeer(uuid, publicSocket, localSocket), _type(type), _activeSocket(NULL), _symmetricSocket(), @@ -52,7 +53,8 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _pingMs(-1), // "Uninitialized" _clockSkewUsec(0), _mutex(), - _clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples + _clockSkewMovingPercentile(30, 0.8f), // moving 80th percentile of 30 samples + _canEdit(canEdit) { } @@ -131,6 +133,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._uuid; out << node._publicSocket; out << node._localSocket; + out << node._canEdit; return out; } @@ -140,6 +143,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { in >> node._uuid; in >> node._publicSocket; in >> node._localSocket; + in >> node._canEdit; return in; } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 3ff8d771e0..dbdca9bbc0 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -45,7 +45,7 @@ namespace NodeType { class Node : public NetworkPeer { Q_OBJECT public: - Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canEdit); ~Node(); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } @@ -76,6 +76,9 @@ public: virtual void setSymmetricSocket(const HifiSockAddr& symmetricSocket); const HifiSockAddr* getActiveSocket() const { return _activeSocket; } + + void setCanEdit(bool canEdit) { _canEdit = canEdit; } + bool getCanEdit() { return _canEdit; } void activatePublicSocket(); void activateLocalSocket(); @@ -101,6 +104,7 @@ private: int _clockSkewUsec; QMutex _mutex; MovingPercentile _clockSkewMovingPercentile; + bool _canEdit; }; QDebug operator<<(QDebug debug, const Node &message); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index bb095b2a3d..972efda79e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -370,13 +370,6 @@ int NodeList::processDomainServerList(const QByteArray& packet) { int readNodes = 0; - // setup variables to read into from QDataStream - qint8 nodeType; - - QUuid nodeUUID, connectionUUID; - - HifiSockAddr nodePublicSocket; - HifiSockAddr nodeLocalSocket; QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); @@ -385,10 +378,20 @@ int NodeList::processDomainServerList(const QByteArray& packet) { QUuid newUUID; packetStream >> newUUID; setSessionUUID(newUUID); + + bool thisNodeCanEdit; + packetStream >> thisNodeCanEdit; + setThisNodeCanEdit(thisNodeCanEdit); // pull each node in the packet while(packetStream.device()->pos() < packet.size()) { - packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket; + // setup variables to read into from QDataStream + qint8 nodeType; + QUuid nodeUUID, connectionUUID; + HifiSockAddr nodePublicSocket, nodeLocalSocket; + bool canEdit; + + packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> canEdit; // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -396,7 +399,7 @@ int NodeList::processDomainServerList(const QByteArray& packet) { nodePublicSocket.setAddress(_domainHandler.getIP()); } - SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket); + SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket, canEdit); packetStream >> connectionUUID; node->setConnectionSecret(connectionUUID); diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 21625dc7d5..d2806f3db5 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -64,7 +64,7 @@ PacketVersion versionForPacketType(PacketType type) { return 2; case PacketTypeDomainList: case PacketTypeDomainListRequest: - return 3; + return 4; case PacketTypeCreateAssignment: case PacketTypeRequestAssignment: return 2;