mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-16 22:30:42 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into sessionDisplayNames
This commit is contained in:
commit
60cb7acb50
19 changed files with 331 additions and 22 deletions
|
@ -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 “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>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></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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
QList<NodeType_t> interestList;
|
||||
QString placeName;
|
||||
QString hardwareAddress;
|
||||
QUuid machineFingerprint;
|
||||
|
||||
QByteArray protocolVersion;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue