It's a start

This commit is contained in:
Zach Fox 2017-10-31 11:08:02 -07:00
parent 19420a0ff2
commit 90e9251176
7 changed files with 119 additions and 30 deletions

View file

@ -96,6 +96,10 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer<ReceivedMessage>
_myServer->getOctree()->withWriteLock([&] {
_myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode);
});
} else if (packetType == PacketType::ChallengeOwnershipRequest) {
_myServer->getOctree()->withWriteLock([&] {
_myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode);
});
} else if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket);
_receivedPacketCount++;

View file

@ -42,6 +42,8 @@ ContextOverlayInterface::ContextOverlayInterface() {
_entityPropertyFlags += PROP_DIMENSIONS;
_entityPropertyFlags += PROP_REGISTRATION_POINT;
_entityPropertyFlags += PROP_CERTIFICATE_ID;
_entityPropertyFlags += PROP_CLIENT_ONLY;
_entityPropertyFlags += PROP_OWNING_AVATAR_ID;
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay);
@ -260,6 +262,41 @@ void ContextOverlayInterface::openInspectionCertificate() {
auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH);
_hmdScriptingInterface->openTablet();
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_currentEntityWithContextOverlay, _entityPropertyFlags);
QUuid nodeToChallenge = entityProperties.getOwningAvatarID();
auto nodeList = DependencyManager::get<NodeList>();
qDebug() << "ZRF FIXME" << entityProperties.getClientOnly() << nodeToChallenge << nodeList->getSessionUUID();
// Don't challenge ownership of avatar entities that I own
if (entityProperties.getClientOnly() && nodeToChallenge != nodeList->getSessionUUID()) {
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
if (entityServer) {
QByteArray certID = entityProperties.getCertificateID().toUtf8();
QByteArray ownerKey; // ZRF FIXME!
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
int certIDByteArraySize = certID.length();
int ownerKeyByteArraySize = ownerKey.length();
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + ownerKeyByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(ownerKeyByteArraySize);
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
challengeOwnershipPacket->write(certID);
challengeOwnershipPacket->write(ownerKey);
challengeOwnershipPacket->write(nodeToChallengeByteArray);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
} else {
qCWarning(context_overlay) << "Couldn't get Entity Server!";
}
}
}
}

View file

@ -73,7 +73,7 @@ public slots:
private:
bool _verboseLogging { true };
bool _enabled { true };
QUuid _currentEntityWithContextOverlay{};
EntityItemID _currentEntityWithContextOverlay{};
QString _entityMarketplaceID;
bool _contextOverlayJustClicked { false };

View file

@ -1153,8 +1153,8 @@ void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID)
_challengeOwnershipTimeoutTimer->deleteLater();
}
});
_challengeOwnershipTimeoutTimer->setSingleShot(true);
_challengeOwnershipTimeoutTimer->start(5000);
_challengeOwnershipTimeoutTimer->setSingleShot(true);
_challengeOwnershipTimeoutTimer->start(5000);
}
void EntityTree::startPendingTransferStatusTimer(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) {
@ -1225,7 +1225,7 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr
if (!id.isNull()) {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed; deleting entity" << id
<< "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce;
deleteEntity(id, true);
deleteEntity(id, true);
}
} else {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded; keeping entity" << id;
@ -1234,6 +1234,71 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr
return verificationSuccess;
}
void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
int certIDByteArraySize;
int ownerKeyByteArraySize;
int nodeToChallengeByteArraySize;
message.readPrimitive(&certIDByteArraySize);
message.readPrimitive(&ownerKeyByteArraySize);
message.readPrimitive(&nodeToChallengeByteArraySize);
QString certID(message.read(certIDByteArraySize));
QString ownerKey(message.read(ownerKeyByteArraySize));
QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize));
sendChallengeOwnershipPacket(certID, ownerKey, EntityItemID(), sourceNode, nodeToChallenge);
}
void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) {
// 1. Encrypt a nonce with the owner's public key
auto nodeList = DependencyManager::get<NodeList>();
QByteArray encryptedText = computeEncryptedNonce(certID, ownerKey);
if (encryptedText == "") {
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce.";
} else {
// In this case, the server is challenging a client. That client has just rezzed a new certified entity.
if (nodeToChallenge.isNull()) {
// 2. Send the encrypted text to the rezzing avatar's node
QByteArray certIDByteArray = certID.toUtf8();
int certIDByteArraySize = certIDByteArray.size();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership,
certIDByteArraySize + encryptedText.length() + 2 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(encryptedText.length());
challengeOwnershipPacket->write(certIDByteArray);
challengeOwnershipPacket->write(encryptedText);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode);
// 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityItemID));
return;
} else {
startChallengeOwnershipTimer(entityItemID);
}
// In this case, Client A is challenging Client B. Client A is inspecting a certified entity that it wants
// to make sure belongs to Avatar B.
} else {
QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122();
QByteArray certIDByteArray = certID.toUtf8();
int certIDByteArraySize = certIDByteArray.size();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + encryptedText.length() + senderNodeUUID.length() + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(encryptedText.length());
challengeOwnershipPacket->writePrimitive(senderNodeUUID.length());
challengeOwnershipPacket->write(certIDByteArray);
challengeOwnershipPacket->write(encryptedText);
challengeOwnershipPacket->write(senderNodeUUID);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(nodeToChallenge)));
}
}
}
void EntityTree::validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation) {
// Start owner verification.
auto nodeList = DependencyManager::get<NodeList>();
@ -1279,33 +1344,11 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
}
} else {
// Second, challenge ownership of the PoP cert
// 1. Encrypt a nonce with the owner's public key
QByteArray encryptedText = computeEncryptedNonce(certID, jsonObject["transfer_recipient_key"].toString());
sendChallengeOwnershipPacket(certID,
jsonObject["transfer_recipient_key"].toString(),
entityItemID,
senderNode);
if (encryptedText == "") {
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity...";
deleteEntity(entityItemID, true);
} else {
// 2. Send the encrypted text to the rezzing avatar's node
QByteArray certIDByteArray = certID.toUtf8();
int certIDByteArraySize = certIDByteArray.size();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership,
certIDByteArraySize + encryptedText.length() + 2 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(encryptedText.length());
challengeOwnershipPacket->write(certIDByteArray);
challengeOwnershipPacket->write(encryptedText);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode);
// 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityItemID));
return;
} else {
startChallengeOwnershipTimer(entityItemID);
}
}
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityItemID

View file

@ -93,6 +93,7 @@ public:
void fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties);
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
const SharedNodePointer& senderNode) override;
virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@ -377,6 +378,7 @@ protected:
private:
QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey);
bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce);
void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge = NULL);
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
};

View file

@ -124,6 +124,8 @@ public:
OctreeFileReplacementFromUrl,
ChallengeOwnership,
EntityScriptCallMethod,
ChallengeOwnershipRequest,
ChallengeOwnershipReply,
NUM_PACKET_TYPE
};

View file

@ -212,6 +212,7 @@ public:
virtual bool handlesEditPacketType(PacketType packetType) const { return false; }
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
const SharedNodePointer& sourceNode) { return 0; }
virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; }
virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; }
virtual bool recurseChildrenWithData() const { return true; }