Merge branch 'master' of https://github.com/highfidelity/hifi into sessionDisplayNames

This commit is contained in:
howard-stearns 2016-12-19 15:28:07 -08:00
commit 60cb7acb50
19 changed files with 331 additions and 22 deletions

View file

@ -845,6 +845,78 @@
}
],
"columns": [
{
"name": "permissions_id",
"label": ""
},
{
"name": "id_can_connect",
"label": "Connect",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_adjust_locks",
"label": "Lock / Unlock",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_rez",
"label": "Rez",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_rez_tmp",
"label": "Rez Temporary",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_write_to_asset_server",
"label": "Write Assets",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_connect_past_max_capacity",
"label": "Ignore Max Capacity",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_kick",
"label": "Kick Users",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
{
"name": "machine_fingerprint_permissions",
"type": "table",
"caption": "Permissions for Users with Machine Fingerprints",
"can_add_new_rows": true,
"groups": [
{
"label": "Machine Fingerprint",
"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 &ldquo;locked&rdquo; 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>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain&rsquo;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></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": 7
}
],
"columns": [
{
"name": "permissions_id",

View file

@ -120,19 +120,21 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
nodeData->setPlaceName(nodeConnection.placeName);
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress;
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
// signal that we just connected a node so the DomainServer can get it a list
// and broadcast its presence right away
emit connectedNode(node);
} else {
qDebug() << "Refusing connection from node at" << message->getSenderSockAddr()
<< "with hardware address" << nodeConnection.hardwareAddress;
<< "with hardware address" << nodeConnection.hardwareAddress
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
}
}
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
const QHostAddress& senderAddress, const QString& hardwareAddress) {
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
const QString& hardwareAddress, const QUuid& machineFingerprint) {
NodePermissions userPerms;
userPerms.setAll(false);
@ -155,6 +157,11 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
#ifdef WANT_DEBUG
qDebug() << "| user-permissions: specific MAC matches, so:" << userPerms;
#endif
} else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) {
userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint);
#ifdef WANT_DEBUG
qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
#endif
} else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) {
// this user comes from an IP we have in our permissions table, apply those permissions
@ -274,13 +281,15 @@ void DomainGatekeeper::updateNodePermissions() {
HifiSockAddr connectingAddr = node->getActiveSocket() ? *node->getActiveSocket() : node->getPublicSocket();
QString hardwareAddress;
QUuid machineFingerprint;
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
if (nodeData) {
hardwareAddress = nodeData->getHardwareAddress();
machineFingerprint = nodeData->getMachineFingerprint();
}
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress);
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress, machineFingerprint);
}
node->setPermissions(userPerms);
@ -334,6 +343,8 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
nodeData->setWalletUUID(it->second.getWalletUUID());
nodeData->setNodeVersion(it->second.getNodeVersion());
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
nodeData->setWasAssigned(true);
// cleanup the PendingAssignedNodeData for this assignment now that it's connecting
@ -396,7 +407,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
}
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, nodeConnection.senderSockAddr.getAddress(),
nodeConnection.hardwareAddress);
nodeConnection.hardwareAddress, nodeConnection.machineFingerprint);
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
@ -455,6 +466,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
// set the hardware address passed in the connect request
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
// set the machine fingerprint passed in the connect request
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
// also add an interpolation to DomainServerNodeData so that servers can get username in stats
nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);

View file

@ -107,8 +107,8 @@ private:
QSet<QString> _domainOwnerFriends; // keep track of friends of the domain owner
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
const QHostAddress& senderAddress, const QString& hardwareAddress);
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
const QString& hardwareAddress, const QUuid& machineFingerprint);
void getGroupMemberships(const QString& username);
// void getIsGroupMember(const QString& username, const QUuid groupID);

View file

