add canViewAssetURLs domain permissions

This commit is contained in:
HifiExperiments 2022-03-12 19:41:33 -08:00
parent edb8cc55b4
commit 8bdc5bb4cf
14 changed files with 152 additions and 24 deletions

View file

@ -1,5 +1,5 @@
{
"version": 2.6,
"version": 2.7,
"settings": [
{
"name": "metaverse",
@ -479,6 +479,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
],
"non-deletable-row-key": "permissions_id",
@ -505,6 +512,7 @@
"id_can_rez_tmp": true,
"id_can_write_to_asset_server": true,
"id_can_get_and_set_private_user_data": true,
"id_can_view_asset_urls": true,
"permissions_id": "localhost"
},
{
@ -633,6 +641,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
@ -752,6 +767,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
@ -844,6 +866,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
@ -936,6 +965,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
@ -1022,13 +1058,20 @@
"editable": true,
"default": false
},
{
"name": "id_can_get_and_set_private_user_data",
"label": "Get and Set Private User Data",
"type": "checkbox",
"editable": true,
"default": false
}
{
"name": "id_can_get_and_set_private_user_data",
"label": "Get and Set Private User Data",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
{
@ -1120,6 +1163,13 @@
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_view_asset_urls",
"label": "View Asset URLs",
"type": "checkbox",
"editable": true,
"default": false
}
]
},

View file

@ -353,6 +353,7 @@ void DomainGatekeeper::updateNodePermissions() {
userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent;
userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData;
userPerms.permissions |= NodePermissions::Permission::canRezAvatarEntities;
userPerms.permissions |= NodePermissions::Permission::canViewAssetURLs;
} 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
@ -446,6 +447,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent;
userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData;
userPerms.permissions |= NodePermissions::Permission::canRezAvatarEntities;
userPerms.permissions |= NodePermissions::Permission::canViewAssetURLs;
newNode->setPermissions(userPerms);
return newNode;
}

View file

@ -547,6 +547,29 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena
// No migration needed to version 2.6.
if (oldVersion < 2.7) {
// Default values for new canViewAssetURLs permission.
unpackPermissions();
std::list<std::unordered_map<NodePermissionsKey, NodePermissionsPointer>> permissionsSets{
_standardAgentPermissions.get(),
_agentPermissions.get(),
_ipPermissions.get(),
_macPermissions.get(),
_machineFingerprintPermissions.get(),
_groupPermissions.get(),
_groupForbiddens.get()
};
foreach (auto permissionsSet, permissionsSets) {
for (auto entry : permissionsSet) {
const auto& userKey = entry.first;
if (permissionsSet[userKey]->can(NodePermissions::Permission::canConnectToDomain)) {
permissionsSet[userKey]->set(NodePermissions::Permission::canViewAssetURLs);
}
}
}
packPermissions();
}
// write the current description version to our settings
*versionVariant = _descriptionVersion;

View file

@ -1681,6 +1681,14 @@ float AvatarData::getUpdateRate(const QString& rateName) const {
return 0.0f;
}
QString AvatarData::getSkeletonModelURLFromScript() const {
if (DependencyManager::get<NodeList>()->getThisNodeCanViewAssetURLs()) {
return _skeletonModelURL.toString();
} else {
return QString();
}
}
int AvatarData::getAverageBytesReceivedPerSecond() const {
return lrint(_averageBytesReceived.getAverageSampleValuePerSecond());
}

View file

