diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index a6542689e0..2b964ae674 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -372,7 +372,7 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream // Record explicitly filtered-in entity so that extra entities can be flagged. entityNodeData->insertSentFilteredEntity(entityID); } - OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData); + OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData, entityNode->getCanGetAndSetPrivateUserData()); if (appendEntityState != OctreeElement::COMPLETED) { if (appendEntityState == OctreeElement::PARTIAL) { diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 74c744aced..488b2091f3 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,5 +1,5 @@ { - "version": 2.2, + "version": 2.3, "settings": [ { "name": "metaverse", @@ -224,7 +224,7 @@ "name": "standard_permissions", "type": "table", "label": "Domain-Wide User Permissions", - "help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.", + "help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.", "caption": "Standard Permissions", "can_add_new_rows": false, "groups": [ @@ -233,8 +233,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -311,6 +311,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ], "non-deletable-row-key": "permissions_id", @@ -337,6 +344,7 @@ "id_can_rez_tmp": true, "id_can_rez_tmp_certified": true, "id_can_write_to_asset_server": true, + "id_can_get_and_set_private_user_data": true, "permissions_id": "localhost" }, { @@ -361,8 +369,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -464,6 +472,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ] }, @@ -482,8 +497,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -582,6 +597,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ] }, @@ -596,8 +618,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -674,6 +696,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ] }, @@ -688,8 +717,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -766,6 +795,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ] }, @@ -780,8 +816,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -858,7 +894,14 @@ "type": "checkbox", "editable": true, "default": false - } + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false + } ] }, { @@ -872,8 +915,8 @@ "span": 1 }, { - "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", - "span": 10 + "label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>", + "span": 11 } ], "columns": [ @@ -950,6 +993,13 @@ "type": "checkbox", "editable": true, "default": false + }, + { + "name": "id_can_get_and_set_private_user_data", + "label": "Can Get and Set Private User Data", + "type": "checkbox", + "editable": true, + "default": false } ] }, diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index e53196c67f..29656f4465 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -282,6 +282,7 @@ void DomainGatekeeper::updateNodePermissions() { userPerms.permissions |= NodePermissions::Permission::canRezTemporaryCertifiedEntities; userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer; userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent; + userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData; } else { // at this point we don't have a sending socket for packets from this node - assume it is the active socket // or the public socket if we haven't activated a socket for the node yet @@ -374,6 +375,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo userPerms.permissions |= NodePermissions::Permission::canRezTemporaryCertifiedEntities; userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer; userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent; + userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData; newNode->setPermissions(userPerms); return newNode; } diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 4e833f6b77..2deb51f2e3 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -441,6 +441,12 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena } } + if (oldVersion < 2.3) { + unpackPermissions(); + _standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canGetAndSetPrivateUserData); + packPermissions(); + } + // write the current description version to our settings *versionVariant = _descriptionVersion; diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 0491bdedae..dbb3ab076e 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -110,6 +110,10 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityPropertyFlags requestedProperties = propertiesCopy.getChangedProperties(); + if (!nodeList->getThisNodeCanGetAndSetPrivateUserData() && requestedProperties.getHasProperty(PROP_PRIVATE_USER_DATA)) { + requestedProperties -= PROP_PRIVATE_USER_DATA; + } + while (encodeResult == OctreeElement::PARTIAL) { encodeResult = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut, requestedProperties, didntFitProperties); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4232e9d1b9..d39924dcd3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -86,6 +86,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_NAME; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; + requestedProperties += PROP_PRIVATE_USER_DATA; requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; requestedProperties += PROP_POSITION; @@ -154,7 +155,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param } OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData) const { + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + const bool destinationNodeCanGetAndSetPrivateUserData) const { // ALL this fits... // object ID [16 bytes] @@ -198,6 +200,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet requestedProperties = entityTreeElementExtraEncodeData->entities.value(getEntityItemID()); } + QString privateUserData = ""; + if (destinationNodeCanGetAndSetPrivateUserData) { + privateUserData = getPrivateUserData(); + } + EntityPropertyFlags propertiesDidntFit = requestedProperties; LevelDetails entityLevel = packetData->startLevel(); @@ -266,8 +273,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); // convert AVATAR_SELF_ID to actual sessionUUID. QUuid actualParentID = getParentID(); + auto nodeList = DependencyManager::get<NodeList>(); if (actualParentID == AVATAR_SELF_ID) { - auto nodeList = DependencyManager::get<NodeList>(); actualParentID = nodeList->getSessionUUID(); } APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, actualParentID); @@ -276,6 +283,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); + APPEND_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, privateUserData); APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); @@ -812,6 +820,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); + READ_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, QString, setPrivateUserData); READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); { // When we own the simulation we don't accept updates to the entity's transform/velocities @@ -1331,6 +1340,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(privateUserData, getPrivateUserData); COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); @@ -1479,6 +1489,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(privateUserData, setPrivateUserData); SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); @@ -3121,6 +3132,20 @@ void EntityItem::setUserData(const QString& value) { }); } +QString EntityItem::getPrivateUserData() const { + QString result; + withReadLock([&] { + result = _privateUserData; + }); + return result; +} + +void EntityItem::setPrivateUserData(const QString& value) { + withWriteLock([&] { + _privateUserData = value; + }); +} + // Certifiable Properties #define DEFINE_PROPERTY_GETTER(type, accessor, var) \ type EntityItem::get##accessor() const { \ diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a8c3d31344..424454f528 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -134,7 +134,8 @@ public: virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData) const; + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + const bool destinationNodeCanGetAndSetPrivateUserData = false) const; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, @@ -332,6 +333,9 @@ public: QString getUserData() const; virtual void setUserData(const QString& value); // FIXME: This is suspicious + QString getPrivateUserData() const; + void setPrivateUserData(const QString& value); + // FIXME not thread safe? const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } void setSimulationOwner(const QUuid& id, uint8_t priority); @@ -644,6 +648,7 @@ protected: bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC }; bool _locked { ENTITY_ITEM_DEFAULT_LOCKED }; QString _userData { ENTITY_ITEM_DEFAULT_USER_DATA }; + QString _privateUserData{ ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA }; SimulationOwner _simulationOwner; bool _shouldHighlight { false }; QString _name { ENTITY_ITEM_DEFAULT_NAME }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5d39139b46..ce4387a006 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -487,6 +487,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); + CHECK_PROPERTY_CHANGE(PROP_PRIVATE_USER_DATA, privateUserData); CHECK_PROPERTY_CHANGE(PROP_HREF, href); CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description); CHECK_PROPERTY_CHANGE(PROP_POSITION, position); @@ -818,6 +819,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * which you can manipulate the properties of, and use <code>JSON.stringify()</code> to convert the object into a string to * put in the property. * + * @property {string} privateUserData="" - Like userData, but only accessible by Entity Server Scripts, AC scripts, and users + * who are given "Can Get and Set Private User Data" permissions from the ACL matrix on the Domain Settings page. + * * @property {string} script="" - The URL of the client entity script, if any, that is attached to the entity. * @property {number} scriptTimestamp=0 - Intended to be used to indicate when the client entity script was loaded. Should be * an integer number of milliseconds since midnight GMT on January 1, 1970 (e.g., as supplied by <code>Date.now()</code>. @@ -1591,6 +1595,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PRIVATE_USER_DATA, privateUserData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position); @@ -1999,6 +2004,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData); + COPY_PROPERTY_FROM_QSCRIPTVALUE(privateUserData, QString, setPrivateUserData); COPY_PROPERTY_FROM_QSCRIPTVALUE(href, QString, setHref); COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription); COPY_PROPERTY_FROM_QSCRIPTVALUE(position, vec3, setPosition); @@ -2288,6 +2294,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(name); COPY_PROPERTY_IF_CHANGED(locked); COPY_PROPERTY_IF_CHANGED(userData); + COPY_PROPERTY_IF_CHANGED(privateUserData); COPY_PROPERTY_IF_CHANGED(href); COPY_PROPERTY_IF_CHANGED(description); COPY_PROPERTY_IF_CHANGED(position); @@ -2573,6 +2580,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool); ADD_PROPERTY_TO_MAP(PROP_USER_DATA, UserData, userData, QString); + ADD_PROPERTY_TO_MAP(PROP_PRIVATE_USER_DATA, PrivateUserData, privateUserData, QString); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString); ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, vec3); @@ -3047,6 +3055,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); + APPEND_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, properties.getPrivateUserData()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); @@ -3530,6 +3539,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIVATE_USER_DATA, QString, setPrivateUserData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, vec3, setPosition); @@ -3941,6 +3951,7 @@ void EntityItemProperties::markAllChanged() { _nameChanged = true; _lockedChanged = true; _userDataChanged = true; + _privateUserDataChanged = true; _hrefChanged = true; _descriptionChanged = true; _positionChanged = true; @@ -4303,6 +4314,9 @@ QList<QString> EntityItemProperties::listChangedProperties() { if (userDataChanged()) { out += "userData"; } + if (privateUserDataChanged()) { + out += "privateUserData"; + } if (hrefChanged()) { out += "href"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 0142f42536..af945a89de 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -180,6 +180,7 @@ public: DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString, ENTITY_ITEM_DEFAULT_NAME); DEFINE_PROPERTY(PROP_LOCKED, Locked, locked, bool, ENTITY_ITEM_DEFAULT_LOCKED); DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString, ENTITY_ITEM_DEFAULT_USER_DATA); + DEFINE_PROPERTY_REF(PROP_PRIVATE_USER_DATA, PrivateUserData, privateUserData, QString, ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString, ""); DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3, ENTITY_ITEM_ZERO_VEC3); @@ -607,6 +608,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Textures, textures, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, UserData, userData, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, PrivateUserData, privateUserData, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulationOwner, simulationOwner, SimulationOwner()); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Text, text, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LineHeight, lineHeight, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index be3c566724..cc12eb37b4 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -28,6 +28,7 @@ const QVector<glm::vec3> ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC = QVector<glm::vec3 const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); +const QString ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA = QString(""); const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); // Certifiable Properties diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 969fd007f1..e86cccb997 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -26,6 +26,7 @@ enum EntityPropertyList { PROP_NAME, PROP_LOCKED, PROP_USER_DATA, + PROP_PRIVATE_USER_DATA, PROP_HREF, PROP_DESCRIPTION, PROP_POSITION, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f8c45b792a..87f15896f2 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -56,6 +56,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged); connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged); connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged); + connect(nodeList.data(), &NodeList::canGetAndSetPrivateUserDataChanged, this, &EntityScriptingInterface::canGetAndSetPrivateUserDataChanged); auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket"); @@ -107,6 +108,11 @@ bool EntityScriptingInterface::canReplaceContent() { return nodeList->getThisNodeCanReplaceContent(); } +bool EntityScriptingInterface::canGetAndSetPrivateUserData() { + auto nodeList = DependencyManager::get<NodeList>(); + return nodeList->getThisNodeCanGetAndSetPrivateUserData(); +} + void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { if (_entityTree) { disconnect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 38b73aaf45..c072dedaf9 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -236,6 +236,14 @@ public slots: */ Q_INVOKABLE bool canReplaceContent(); + /**jsdoc + * Check whether or not you can get and set private user data. + * @function Entities.canGetAndSetPrivateUserData + * @returns {boolean} <code>true</code> if the domain server will allow the user to get and set private user data, + * otherwise <code>false</code>. + */ + Q_INVOKABLE bool canGetAndSetPrivateUserData(); + /**jsdoc * <p>How an entity is sent over the wire.</p> * <table> @@ -1861,6 +1869,15 @@ signals: */ void canWriteAssetsChanged(bool canWriteAssets); + /**jsdoc + * Triggered when your ability to get and set private user data changes. + * @function Entities.canGetAndSetPrivateUserDataChanged + * @param {boolean} canGetAndSetPrivateUserData - <code>true</code> if you can change the <code>privateUserData</code> property of an entity, + * otherwise <code>false</code>. + * @returns {Signal} + */ + void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData); + /**jsdoc * Triggered when a mouse button is clicked while the mouse cursor is on an entity, or a controller trigger is fully diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index fe8c8c9336..652266bd48 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1286,6 +1286,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q } } + if (properties.privateUserDataChanged()) { + int index = changedProperties.indexOf("privateUserData"); + if (index >= 0) { + QString changeHint = properties.getPrivateUserData(); + changedProperties[index] = QString("privateUserData:") + changeHint; + } + } + if (properties.parentJointIndexChanged()) { int index = changedProperties.indexOf("parentJointIndex"); if (index >= 0) { @@ -1772,6 +1780,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c bool suppressDisallowedClientScript = false; bool suppressDisallowedServerScript = false; + bool suppressDisallowedPrivateUserData = false; bool isPhysics = message.getType() == PacketType::EntityPhysics; _totalEditMessages++; @@ -1860,7 +1869,22 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } } } + } + if (!properties.getPrivateUserData().isEmpty() && validEditPacket && !senderNode->getCanGetAndSetPrivateUserData()) { + if (wantEditLogging()) { + qCDebug(entities) << "User [" << senderNode->getUUID() + << "] is attempting to set private user data but user isn't allowed; edit rejected..."; + } + + // If this was an add, we also want to tell the client that sent this edit that the entity was not added. + if (isAdd) { + QWriteLocker locker(&_recentlyDeletedEntitiesLock); + _recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), entityItemID); + validEditPacket = false; + } else { + suppressDisallowedPrivateUserData = true; + } } if (!isClone) { @@ -1915,6 +1939,11 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c properties.setServerScripts(existingEntity->getServerScripts()); } + if (suppressDisallowedPrivateUserData) { + bumpTimestamp(properties); + properties.setPrivateUserData(existingEntity->getPrivateUserData()); + } + // if the EntityItem exists, then update it startLogging = usecTimestampNow(); if (wantEditLogging()) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d87d74c188..563d6e7ad1 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -197,6 +197,10 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) { newPermissions.can(NodePermissions::Permission::canReplaceDomainContent)) { emit canReplaceContentChanged(_permissions.can(NodePermissions::Permission::canReplaceDomainContent)); } + if (originalPermissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData) != + newPermissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData)) { + emit canGetAndSetPrivateUserDataChanged(_permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData)); + } } void LimitedNodeList::setSocketLocalPort(quint16 socketLocalPort) { diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 4db4f3136a..60c91c8ff6 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -124,6 +124,7 @@ public: bool getThisNodeCanWriteAssets() const { return _permissions.can(NodePermissions::Permission::canWriteToAssetServer); } bool getThisNodeCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); } bool getThisNodeCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); } + bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); } quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); } Q_INVOKABLE void setSocketLocalPort(quint16 socketLocalPort); @@ -368,6 +369,7 @@ signals: void canWriteAssetsChanged(bool canWriteAssets); void canKickChanged(bool canKick); void canReplaceContentChanged(bool canReplaceContent); + void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData); protected slots: void connectedForLocalSocketTest(); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index fe3177d785..07c599913b 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -83,6 +83,7 @@ public: bool getCanWriteToAssetServer() const { return _permissions.can(NodePermissions::Permission::canWriteToAssetServer); } bool getCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); } bool getCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); } + bool getCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); } using NodesIgnoredPair = std::pair<std::vector<QUuid>, bool>; diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index 92ebf1d01e..e0de649c05 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -67,6 +67,7 @@ NodePermissions::NodePermissions(QMap<QString, QVariant> perms) { Permission::canConnectPastMaxCapacity : Permission::none; permissions |= perms["id_can_kick"].toBool() ? Permission::canKick : Permission::none; permissions |= perms["id_can_replace_content"].toBool() ? Permission::canReplaceDomainContent : Permission::none; + permissions |= perms["id_can_get_and_set_private_user_data"].toBool() ? Permission::canGetAndSetPrivateUserData : Permission::none; } QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) { @@ -94,6 +95,7 @@ QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) { values["id_can_connect_past_max_capacity"] = can(Permission::canConnectPastMaxCapacity); values["id_can_kick"] = can(Permission::canKick); values["id_can_replace_content"] = can(Permission::canReplaceDomainContent); + values["id_can_get_and_set_private_user_data"] = can(Permission::canGetAndSetPrivateUserData); return QVariant(values); } @@ -166,6 +168,9 @@ QDebug operator<<(QDebug debug, const NodePermissions& perms) { if (perms.can(NodePermissions::Permission::canReplaceDomainContent)) { debug << " can_replace_content"; } + if (perms.can(NodePermissions::Permission::canGetAndSetPrivateUserData)) { + debug << " get-and-set-private-user-data"; + } debug.nospace() << "]"; return debug.nospace(); } diff --git a/libraries/networking/src/NodePermissions.h b/libraries/networking/src/NodePermissions.h index 1b0b9d220d..583c1b29ac 100644 --- a/libraries/networking/src/NodePermissions.h +++ b/libraries/networking/src/NodePermissions.h @@ -75,7 +75,8 @@ public: canKick = 64, canReplaceDomainContent = 128, canRezPermanentCertifiedEntities = 256, - canRezTemporaryCertifiedEntities = 512 + canRezTemporaryCertifiedEntities = 512, + canGetAndSetPrivateUserData = 1024 }; Q_DECLARE_FLAGS(Permissions, Permission) Permissions permissions; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index ed81a6d9ca..5deadd8c43 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -270,6 +270,7 @@ enum class EntityVersion : PacketVersion { DisableWebMedia, ParticleShapeType, ParticleShapeTypeDeadlockFix, + PrivateUserData, // Add new versions above here NUM_PACKET_TYPE,