@ -532,6 +532,7 @@ void DomainServer::setupNodeListAndAssignments() {
// NodeList won't be available to the settings manager when it is created, so call registerListener here
packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket");
packetReceiver.registerListener(PacketType::NodeKickRequest, &_settingsManager, "processNodeKickRequestPacket");
packetReceiver.registerListener(PacketType::UsernameFromIDRequest, &_settingsManager, "processUsernameFromIDRequestPacket");
// register the gatekeeper for the packets it needs to receive
packetReceiver.registerListener(PacketType::DomainConnectRequest, &_gatekeeper, "processConnectRequestPacket");

View file

@ -56,7 +56,10 @@ public:
void setHardwareAddress(const QString& hardwareAddress) { _hardwareAddress = hardwareAddress; }
const QString& getHardwareAddress() { return _hardwareAddress; }
void setMachineFingerprint(const QUuid& machineFingerprint) { _machineFingerprint = machineFingerprint; }
const QUuid& getMachineFingerprint() { return _machineFingerprint; }
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
void removeOverrideForKey(const QString& key, const QString& value);
@ -85,6 +88,7 @@ private:
NodeSet _nodeInterestSet;
QString _nodeVersion;
QString _hardwareAddress;
QUuid _machineFingerprint;
QString _placeName;

View file

@ -444,6 +444,9 @@ void DomainServerSettingsManager::packPermissions() {
// save settings for MAC addresses
packPermissionsForMap("permissions", _macPermissions, MAC_PERMISSIONS_KEYPATH);
// save settings for Machine Fingerprint
packPermissionsForMap("permissions", _machineFingerprintPermissions, MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH);
// save settings for groups
packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH);
@ -522,6 +525,18 @@ void DomainServerSettingsManager::unpackPermissions() {
}
});
needPack |= unpackPermissionsForKeypath(MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH, &_machineFingerprintPermissions,
[&](NodePermissionsPointer perms){
// make sure that this permission row has valid machine fingerprint
if (QUuid(perms->getKey().first) == QUuid()) {
_machineFingerprintPermissions.remove(perms->getKey());
// we removed a row, so we'll need a re-pack
needPack = true;
}
});
needPack |= unpackPermissionsForKeypath(GROUP_PERMISSIONS_KEYPATH, &_groupPermissions,
[&](NodePermissionsPointer perms){
@ -575,7 +590,9 @@ void DomainServerSettingsManager::unpackPermissions() {
QList<QHash<NodePermissionsKey, NodePermissionsPointer>> permissionsSets;
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get()
<< _groupPermissions.get() << _groupForbiddens.get()
<< _ipPermissions.get() << _macPermissions.get();
<< _ipPermissions.get() << _macPermissions.get()
<< _machineFingerprintPermissions.get();
foreach (auto permissionSet, permissionsSets) {
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(permissionSet);
while (i.hasNext()) {
@ -707,9 +724,10 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
ipPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
// potentially remove connect permissions for the MAC address
// potentially remove connect permissions for the MAC address and machine fingerprint
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
if (nodeData) {
// mac address first
NodePermissionsKey macAddressKey(nodeData->getHardwareAddress(), 0);
bool hadMACPermissions = hasPermissionsForMAC(nodeData->getHardwareAddress());
@ -721,6 +739,18 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
macPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
// now for machine fingerprint
NodePermissionsKey machineFingerprintKey(nodeData->getMachineFingerprint().toString(), 0);
bool hadFingerprintPermissions = hasPermissionsForMachineFingerprint(nodeData->getMachineFingerprint());
auto fingerprintPermissions = _machineFingerprintPermissions[machineFingerprintKey];
if (!hadFingerprintPermissions || fingerprintPermissions->can(NodePermissions::Permission::canConnectToDomain)) {
newPermissions = true;
fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
}
}
@ -748,6 +778,45 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
}
}
// This function processes the "Get Username from ID" request.
void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin)
if (sendingNode->getCanKick()) {
// From the packet, pull the UUID we're identifying
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
if (!nodeUUID.isNull()) {
// First, make sure we actually have a node with this UUID
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
auto matchingNode = limitedNodeList->nodeWithUUID(nodeUUID);
// If we do have a matching node...
if (matchingNode) {
// It's time to figure out the username
QString verifiedUsername = matchingNode->getPermissions().getVerifiedUserName();
// Setup the packet
auto usernameFromIDReplyPacket = NLPacket::create(PacketType::UsernameFromIDReply);
usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
usernameFromIDReplyPacket->writeString(verifiedUsername);
qDebug() << "Sending username" << verifiedUsername << "associated with node" << nodeUUID;
// Ship it!
limitedNodeList->sendPacket(std::move(usernameFromIDReplyPacket), *sendingNode);
} else {
qWarning() << "Node username request received for unknown node. Refusing to process.";
}
} else {
qWarning() << "Node username request received for invalid node ID. Refusing to process.";
}
} else {
qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID())
<< "that does not have kick permissions.";
}
}
QStringList DomainServerSettingsManager::getAllNames() const {
QStringList result;
foreach (auto key, _agentPermissions.keys()) {
@ -795,6 +864,16 @@ NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString&
return nullPermissions;
}
NodePermissions DomainServerSettingsManager::getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const {
NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), 0);
if (_machineFingerprintPermissions.contains(fingerprintKey)) {
return *(_machineFingerprintPermissions[fingerprintKey].get());
}
NodePermissions nullPermissions;
nullPermissions.setAll(false);
return nullPermissions;
}
NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, QUuid rankID) const {
NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID);
if (_groupPermissions.contains(groupRankKey)) {

View file

@ -32,6 +32,7 @@ const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permission
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions";
const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions";
const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
@ -70,6 +71,10 @@ public:
bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); }
NodePermissions getPermissionsForMAC(const QString& macAddress) const;
// these give access to permissions for specific machine fingerprints from the domain-server settings page
bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); }
NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const;
// these give access to permissions for specific groups from the domain-server settings page
bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const {
return _groupPermissions.contains(groupName, rankID);
@ -113,6 +118,7 @@ public slots:
private slots:
void processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message);
void processNodeKickRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
private:
QStringList _argumentList;
@ -151,6 +157,7 @@ private:
NodePermissionsMap _ipPermissions; // permissions granted by node IP address
NodePermissionsMap _macPermissions; // permissions granted by node MAC address
NodePermissionsMap _machineFingerprintPermissions; // permissions granted by Machine Fingerprint
NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups
NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group