@ -13,6 +13,7 @@
#include "ScriptAvatarData.h"
#include <NodeList.h>
#include <ScriptEngineCast.h>
#include <ScriptManager.h>
@ -204,7 +205,8 @@ bool ScriptAvatarData::getLookAtSnappingEnabled() const {
//
QString ScriptAvatarData::getSkeletonModelURLFromScript() const {
if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) {
if (sharedAvatarData->isMyAvatar() && !sharedAvatarData->isMyAvatarURLProtected()) {
auto nodeList = DependencyManager::get<NodeList>();
if (sharedAvatarData->isMyAvatar() && !sharedAvatarData->isMyAvatarURLProtected() && nodeList->getThisNodeCanViewAssetURLs()) {
return sharedAvatarData->getSkeletonModelURLFromScript();
}

View file

@ -1566,6 +1566,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
return properties;
}
auto nodeList = DependencyManager::get<NodeList>();
if (_idSet && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::ID))) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString());
}
@ -1634,7 +1635,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, collidesWith, getCollisionMaskAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DYNAMIC, dynamic);
COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COLLISION_SOUND_URL, collisionSoundURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData);
// Cloning
@ -1660,7 +1661,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
// Particles only
if (_type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags);
@ -1710,11 +1711,11 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
// Models only
if (_type == EntityTypes::Model) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_MODEL_URL, modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_SCALE, modelScale);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations);
@ -1777,7 +1778,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
// Zones only
if (_type == EntityTypes::Zone) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
_keyLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags);
_ambientLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags);
@ -1787,7 +1788,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FILTER_URL, filterURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_FILTER_URL, filterURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString());
@ -1804,9 +1805,9 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_SOURCE_URL, sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_URL, scriptURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_SCRIPT_URL, scriptURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_FPS, maxFPS);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_INPUT_MODE, inputMode, getInputModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight);
@ -1819,9 +1820,9 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_X_TEXTURE_URL, xTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_Y_TEXTURE_URL, yTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_Z_TEXTURE_URL, zTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID);
@ -1855,7 +1856,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
// Materials
if (_type == EntityTypes::Material) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_MATERIAL_URL, materialURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_MAPPING_MODE, materialMappingMode, getMaterialMappingModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_NAME, parentMaterialName);
@ -1872,13 +1873,13 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_IMAGE_URL, imageURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SUB_IMAGE, subImage);
// Handle conversions to old 'textures' property from "imageURL"
if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) &&
if (nodeList->getThisNodeCanViewAssetURLs() && ((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) &&
(!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) {
ScriptValue textures = engine->newObject();
textures.setProperty("tex.picture", _imageURL);

View file

@ -218,6 +218,13 @@ inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return
properties.setProperty(#P, V); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(p, P) \
if (nodeList->getThisNodeCanViewAssetURLs() && ((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
ScriptValue V = convertScriptValue(engine, _##P); \
properties.setProperty(#P, V); \
}
typedef QVector<glm::vec3> qVectorVec3;
typedef QVector<glm::quat> qVectorQuat;
typedef QVector<bool> qVectorBool;

View file

@ -97,6 +97,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
connect(nodeList.data(), &NodeList::canGetAndSetPrivateUserDataChanged, this, &EntityScriptingInterface::canGetAndSetPrivateUserDataChanged);
connect(nodeList.data(), &NodeList::canRezAvatarEntitiesChanged, this, &EntityScriptingInterface::canRezAvatarEntitiesChanged);
connect(nodeList.data(), &NodeList::canViewAssetURLsChanged, this, &EntityScriptingInterface::canViewAssetURLsChanged);
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::EntityScriptCallMethod,
@ -291,6 +292,11 @@ bool EntityScriptingInterface::canRezAvatarEntities() {
return nodeList->getThisNodeCanRezAvatarEntities();
}
bool EntityScriptingInterface::canViewAssetURLs() {
auto nodeList = DependencyManager::get<NodeList>();
return nodeList->getThisNodeCanViewAssetURLs();
}
void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
if (_entityTree) {
disconnect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity);

View file

@ -288,6 +288,14 @@ public slots:
*/
Q_INVOKABLE bool canRezAvatarEntities();
/*@jsdoc
* Checks whether or not the script can view asset URLs
* @function Entities.canViewAssetURLs
* @returns {boolean} <code>true</code> if the domain server will allow the script to view asset URLs,
* otherwise <code>false</code>.
*/
Q_INVOKABLE bool canViewAssetURLs();
/*@jsdoc
* <p>How an entity is hosted and sent to others for display.</p>
* <table>
@ -2249,6 +2257,14 @@ signals:
*/
void canRezAvatarEntitiesChanged(bool canRezAvatarEntities);
/*@jsdoc
* Triggered when your ability to view asset URLs is changed.
* @function Entities.canViewAssetURLsChanged
* @param {boolean} canViewAssetURLs - <code>true</code> if the script can view asset URLs,
* <code>false</code> if it can't.
* @returns {Signal}
*/
void canViewAssetURLsChanged(bool canViewAssetURLs);
/*@jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is on an entity, or a controller trigger is fully

View file

@ -197,6 +197,10 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
newPermissions.can(NodePermissions::Permission::canRezAvatarEntities)) {
emit canRezAvatarEntitiesChanged(_permissions.can(NodePermissions::Permission::canRezAvatarEntities));
}
if (originalPermissions.can(NodePermissions::Permission::canViewAssetURLs) !=
newPermissions.can(NodePermissions::Permission::canViewAssetURLs)) {
emit canViewAssetURLsChanged(_permissions.can(NodePermissions::Permission::canViewAssetURLs));
}
}
void LimitedNodeList::setSocketLocalPort(SocketType socketType, quint16 socketLocalPort) {

View file

@ -132,6 +132,7 @@ public:
bool getThisNodeCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); }
bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
bool getThisNodeCanViewAssetURLs() const { return _permissions.can(NodePermissions::Permission::canViewAssetURLs); }
quint16 getSocketLocalPort(SocketType socketType) const { return _nodeSocket.localPort(socketType); }
Q_INVOKABLE void setSocketLocalPort(SocketType socketType, quint16 socketLocalPort);
@ -392,6 +393,7 @@ signals:
void canReplaceContentChanged(bool canReplaceContent);
void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData);
void canRezAvatarEntitiesChanged(bool canRezAvatarEntities);
void canViewAssetURLsChanged(bool canViewAssetURLs);
protected slots:
void connectedForLocalSocketTest();

View file

@ -84,6 +84,7 @@ public:
bool getCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); }
bool getCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
bool getCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
bool getCanViewAssetURLs() const { return _permissions.can(NodePermissions::Permission::canViewAssetURLs); }
using NodesIgnoredPair = std::pair<std::vector<QUuid>, bool>;

View file

@ -68,6 +68,7 @@ NodePermissions::NodePermissions(QMap<QString, QVariant> perms) {
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;
permissions |= perms["id_can_view_asset_urls"].toBool() ? Permission::canViewAssetURLs : Permission::none;
}
QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) {
@ -95,6 +96,7 @@ QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) {
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);
values["id_can_view_asset_urls"] = can(Permission::canViewAssetURLs);
return QVariant(values);
}
@ -167,6 +169,9 @@ QDebug operator<<(QDebug debug, const NodePermissions& perms) {
if (perms.can(NodePermissions::Permission::canGetAndSetPrivateUserData)) {
debug << " get-and-set-private-user-data";
}
if (perms.can(NodePermissions::Permission::canViewAssetURLs)) {
debug << " can-view-asset-urls";
}
debug.nospace() << "]";
return debug.nospace();
}

View file

@ -79,7 +79,8 @@ public:
canKick = 64,
canReplaceDomainContent = 128,
canGetAndSetPrivateUserData = 1024,
canRezAvatarEntities = 2048
canRezAvatarEntities = 2048,
canViewAssetURLs = 4096
};
Q_DECLARE_FLAGS(Permissions, Permission)
Permissions permissions;