First checkpoint

This commit is contained in:
Zach Fox 2017-01-17 14:16:31 -08:00
parent d60d183c8c
commit 346cfbfe02
7 changed files with 113 additions and 50 deletions

View file

@ -782,21 +782,24 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) { void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// From the packet, pull the UUID we're identifying // From the packet, pull the UUID we're identifying
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
if (!nodeUUID.isNull()) {
// Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin)
// OR from a node whose UUID matches the one in the packet
if (sendingNode->getCanKick() || nodeUUID == sendingNode->getUUID()) {
// 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 (!nodeUUID.isNull()) {
if (matchingNode) { // 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) {
// Setup the packet
auto usernameFromIDReplyPacket = NLPacket::create(PacketType::UsernameFromIDReply);
bool isAdmin = matchingNode->getCanKick();
// Check if the sending node has permission to kick (is an admin)
if (sendingNode->getCanKick()) {
// It's time to figure out the username // It's time to figure out the username
QString verifiedUsername = matchingNode->getPermissions().getVerifiedUserName(); QString verifiedUsername = matchingNode->getPermissions().getVerifiedUserName();
// Setup the packet
auto usernameFromIDReplyPacket = NLPacket::create(PacketType::UsernameFromIDReply);
usernameFromIDReplyPacket->write(nodeUUID.toRfc4122()); usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
usernameFromIDReplyPacket->writeString(verifiedUsername); usernameFromIDReplyPacket->writeString(verifiedUsername);
@ -804,19 +807,20 @@ void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPoin
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData()); DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
QUuid machineFingerprint = nodeData ? nodeData->getMachineFingerprint() : QUuid(); QUuid machineFingerprint = nodeData ? nodeData->getMachineFingerprint() : QUuid();
usernameFromIDReplyPacket->write(machineFingerprint.toRfc4122()); usernameFromIDReplyPacket->write(machineFingerprint.toRfc4122());
qDebug() << "Sending username" << verifiedUsername << "and machine fingerprint" << machineFingerprint << "associated with node" << nodeUUID << ". Node admin status: " << isAdmin;
qDebug() << "Sending username" << verifiedUsername << "and machine fingerprint" << machineFingerprint << "associated with node" << nodeUUID;
// Ship it!
limitedNodeList->sendPacket(std::move(usernameFromIDReplyPacket), *sendingNode);
} else { } else {
qWarning() << "Node username request received for unknown node. Refusing to process."; usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
usernameFromIDReplyPacket->writeString("");
usernameFromIDReplyPacket->writeString("");
} }
// Write whether or not the user is an admin
usernameFromIDReplyPacket->writePrimitive(isAdmin);
// Ship it!
limitedNodeList->sendPacket(std::move(usernameFromIDReplyPacket), *sendingNode);
} else { } else {
qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()) qWarning() << "Node username request received for unknown node. Refusing to process.";
<< ". Either node doesn't have kick permissions or is requesting a username not from their UUID.";
} }
} else { } else {
qWarning() << "Node username request received for invalid node ID. Refusing to process."; qWarning() << "Node username request received for invalid node ID. Refusing to process.";
} }

View file

@ -33,6 +33,7 @@ Item {
property real audioLevel: 0.0 property real audioLevel: 0.0
property bool isMyCard: false property bool isMyCard: false
property bool selected: false property bool selected: false
property bool isAdmin: false
/* User image commented out for now - will probably be re-introduced later. /* User image commented out for now - will probably be re-introduced later.
Column { Column {
@ -139,32 +140,84 @@ Item {
} }
} }
// Spacer for DisplayName for my card // Spacer for DisplayName for my card
Rectangle { Item {
id: myDisplayNameSpacer id: myDisplayNameSpacer
width: myDisplayName.width width: 1
height: 4
// Anchors // Anchors
anchors.top: myDisplayName.bottom anchors.top: myDisplayName.bottom
height: 5
visible: isMyCard
opacity: 0
} }
// DisplayName Text for others' cards // DisplayName container for others' cards
FiraSansSemiBold { Item {
id: displayNameText id: displayNameContainer
// Properties
text: thisNameCard.displayName
elide: Text.ElideRight
visible: !isMyCard visible: !isMyCard
// Size // Size
width: parent.width width: parent.width
height: displayNameTextPixelSize + 4
// Anchors // Anchors
anchors.top: parent.top anchors.top: parent.top
// Text Size anchors.left: parent.left
size: displayNameTextPixelSize // DisplayName Text for others' cards
// Text Positioning FiraSansSemiBold {
verticalAlignment: Text.AlignVCenter id: displayNameText
// Style // Properties
color: hifi.colors.darkGray text: thisNameCard.displayName
elide: Text.ElideRight
// Anchors
anchors.top: parent.top
anchors.left: parent.left
// Text Size
size: displayNameTextPixelSize
// Text Positioning
verticalAlignment: Text.AlignVCenter
// Style
color: hifi.colors.darkGray
}
// "ADMIN" label for other users' cards
RalewaySemiBold {
id: adminLabelText
text: "ADMIN"
// Text size
size: displayNameText.size - 4
// Anchors
anchors.verticalCenter: parent.verticalCenter
anchors.left: displayNameText.right
anchors.leftMargin: 8
// Style
font.capitalization: Font.AllUppercase
color: hifi.colors.redHighlight
// Alignment
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
}
// This Rectangle refers to the [?] popup button next to "ADMIN"
Item {
// Size
width: 20
height: displayNameText.height
// Anchors
anchors.verticalCenter: parent.verticalCenter
anchors.left: adminLabelText.right
RalewayRegular {
id: adminLabelQuestionMark
text: "[?]"
size: adminLabelText.size
font.capitalization: Font.AllUppercase
color: hifi.colors.redHighlight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: letterbox('Silencing a user mutes their microphone. Silenced users can unmute themselves by clicking the "UNMUTE" button on their HUD.\n\n' +
"Banning a user will remove them from this domain and prevent them from returning. You can un-ban users from your domain's settings page.)")
onEntered: adminLabelQuestionMark.color = "#94132e"
onExited: adminLabelQuestionMark.color = hifi.colors.redHighlight
}
}
} }
// UserName Text // UserName Text
@ -177,7 +230,7 @@ Item {
// Size // Size
width: parent.width width: parent.width
// Anchors // Anchors
anchors.top: isMyCard ? myDisplayNameSpacer.bottom : displayNameText.bottom anchors.top: isMyCard ? myDisplayNameSpacer.bottom : displayNameContainer.bottom
// Text Size // Text Size
size: thisNameCard.usernameTextHeight size: thisNameCard.usernameTextHeight
// Text Positioning // Text Positioning
@ -188,7 +241,7 @@ Item {
// Spacer // Spacer
Item { Item {
id: spacer id: userNameSpacer
height: 4 height: 4
width: parent.width width: parent.width
// Anchors // Anchors
@ -202,7 +255,7 @@ Item {
width: isMyCard ? myDisplayName.width - 20 : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width width: isMyCard ? myDisplayName.width - 20 : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width
height: 8 height: 8
// Anchors // Anchors
anchors.top: spacer.bottom anchors.top: userNameSpacer.bottom
// Style // Style
radius: 4 radius: 4
color: "#c5c5c5" color: "#c5c5c5"

View file

@ -221,6 +221,7 @@ Rectangle {
visible: !isCheckBox && !isButton visible: !isCheckBox && !isButton
uuid: model && model.sessionId uuid: model && model.sessionId
selected: styleData.selected selected: styleData.selected
isAdmin: model && model.isAdmin
// Size // Size
width: nameCardWidth width: nameCardWidth
height: parent.height height: parent.height
@ -465,6 +466,7 @@ Rectangle {
var userId = message.params[0]; var userId = message.params[0];
// The text that goes in the userName field is the second parameter in the message. // The text that goes in the userName field is the second parameter in the message.
var userName = message.params[1]; var userName = message.params[1];
var isAdmin = message.params[2];
// If the userId is empty, we're updating "myData". // If the userId is empty, we're updating "myData".
if (!userId) { if (!userId) {
myData.userName = userName; myData.userName = userName;
@ -476,6 +478,9 @@ Rectangle {
// Set the userName appropriately // Set the userName appropriately
userModel.setProperty(userIndex, "userName", userName); userModel.setProperty(userIndex, "userName", userName);
userModelData[userIndex].userName = userName; // Defensive programming userModelData[userIndex].userName = userName; // Defensive programming
// Set the admin status appropriately
userModel.setProperty(userIndex, "isAdmin", isAdmin);
userModelData[userIndex].isAdmin = isAdmin; // Defensive programming
} else { } else {
console.log("updateUsername() called with unknown UUID: ", userId); console.log("updateUsername() called with unknown UUID: ", userId);
} }

View file

@ -1068,10 +1068,12 @@ void NodeList::processUsernameFromIDReply(QSharedPointer<ReceivedMessage> messag
QString username = message->readString(); QString username = message->readString();
// read the machine fingerprint from the packet // read the machine fingerprint from the packet
QString machineFingerprintString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString(); QString machineFingerprintString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
bool isAdmin;
message->readPrimitive(&isAdmin);
qCDebug(networking) << "Got username" << username << "and machine fingerprint" << machineFingerprintString << "for node" << nodeUUIDString; qCDebug(networking) << "Got username" << username << "and machine fingerprint" << machineFingerprintString << "for node" << nodeUUIDString;
emit usernameFromIDReply(nodeUUIDString, username, machineFingerprintString); emit usernameFromIDReply(nodeUUIDString, username, machineFingerprintString, isAdmin);
} }
void NodeList::setRequestsDomainListData(bool isRequesting) { void NodeList::setRequestsDomainListData(bool isRequesting) {

View file

@ -120,7 +120,7 @@ signals:
void receivedDomainServerList(); void receivedDomainServerList();
void ignoredNode(const QUuid& nodeID, bool enabled); void ignoredNode(const QUuid& nodeID, bool enabled);
void ignoreRadiusEnabledChanged(bool isIgnored); void ignoreRadiusEnabledChanged(bool isIgnored);
void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint); void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint, bool isAdmin);
private slots: private slots:
void stopKeepalivePingTimer(); void stopKeepalivePingTimer();

View file

@ -135,9 +135,10 @@ signals:
/**jsdoc /**jsdoc
* Notifies scripts of the username and machine fingerprint associated with a UUID. * Notifies scripts of the username and machine fingerprint associated with a UUID.
* Username and machineFingerprint will be empty strings if the requesting user isn't an admin.
* @function Users.usernameFromIDReply * @function Users.usernameFromIDReply
*/ */
void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint); void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint, bool isAdmin);
/**jsdoc /**jsdoc
* Notifies scripts that a user has disconnected from the domain * Notifies scripts that a user has disconnected from the domain

View file

@ -269,12 +269,9 @@ function populateUserList() {
sessionId: id || '', sessionId: id || '',
audioLevel: 0.0 audioLevel: 0.0
}; };
// If the current user is an admin OR // Request the username, fingerprint, and admin status from the given UUID
// they're requesting their own username ("id" is blank)... // Username and fingerprint returns "" if the requesting user isn't an admin
if (Users.canKick || !id) { Users.requestUsernameFromID(id);
// Request the username from the given UUID
Users.requestUsernameFromID(id);
}
// Request personal mute status and ignore status // Request personal mute status and ignore status
// from NodeList (as long as we're not requesting it for our own ID) // from NodeList (as long as we're not requesting it for our own ID)
if (id) { if (id) {
@ -289,7 +286,7 @@ function populateUserList() {
} }
// The function that handles the reply from the server // The function that handles the reply from the server
function usernameFromIDReply(id, username, machineFingerprint) { function usernameFromIDReply(id, username, machineFingerprint, isAdmin) {
var data; var data;
// If the ID we've received is our ID... // If the ID we've received is our ID...
if (MyAvatar.sessionUUID === id) { if (MyAvatar.sessionUUID === id) {
@ -300,6 +297,7 @@ function usernameFromIDReply(id, username, machineFingerprint) {
// or fingerprint (if we don't have a username) string. // or fingerprint (if we don't have a username) string.
data = [id, username || machineFingerprint]; data = [id, username || machineFingerprint];
} }
data.push(isAdmin);
print('Username Data:', JSON.stringify(data)); print('Username Data:', JSON.stringify(data));
// Ship the data off to QML // Ship the data off to QML
pal.sendToQml({ method: 'updateUsername', params: data }); pal.sendToQml({ method: 'updateUsername', params: data });