View file

@ -32,6 +32,9 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
// read the hardware address sent by the client
dataStream >> newHeader.hardwareAddress;
// now the machine fingerprint
dataStream >> newHeader.machineFingerprint;
}
dataStream >> newHeader.nodeType

View file

@ -29,6 +29,7 @@ public:
QList<NodeType_t> interestList;
QString placeName;
QString hardwareAddress;
QUuid machineFingerprint;
QByteArray protocolVersion;
};

View file

@ -72,6 +72,24 @@ Rectangle {
table.selection.deselect(userIndex);
}
break;
// Received an "updateUsername()" request from the JS
case 'updateUsername':
// The User ID (UUID) is the first parameter in the message.
var userId = message.params[0];
// The text that goes in the userName field is the second parameter in the message.
var userName = message.params[1];
// If the userId is empty, we're updating "myData".
if (!userId) {
myData.userName = userName;
myCard.userName = userName; // Defensive programming
} else {
// Get the index in userModel and userData associated with the passed UUID
var userIndex = findSessionIndex(userId);
// Set the userName appropriately
userModel.get(userIndex).userName = userName;
userData[userIndex].userName = userName; // Defensive programming
}
break;
default:
console.log('Unrecognized message:', JSON.stringify(message));
}

View file

@ -17,6 +17,7 @@ find_package(TBB REQUIRED)
if (APPLE)
find_library(FRAMEWORK_IOKIT IOKit)
find_library(CORE_FOUNDATION CoreFoundation)
endif ()
if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
@ -32,7 +33,7 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES})
# IOKit is needed for getting machine fingerprint
if (APPLE)
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT})
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION})
endif (APPLE)
# libcrypto uses dlopen in libdl

View file

@ -10,8 +10,13 @@
//
#include "FingerprintUtils.h"
#include <QDebug>
#include <SettingHandle.h>
#include <SettingManager.h>
#include <DependencyManager.h>
#ifdef Q_OS_WIN
#include <comdef.h>
#include <Wbemidl.h>
@ -44,7 +49,15 @@ QString FingerprintUtils::getMachineFingerprintString() {
HRESULT hres;
IWbemLocator *pLoc = NULL;
// initialize com
// initialize com. Interface already does, but other
// users of this lib don't necessarily do so.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) {
qDebug() << "Failed to initialize COM library!";
return uuidString;
}
// initialize WbemLocator
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
@ -164,6 +177,11 @@ QUuid FingerprintUtils::getMachineFingerprint() {
// any errors in getting the string
QUuid uuid(uuidString);
if (uuid == QUuid()) {
// if you cannot read a fallback key cuz we aren't saving them, just generate one for
// this session and move on
if (DependencyManager::get<Setting::Manager>().isNull()) {
return QUuid::createUuid();
}
// read fallback key (if any)
Settings settings;
uuid = QUuid(settings.value(FALLBACK_FINGERPRINT_KEY).toString());

View file

@ -27,6 +27,7 @@
#include "AddressManager.h"
#include "Assignment.h"
#include "HifiSockAddr.h"
#include "FingerprintUtils.h"
#include "NetworkLogging.h"
#include "udt/PacketHeaders.h"
@ -127,6 +128,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
packetReceiver.registerListener(PacketType::DomainServerPathResponse, this, "processDomainServerPathResponse");
packetReceiver.registerListener(PacketType::DomainServerRemovedNode, this, "processDomainServerRemovedNode");
packetReceiver.registerListener(PacketType::UsernameFromIDReply, this, "processUsernameFromIDReply");
}
qint64 NodeList::sendStats(QJsonObject statsObject, HifiSockAddr destination) {
@ -370,6 +372,10 @@ void NodeList::sendDomainServerCheckIn() {
}
packetStream << hardwareAddress;
// add in machine fingerprint
QUuid machineFingerprint = FingerprintUtils::getMachineFingerprint();
packetStream << machineFingerprint;
}
// pack our data to send to the domain-server including
@ -889,3 +895,36 @@ void NodeList::muteNodeBySessionID(const QUuid& nodeID) {
}
}
void NodeList::requestUsernameFromSessionID(const QUuid& nodeID) {
// send a request to domain-server to get the username associated with the given session ID
if (getThisNodeCanKick() || nodeID.isNull()) {
// setup the packet
auto usernameFromIDRequestPacket = NLPacket::create(PacketType::UsernameFromIDRequest, NUM_BYTES_RFC4122_UUID, true);
// write the node ID to the packet
if (nodeID.isNull()) {
usernameFromIDRequestPacket->write(getSessionUUID().toRfc4122());
} else {
usernameFromIDRequestPacket->write(nodeID.toRfc4122());
}
qDebug() << "Sending packet to get username of node" << uuidStringWithoutCurlyBraces(nodeID);
sendPacket(std::move(usernameFromIDRequestPacket), _domainHandler.getSockAddr());
} else {
qWarning() << "You do not have permissions to kick in this domain."
<< "Request to get the username of node" << uuidStringWithoutCurlyBraces(nodeID) << "will not be sent";
}
}
void NodeList::processUsernameFromIDReply(QSharedPointer<ReceivedMessage> message) {
// read the UUID from the packet
QString nodeUUIDString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
// read the username from the packet
QString username = message->readString();
qDebug() << "Got username" << username << "for node" << nodeUUIDString;
emit usernameFromIDReply(nodeUUIDString, username);
}

View file

@ -81,6 +81,7 @@ public:
void kickNodeBySessionID(const QUuid& nodeID);
void muteNodeBySessionID(const QUuid& nodeID);
void requestUsernameFromSessionID(const QUuid& nodeID);
public slots:
void reset();
@ -99,6 +100,8 @@ public slots:
void processICEPingPacket(QSharedPointer<ReceivedMessage> message);
void processUsernameFromIDReply(QSharedPointer<ReceivedMessage> message);
#if (PR_BUILD || DEV_BUILD)
void toggleSendNewerDSConnectVersion(bool shouldSendNewerVersion) { _shouldSendNewerVersion = shouldSendNewerVersion; }
#endif
@ -108,6 +111,7 @@ signals:
void receivedDomainServerList();
void ignoredNode(const QUuid& nodeID);
void ignoreRadiusEnabledChanged(bool isIgnored);
void usernameFromIDReply(const QString& nodeID, const QString& username);
private slots:
void stopKeepalivePingTimer();

View file

@ -26,8 +26,8 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
<< PacketType::NodeJsonStats << PacketType::EntityQuery
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
<< PacketType::DomainListRequest << PacketType::StopNode
<< PacketType::DomainDisconnectRequest << PacketType::NodeKickRequest
<< PacketType::NodeMuteRequest;
<< PacketType::DomainDisconnectRequest << PacketType::UsernameFromIDRequest
<< PacketType::NodeKickRequest << PacketType::NodeMuteRequest;
const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
<< PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment
@ -39,12 +39,12 @@ const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
<< PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat
<< PacketType::ICEServerHeartbeatACK << PacketType::ICEPing << PacketType::ICEPingReply
<< PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode
<< PacketType::DomainServerRemovedNode;
<< PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply;
PacketVersion versionForPacketType(PacketType packetType) {
switch (packetType) {
case PacketType::DomainList:
return static_cast<PacketVersion>(DomainListVersion::PermissionsGrid);
return static_cast<PacketVersion>(DomainListVersion::GetUsernameFromUUIDSupport);
case PacketType::EntityAdd:
case PacketType::EntityEdit:
case PacketType::EntityData:
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
return static_cast<PacketVersion>(DomainConnectionDeniedVersion::IncludesExtraInfo);
case PacketType::DomainConnectRequest:
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasMACAddress);
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasMachineFingerprint);
case PacketType::DomainServerAddedNode:
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);

View file

