mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 05:03:31 +02:00
Add improved functionality for Users.kick
API.
Add banByUsername, banByFingerprint, and banByIP parameters.
This commit is contained in:
parent
bab76f777d
commit
78cc98bc7b
7 changed files with 90 additions and 50 deletions
|
@ -863,6 +863,18 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
|
||||||
// pull the UUID being kicked from the packet
|
// pull the UUID being kicked from the packet
|
||||||
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
|
bool hasOptionalBanParameters = false;
|
||||||
|
bool banByUsername = false;
|
||||||
|
bool banByFingerprint = false;
|
||||||
|
bool banByIP = false;
|
||||||
|
// pull optional ban parameters from the packet
|
||||||
|
if (message.data()->getSize() > NUM_BYTES_RFC4122_UUID) {
|
||||||
|
hasOptionalBanParameters = true;
|
||||||
|
message->readPrimitive(&banByUsername);
|
||||||
|
message->readPrimitive(&banByFingerprint);
|
||||||
|
message->readPrimitive(&banByIP);
|
||||||
|
}
|
||||||
|
|
||||||
if (!nodeUUID.isNull() && nodeUUID != sendingNode->getUUID()) {
|
if (!nodeUUID.isNull() && nodeUUID != sendingNode->getUUID()) {
|
||||||
// make sure we actually have a node with this UUID
|
// make sure we actually have a node with this UUID
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
@ -881,24 +893,40 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
|
||||||
if (!verifiedUsername.isEmpty()) {
|
if (!verifiedUsername.isEmpty()) {
|
||||||
// if we have a verified user name for this user, we first apply the kick to the username
|
// if we have a verified user name for this user, we first apply the kick to the username
|
||||||
|
|
||||||
// check if there were already permissions
|
// if we have optional ban parameters, we should ban the username based on the parameter
|
||||||
bool hadPermissions = havePermissionsForName(verifiedUsername);
|
if (hasOptionalBanParameters) {
|
||||||
|
if (banByUsername) {
|
||||||
// grab or create permissions for the given username
|
// check if there were already permissions
|
||||||
auto userPermissions = _agentPermissions[matchingNode->getPermissions().getKey()];
|
bool hadPermissions = havePermissionsForName(verifiedUsername);
|
||||||
|
|
||||||
newPermissions = !hadPermissions || userPermissions->can(NodePermissions::Permission::canConnectToDomain);
|
// grab or create permissions for the given username
|
||||||
|
auto userPermissions = _agentPermissions[matchingNode->getPermissions().getKey()];
|
||||||
// ensure that the connect permission is clear
|
|
||||||
userPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
newPermissions = !hadPermissions || userPermissions->can(NodePermissions::Permission::canConnectToDomain);
|
||||||
|
|
||||||
|
// ensure that the connect permission is clear
|
||||||
|
userPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// check if there were already permissions
|
||||||
|
bool hadPermissions = havePermissionsForName(verifiedUsername);
|
||||||
|
|
||||||
|
// grab or create permissions for the given username
|
||||||
|
auto userPermissions = _agentPermissions[matchingNode->getPermissions().getKey()];
|
||||||
|
|
||||||
|
newPermissions = !hadPermissions || userPermissions->can(NodePermissions::Permission::canConnectToDomain);
|
||||||
|
|
||||||
|
// ensure that the connect permission is clear
|
||||||
|
userPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we didn't have a username, or this domain-server uses the "multi-kick" setting to
|
// if we didn't have a username, or this domain-server uses the "multi-kick" setting to
|
||||||
// kick logged in users via username AND machine fingerprint (or IP as fallback)
|
// kick logged in users via username AND machine fingerprint (or IP as fallback)
|
||||||
// then we remove connect permissions for the machine fingerprint (or IP as fallback)
|
// then we remove connect permissions for the machine fingerprint (or IP as fallback)
|
||||||
const QString MULTI_KICK_SETTINGS_KEYPATH = "security.multi_kick_logged_in";
|
const QString MULTI_KICK_SETTINGS_KEYPATH = "security.multi_kick_logged_in";
|
||||||
|
qDebug() << "verifiedUsername.isEmpty()" << verifiedUsername.isEmpty();
|
||||||
if (verifiedUsername.isEmpty() || valueOrDefaultValueForKeyPath(MULTI_KICK_SETTINGS_KEYPATH).toBool()) {
|
if (banByFingerprint || verifiedUsername.isEmpty() || valueOrDefaultValueForKeyPath(MULTI_KICK_SETTINGS_KEYPATH).toBool()) {
|
||||||
// remove connect permissions for the machine fingerprint
|
// remove connect permissions for the machine fingerprint
|
||||||
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
|
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
|
@ -923,36 +951,39 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
|
||||||
fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if no node data, all we can do is IP address
|
// if no node data, all we can do is ban by IP address
|
||||||
auto& kickAddress = matchingNode->getActiveSocket()
|
banByIP = true;
|
||||||
? matchingNode->getActiveSocket()->getAddress()
|
}
|
||||||
: matchingNode->getPublicSocket().getAddress();
|
}
|
||||||
|
|
||||||
|
if (banByIP) {
|
||||||
|
auto& kickAddress = matchingNode->getActiveSocket()
|
||||||
|
? matchingNode->getActiveSocket()->getAddress()
|
||||||
|
: matchingNode->getPublicSocket().getAddress();
|
||||||
|
|
||||||
// probably isLoopback covers it, as whenever I try to ban an agent on same machine as the domain-server
|
// probably isLoopback covers it, as whenever I try to ban an agent on same machine as the domain-server
|
||||||
// it is always 127.0.0.1, but looking at the public and local addresses just to be sure
|
// it is always 127.0.0.1, but looking at the public and local addresses just to be sure
|
||||||
// TODO: soon we will have feedback (in the form of a message to the client) after we kick. When we
|
// TODO: soon we will have feedback (in the form of a message to the client) after we kick. When we
|
||||||
// do, we will have a success flag, and perhaps a reason for failure. For now, just don't do it.
|
// do, we will have a success flag, and perhaps a reason for failure. For now, just don't do it.
|
||||||
if (kickAddress == limitedNodeList->getPublicSockAddr().getAddress() ||
|
if (kickAddress == limitedNodeList->getPublicSockAddr().getAddress() ||
|
||||||
kickAddress == limitedNodeList->getLocalSockAddr().getAddress() ||
|
kickAddress == limitedNodeList->getLocalSockAddr().getAddress() ||
|
||||||
kickAddress.isLoopback() ) {
|
kickAddress.isLoopback() ) {
|
||||||
qWarning() << "attempt to kick node running on same machine as domain server, ignoring KickRequest";
|
qWarning() << "attempt to kick node running on same machine as domain server, ignoring KickRequest";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodePermissionsKey ipAddressKey(kickAddress.toString(), QUuid());
|
||||||
|
|
||||||
NodePermissionsKey ipAddressKey(kickAddress.toString(), QUuid());
|
// check if there were already permissions for the IP
|
||||||
|
bool hadIPPermissions = hasPermissionsForIP(kickAddress);
|
||||||
|
|
||||||
// check if there were already permissions for the IP
|
// grab or create permissions for the given IP address
|
||||||
bool hadIPPermissions = hasPermissionsForIP(kickAddress);
|
auto ipPermissions = _ipPermissions[ipAddressKey];
|
||||||
|
|
||||||
// grab or create permissions for the given IP address
|
if (!hadIPPermissions || ipPermissions->can(NodePermissions::Permission::canConnectToDomain)) {
|
||||||
auto ipPermissions = _ipPermissions[ipAddressKey];
|
newPermissions = true;
|
||||||
|
|
||||||
if (!hadIPPermissions || ipPermissions->can(NodePermissions::Permission::canConnectToDomain)) {
|
ipPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||||
newPermissions = true;
|
|
||||||
|
|
||||||
ipPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2493,7 +2493,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
return viewFrustum.getPosition();
|
return viewFrustum.getPosition();
|
||||||
});
|
});
|
||||||
|
|
||||||
DependencyManager::get<UsersScriptingInterface>()->setKickConfirmationOperator([this] (const QUuid& nodeID) { userKickConfirmation(nodeID); });
|
DependencyManager::get<UsersScriptingInterface>()->setKickConfirmationOperator([this] (const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP) { userKickConfirmation(nodeID, banByUsername, banByFingerprint, banByIP); });
|
||||||
|
|
||||||
render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([=](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
|
render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([=](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
|
||||||
bool isTablet = url == TabletScriptingInterface::QML;
|
bool isTablet = url == TabletScriptingInterface::QML;
|
||||||
|
@ -3575,7 +3575,7 @@ void Application::onDesktopRootItemCreated(QQuickItem* rootItem) {
|
||||||
_desktopRootItemCreated = true;
|
_desktopRootItemCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::userKickConfirmation(const QUuid& nodeID) {
|
void Application::userKickConfirmation(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP) {
|
||||||
auto avatarHashMap = DependencyManager::get<AvatarHashMap>();
|
auto avatarHashMap = DependencyManager::get<AvatarHashMap>();
|
||||||
auto avatar = avatarHashMap->getAvatarBySessionID(nodeID);
|
auto avatar = avatarHashMap->getAvatarBySessionID(nodeID);
|
||||||
|
|
||||||
|
@ -3600,7 +3600,7 @@ void Application::userKickConfirmation(const QUuid& nodeID) {
|
||||||
// ask the NodeList to kick the user with the given session ID
|
// ask the NodeList to kick the user with the given session ID
|
||||||
|
|
||||||
if (yes) {
|
if (yes) {
|
||||||
DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID);
|
DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID, banByUsername, banByFingerprint, banByIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
DependencyManager::get<UsersScriptingInterface>()->setWaitForKickResponse(false);
|
DependencyManager::get<UsersScriptingInterface>()->setWaitForKickResponse(false);
|
||||||
|
|
|
@ -608,7 +608,7 @@ private:
|
||||||
void toggleTabletUI(bool shouldOpen = false) const;
|
void toggleTabletUI(bool shouldOpen = false) const;
|
||||||
bool shouldCaptureMouse() const;
|
bool shouldCaptureMouse() const;
|
||||||
|
|
||||||
void userKickConfirmation(const QUuid& nodeID);
|
void userKickConfirmation(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP);
|
||||||
|
|
||||||
MainWindow* _window;
|
MainWindow* _window;
|
||||||
QElapsedTimer& _sessionRunTimer;
|
QElapsedTimer& _sessionRunTimer;
|
||||||
|
|
|
@ -1263,17 +1263,21 @@ float NodeList::getInjectorGain() {
|
||||||
return _injectorGain;
|
return _injectorGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::kickNodeBySessionID(const QUuid& nodeID) {
|
void NodeList::kickNodeBySessionID(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP) {
|
||||||
// send a request to domain-server to kick the node with the given session ID
|
// send a request to domain-server to kick the node with the given session ID
|
||||||
// the domain-server will handle the persistence of the kick (via username or IP)
|
// the domain-server will handle the persistence of the kick (via username or IP)
|
||||||
|
|
||||||
if (!nodeID.isNull() && getSessionUUID() != nodeID ) {
|
if (!nodeID.isNull() && getSessionUUID() != nodeID ) {
|
||||||
if (getThisNodeCanKick()) {
|
if (getThisNodeCanKick()) {
|
||||||
// setup the packet
|
// setup the packet
|
||||||
auto kickPacket = NLPacket::create(PacketType::NodeKickRequest, NUM_BYTES_RFC4122_UUID, true);
|
auto kickPacket = NLPacket::create(PacketType::NodeKickRequest, NUM_BYTES_RFC4122_UUID + (sizeof(bool) * 3), true);
|
||||||
|
|
||||||
// write the node ID to the packet
|
// write the node ID to the packet
|
||||||
kickPacket->write(nodeID.toRfc4122());
|
kickPacket->write(nodeID.toRfc4122());
|
||||||
|
// write the ban parameters to the packet
|
||||||
|
kickPacket->writePrimitive(banByUsername);
|
||||||
|
kickPacket->writePrimitive(banByFingerprint);
|
||||||
|
kickPacket->writePrimitive(banByIP);
|
||||||
|
|
||||||
qCDebug(networking) << "Sending packet to kick node" << uuidStringWithoutCurlyBraces(nodeID);
|
qCDebug(networking) << "Sending packet to kick node" << uuidStringWithoutCurlyBraces(nodeID);
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ public:
|
||||||
void setInjectorGain(float gain);
|
void setInjectorGain(float gain);
|
||||||
float getInjectorGain();
|
float getInjectorGain();
|
||||||
|
|
||||||
void kickNodeBySessionID(const QUuid& nodeID);
|
void kickNodeBySessionID(const QUuid& nodeID, bool banByUsername = true, bool banByFingerprint = true, bool banByIP = false);
|
||||||
void muteNodeBySessionID(const QUuid& nodeID);
|
void muteNodeBySessionID(const QUuid& nodeID);
|
||||||
void requestUsernameFromSessionID(const QUuid& nodeID);
|
void requestUsernameFromSessionID(const QUuid& nodeID);
|
||||||
bool getRequestsDomainListData() { return _requestsDomainListData; }
|
bool getRequestsDomainListData() { return _requestsDomainListData; }
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 2016-07-11.
|
// Created by Stephen Birarda on 2016-07-11.
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
// Copyright 2021 Vircadia contributors.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -51,15 +52,15 @@ float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) {
|
||||||
return DependencyManager::get<NodeList>()->getAvatarGain(nodeID);
|
return DependencyManager::get<NodeList>()->getAvatarGain(nodeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsersScriptingInterface::kick(const QUuid& nodeID) {
|
void UsersScriptingInterface::kick(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP) {
|
||||||
|
|
||||||
if (_kickConfirmationOperator) {
|
if (_kickConfirmationOperator) {
|
||||||
bool waitingForKickResponse = _kickResponseLock.resultWithReadLock<bool>([&] { return _waitingForKickResponse; });
|
bool waitingForKickResponse = _kickResponseLock.resultWithReadLock<bool>([&] { return _waitingForKickResponse; });
|
||||||
if (getCanKick() && !waitingForKickResponse) {
|
if (getCanKick() && !waitingForKickResponse) {
|
||||||
_kickConfirmationOperator(nodeID);
|
_kickConfirmationOperator(nodeID, banByUsername, banByFingerprint, banByIP);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID);
|
DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID, banByUsername, banByFingerprint, banByIP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 2016-07-11.
|
// Created by Stephen Birarda on 2016-07-11.
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
// Copyright 2021 Vircadia contributors.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -41,7 +42,7 @@ class UsersScriptingInterface : public QObject, public Dependency {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UsersScriptingInterface();
|
UsersScriptingInterface();
|
||||||
void setKickConfirmationOperator(std::function<void(const QUuid& nodeID)> kickConfirmationOperator) {
|
void setKickConfirmationOperator(std::function<void(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP)> kickConfirmationOperator) {
|
||||||
_kickConfirmationOperator = kickConfirmationOperator;
|
_kickConfirmationOperator = kickConfirmationOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,12 +113,15 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Kicks and bans a user. This removes them from the server and prevents them from returning. The ban is by user name if
|
* Kicks and bans a user. This removes them from the server and prevents them from returning. The ban is by user name if
|
||||||
* available, or machine fingerprint otherwise.
|
* available and by machine fingerprint.
|
||||||
* <p>This function only works if you're an administrator of the domain you're in.</p>
|
* <p>This function only works if you're an administrator of the domain you're in.</p>
|
||||||
* @function Users.kick
|
* @function Users.kick
|
||||||
* @param {Uuid} sessionID - The session ID of the user to kick and ban.
|
* @param {Uuid} sessionID - The session ID of the user to kick and ban.
|
||||||
|
* @param {boolean} [banByUsername=true] - Should ban the user's username.
|
||||||
|
* @param {boolean} [banByFingerprint=true] - Should ban the user's machine fingerprint.
|
||||||
|
* @param {boolean} [banByIP=false] - Should ban the user's IP address.
|
||||||
*/
|
*/
|
||||||
void kick(const QUuid& nodeID);
|
void kick(const QUuid& nodeID, bool banByUsername = true, bool banByFingerprint = true, bool banByIP = false);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Mutes a user's microphone for everyone. The mute is not permanent: the user can unmute themselves.
|
* Mutes a user's microphone for everyone. The mute is not permanent: the user can unmute themselves.
|
||||||
|
@ -237,7 +241,7 @@ private:
|
||||||
bool getRequestsDomainListData();
|
bool getRequestsDomainListData();
|
||||||
void setRequestsDomainListData(bool requests);
|
void setRequestsDomainListData(bool requests);
|
||||||
|
|
||||||
std::function<void(const QUuid& nodeID)> _kickConfirmationOperator;
|
std::function<void(const QUuid& nodeID, bool banByUsername, bool banByFingerprint, bool banByIP)> _kickConfirmationOperator;
|
||||||
|
|
||||||
ReadWriteLockable _kickResponseLock;
|
ReadWriteLockable _kickResponseLock;
|
||||||
bool _waitingForKickResponse { false };
|
bool _waitingForKickResponse { false };
|
||||||
|
|
Loading…
Reference in a new issue