From b335ba9a75f92c50a2fdde765201f5203b16da66 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Nov 2017 11:34:29 -0700 Subject: [PATCH] Timeout timer --- .../InspectionCertificate.qml | 25 ++++++++ interface/src/commerce/Ledger.h | 18 +++--- interface/src/commerce/QmlCommerce.cpp | 1 + interface/src/commerce/QmlCommerce.h | 2 + interface/src/commerce/Wallet.cpp | 62 +++++++++---------- .../ui/overlays/ContextOverlayInterface.cpp | 40 ++++++++---- .../src/ui/overlays/ContextOverlayInterface.h | 5 ++ libraries/entities/src/EntityTree.cpp | 4 +- 8 files changed, 105 insertions(+), 52 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index aa1372494f..06e04d6929 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -65,6 +65,31 @@ Rectangle { } } } + + onUpdateCertificateStatus: { + if (root.certificateId === certID) { + if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS + + } else if (certStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT + errorText.text = "Verification of this certificate timed out."; + errorText.color = hifi.colors.redHighlight; + } else if (certStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED + titleBarText.text = "Invalid Certificate"; + titleBarText.color = hifi.colors.redHighlight; + root.itemEdition = "Uncertified Copy"; + errorText.text = "The certificate associated with this entity is invalid."; + errorText.color = hifi.colors.redHighlight; + } else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED + titleBarText.text = "Invalid Certificate"; + titleBarText.color = hifi.colors.redHighlight; + root.itemEdition = "Uncertified Copy"; + errorText.text = "The certificate associated with this entity is invalid."; + errorText.color = hifi.colors.redHighlight; + } else { + console.log("Unknown certificate status received from ledger signal!"); + } + } + } } onCertificateIdChanged: { diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 75f6fb1ba8..42eb0ffc49 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -35,6 +35,14 @@ public: void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); + enum CertificateStatus { + CERTIFICATE_STATUS_UNKNOWN = 0, + CERTIFICATE_STATUS_VERIFICATION_SUCCESS, + CERTIFICATE_STATUS_VERIFICATION_TIMEOUT, + CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED, + CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED, + }; + signals: void buyResult(QJsonObject result); void receiveAtResult(QJsonObject result); @@ -45,6 +53,8 @@ signals: void locationUpdateResult(QJsonObject result); void certificateInfoResult(QJsonObject result); + void updateCertificateStatus(const QString& certID, uint certStatus); + public slots: void buySuccess(QNetworkReply& reply); void buyFailure(QNetworkReply& reply); @@ -65,14 +75,6 @@ public slots: void certificateInfoSuccess(QNetworkReply& reply); void certificateInfoFailure(QNetworkReply& reply); - void updateCertificateStatus(const QString& certID, uint certStatus); - enum CertificateStatus { - CERTIFICATE_STATUS_UNKNOWN = 0, - CERTIFICATE_STATUS_VERIFICATION_SUCCESS, - CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED, - CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED, - }; - private: QJsonObject apiResponse(const QString& label, QNetworkReply& reply); QJsonObject failResponse(const QString& label, QNetworkReply& reply); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 803264fa9f..ac5d0e6a2d 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -30,6 +30,7 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult); connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult); connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult); + connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus); } void QmlCommerce::getWalletStatus() { diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index ae63133425..d4f4aa35d2 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -45,6 +45,8 @@ signals: void accountResult(QJsonObject result); void certificateInfoResult(QJsonObject result); + void updateCertificateStatus(const QString& certID, uint certStatus); + protected: Q_INVOKABLE void getWalletStatus(); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index c31184eb56..c6d77982b8 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -740,6 +740,8 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); if (rsa) { + auto nodeList = DependencyManager::get(); + ERR_clear_error(); const int decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, reinterpret_cast(encryptedText.constData()), @@ -749,41 +751,39 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack RSA_free(rsa); - if (decryptionStatus != -1) { - auto nodeList = DependencyManager::get(); + QByteArray decryptedTextByteArray = QByteArray(reinterpret_cast(decryptedText), decryptionStatus); + int decryptedTextByteArraySize = decryptedTextByteArray.size(); + int certIDSize = certID.size(); + // setup the packet + if (challengeOriginatedFromClient) { + auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, + certIDSize + decryptedTextByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int), + true); - QByteArray decryptedTextByteArray = QByteArray(reinterpret_cast(decryptedText), decryptionStatus); - int decryptedTextByteArraySize = decryptedTextByteArray.size(); - int certIDSize = certID.size(); - // setup the packet - if (challengeOriginatedFromClient) { - auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, - certIDSize + decryptedTextByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int), - true); + decryptedTextPacket->writePrimitive(certIDSize); + decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); + decryptedTextPacket->writePrimitive(challengingNodeUUIDByteArraySize); + decryptedTextPacket->write(certID); + decryptedTextPacket->write(decryptedTextByteArray); + decryptedTextPacket->write(challengingNodeUUID); - decryptedTextPacket->writePrimitive(certIDSize); - decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); - decryptedTextPacket->writePrimitive(challengingNodeUUIDByteArraySize); - decryptedTextPacket->write(certID); - decryptedTextPacket->write(decryptedTextByteArray); - decryptedTextPacket->write(challengingNodeUUID); + qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; - qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; - - nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); - } else { - auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true); - - decryptedTextPacket->writePrimitive(certIDSize); - decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); - decryptedTextPacket->write(certID); - decryptedTextPacket->write(decryptedTextByteArray); - - qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; - - nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); - } + nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); } else { + auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true); + + decryptedTextPacket->writePrimitive(certIDSize); + decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); + decryptedTextPacket->write(certID); + decryptedTextPacket->write(decryptedTextByteArray); + + qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; + + nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); + } + + if (decryptionStatus == -1) { qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; long error = ERR_get_error(); if (error != 0) { diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 48f2394ca3..75aefdc585 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -76,6 +76,7 @@ ContextOverlayInterface::ContextOverlayInterface() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::ChallengeOwnershipReply, this, "handleChallengeOwnershipReplyPacket"); + _challengeOwnershipTimeoutTimer.setSingleShot(true); } static const uint32_t MOUSE_HW_ID = 0; @@ -271,16 +272,16 @@ void ContextOverlayInterface::openInspectionCertificate() { tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH); _hmdScriptingInterface->openTablet(); - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_currentEntityWithContextOverlay, _entityPropertyFlags); + setLastInspectedEntity(_currentEntityWithContextOverlay); + + EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags); QUuid nodeToChallenge = entityProperties.getOwningAvatarID(); auto nodeList = DependencyManager::get(); // ZRF FIXME: Don't challenge ownership of avatar entities that I own if (entityProperties.getClientOnly()/* && nodeToChallenge != nodeList->getSessionUUID()*/) { - // ZRF FIXME! - //if (entityProperties.verifyStaticCertificateProperties()) { - if (true) { + if (entityProperties.verifyStaticCertificateProperties()) { SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); if (entityServer) { @@ -331,12 +332,12 @@ void ContextOverlayInterface::openInspectionCertificate() { nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer); // Kickoff a 10-second timeout timer that marks the cert 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); - //} + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer"); + return; + } else { + startChallengeOwnershipTimer(); + } } } else { qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << @@ -350,8 +351,9 @@ void ContextOverlayInterface::openInspectionCertificate() { } } else { auto ledger = DependencyManager::get(); + _challengeOwnershipTimeoutTimer.stop(); emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED)); - qCDebug(context_overlay) << "Entity" << _currentEntityWithContextOverlay << "failed static certificate verification!"; + qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!"; } } } @@ -388,9 +390,23 @@ void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { } } +void ContextOverlayInterface::startChallengeOwnershipTimer() { + auto ledger = DependencyManager::get(); + EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags); + + connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() { + qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity; + emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT)); + }); + + _challengeOwnershipTimeoutTimer.start(5000); +} + void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) { auto ledger = DependencyManager::get(); + _challengeOwnershipTimeoutTimer.stop(); + int certIDByteArraySize; int decryptedTextByteArraySize; @@ -403,6 +419,8 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer EntityItemID id; bool verificationSuccess = DependencyManager::get()->getTree()->verifyDecryptedNonce(certID, decryptedText, id); + qDebug() << "ZRF" << verificationSuccess; + if (verificationSuccess) { emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS)); } else { diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index eedc1790d3..8f0a40ef8e 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -51,6 +51,7 @@ public: Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; } void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; } + void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; } void setEnabled(bool enabled); bool getEnabled() { return _enabled; } bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; } @@ -77,6 +78,7 @@ private: bool _verboseLogging { true }; bool _enabled { true }; EntityItemID _currentEntityWithContextOverlay{}; + EntityItemID _lastInspectedEntity{}; QString _entityMarketplaceID; bool _contextOverlayJustClicked { false }; @@ -90,6 +92,9 @@ private: void deletingEntity(const EntityItemID& entityItemID); SelectionToSceneHandler _selectionToSceneHandler; + + Q_INVOKABLE void startChallengeOwnershipTimer(); + QTimer _challengeOwnershipTimeoutTimer; }; #endif // hifi_ContextOverlayInterface_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f748291077..333a514377 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1220,9 +1220,9 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr bool verificationSuccess = (actualNonce == decryptedNonce); if (verificationSuccess) { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded for entity" << id; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for entity" << id + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed." << "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce; }