@ -101,7 +101,9 @@ public:
NodeKickRequest,
NodeMuteRequest,
RadiusIgnoreRequest,
LAST_PACKET_TYPE = RadiusIgnoreRequest
UsernameFromIDRequest,
UsernameFromIDReply,
LAST_PACKET_TYPE = UsernameFromIDReply
};
};
@ -211,7 +213,8 @@ enum class DomainConnectRequestVersion : PacketVersion {
NoHostname = 17,
HasHostname,
HasProtocolVersions,
HasMACAddress
HasMACAddress,
HasMachineFingerprint
};
enum class DomainConnectionDeniedVersion : PacketVersion {
@ -227,7 +230,8 @@ enum class DomainServerAddedNodeVersion : PacketVersion {
enum class DomainListVersion : PacketVersion {
PrePermissionsGrid = 18,
PermissionsGrid
PermissionsGrid,
GetUsernameFromUUIDSupport
};
enum class AudioVersion : PacketVersion {

View file

@ -18,6 +18,7 @@ UsersScriptingInterface::UsersScriptingInterface() {
auto nodeList = DependencyManager::get<NodeList>();
connect(nodeList.data(), &LimitedNodeList::canKickChanged, this, &UsersScriptingInterface::canKickChanged);
connect(nodeList.data(), &NodeList::ignoreRadiusEnabledChanged, this, &UsersScriptingInterface::ignoreRadiusEnabledChanged);
connect(nodeList.data(), &NodeList::usernameFromIDReply, this, &UsersScriptingInterface::usernameFromIDReply);
}
void UsersScriptingInterface::ignore(const QUuid& nodeID) {
@ -35,6 +36,11 @@ void UsersScriptingInterface::mute(const QUuid& nodeID) {
DependencyManager::get<NodeList>()->muteNodeBySessionID(nodeID);
}
void UsersScriptingInterface::requestUsernameFromID(const QUuid& nodeID) {
// ask the Domain Server via the NodeList for the username associated with the given session ID
DependencyManager::get<NodeList>()->requestUsernameFromSessionID(nodeID);
}
bool UsersScriptingInterface::getCanKick() {
// ask the NodeList to return our ability to kick
return DependencyManager::get<NodeList>()->getThisNodeCanKick();

View file

@ -51,6 +51,13 @@ public slots:
*/
void mute(const QUuid& nodeID);
/**jsdoc
* Returns a string containing the username associated with the given Avatar UUID
* @function Users.getUsernameFromID
* @param {nodeID} nodeID The node or session ID of the user whose username you want.
*/
void requestUsernameFromID(const QUuid& nodeID);
/**jsdoc
* Returns `true` if the DomainServer will allow this Node/Avatar to make kick
* @function Users.getCanKick
@ -92,6 +99,12 @@ signals:
* @function Users.enteredIgnoreRadius
*/
void enteredIgnoreRadius();
/**jsdoc
* Notifies scripts of the username associated with a UUID.
* @function Users.enteredIgnoreRadius
*/
void usernameFromIDReply(const QString& nodeID, const QString& username);
};

View file

@ -118,9 +118,15 @@ function populateUserList() {
var avatar = AvatarList.getAvatar(id);
var avatarPalDatum = {
displayName: avatar.sessionDisplayName,
userName: "fakeAcct" + (id || "Me"),
userName: '',
sessionId: id || ''
};
// If the current user is an admin OR
// they're requesting their own username ("id" is blank)...
if (Users.canKick || !id) {
// Request the username from the given UUID
Users.requestUsernameFromID(id);
}
data.push(avatarPalDatum);
if (id) { // No overlay for ourself.
addAvatarNode(id);
@ -129,6 +135,23 @@ function populateUserList() {
});
pal.sendToQml({method: 'users', params: data});
}
// The function that handles the reply from the server
function usernameFromIDReply(id, username) {
var data;
// If the ID we've received is our ID...
if (AvatarList.getAvatar('').sessionUUID === id) {
// Set the data to contain specific strings.
data = ['', username + ' (hidden)']
} else {
// Set the data to contain the ID and the username+ID concat string.
data = [id, username + '/' + id];
}
print('Username Data:', JSON.stringify(data));
// Ship the data off to QML
pal.sendToQml({ method: 'updateUsername', params: data });
}
var pingPong = true;
function updateOverlays() {
var eye = Camera.position;
@ -249,6 +272,7 @@ function onVisibileChanged() {
button.clicked.connect(onClicked);
pal.visibleChanged.connect(onVisibileChanged);
pal.closed.connect(off);
Users.usernameFromIDReply.connect(usernameFromIDReply);
//
// Cleanup.
@ -258,6 +282,7 @@ Script.scriptEnding.connect(function () {
toolBar.removeButton(buttonName);
pal.visibleChanged.disconnect(onVisibileChanged);
pal.closed.disconnect(off);
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
off();
});