From 6f81dd53f2cdbc730fc84eae648f72bea3807d56 Mon Sep 17 00:00:00 2001 From: Gerard Maguire Date: Tue, 8 Aug 2017 05:08:20 +0100 Subject: [PATCH 01/42] Fixed avatar rotation upon teleportation using Pal Added "VisitUserFromPAL" to LookupTrigger enum and bool "shouldMatchOrientation" to goToUser() --- interface/resources/qml/hifi/NameCard.qml | 4 +++- interface/resources/qml/hifi/Pal.qml | 2 +- libraries/networking/src/AddressManager.cpp | 18 ++++++++++++------ libraries/networking/src/AddressManager.h | 5 +++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 65517f5a73..937c67d8ba 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -433,7 +433,7 @@ Item { anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter x: 240 onClicked: { - AddressManager.goToUser(thisNameCard.userName); + AddressManager.goToUser(thisNameCard.userName, false); UserActivityLogger.palAction("go_to_user", thisNameCard.userName); } } @@ -595,7 +595,9 @@ Item { // the avatar goes into fly mode rather than falling. However, that is not exposed to Javascript right now. // FIXME: it would be nice if this used the same teleport steps and smoothing as in the teleport.js script. // Note, however, that this script allows teleporting to a person in the air, while teleport.js is going to a grounded target. + // Position avatar 2 metres from the target in the direction that target avatar was facing. MyAvatar.position = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.orientation, {x: 0, y: 0, z: -2})); + // Rotate avatar on Y axis to face target avatar. MyAvatar.orientation = Quat.multiply(avatar.orientation, {y: 1}); } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c98cfba1ba..134fea5170 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -830,7 +830,7 @@ Rectangle { hoverEnabled: enabled enabled: connectionsNameCard.selected && pal.activeTab == "connectionsTab" onClicked: { - AddressManager.goToUser(model.userName); + AddressManager.goToUser(model.userName, false); UserActivityLogger.palAction("go_to_user", model.userName); } onEntered: connectionsLocationData.color = hifi.colors.blueHighlight; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 99e1962387..588df71e41 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -665,6 +665,11 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should } } + if (trigger == LookupTrigger::VisitUserFromPAL) { + qCDebug(networking) << "trigger is VisitUserFromPAL -- applying Quat.cancelOutRollAndPitch"; + newOrientation = cancelOutRollAndPitch(newOrientation); + } + emit locationChangeRequired(newPosition, orientationChanged, newOrientation, shouldFace); } else { @@ -729,13 +734,14 @@ bool AddressManager::setDomainInfo(const QString& hostname, quint16 port, Lookup return hostChanged; } -void AddressManager::goToUser(const QString& username) { +void AddressManager::goToUser(const QString& username, bool shouldMatchOrientation) { QString formattedUsername = QUrl::toPercentEncoding(username); - // for history storage handling we remember how this lookup was trigged - for a username it's always user input + // for history storage handling we remember how this lookup was triggered - for a username it's always user input QVariantMap requestParams; - requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast(LookupTrigger::UserInput)); - + requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast( + shouldMatchOrientation ? LookupTrigger::UserInput : LookupTrigger::VisitUserFromPAL + )); // this is a username - pull the captured name and lookup that user's location DependencyManager::get()->sendRequest(GET_USER_LOCATION.arg(formattedUsername), AccountManagerAuth::Optional, @@ -841,8 +847,8 @@ void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) { // and do not but it into the back stack _forwardStack.push(currentAddress()); } else { - if (trigger == LookupTrigger::UserInput) { - // anyime the user has manually looked up an address we know we should clear the forward stack + if (trigger == LookupTrigger::UserInput || trigger == LookupTrigger::VisitUserFromPAL) { + // anyime the user has actively triggered an address we know we should clear the forward stack _forwardStack.clear(); emit goForwardPossible(false); diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 83eedfc82f..98b2048601 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -55,7 +55,8 @@ public: DomainPathResponse, Internal, AttemptedRefresh, - Suggestions + Suggestions, + VisitUserFromPAL }; bool isConnected(); @@ -95,7 +96,7 @@ public slots: void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); } void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(DEFAULT_HIFI_ADDRESS, trigger); } - void goToUser(const QString& username); + void goToUser(const QString& username, bool shouldMatchOrientation = true); void refreshPreviousLookup(); From 356f055b53284ba22b0a7c0763452e9b89fee9ac Mon Sep 17 00:00:00 2001 From: Gerard Maguire Date: Tue, 8 Aug 2017 15:26:21 +0100 Subject: [PATCH 02/42] fixed missing bool --- interface/resources/qml/hifi/NameCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 937c67d8ba..78dff425c7 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -244,7 +244,7 @@ Item { enabled: selected && pal.activeTab == "nearbyTab" && thisNameCard.userName !== "" && isPresent; hoverEnabled: enabled onClicked: { - goToUserInDomain(thisNameCard.uuid); + goToUserInDomain(thisNameCard.uuid, false); UserActivityLogger.palAction("go_to_user_in_domain", thisNameCard.uuid); } onEntered: { From 47b37ac04ef315bdf2d2cadec595fadaf4db9d0a Mon Sep 17 00:00:00 2001 From: Gerard Maguire Date: Tue, 8 Aug 2017 15:35:14 +0100 Subject: [PATCH 03/42] Bool --- interface/resources/qml/hifi/NameCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 78dff425c7..7e93d2c397 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -339,7 +339,7 @@ Item { enabled: selected && pal.activeTab == "nearbyTab" && thisNameCard.userName !== "" && isPresent; hoverEnabled: enabled onClicked: { - goToUserInDomain(thisNameCard.uuid); + goToUserInDomain(thisNameCard.uuid, false); UserActivityLogger.palAction("go_to_user_in_domain", thisNameCard.uuid); } onEntered: { From afb03b3d2d8ae66fa112f16d75aa7422828a9115 Mon Sep 17 00:00:00 2001 From: Gerard Maguire Date: Tue, 10 Oct 2017 16:19:31 +0100 Subject: [PATCH 04/42] Avatar pitch and roll cleared --- interface/resources/qml/hifi/NameCard.qml | 10 ++++++---- libraries/networking/src/AddressManager.cpp | 12 +++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 7e93d2c397..b122f71760 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -244,7 +244,7 @@ Item { enabled: selected && pal.activeTab == "nearbyTab" && thisNameCard.userName !== "" && isPresent; hoverEnabled: enabled onClicked: { - goToUserInDomain(thisNameCard.uuid, false); + goToUserInDomain(thisNameCard.uuid); UserActivityLogger.palAction("go_to_user_in_domain", thisNameCard.uuid); } onEntered: { @@ -339,7 +339,7 @@ Item { enabled: selected && pal.activeTab == "nearbyTab" && thisNameCard.userName !== "" && isPresent; hoverEnabled: enabled onClicked: { - goToUserInDomain(thisNameCard.uuid, false); + goToUserInDomain(thisNameCard.uuid); UserActivityLogger.palAction("go_to_user_in_domain", thisNameCard.uuid); } onEntered: { @@ -433,6 +433,7 @@ Item { anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter x: 240 onClicked: { + console.log("Vist user button clicked."); // Remove after debugging. AddressManager.goToUser(thisNameCard.userName, false); UserActivityLogger.palAction("go_to_user", thisNameCard.userName); } @@ -597,7 +598,8 @@ Item { // Note, however, that this script allows teleporting to a person in the air, while teleport.js is going to a grounded target. // Position avatar 2 metres from the target in the direction that target avatar was facing. MyAvatar.position = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.orientation, {x: 0, y: 0, z: -2})); - // Rotate avatar on Y axis to face target avatar. - MyAvatar.orientation = Quat.multiply(avatar.orientation, {y: 1}); + + // Rotate avatar on Y axis to face target avatar and cancel out any inherited roll and pitch. + MyAvatar.orientation = Quat.cancelOutRollAndPitch(Quat.multiply(avatar.orientation, {y: 1})); } } diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 4030e2101b..772f9df2e1 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -668,13 +668,11 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should qCDebug(networking) << "Orientation parsed from lookup string is invalid. Will not use for location change."; } } - - if (trigger == LookupTrigger::VisitUserFromPAL) { - qCDebug(networking) << "trigger is VisitUserFromPAL -- applying Quat.cancelOutRollAndPitch"; - newOrientation = cancelOutRollAndPitch(newOrientation); - } - - emit locationChangeRequired(newPosition, orientationChanged, newOrientation, shouldFace); + + emit locationChangeRequired(newPosition, orientationChanged, + LookupTrigger::VisitUserFromPAL ? cancelOutRollAndPitch(newOrientation): newOrientation, + shouldFace + ); } else { qCDebug(networking) << "Could not jump to position from lookup string because it has an invalid value."; From 9345f4545f29cb24112bd76a012142a479769391 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 Oct 2017 13:35:42 -0700 Subject: [PATCH 05/42] sanitize the ice-server addresses before using --- domain-server/src/DomainServer.cpp | 37 +++++++++++------------------- domain-server/src/DomainServer.h | 2 -- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 436f49c7ca..46eda163d8 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -754,26 +754,6 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { void DomainServer::updateICEServerAddresses() { if (_iceAddressLookupID == INVALID_ICE_LOOKUP_ID) { _iceAddressLookupID = QHostInfo::lookupHost(_iceServerAddr, this, SLOT(handleICEHostInfo(QHostInfo))); - - // there seems to be a 5.9 bug where lookupHost never calls our slot - // so we add a single shot manual "timeout" to fire it off again if it hasn't called back yet - static const int ICE_ADDRESS_LOOKUP_TIMEOUT_MS = 5000; - QTimer::singleShot(ICE_ADDRESS_LOOKUP_TIMEOUT_MS, this, &DomainServer::timeoutICEAddressLookup); - } -} - -void DomainServer::timeoutICEAddressLookup() { - if (_iceAddressLookupID != INVALID_ICE_LOOKUP_ID) { - // we waited 5s and didn't hear back for our ICE DNS lookup - // so time that one out and kick off another - - qDebug() << "IP address lookup timed out for" << _iceServerAddr << "- retrying"; - - QHostInfo::abortHostLookup(_iceAddressLookupID); - - _iceAddressLookupID = INVALID_ICE_LOOKUP_ID; - - updateICEServerAddresses(); } } @@ -2799,9 +2779,20 @@ void DomainServer::handleKeypairChange() { void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) { // clear the ICE address lookup ID so that it can fire again - _iceAddressLookupID = -1; + _iceAddressLookupID = INVALID_ICE_LOOKUP_ID; - if (hostInfo.error() != QHostInfo::NoError) { + // enumerate the returned addresses and collect only valid IPv4 addresses + QList sanitizedAddresses = hostInfo.addresses(); + auto it = sanitizedAddresses.begin(); + while (it != sanitizedAddresses.end()) { + if (!it->isNull() && it->protocol() == QAbstractSocket::IPv4Protocol) { + ++it; + } else { + it = sanitizedAddresses.erase(it); + } + } + + if (hostInfo.error() != QHostInfo::NoError || sanitizedAddresses.empty()) { qWarning() << "IP address lookup failed for" << _iceServerAddr << ":" << hostInfo.errorString(); // if we don't have an ICE server to use yet, trigger a retry @@ -2814,7 +2805,7 @@ void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) { } else { int countBefore = _iceServerAddresses.count(); - _iceServerAddresses = hostInfo.addresses(); + _iceServerAddresses = sanitizedAddresses; if (countBefore == 0) { qInfo() << "Found" << _iceServerAddresses.count() << "ice-server IP addresses for" << _iceServerAddr; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 52ac435517..982d39d046 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -116,8 +116,6 @@ private slots: void tokenGrantFinished(); void profileRequestFinished(); - void timeoutICEAddressLookup(); - signals: void iceServerChanged(); void userConnected(); From 60fbbe4bc0e4f725353202650b93d7f44675a6c1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 Oct 2017 13:12:53 -0700 Subject: [PATCH 06/42] disable baking of JS files --- assignment-client/src/assets/AssetServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 9c03bdd3bb..d13e031c03 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -50,9 +50,9 @@ static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000; const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -static const QStringList BAKEABLE_MODEL_EXTENSIONS = {"fbx"}; +static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" }; static QStringList BAKEABLE_TEXTURE_EXTENSIONS; -static const QStringList BAKEABLE_SCRIPT_EXTENSIONS = {"js"}; +static const QStringList BAKEABLE_SCRIPT_EXTENSIONS = {}; static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx"; static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx"; static const QString BAKED_SCRIPT_SIMPLE_NAME = "asset.js"; From e450ac5bd3b5fd13357b85a1d31ded73aa9dbe7a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 Oct 2017 15:28:30 -0700 Subject: [PATCH 07/42] don't use COW-less SpecialAddress assignment --- libraries/networking/src/HifiSockAddr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index b582198139..3c753f0434 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -34,7 +34,7 @@ public: HifiSockAddr(const sockaddr* sockaddr); bool isNull() const { return _address.isNull() && _port == 0; } - void clear() { _address = QHostAddress::Null; _port = 0;} + void clear() { _address.clear(); _port = 0;} HifiSockAddr& operator=(const HifiSockAddr& rhsSockAddr); void swap(HifiSockAddr& otherSockAddr); From 19420a0ff26b691ee7e0eeb2e1a734302c244be8 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 30 Oct 2017 17:01:55 -0700 Subject: [PATCH 08/42] Move static cert verify to properties --- .../src/entities/EntityServer.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 114 ----------------- libraries/entities/src/EntityItem.h | 3 - .../entities/src/EntityItemProperties.cpp | 116 ++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 4 + .../entities/src/EntityScriptingInterface.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- 7 files changed, 123 insertions(+), 120 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index fa9c73b12d..702ca88787 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -459,7 +459,7 @@ void EntityServer::startDynamicDomainVerification() { EntityItemPointer entity = tree->findEntityByEntityItemID(i.value()); if (entity) { - if (!entity->verifyStaticCertificateProperties()) { + if (!entity->getProperties().verifyStaticCertificateProperties()) { qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed" << "static certificate verification."; // Delete the entity if it doesn't pass static certificate verification diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4f5db991c8..c355ce90fc 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -14,10 +14,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -1575,116 +1571,6 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(getDimensions()); } -// Checking Certifiable Properties -#define ADD_STRING_PROPERTY(n, N) if (!propertySet.get##N().isEmpty()) json[#n] = propertySet.get##N() -#define ADD_ENUM_PROPERTY(n, N) json[#n] = propertySet.get##N##AsString() -#define ADD_INT_PROPERTY(n, N) if (propertySet.get##N() != 0) json[#n] = (propertySet.get##N() == (quint32) -1) ? -1.0 : ((double) propertySet.get##N()) -QByteArray EntityItem::getStaticCertificateJSON() const { - // Produce a compact json of every non-default static certificate property, with the property names in alphabetical order. - // The static certificate properties include all an only those properties that cannot be changed without altering the identity - // of the entity as reviewed during the certification submission. - - QJsonObject json; - EntityItemProperties propertySet = getProperties(); // Note: neither EntityItem nor EntityitemProperties "properties" are QObject "properties"! - // It is important that this be reproducible in the same order each time. Since we also generate these on the server, we do it alphabetically - // to help maintainence in two different code bases. - if (!propertySet.getAnimation().getURL().isEmpty()) { - json["animationURL"] = propertySet.getAnimation().getURL(); - } - ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL); - ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL); - ADD_INT_PROPERTY(editionNumber, EditionNumber); - ADD_INT_PROPERTY(instanceNumber, EntityInstanceNumber); - ADD_STRING_PROPERTY(itemArtist, ItemArtist); - ADD_STRING_PROPERTY(itemCategories, ItemCategories); - ADD_STRING_PROPERTY(itemDescription, ItemDescription); - ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense); - ADD_STRING_PROPERTY(itemName, ItemName); - ADD_INT_PROPERTY(limitedRun, LimitedRun); - ADD_STRING_PROPERTY(marketplaceID, MarketplaceID); - ADD_STRING_PROPERTY(modelURL, ModelURL); - ADD_STRING_PROPERTY(script, Script); - ADD_ENUM_PROPERTY(shapeType, ShapeType); - json["type"] = EntityTypes::getEntityTypeName(propertySet.getType()); - - return QJsonDocument(json).toJson(QJsonDocument::Compact); -} -QByteArray EntityItem::getStaticCertificateHash() const { - return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256); -} - -bool EntityItem::verifyStaticCertificateProperties() { - // True IIF a non-empty certificateID matches the static certificate json. - // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash. - - if (getCertificateID().isEmpty()) { - return false; - } - - const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8(); - const unsigned char* marketplacePublicKey = reinterpret_cast(marketplacePublicKeyByteArray.constData()); - int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length(); - - BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength); - EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (evp_key) { - RSA* rsa = EVP_PKEY_get1_RSA(evp_key); - if (rsa) { - const QByteArray digestByteArray = getStaticCertificateHash(); - const unsigned char* digest = reinterpret_cast(digestByteArray.constData()); - int digestLength = digestByteArray.length(); - - const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8()); - const unsigned char* signature = reinterpret_cast(signatureByteArray.constData()); - int signatureLength = signatureByteArray.length(); - - ERR_clear_error(); - bool answer = RSA_verify(NID_sha256, - digest, - digestLength, - signature, - signatureLength, - rsa); - long error = ERR_get_error(); - if (error != 0) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "ERROR while verifying static certificate properties! RSA error:" << error_str - << "\nStatic Cert JSON:" << getStaticCertificateJSON() - << "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength - << "\nDigest:" << digest << "\nDigest Length:" << digestLength - << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; - } - RSA_free(rsa); - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - return answer; - } else { - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str; - return false; - } - } else { - if (bio) { - BIO_free(bio); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str; - return false; - } -} - void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const { if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) { glm::mat4 scale = glm::scale(getDimensions()); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 79862b9bd2..76a5205960 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -328,9 +328,6 @@ public: void setEntityInstanceNumber(const quint32&); QString getCertificateID() const; void setCertificateID(const QString& value); - QByteArray getStaticCertificateJSON() const; - QByteArray getStaticCertificateHash() const; - bool verifyStaticCertificateProperties(); // TODO: get rid of users of getRadius()... float getRadius() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 3bbd6ce8e6..f774b208c4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -14,6 +14,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -2471,3 +2480,110 @@ bool EntityItemProperties::parentRelatedPropertyChanged() const { bool EntityItemProperties::queryAACubeRelatedPropertyChanged() const { return parentRelatedPropertyChanged() || dimensionsChanged(); } + +// Checking Certifiable Properties +#define ADD_STRING_PROPERTY(n, N) if (!get##N().isEmpty()) json[#n] = get##N() +#define ADD_ENUM_PROPERTY(n, N) json[#n] = get##N##AsString() +#define ADD_INT_PROPERTY(n, N) if (get##N() != 0) json[#n] = (get##N() == (quint32) -1) ? -1.0 : ((double) get##N()) +QByteArray EntityItemProperties::getStaticCertificateJSON() const { + // Produce a compact json of every non-default static certificate property, with the property names in alphabetical order. + // The static certificate properties include all an only those properties that cannot be changed without altering the identity + // of the entity as reviewed during the certification submission. + + QJsonObject json; + if (!getAnimation().getURL().isEmpty()) { + json["animationURL"] = getAnimation().getURL(); + } + ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL); + ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL); + ADD_INT_PROPERTY(editionNumber, EditionNumber); + ADD_INT_PROPERTY(instanceNumber, EntityInstanceNumber); + ADD_STRING_PROPERTY(itemArtist, ItemArtist); + ADD_STRING_PROPERTY(itemCategories, ItemCategories); + ADD_STRING_PROPERTY(itemDescription, ItemDescription); + ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense); + ADD_STRING_PROPERTY(itemName, ItemName); + ADD_INT_PROPERTY(limitedRun, LimitedRun); + ADD_STRING_PROPERTY(marketplaceID, MarketplaceID); + ADD_STRING_PROPERTY(modelURL, ModelURL); + ADD_STRING_PROPERTY(script, Script); + ADD_ENUM_PROPERTY(shapeType, ShapeType); + json["type"] = EntityTypes::getEntityTypeName(getType()); + + return QJsonDocument(json).toJson(QJsonDocument::Compact); +} +QByteArray EntityItemProperties::getStaticCertificateHash() const { + return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256); +} + +bool EntityItemProperties::verifyStaticCertificateProperties() { + // True IIF a non-empty certificateID matches the static certificate json. + // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash. + + if (getCertificateID().isEmpty()) { + return false; + } + + const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8(); + const unsigned char* marketplacePublicKey = reinterpret_cast(marketplacePublicKeyByteArray.constData()); + int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length(); + + BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength); + EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (evp_key) { + RSA* rsa = EVP_PKEY_get1_RSA(evp_key); + if (rsa) { + const QByteArray digestByteArray = getStaticCertificateHash(); + const unsigned char* digest = reinterpret_cast(digestByteArray.constData()); + int digestLength = digestByteArray.length(); + + const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8()); + const unsigned char* signature = reinterpret_cast(signatureByteArray.constData()); + int signatureLength = signatureByteArray.length(); + + ERR_clear_error(); + bool answer = RSA_verify(NID_sha256, + digest, + digestLength, + signature, + signatureLength, + rsa); + long error = ERR_get_error(); + if (error != 0) { + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "ERROR while verifying static certificate properties! RSA error:" << error_str + << "\nStatic Cert JSON:" << getStaticCertificateJSON() + << "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength + << "\nDigest:" << digest << "\nDigest Length:" << digestLength + << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; + } + RSA_free(rsa); + if (bio) { + BIO_free(bio); + } + if (evp_key) { + EVP_PKEY_free(evp_key); + } + return answer; + } else { + if (bio) { + BIO_free(bio); + } + if (evp_key) { + EVP_PKEY_free(evp_key); + } + long error = ERR_get_error(); + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str; + return false; + } + } else { + if (bio) { + BIO_free(bio); + } + long error = ERR_get_error(); + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str; + return false; + } +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6547026e5c..a8bb063934 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -336,6 +336,10 @@ public: QByteArray getPackedStrokeColors() const; QByteArray packStrokeColors(const QVector& strokeColors) const; + QByteArray getStaticCertificateJSON() const; + QByteArray getStaticCertificateHash() const; + bool verifyStaticCertificateProperties(); + protected: QString getCollisionMaskAsString() const; void setCollisionMaskFromString(const QString& maskString); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c83a5f60a1..998a2d4dfe 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1827,7 +1827,7 @@ bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& en _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { - result = entity->verifyStaticCertificateProperties(); + result = entity->getProperties().verifyStaticCertificateProperties(); } }); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9397f38cdd..22348360ed 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1528,7 +1528,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c _totalCreates++; if (newEntity && isCertified && getIsServer()) { - if (!newEntity->verifyStaticCertificateProperties()) { + if (!properties.verifyStaticCertificateProperties()) { qCDebug(entities) << "User" << senderNode->getUUID() << "attempted to add a certified entity with ID" << entityItemID << "which failed" << "static certificate verification."; From 90e92511767a5bbe3f248afd4d474e423bac5791 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 11:08:02 -0700 Subject: [PATCH 09/42] It's a start --- .../octree/OctreeInboundPacketProcessor.cpp | 4 + .../ui/overlays/ContextOverlayInterface.cpp | 37 +++++++ .../src/ui/overlays/ContextOverlayInterface.h | 2 +- libraries/entities/src/EntityTree.cpp | 101 +++++++++++++----- libraries/entities/src/EntityTree.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 2 + libraries/octree/src/Octree.h | 1 + 7 files changed, 119 insertions(+), 30 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 3f835678ac..50c95ffc5d 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -96,6 +96,10 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer _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++; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 70b75a0b17..402e72f2cf 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -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().data(); connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay); @@ -260,6 +262,41 @@ void ContextOverlayInterface::openInspectionCertificate() { auto tablet = dynamic_cast(_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(); + + 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!"; + } + } } } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b4d3ddc0c2..a063fdde23 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -73,7 +73,7 @@ public slots: private: bool _verboseLogging { true }; bool _enabled { true }; - QUuid _currentEntityWithContextOverlay{}; + EntityItemID _currentEntityWithContextOverlay{}; QString _entityMarketplaceID; bool _contextOverlayJustClicked { false }; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 22348360ed..90ee1190d5 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -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(); + 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(); @@ -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 diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 518cde9a59..3c11557dac 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -93,6 +93,7 @@ public: void fixupTerseEditLogging(EntityItemProperties& properties, QList& 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); }; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 049cb0f1a8..8d48b106e4 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -124,6 +124,8 @@ public: OctreeFileReplacementFromUrl, ChallengeOwnership, EntityScriptCallMethod, + ChallengeOwnershipRequest, + ChallengeOwnershipReply, NUM_PACKET_TYPE }; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 2761dffb1b..fe8868b342 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -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; } From 6f96e0c7bd30623c33add2fbaebfad6e8f4ea6e3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 12:14:12 -0700 Subject: [PATCH 10/42] More progress --- .../octree/OctreeInboundPacketProcessor.cpp | 6 +- interface/src/commerce/Wallet.cpp | 41 +++++-- interface/src/commerce/Wallet.h | 1 + .../ui/overlays/ContextOverlayInterface.cpp | 85 +++++++++---- libraries/entities/src/EntityTree.cpp | 112 ++++++++++++------ libraries/entities/src/EntityTree.h | 9 +- libraries/octree/src/Octree.h | 1 + 7 files changed, 186 insertions(+), 69 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 50c95ffc5d..bce6e7fe44 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -98,7 +98,11 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer }); } else if (packetType == PacketType::ChallengeOwnershipRequest) { _myServer->getOctree()->withWriteLock([&] { - _myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode); + _myServer->getOctree()->processChallengeOwnershipRequestPacket(*message, sendingNode); + }); + } else if (packetType == PacketType::ChallengeOwnershipReply) { + _myServer->getOctree()->withWriteLock([&] { + _myServer->getOctree()->processChallengeOwnershipReplyPacket(*message, sendingNode); }); } else if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index c7c09d8b03..2389e8e39d 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -319,6 +319,7 @@ Wallet::Wallet() { auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket"); + packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket"); connect(ledger.data(), &Ledger::accountResult, this, [&]() { auto wallet = DependencyManager::get(); @@ -717,15 +718,24 @@ bool Wallet::changePassphrase(const QString& newPassphrase) { } void Wallet::handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest; unsigned char decryptedText[64]; int certIDByteArraySize; int encryptedTextByteArraySize; + int senderNodeUUIDByteArraySize; packet->readPrimitive(&certIDByteArraySize); packet->readPrimitive(&encryptedTextByteArraySize); + if (challengeOriginatedFromClient) { + packet->readPrimitive(&senderNodeUUIDByteArraySize); + } QByteArray certID = packet->read(certIDByteArraySize); QByteArray encryptedText = packet->read(encryptedTextByteArraySize); + QByteArray senderNodeUUID; + if (challengeOriginatedFromClient) { + packet->readPrimitive(&senderNodeUUID); + } RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); @@ -745,16 +755,33 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack int decryptedTextByteArraySize = decryptedTextByteArray.size(); int certIDSize = certID.size(); // setup the packet - auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true); + if (challengeOriginatedFromClient) { + auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, + certIDSize + decryptedTextByteArraySize + senderNodeUUIDByteArraySize + 3 * sizeof(int), + true); - decryptedTextPacket->writePrimitive(certIDSize); - decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); - decryptedTextPacket->write(certID); - decryptedTextPacket->write(decryptedTextByteArray); + decryptedTextPacket->writePrimitive(certIDSize); + decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); + decryptedTextPacket->writePrimitive(senderNodeUUIDByteArraySize); + decryptedTextPacket->write(certID); + decryptedTextPacket->write(decryptedTextByteArray); + decryptedTextPacket->write(senderNodeUUID); - qCDebug(commerce) << "Sending ChallengeOwnership 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); + 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); + } } else { qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; } diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index ed145df451..fcc508b4e9 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -67,6 +67,7 @@ signals: private slots: void handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handleChallengeOwnershipRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); private: QStringList _publicKeys{}; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 402e72f2cf..cfc2156a0f 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -14,6 +14,9 @@ #include #include +#include +#include +#include #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -268,31 +271,73 @@ void ContextOverlayInterface::openInspectionCertificate() { QUuid nodeToChallenge = entityProperties.getOwningAvatarID(); auto nodeList = DependencyManager::get(); - qDebug() << "ZRF FIXME" << entityProperties.getClientOnly() << nodeToChallenge << nodeList->getSessionUUID(); - - // Don't challenge ownership of avatar entities that I own - if (entityProperties.getClientOnly() && nodeToChallenge != nodeList->getSessionUUID()) { + // ZRF FIXME: 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(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest; + networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL; + requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); + QJsonObject request; + request["certificate_id"] = entityProperties.getCertificateID(); + networkRequest.setUrl(requestURL); - int certIDByteArraySize = certID.length(); - int ownerKeyByteArraySize = ownerKey.length(); - int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length(); + QNetworkReply* networkReply = NULL; + networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - 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); + connect(networkReply, &QNetworkReply::finished, [=]() { + QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); + jsonObject = jsonObject["data"].toObject(); + + if (networkReply->error() == QNetworkReply::NoError) { + if (!jsonObject["invalid_reason"].toString().isEmpty()) { + qCDebug(entities) << "invalid_reason not empty"; + } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { + qCDebug(entities) << "'transfer_status' is 'failed'";; + } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { + qCDebug(entities) << "'transfer_status' is 'pending'";; + } else { + QByteArray certID = entityProperties.getCertificateID().toUtf8(); + QByteArray ownerKey = jsonObject["transfer_recipient_key"].toString().toUtf8(); + QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122(); + QByteArray encryptedText = DependencyManager::get()->getTree()->computeEncryptedNonce(certID, ownerKey); + + int certIDByteArraySize = certID.length(); + int ownerKeyByteArraySize = ownerKey.length(); + int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length(); + int encryptedTextByteArraySize = encryptedText.length(); + + auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, + certIDByteArraySize + ownerKeyByteArraySize + nodeToChallengeByteArraySize + encryptedTextByteArraySize + 4 * sizeof(int), + true); + challengeOwnershipPacket->writePrimitive(certIDByteArraySize); + challengeOwnershipPacket->writePrimitive(ownerKeyByteArraySize); + challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize); + challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize); + challengeOwnershipPacket->write(certID); + challengeOwnershipPacket->write(ownerKey); + challengeOwnershipPacket->write(nodeToChallengeByteArray); + challengeOwnershipPacket->write(encryptedText); + 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); + //} + } + } else { + qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error(); + } + + networkReply->deleteLater(); + }); } else { qCWarning(context_overlay) << "Couldn't get Entity Server!"; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 90ee1190d5..71c6864b4f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1237,68 +1237,104 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { int certIDByteArraySize; int ownerKeyByteArraySize; + int encryptedTextByteArraySize; int nodeToChallengeByteArraySize; message.readPrimitive(&certIDByteArraySize); message.readPrimitive(&ownerKeyByteArraySize); + message.readPrimitive(&encryptedTextByteArraySize); message.readPrimitive(&nodeToChallengeByteArraySize); QString certID(message.read(certIDByteArraySize)); QString ownerKey(message.read(ownerKeyByteArraySize)); + QString encryptedText(message.read(encryptedTextByteArraySize)); QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize)); - sendChallengeOwnershipPacket(certID, ownerKey, EntityItemID(), sourceNode, nodeToChallenge); + sendChallengeOwnershipRequestPacket(certID, ownerKey, encryptedText, sourceNode, nodeToChallenge); } -void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) { +void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { + auto nodeList = DependencyManager::get(); + + int certIDByteArraySize; + int decryptedTextByteArraySize; + int senderNodeUUIDByteArraySize; + + message.readPrimitive(&certIDByteArraySize); + message.readPrimitive(&decryptedTextByteArraySize); + message.readPrimitive(&senderNodeUUIDByteArraySize); + + QByteArray certID(message.read(certIDByteArraySize)); + QByteArray decryptedText(message.read(decryptedTextByteArraySize)); + QUuid challengingNode = QUuid::fromRfc4122(message.read(senderNodeUUIDByteArraySize)); + + + + auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, + certIDByteArraySize + decryptedText.length() + 2 * sizeof(int), + true); + challengeOwnershipReplyPacket->writePrimitive(certIDByteArraySize); + challengeOwnershipReplyPacket->writePrimitive(decryptedText.length()); + challengeOwnershipReplyPacket->write(certID); + challengeOwnershipReplyPacket->write(decryptedText); + + nodeList->sendPacket(std::move(challengeOwnershipReplyPacket), *(nodeList->nodeWithUUID(challengingNode))); +} + +void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) { // 1. Encrypt a nonce with the owner's public key auto nodeList = DependencyManager::get(); + QByteArray encryptedText = computeEncryptedNonce(certID, ownerKey); if (encryptedText == "") { - qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce."; + qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity..."; + deleteEntity(entityItemID, true); } 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); + // 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. + // 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 { - 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))); + startChallengeOwnershipTimer(entityItemID); } } } +void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, const QString& ownerKey, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) { + // 1. Encrypt a nonce with the owner's public key + auto nodeList = DependencyManager::get(); + + // 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. + QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122(); + QByteArray encryptedTextByteArray = encryptedText.toUtf8(); + QByteArray certIDByteArray = certID.toUtf8(); + int certIDByteArraySize = certIDByteArray.size(); + auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, + certIDByteArraySize + encryptedTextByteArray.length() + senderNodeUUID.length() + 3 * sizeof(int), + true); + challengeOwnershipPacket->writePrimitive(certIDByteArraySize); + challengeOwnershipPacket->writePrimitive(encryptedTextByteArray.length()); + challengeOwnershipPacket->writePrimitive(senderNodeUUID.length()); + challengeOwnershipPacket->write(certIDByteArray); + challengeOwnershipPacket->write(encryptedTextByteArray); + 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(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 3c11557dac..05b32676ed 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -94,6 +94,7 @@ public: 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 processChallengeOwnershipReplyPacket(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, @@ -274,6 +275,9 @@ public: static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME; + QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey); + bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce); + signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); @@ -376,9 +380,8 @@ protected: Q_INVOKABLE void startPendingTransferStatusTimer(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); 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 sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); + void sendChallengeOwnershipRequestPacket(const QString& certID, const QString& ownerKey, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge); void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); }; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index fe8868b342..ec6a0e810d 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -213,6 +213,7 @@ public: 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 processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } virtual bool recurseChildrenWithData() const { return true; } From f5ada4fe62b94bb1703c18c19a977a51e4ac0bf9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 12:31:42 -0700 Subject: [PATCH 11/42] Will it compile? --- interface/src/commerce/Wallet.h | 1 - .../ui/overlays/ContextOverlayInterface.cpp | 20 +++++++++ .../src/ui/overlays/ContextOverlayInterface.h | 3 ++ libraries/entities/src/EntityTree.cpp | 42 ++++++++++--------- libraries/entities/src/EntityTree.h | 2 +- 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index fcc508b4e9..ed145df451 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -67,7 +67,6 @@ signals: private slots: void handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void handleChallengeOwnershipRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); private: QStringList _publicKeys{}; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index cfc2156a0f..8f6a38ce09 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -71,6 +71,10 @@ ContextOverlayInterface::ContextOverlayInterface() { connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged); + + auto nodeList = DependencyManager::get(); + auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::ChallengeOwnershipReply, this, "handleChallengeOwnershipReplyPacket"); } static const uint32_t MOUSE_HW_ID = 0; @@ -375,3 +379,19 @@ void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { destroyContextOverlay(_currentEntityWithContextOverlay, PointerEvent()); } } + +void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + int certIDByteArraySize; + int decryptedTextByteArraySize; + + packet->readPrimitive(&certIDByteArraySize); + packet->readPrimitive(&decryptedTextByteArraySize); + + QString certID(packet->read(certIDByteArraySize)); + QString decryptedText(packet->read(decryptedTextByteArraySize)); + + EntityItemID id; + bool verificationSuccess = DependencyManager::get()->getTree()->verifyDecryptedNonce(certID, decryptedText, id); + + qDebug() << "ZRF VERIFICATION STATUS:" << verificationSuccess; +} diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index a063fdde23..eedc1790d3 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -70,6 +70,9 @@ public slots: void contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event); bool contextOverlayFilterPassed(const EntityItemID& entityItemID); +private slots: + void handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode); + private: bool _verboseLogging { true }; bool _enabled { true }; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 71c6864b4f..dc99a7b6c9 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1206,9 +1206,7 @@ QByteArray EntityTree::computeEncryptedNonce(const QString& certID, const QStrin } } -bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce) { - - EntityItemID id; +bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id) { { QReadLocker certIdMapLocker(&_entityCertificateIDMapLock); id = _entityCertificateIDMap.value(certID); @@ -1221,14 +1219,12 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr } bool verificationSuccess = (actualNonce == decryptedNonce); - if (!verificationSuccess) { - if (!id.isNull()) { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed; deleting entity" << id - << "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce; - deleteEntity(id, true); - } + + if (verificationSuccess) { + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded for entity" << id; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded; keeping entity" << id; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for entity" << id + << "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce; } return verificationSuccess; @@ -1268,8 +1264,6 @@ void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, QByteArray decryptedText(message.read(decryptedTextByteArraySize)); QUuid challengingNode = QUuid::fromRfc4122(message.read(senderNodeUUIDByteArraySize)); - - auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, certIDByteArraySize + decryptedText.length() + 2 * sizeof(int), true); @@ -1319,19 +1313,24 @@ void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, cons // 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. - QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122(); - QByteArray encryptedTextByteArray = encryptedText.toUtf8(); QByteArray certIDByteArray = certID.toUtf8(); - int certIDByteArraySize = certIDByteArray.size(); + QByteArray encryptedTextByteArray = encryptedText.toUtf8(); + QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122(); + + int certIDByteArraySize = certIDByteArray.length(); + int encryptedTextByteArraySize = encryptedTextByteArray.length(); + int senderNodeUUIDSize = senderNodeUUID.length(); + auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, - certIDByteArraySize + encryptedTextByteArray.length() + senderNodeUUID.length() + 3 * sizeof(int), + certIDByteArraySize + encryptedTextByteArraySize + senderNodeUUIDSize + 3 * sizeof(int), true); challengeOwnershipPacket->writePrimitive(certIDByteArraySize); - challengeOwnershipPacket->writePrimitive(encryptedTextByteArray.length()); - challengeOwnershipPacket->writePrimitive(senderNodeUUID.length()); + challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize); + challengeOwnershipPacket->writePrimitive(senderNodeUUIDSize); challengeOwnershipPacket->write(certIDByteArray); challengeOwnershipPacket->write(encryptedTextByteArray); challengeOwnershipPacket->write(senderNodeUUID); + nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(nodeToChallenge))); } @@ -1408,7 +1407,12 @@ void EntityTree::processChallengeOwnershipPacket(ReceivedMessage& message, const emit killChallengeOwnershipTimeoutTimer(certID); - verifyDecryptedNonce(certID, decryptedText); + EntityItemID id; + if (!verifyDecryptedNonce(certID, decryptedText, id)) { + if (!id.isNull()) { + deleteEntity(id, true); + } + } } int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 05b32676ed..3048917a49 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -276,7 +276,7 @@ public: static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME; QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey); - bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce); + bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id); signals: void deletingEntity(const EntityItemID& entityID); From e9c144892a6d1d3d7e9c17f799b3824097ece56d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 12:55:41 -0700 Subject: [PATCH 12/42] Fixes --- assignment-client/src/entities/EntityServer.cpp | 10 ++++++++-- interface/src/commerce/Wallet.cpp | 2 +- interface/src/ui/overlays/ContextOverlayInterface.cpp | 3 ++- libraries/entities/src/EntityTree.cpp | 4 ++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 702ca88787..3a31b21f08 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -41,8 +41,14 @@ EntityServer::EntityServer(ReceivedMessage& message) : DependencyManager::set(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics, PacketType::ChallengeOwnership }, - this, "handleEntityPacket"); + packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, + PacketType::EntityEdit, + PacketType::EntityErase, + PacketType::EntityPhysics, + PacketType::ChallengeOwnership, + PacketType::ChallengeOwnershipRequest }, + this, + "handleEntityPacket"); connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification); _dynamicDomainVerificationTimer.setSingleShot(true); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 2389e8e39d..4414c7b206 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -734,7 +734,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack QByteArray encryptedText = packet->read(encryptedTextByteArraySize); QByteArray senderNodeUUID; if (challengeOriginatedFromClient) { - packet->readPrimitive(&senderNodeUUID); + senderNodeUUID = packet->read(senderNodeUUIDByteArraySize); } RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 8f6a38ce09..85bdef22ca 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -337,7 +337,8 @@ void ContextOverlayInterface::openInspectionCertificate() { //} } } else { - qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error(); + qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << + "More info:" << networkReply->readAll(); } networkReply->deleteLater(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index dc99a7b6c9..ba84c45311 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1238,13 +1238,13 @@ void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message message.readPrimitive(&certIDByteArraySize); message.readPrimitive(&ownerKeyByteArraySize); - message.readPrimitive(&encryptedTextByteArraySize); message.readPrimitive(&nodeToChallengeByteArraySize); + message.readPrimitive(&encryptedTextByteArraySize); QString certID(message.read(certIDByteArraySize)); QString ownerKey(message.read(ownerKeyByteArraySize)); - QString encryptedText(message.read(encryptedTextByteArraySize)); QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize)); + QString encryptedText(message.read(encryptedTextByteArraySize)); sendChallengeOwnershipRequestPacket(certID, ownerKey, encryptedText, sourceNode, nodeToChallenge); } From d49e281fabfffeb6fede7d7e0dff13d03f3981cf Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 14:12:30 -0700 Subject: [PATCH 13/42] Add RSA error handling --- interface/src/commerce/Wallet.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 4414c7b206..acc0b08afb 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -740,6 +740,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); if (rsa) { + ERR_clear_error(); const int decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, reinterpret_cast(encryptedText.constData()), decryptedText, @@ -784,6 +785,11 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack } } else { qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; + long error = ERR_get_error(); + if (error != 0) { + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "RSA error:" << error_str; + } } } else { qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed."; From f9a410de873679b5371ebe6d8f6039a6de6d62d9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Oct 2017 14:53:37 -0700 Subject: [PATCH 14/42] Change 'GET' to 'BUY' when hovering over costed items --- scripts/system/html/js/marketplacesInject.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 8deb5c0bbd..4b127baef8 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -290,11 +290,17 @@ } }); - // change pricing to GET on button hover + // change pricing to GET/BUY on button hover $('body').on('mouseenter', '#price-or-edit .price', function () { var $this = $(this); $this.data('initialHtml', $this.html()); - $this.text('GET'); + + var cost = $(this).parent().siblings().text(); + if (parseInt(cost) > 0) { + $this.text('BUY'); + } else { + $this.text('GET'); + } }); $('body').on('mouseleave', '#price-or-edit .price', function () { From b8370128ced4dea2e27a7f0ef7de6cdc7e9875f2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 31 Oct 2017 14:34:17 -0700 Subject: [PATCH 15/42] remove master config from HifiConfigVariantMap/domain-server --- .../src/DomainServerSettingsManager.cpp | 28 +---------------- libraries/shared/src/HifiConfigVariantMap.cpp | 30 +------------------ libraries/shared/src/HifiConfigVariantMap.h | 6 ---- 3 files changed, 2 insertions(+), 62 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 43262a1a81..d3360d9ded 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -100,8 +100,7 @@ void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer Date: Tue, 31 Oct 2017 15:59:18 -0700 Subject: [PATCH 16/42] Why did I think this would work before? --- interface/src/commerce/Wallet.cpp | 1 + .../ui/overlays/ContextOverlayInterface.cpp | 124 +++++++++--------- libraries/entities/src/EntityTree.cpp | 18 +-- libraries/entities/src/EntityTree.h | 2 +- 4 files changed, 73 insertions(+), 72 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index acc0b08afb..d0ef3fcaae 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -732,6 +732,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack QByteArray certID = packet->read(certIDByteArraySize); QByteArray encryptedText = packet->read(encryptedTextByteArraySize); + qDebug() << "ZRF encryptedText Inbound:" << QString(encryptedText); QByteArray senderNodeUUID; if (challengeOriginatedFromClient) { senderNodeUUID = packet->read(senderNodeUUIDByteArraySize); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 85bdef22ca..eecf93745a 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -277,74 +277,78 @@ void ContextOverlayInterface::openInspectionCertificate() { // ZRF FIXME: Don't challenge ownership of avatar entities that I own if (entityProperties.getClientOnly()/* && nodeToChallenge != nodeList->getSessionUUID()*/) { - SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); + // ZRF FIXME! + //if (entityProperties.verifyStaticCertificateProperties()) { + if (true) { + SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); - if (entityServer) { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL; - requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); - QJsonObject request; - request["certificate_id"] = entityProperties.getCertificateID(); - networkRequest.setUrl(requestURL); + if (entityServer) { + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest; + networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL; + requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); + QJsonObject request; + request["certificate_id"] = entityProperties.getCertificateID(); + networkRequest.setUrl(requestURL); - QNetworkReply* networkReply = NULL; - networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); + QNetworkReply* networkReply = NULL; + networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - connect(networkReply, &QNetworkReply::finished, [=]() { - QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); - jsonObject = jsonObject["data"].toObject(); + connect(networkReply, &QNetworkReply::finished, [=]() { + QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); + jsonObject = jsonObject["data"].toObject(); - if (networkReply->error() == QNetworkReply::NoError) { - if (!jsonObject["invalid_reason"].toString().isEmpty()) { - qCDebug(entities) << "invalid_reason not empty"; - } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { - qCDebug(entities) << "'transfer_status' is 'failed'";; - } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { - qCDebug(entities) << "'transfer_status' is 'pending'";; + if (networkReply->error() == QNetworkReply::NoError) { + if (!jsonObject["invalid_reason"].toString().isEmpty()) { + qCDebug(entities) << "invalid_reason not empty"; + } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { + qCDebug(entities) << "'transfer_status' is 'failed'";; + } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { + qCDebug(entities) << "'transfer_status' is 'pending'";; + } else { + QString ownerKey = jsonObject["transfer_recipient_key"].toString(); + + QByteArray certID = entityProperties.getCertificateID().toUtf8(); + QByteArray encryptedText = DependencyManager::get()->getTree()->computeEncryptedNonce(certID, ownerKey); + QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122(); + + int certIDByteArraySize = certID.length(); + int encryptedTextByteArraySize = encryptedText.length(); + int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length(); + + auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, + certIDByteArraySize + encryptedTextByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int), + true); + challengeOwnershipPacket->writePrimitive(certIDByteArraySize); + challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize); + challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize); + challengeOwnershipPacket->write(certID); + challengeOwnershipPacket->write(encryptedText); + challengeOwnershipPacket->write(nodeToChallengeByteArray); + 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); + //} + } } else { - QByteArray certID = entityProperties.getCertificateID().toUtf8(); - QByteArray ownerKey = jsonObject["transfer_recipient_key"].toString().toUtf8(); - QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122(); - QByteArray encryptedText = DependencyManager::get()->getTree()->computeEncryptedNonce(certID, ownerKey); - - int certIDByteArraySize = certID.length(); - int ownerKeyByteArraySize = ownerKey.length(); - int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length(); - int encryptedTextByteArraySize = encryptedText.length(); - - auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, - certIDByteArraySize + ownerKeyByteArraySize + nodeToChallengeByteArraySize + encryptedTextByteArraySize + 4 * sizeof(int), - true); - challengeOwnershipPacket->writePrimitive(certIDByteArraySize); - challengeOwnershipPacket->writePrimitive(ownerKeyByteArraySize); - challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize); - challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize); - challengeOwnershipPacket->write(certID); - challengeOwnershipPacket->write(ownerKey); - challengeOwnershipPacket->write(nodeToChallengeByteArray); - challengeOwnershipPacket->write(encryptedText); - 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); - //} + qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << + "More info:" << networkReply->readAll(); } - } else { - qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << - "More info:" << networkReply->readAll(); - } - networkReply->deleteLater(); - }); + networkReply->deleteLater(); + }); + } else { + qCWarning(context_overlay) << "Couldn't get Entity Server!"; + } } else { - qCWarning(context_overlay) << "Couldn't get Entity Server!"; + qCDebug(context_overlay) << "Entity" << _currentEntityWithContextOverlay << "failed static certificate verification!"; } } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba84c45311..1cf9fdfb26 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -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) { @@ -1195,7 +1195,6 @@ QByteArray EntityTree::computeEncryptedNonce(const QString& certID, const QStrin QWriteLocker locker(&_certNonceMapLock); _certNonceMap.insert(certID, nonce); - qCDebug(entities) << "Challenging ownership of Cert ID" << certID << "by encrypting and sending nonce" << nonce << "to owner."; return encryptedText; } else { @@ -1232,21 +1231,18 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { int certIDByteArraySize; - int ownerKeyByteArraySize; int encryptedTextByteArraySize; int nodeToChallengeByteArraySize; message.readPrimitive(&certIDByteArraySize); - message.readPrimitive(&ownerKeyByteArraySize); - message.readPrimitive(&nodeToChallengeByteArraySize); message.readPrimitive(&encryptedTextByteArraySize); + message.readPrimitive(&nodeToChallengeByteArraySize); QString certID(message.read(certIDByteArraySize)); - QString ownerKey(message.read(ownerKeyByteArraySize)); - QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize)); QString encryptedText(message.read(encryptedTextByteArraySize)); + QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize)); - sendChallengeOwnershipRequestPacket(certID, ownerKey, encryptedText, sourceNode, nodeToChallenge); + sendChallengeOwnershipRequestPacket(certID, encryptedText, sourceNode, nodeToChallenge); } void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { @@ -1285,6 +1281,7 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity..."; deleteEntity(entityItemID, true); } else { + qCDebug(entities) << "Challenging ownership of Cert ID" << certID; // 2. Send the encrypted text to the rezzing avatar's node QByteArray certIDByteArray = certID.toUtf8(); int certIDByteArraySize = certIDByteArray.size(); @@ -1307,8 +1304,7 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri } } -void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, const QString& ownerKey, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) { - // 1. Encrypt a nonce with the owner's public key +void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) { auto nodeList = DependencyManager::get(); // In this case, Client A is challenging Client B. Client A is inspecting a certified entity that it wants diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 3048917a49..5eb5d5b569 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -381,7 +381,7 @@ protected: private: void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); - void sendChallengeOwnershipRequestPacket(const QString& certID, const QString& ownerKey, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge); + void sendChallengeOwnershipRequestPacket(const QString& certID, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge); void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); }; From 7616fe193cff920299d44b39cc98c7e97efe8029 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 31 Oct 2017 16:09:26 -0700 Subject: [PATCH 17/42] Migrate the DS config version to the config file --- .../src/DomainServerSettingsManager.cpp | 54 +++++++++++-------- libraries/shared/src/HifiConfigVariantMap.cpp | 6 --- libraries/shared/src/HifiConfigVariantMap.h | 1 - libraries/shared/src/SettingHelpers.cpp | 6 +++ libraries/shared/src/SettingHelpers.h | 7 +-- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index d3360d9ded..6c50e5245d 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include //for KillAvatarReason #include #include "DomainServerNodeData.h" @@ -43,12 +44,7 @@ const QString DESCRIPTION_COLUMNS_KEY = "columns"; const QString SETTINGS_VIEWPOINT_KEY = "viewpoint"; -static Setting::Handle JSON_SETTING_VERSION("json-settings/version", 0.0); - -DomainServerSettingsManager::DomainServerSettingsManager() : - _descriptionArray(), - _configMap() -{ +DomainServerSettingsManager::DomainServerSettingsManager() { // load the description object from the settings description QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH); descriptionFile.open(QIODevice::ReadOnly); @@ -102,9 +98,32 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList _configMap.loadConfig(_argumentList); + static const auto VERSION_SETTINGS_KEYPATH = "version"; + QVariant* versionVariant = _configMap.valueForKeyPath(VERSION_SETTINGS_KEYPATH); + + if (!versionVariant) { + versionVariant = _configMap.valueForKeyPath(VERSION_SETTINGS_KEYPATH, true); + *versionVariant = _descriptionVersion; + persistToFile(); + qDebug() << "No version in config file, setting to current version" << _descriptionVersion; + } + + { + // Backward compatibility migration code + // The config version used to be stored in a different file + // This moves it to the actual config file. + Setting::Handle JSON_SETTING_VERSION("json-settings/version", 0.0); + if (JSON_SETTING_VERSION.isSet()) { + auto version = JSON_SETTING_VERSION.get(); + *versionVariant = version; + persistToFile(); + QFile::remove(settingsFilename()); + } + } + // What settings version were we before and what are we using now? // Do we need to do any re-mapping? - double oldVersion = JSON_SETTING_VERSION.get(); + double oldVersion = versionVariant->toDouble(); if (oldVersion != _descriptionVersion) { const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; @@ -136,9 +155,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList QVariant* restrictedAccess = _configMap.valueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH, true); *restrictedAccess = QVariant(true); - - // write the new settings to the json file - persistToFile(); } } @@ -168,9 +184,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList *entityServerVariant = entityServerMap; } - - // write the new settings to the json file - persistToFile(); } } @@ -188,9 +201,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList qDebug() << "Migrating plaintext password to SHA256 hash in domain-server settings."; *passwordVariant = QCryptographicHash::hash(plaintextPassword.toUtf8(), QCryptographicHash::Sha256).toHex(); - - // write the new settings to file - persistToFile(); } } @@ -293,16 +303,16 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList QVariant* wizardCompletedOnce = _configMap.valueForKeyPath(WIZARD_COMPLETED_ONCE, true); *wizardCompletedOnce = QVariant(true); - - // write the new settings to the json file - persistToFile(); } + + // write the current description version to our settings + *versionVariant = _descriptionVersion; + + // write the new settings to the json file + persistToFile(); } unpackPermissions(); - - // write the current description version to our settings - JSON_SETTING_VERSION.set(_descriptionVersion); } QVariantMap& DomainServerSettingsManager::getDescriptorsMap() { diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 8730906afc..59f660feee 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -91,12 +91,6 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL return mergedMap; } -HifiConfigVariantMap::HifiConfigVariantMap() : - _userConfigFilename() -{ - -} - void HifiConfigVariantMap::loadConfig(const QStringList& argumentList) { // load the user config const QString USER_CONFIG_FILE_OPTION = "--user-config"; diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index e9db93173a..ee248ec3d2 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -21,7 +21,6 @@ class HifiConfigVariantMap { public: static QVariantMap mergeCLParametersWithJSONConfig(const QStringList& argumentList); - HifiConfigVariantMap(); void loadConfig(const QStringList& argumentList); const QVariant value(const QString& key) const { return _userConfig.value(key); } diff --git a/libraries/shared/src/SettingHelpers.cpp b/libraries/shared/src/SettingHelpers.cpp index dd301aa5aa..c6b8ac8f83 100644 --- a/libraries/shared/src/SettingHelpers.cpp +++ b/libraries/shared/src/SettingHelpers.cpp @@ -23,9 +23,15 @@ #include "SharedLogging.h" +const QSettings::Format JSON_FORMAT = QSettings::registerFormat("json", readJSONFile, writeJSONFile); + QSettings::SettingsMap jsonDocumentToVariantMap(const QJsonDocument& document); QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map); +QString settingsFilename() { + return QSettings().fileName(); +} + bool readJSONFile(QIODevice& device, QSettings::SettingsMap& map) { QJsonParseError jsonParseError; diff --git a/libraries/shared/src/SettingHelpers.h b/libraries/shared/src/SettingHelpers.h index 122e56957c..ad61897c65 100644 --- a/libraries/shared/src/SettingHelpers.h +++ b/libraries/shared/src/SettingHelpers.h @@ -14,12 +14,13 @@ #include +extern const QSettings::Format JSON_FORMAT; + +QString settingsFilename(); + bool readJSONFile(QIODevice& device, QSettings::SettingsMap& map); bool writeJSONFile(QIODevice& device, const QSettings::SettingsMap& map); -static const auto JSON_FORMAT = QSettings::registerFormat("json", readJSONFile, writeJSONFile); - void loadOldINIFile(QSettings& settings); - #endif // hifi_SettingHelpers_h From 8a6a744099ed41a56afd89f2628a6f2e4aa45300 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Nov 2017 10:46:13 -0700 Subject: [PATCH 18/42] It's working --- .../src/entities/EntityServer.cpp | 3 +- interface/src/commerce/Ledger.h | 8 ++++++ interface/src/commerce/Wallet.cpp | 15 +++++----- .../ui/overlays/ContextOverlayInterface.cpp | 11 +++++++- libraries/entities/src/EntityTree.cpp | 28 +++++++++---------- libraries/entities/src/EntityTree.h | 2 +- 6 files changed, 41 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 3a31b21f08..995a5bad27 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -46,7 +46,8 @@ EntityServer::EntityServer(ReceivedMessage& message) : PacketType::EntityErase, PacketType::EntityPhysics, PacketType::ChallengeOwnership, - PacketType::ChallengeOwnershipRequest }, + PacketType::ChallengeOwnershipRequest, + PacketType::ChallengeOwnershipReply }, this, "handleEntityPacket"); diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index ae001010f0..75f6fb1ba8 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -65,6 +65,14 @@ 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/Wallet.cpp b/interface/src/commerce/Wallet.cpp index d0ef3fcaae..c31184eb56 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -722,20 +722,19 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack unsigned char decryptedText[64]; int certIDByteArraySize; int encryptedTextByteArraySize; - int senderNodeUUIDByteArraySize; + int challengingNodeUUIDByteArraySize; packet->readPrimitive(&certIDByteArraySize); packet->readPrimitive(&encryptedTextByteArraySize); if (challengeOriginatedFromClient) { - packet->readPrimitive(&senderNodeUUIDByteArraySize); + packet->readPrimitive(&challengingNodeUUIDByteArraySize); } QByteArray certID = packet->read(certIDByteArraySize); QByteArray encryptedText = packet->read(encryptedTextByteArraySize); - qDebug() << "ZRF encryptedText Inbound:" << QString(encryptedText); - QByteArray senderNodeUUID; + QByteArray challengingNodeUUID; if (challengeOriginatedFromClient) { - senderNodeUUID = packet->read(senderNodeUUIDByteArraySize); + challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize); } RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); @@ -759,15 +758,15 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack // setup the packet if (challengeOriginatedFromClient) { auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, - certIDSize + decryptedTextByteArraySize + senderNodeUUIDByteArraySize + 3 * sizeof(int), + certIDSize + decryptedTextByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int), true); decryptedTextPacket->writePrimitive(certIDSize); decryptedTextPacket->writePrimitive(decryptedTextByteArraySize); - decryptedTextPacket->writePrimitive(senderNodeUUIDByteArraySize); + decryptedTextPacket->writePrimitive(challengingNodeUUIDByteArraySize); decryptedTextPacket->write(certID); decryptedTextPacket->write(decryptedTextByteArray); - decryptedTextPacket->write(senderNodeUUID); + decryptedTextPacket->write(challengingNodeUUID); qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index eecf93745a..48f2394ca3 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -348,6 +349,8 @@ void ContextOverlayInterface::openInspectionCertificate() { qCWarning(context_overlay) << "Couldn't get Entity Server!"; } } else { + auto ledger = DependencyManager::get(); + emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED)); qCDebug(context_overlay) << "Entity" << _currentEntityWithContextOverlay << "failed static certificate verification!"; } } @@ -386,6 +389,8 @@ void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { } void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + auto ledger = DependencyManager::get(); + int certIDByteArraySize; int decryptedTextByteArraySize; @@ -398,5 +403,9 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer EntityItemID id; bool verificationSuccess = DependencyManager::get()->getTree()->verifyDecryptedNonce(certID, decryptedText, id); - qDebug() << "ZRF VERIFICATION STATUS:" << verificationSuccess; + if (verificationSuccess) { + emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS)); + } else { + emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED)); + } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1cf9fdfb26..f748291077 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1238,11 +1238,11 @@ void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message message.readPrimitive(&encryptedTextByteArraySize); message.readPrimitive(&nodeToChallengeByteArraySize); - QString certID(message.read(certIDByteArraySize)); - QString encryptedText(message.read(encryptedTextByteArraySize)); - QUuid nodeToChallenge = QUuid::fromRfc4122(message.read(nodeToChallengeByteArraySize)); + QByteArray certID(message.read(certIDByteArraySize)); + QByteArray encryptedText(message.read(encryptedTextByteArraySize)); + QByteArray nodeToChallenge(message.read(nodeToChallengeByteArraySize)); - sendChallengeOwnershipRequestPacket(certID, encryptedText, sourceNode, nodeToChallenge); + sendChallengeOwnershipRequestPacket(certID, encryptedText, nodeToChallenge, sourceNode); } void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { @@ -1250,15 +1250,15 @@ void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, int certIDByteArraySize; int decryptedTextByteArraySize; - int senderNodeUUIDByteArraySize; + int challengingNodeUUIDByteArraySize; message.readPrimitive(&certIDByteArraySize); message.readPrimitive(&decryptedTextByteArraySize); - message.readPrimitive(&senderNodeUUIDByteArraySize); + message.readPrimitive(&challengingNodeUUIDByteArraySize); QByteArray certID(message.read(certIDByteArraySize)); QByteArray decryptedText(message.read(decryptedTextByteArraySize)); - QUuid challengingNode = QUuid::fromRfc4122(message.read(senderNodeUUIDByteArraySize)); + QUuid challengingNode = QUuid::fromRfc4122(message.read(challengingNodeUUIDByteArraySize)); auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, certIDByteArraySize + decryptedText.length() + 2 * sizeof(int), @@ -1304,17 +1304,15 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri } } -void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge) { +void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode) { auto nodeList = DependencyManager::get(); // 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. - QByteArray certIDByteArray = certID.toUtf8(); - QByteArray encryptedTextByteArray = encryptedText.toUtf8(); QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122(); - int certIDByteArraySize = certIDByteArray.length(); - int encryptedTextByteArraySize = encryptedTextByteArray.length(); + int certIDByteArraySize = certID.length(); + int encryptedTextByteArraySize = encryptedText.length(); int senderNodeUUIDSize = senderNodeUUID.length(); auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, @@ -1323,11 +1321,11 @@ void EntityTree::sendChallengeOwnershipRequestPacket(const QString& certID, cons challengeOwnershipPacket->writePrimitive(certIDByteArraySize); challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize); challengeOwnershipPacket->writePrimitive(senderNodeUUIDSize); - challengeOwnershipPacket->write(certIDByteArray); - challengeOwnershipPacket->write(encryptedTextByteArray); + challengeOwnershipPacket->write(certID); + challengeOwnershipPacket->write(encryptedText); challengeOwnershipPacket->write(senderNodeUUID); - nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(nodeToChallenge))); + nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(QUuid::fromRfc4122(nodeToChallenge)))); } void EntityTree::validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 5eb5d5b569..86bfe984f6 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -381,7 +381,7 @@ protected: private: void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); - void sendChallengeOwnershipRequestPacket(const QString& certID, const QString& encryptedText, const SharedNodePointer& senderNode, const QUuid& nodeToChallenge); + void sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode); void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); }; From 3d3c93f1a581a769001f58307e328a80d889f44f Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 1 Nov 2017 11:23:18 -0700 Subject: [PATCH 19/42] Fixes Bug 8802 --- libraries/entities/src/EntityPropertyFlags.h | 36 +++++++++---------- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index c20b362b04..f0f22b0091 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -202,6 +202,24 @@ enum EntityPropertyList { PROP_ENTITY_INSTANCE_NUMBER, PROP_CERTIFICATE_ID, + PROP_HAZE_MODE, + + PROP_HAZE_RANGE, + PROP_HAZE_COLOR, + PROP_HAZE_GLARE_COLOR, + PROP_HAZE_ENABLE_GLARE, + PROP_HAZE_GLARE_ANGLE, + + PROP_HAZE_ALTITUDE_EFFECT, + PROP_HAZE_CEILING, + PROP_HAZE_BASE_REF, + + PROP_HAZE_BACKGROUND_BLEND, + + PROP_HAZE_ATTENUATE_KEYLIGHT, + PROP_HAZE_KEYLIGHT_RANGE, + PROP_HAZE_KEYLIGHT_ALTITUDE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, @@ -234,24 +252,6 @@ enum EntityPropertyList { PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX, PROP_BACKGROUND_MODE = PROP_MODEL_URL, - PROP_HAZE_MODE = PROP_COLOR, - - PROP_HAZE_RANGE = PROP_INTENSITY, - PROP_HAZE_COLOR = PROP_CUTOFF, - PROP_HAZE_GLARE_COLOR = PROP_EXPONENT, - PROP_HAZE_ENABLE_GLARE = PROP_IS_SPOTLIGHT, - PROP_HAZE_GLARE_ANGLE = PROP_DIFFUSE_COLOR, - - PROP_HAZE_ALTITUDE_EFFECT = PROP_AMBIENT_COLOR_UNUSED, - PROP_HAZE_CEILING = PROP_SPECULAR_COLOR_UNUSED, - PROP_HAZE_BASE_REF = PROP_LINEAR_ATTENUATION_UNUSED, - - PROP_HAZE_BACKGROUND_BLEND = PROP_QUADRATIC_ATTENUATION_UNUSED, - - PROP_HAZE_ATTENUATE_KEYLIGHT = PROP_ANIMATION_FRAME_INDEX, - PROP_HAZE_KEYLIGHT_RANGE = PROP_MODEL_URL, - PROP_HAZE_KEYLIGHT_ALTITUDE = PROP_ANIMATION_URL, - PROP_SKYBOX_COLOR = PROP_ANIMATION_URL, PROP_SKYBOX_URL = PROP_ANIMATION_FPS, PROP_KEYLIGHT_AMBIENT_URL = PROP_ANIMATION_PLAYING, diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 09ee41b31d..9a98393fa1 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::HasDynamicOwnershipTests); + return static_cast(EntityVersion::HazeEffect); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::JSONFilterWithFamilyTree); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 049cb0f1a8..e00b4139c3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -196,7 +196,8 @@ QDebug operator<<(QDebug debug, const PacketType& type); enum class EntityVersion : PacketVersion { StrokeColorProperty = 77, - HasDynamicOwnershipTests + HasDynamicOwnershipTests, + HazeEffect }; enum class EntityScriptCallMethodVersion : PacketVersion { From b335ba9a75f92c50a2fdde765201f5203b16da66 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Nov 2017 11:34:29 -0700 Subject: [PATCH 20/42] 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; } From 56cb98d96f64f9f3f4458ae072c3507a4db0b268 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Nov 2017 12:02:09 -0700 Subject: [PATCH 21/42] Make inspection cert work --- .../InspectionCertificate.qml | 40 +++++++++---------- .../ui/overlays/ContextOverlayInterface.cpp | 3 +- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index 06e04d6929..bd8808f05f 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -67,27 +67,25 @@ 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!"); - } + if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS + // NOP + } 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!"); } } } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 75aefdc585..5990c710ad 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -279,8 +279,7 @@ void ContextOverlayInterface::openInspectionCertificate() { 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()*/) { + if (entityProperties.getClientOnly()) { if (entityProperties.verifyStaticCertificateProperties()) { SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); From 72d61f1825c83023029936930b1437c626c12715 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Nov 2017 12:03:44 -0700 Subject: [PATCH 22/42] Remove unnecessary log - static verif isn't working --- interface/src/ui/overlays/ContextOverlayInterface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 5990c710ad..e6568b56dd 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -418,8 +418,6 @@ 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 { From edc7b91a425353b47f38a98ad94ad8ced981229d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Nov 2017 12:57:07 -0700 Subject: [PATCH 23/42] Fix comment in NetworkingConstants referencing shared.js location --- libraries/networking/src/NetworkingConstants.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h index 0bb0cee5d2..0c210e4360 100644 --- a/libraries/networking/src/NetworkingConstants.h +++ b/libraries/networking/src/NetworkingConstants.h @@ -16,8 +16,8 @@ namespace NetworkingConstants { // If you want to use STAGING instead of STABLE, - // don't forget to ALSO change the Domain Server Metaverse Server URL, which is at the top of: - // \domain-server\resources\web\settings\js\settings.js + // don't forget to ALSO change the Domain Server Metaverse Server URL inside of: + // \domain-server\resources\web\js\shared.js const QUrl METAVERSE_SERVER_URL_STABLE("https://metaverse.highfidelity.com"); const QUrl METAVERSE_SERVER_URL_STAGING("https://staging.highfidelity.com"); const QUrl METAVERSE_SERVER_URL = METAVERSE_SERVER_URL_STABLE; From 8401aecef566c642c942e60f30975c186e4d5158 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Nov 2017 15:42:35 -0700 Subject: [PATCH 24/42] Update wizard to make request for domain info --- domain-server/resources/web/js/shared.js | 384 +++++++++++------- .../resources/web/settings/js/settings.js | 16 - .../resources/web/wizard/js/wizard.js | 1 + 3 files changed, 227 insertions(+), 174 deletions(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index a5dd522a53..4db608ddb4 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -146,187 +146,255 @@ function sendUpdatePlaceRequest(id, path, domainID, clearDomainID, onSuccess, on }); } +var pendingDomainRequest = null; +function getDomainFromAPI(callback) { + if (pendingDomainRequest !== null) { + pendingDomainRequest.success(callback); + pendingDomainRequest.error(function() { callback({ status: 'fail' }) }); + return pendingDomainRequest; + } + + if (callback === undefined) { + callback = function() {}; + } + + var domainID = Settings.data.values.metaverse.id; + if (domainID === null || domainID === undefined || domainID === '') { + callback({ status: 'fail' }); + return null; + } + + pendingDomainRequest = $.ajax({ + url: "/api/domains/" + domainID, + dataType: 'json', + success: function(data) { + pendingDomainRequest = null; + + if (data.status === 'success') { + DomainInfo = data.domain; + } else { + DomainInfo = null; + } + callback(data); + }, + error: function() { + pendingDomainRequest = null; + + DomainInfo = null; + callback({ status: 'fail' }); + } + }); + + return pendingDomainRequest; +} + function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded) { if (accessToken) { var loadingDialog = showLoadingDialog(Strings.ADD_PLACE_LOADING_DIALOG); - $.ajax("/api/places", { - dataType: 'json', - jsonp: false, - success: function(data) { - if (data.status == 'success') { - var modal_buttons = { - cancel: { - label: Strings.ADD_PLACE_CANCEL_BUTTON, - className: 'add-place-cancel-button btn-default' - } - }; - - var dialog; - var modal_body; - - if (data.data.places.length) { - var places_by_id = {}; - - modal_body = $('
'); - - modal_body.append($("

Choose a place name that you own or register a new place name

")); - - var currentDomainIDType = getCurrentDomainIDType(); - if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) { - var warning = "
"; - warning += "If you choose a place name it will replace your current temporary place name."; - warning += "
"; - modal_body.append(warning); - } - - // setup a select box for the returned places - modal_body.append($("")); - place_select = $(""); - _.each(data.data.places, function(place) { - places_by_id[place.id] = place; - place_select.append(""); - }) - modal_body.append(place_select); - modal_body.append($("")); - - if (forcePathTo === undefined || forcePathTo === null) { - var path = "
"; - path += ""; - path += ""; - path += "
"; - modal_body.append($(path)); - } - - var place_select = modal_body.find("#place-name-select") - place_select.change(function(ev) { - var warning = modal_body.find("#place-name-warning"); - var place = places_by_id[$(this).val()]; - if (place === undefined || place.pointee === null) { - warning.hide(); - } else { - warning.show(); + function loadPlaces() { + $.ajax("/api/places", { + dataType: 'json', + jsonp: false, + success: function(data) { + if (data.status == 'success') { + var modal_buttons = { + cancel: { + label: Strings.ADD_PLACE_CANCEL_BUTTON, + className: 'add-place-cancel-button btn-default' } - }); - place_select.trigger('change'); + }; - modal_buttons["success"] = { - label: Strings.ADD_PLACE_CONFIRM_BUTTON, - className: 'add-place-confirm-button btn btn-primary', - callback: function() { - var placeID = $('#place-name-select').val(); - // set the place ID on the form - $(Settings.place_ID_SELECTOR).val(placeID).change(); + var dialog; + var modal_body; - if (forcePathTo === undefined || forcePathTo === null) { - var placePath = $('#place-path-input').val(); + if (data.data.places.length) { + var places_by_id = {}; + + modal_body = $('
'); + + modal_body.append($("

Choose a place name that you own or register a new place name

")); + + var currentDomainIDType = getCurrentDomainIDType(); + if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) { + var warning = "
"; + warning += "If you choose a place name it will replace your current temporary place name."; + warning += "
"; + modal_body.append(warning); + } + + // setup a select box for the returned places + modal_body.append($("")); + place_select = $(""); + _.each(data.data.places, function(place) { + places_by_id[place.id] = place; + place_select.append(""); + }) + modal_body.append(place_select); + modal_body.append($("")); + + if (forcePathTo === undefined || forcePathTo === null) { + var path = "
"; + path += ""; + path += ""; + path += "
"; + modal_body.append($(path)); + } + + var place_select = modal_body.find("#place-name-select") + place_select.change(function(ev) { + var warning = modal_body.find("#place-name-warning"); + var place = places_by_id[$(this).val()]; + if (place === undefined || place.pointee === null) { + warning.hide(); } else { - var placePath = forcePathTo; + warning.show(); } + }); + place_select.trigger('change'); - $('.add-place-confirm-button').attr('disabled', 'disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING); - $('.add-place-cancel-button').attr('disabled', 'disabled'); + modal_buttons["success"] = { + label: Strings.ADD_PLACE_CONFIRM_BUTTON, + className: 'add-place-confirm-button btn btn-primary', + callback: function() { + var placeID = $('#place-name-select').val(); + // set the place ID on the form + $(Settings.place_ID_SELECTOR).val(placeID).change(); - function finalizeSaveDomainID(domainID) { - var jsonSettings = { - metaverse: { - id: domainID + if (forcePathTo === undefined || forcePathTo === null) { + var placePath = $('#place-path-input').val(); + } else { + var placePath = forcePathTo; + } + + $('.add-place-confirm-button').attr('disabled', 'disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING); + $('.add-place-cancel-button').attr('disabled', 'disabled'); + + function finalizeSaveDomainID(domainID) { + var jsonSettings = { + metaverse: { + id: domainID + } + } + var dialog = showLoadingDialog("Waiting for Domain Server to restart..."); + $.ajax('/settings.json', { + data: JSON.stringify(jsonSettings), + contentType: 'application/json', + type: 'POST' + }).done(function(data) { + if (data.status == "success") { + waitForDomainServerRestart(function() { + dialog.modal('hide'); + if (onSuccessfullyAdded) { + onSuccessfullyAdded(places_by_id[placeID].name, domainID); + } + }); + } else { + bootbox.alert("Failed to add place"); + } + }).fail(function() { + bootbox.alert("Failed to add place"); + }); + } + + function finishSettingUpPlace(domainID) { + sendUpdatePlaceRequest( + placeID, + placePath, + domainID, + false, + function(data) { + $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); + dialog.modal('hide') + if (domainID) { + finalizeSaveDomainID(domainID); + } else { + if (onSuccessfullyAdded) { + onSuccessfullyAdded(places_by_id[placeID].name); + } + } + }, + function(data) { + $('.add-place-confirm-button').removeAttr('disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); + $('.add-place-cancel-button').removeAttr('disabled'); + bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); + } + ); + } + + function maybeCreateNewDomainID() { + console.log("Maybe creating domain id", currentDomainIDType) + if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) { + finishSettingUpPlace(); + } else { + sendCreateDomainRequest(function(domainID) { + console.log("Created domain", domainID); + finishSettingUpPlace(domainID); + }, function() { + $('.add-place-confirm-button').removeAttr('disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); + $('.add-place-cancel-button').removeAttr('disabled'); + bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); + bootbox.alert("FAIL"); + }); } } - var dialog = showLoadingDialog("Waiting for Domain Server to restart..."); - $.ajax('/settings.json', { - data: JSON.stringify(jsonSettings), - contentType: 'application/json', - type: 'POST' - }).done(function(data) { - if (data.status == "success") { - waitForDomainServerRestart(function() { - dialog.modal('hide'); - if (onSuccessfullyAdded) { - onSuccessfullyAdded(places_by_id[placeID].name, domainID); - } - }); - } else { - bootbox.alert("Failed to add place"); - } - }).fail(function() { - bootbox.alert("Failed to add place"); - }); - } - function finishSettingUpPlace(domainID) { - sendUpdatePlaceRequest( - placeID, - placePath, - domainID, - false, - function(data) { - $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); - dialog.modal('hide') - if (domainID) { - finalizeSaveDomainID(domainID); - } else { - if (onSuccessfullyAdded) { - onSuccessfullyAdded(places_by_id[placeID].name); - } - } - }, - function(data) { - $('.add-place-confirm-button').removeAttr('disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); - $('.add-place-cancel-button').removeAttr('disabled'); - bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); - } - ); - } + maybeCreateNewDomainID(); - if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) { - finishSettingUpPlace(); - } else { - sendCreateDomainRequest(function(domainID) { - console.log("Created domain", domainID); - finishSettingUpPlace(domainID); - }, function() { - $('.add-place-confirm-button').removeAttr('disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); - $('.add-place-cancel-button').removeAttr('disabled'); - bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); - bootbox.alert("FAIL"); - }); + return false; } - - return false; } + } else { + modal_buttons["success"] = { + label: Strings.ADD_PLACE_NO_PLACES_BUTTON, + callback: function() { + window.open(URLs.METAVERSE_URL + "/user/places", '_blank'); + } + } + modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE; } + + dialog = bootbox.dialog({ + title: Strings.ADD_PLACE_TITLE, + message: modal_body, + closeButton: false, + buttons: modal_buttons + }); } else { - modal_buttons["success"] = { - label: Strings.ADD_PLACE_NO_PLACES_BUTTON, - callback: function() { - window.open(URLs.METAVERSE_URL + "/user/places", '_blank'); - } - } - modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE; + bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); } - - dialog = bootbox.dialog({ - title: Strings.ADD_PLACE_TITLE, - message: modal_body, - closeButton: false, - buttons: modal_buttons - }); - } else { + }, + error: function() { bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); + }, + complete: function() { + loadingDialog.modal('hide'); } - }, - error: function() { - bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); - }, - complete: function() { - loadingDialog.modal('hide'); - } - }); + }); + } + + var domainType = getCurrentDomainIDType(); + if (domainType !== DOMAIN_ID_TYPE_UNKNOWN) { + loadPlaces(); + } else { + getDomainFromAPI(function(data) { + if (data.status === 'success') { + var domainType = getCurrentDomainIDType(); + loadPlaces(); + } else { + loadingDialog.modal('hide'); + bootbox.confirm("We were not able to load your domain information from the Metaverse. Would you like to retry?", function(response) { + if (response) { + chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded); + } + }); + } + }) + } } else { bootbox.alert({ diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 1224b724da..7f99b367a3 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -980,20 +980,6 @@ function placeTableRowForPlaceObject(place) { return placeTableRow(place.name, placePathOrIndex, false, place.id); } -function getDomainFromAPI(callback) { - var domainID = Settings.data.values.metaverse.id; - $.ajax({ - url: "/api/domains/" + domainID, - dataType: 'json', - success: function(data) { - callback(data); - }, - error: function() { - callback({ status: 'fail' }); - } - }); -} - function reloadDomainInfo() { $('#' + Settings.PLACES_TABLE_ID + " tbody tr").not('.headers').remove(); @@ -1010,7 +996,6 @@ function reloadDomainInfo() { // check if we have owner_places (for a real domain) or a name (for a temporary domain) if (data.status == "success") { $('.domain-loading-hide').show(); - DomainInfo = data.domain; if (data.domain.owner_places) { // add a table row for each of these names _.each(data.domain.owner_places, function(place){ @@ -1043,7 +1028,6 @@ function reloadDomainInfo() { appendAddButtonToPlacesTable(); } else { - DomainInfo = null; $('.domain-loading-error').show(); } }) diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 24a82402a6..1af3f305b7 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -58,6 +58,7 @@ $(document).ready(function(){ reloadSettings(function(success) { if (success) { + getDomainFromAPI(); setupWizardSteps(); updatePlaceNameDisplay(); updateUsernameDisplay(); From 12792c3821730a8f271d2f802cf57606c02c1ca3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 1 Nov 2017 17:26:00 -0700 Subject: [PATCH 25/42] stop drawing ignored avatars, even if PAL is still open --- interface/src/avatar/AvatarManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e8b800db69..4cf8ba6d4e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -179,6 +179,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); + bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); + if (ignoring) { + sortedAvatars.pop(); + continue; + } + // for ALL avatars... if (_shouldRender) { avatar->ensureInScene(avatar, qApp->getMain3DScene()); From f8718efe25dbeb5e6f3a8162e3bdaa5be19e4cd3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 2 Nov 2017 09:42:33 -0700 Subject: [PATCH 26/42] Fix warnings --- interface/src/ui/overlays/ContextOverlayInterface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index e6568b56dd..f83427a1a1 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -276,7 +276,6 @@ void ContextOverlayInterface::openInspectionCertificate() { EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags); - QUuid nodeToChallenge = entityProperties.getOwningAvatarID(); auto nodeList = DependencyManager::get(); if (entityProperties.getClientOnly()) { From 19945c5991425745be0355d953f6537248837dd3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 2 Nov 2017 10:22:00 -0700 Subject: [PATCH 27/42] Update cert UI --- .../InspectionCertificate.qml | 31 ++++++++++++++----- .../ui/overlays/ContextOverlayInterface.cpp | 4 +-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index bd8808f05f..6a7a181b92 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -33,6 +33,7 @@ Rectangle { property string dateOfPurchase: "--"; property bool isLightbox: false; property bool isMyCert: false; + property bool isCertificateInvalid: false; // Style color: hifi.colors.faintGray; Hifi.QmlCommerce { @@ -44,10 +45,11 @@ Rectangle { } else { root.marketplaceUrl = result.data.marketplace_item_url; root.isMyCert = result.isMyCert ? result.isMyCert : false; - root.itemOwner = root.isMyCert ? Account.username : - "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"; - root.itemEdition = result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run); - root.dateOfPurchase = getFormattedDate(result.data.transfer_created_at * 1000); + root.itemOwner = root.isCertificateInvalid ? "--" : (root.isMyCert ? Account.username : + "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"); + root.itemEdition = root.isCertificateInvalid ? "Uncertified Copy" : + (result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run)); + root.dateOfPurchase = root.isCertificateInvalid ? "" : getFormattedDate(result.data.transfer_created_at * 1000); root.itemName = result.data.marketplace_item_name; if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") { @@ -70,20 +72,35 @@ Rectangle { if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS // NOP } else if (certStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT + root.isCertificateInvalid = true; errorText.text = "Verification of this certificate timed out."; errorText.color = hifi.colors.redHighlight; } else if (certStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED + root.isCertificateInvalid = true; titleBarText.text = "Invalid Certificate"; titleBarText.color = hifi.colors.redHighlight; + + popText.text = ""; + root.itemOwner = ""; + dateOfPurchaseHeader.text = ""; + root.dateOfPurchase = ""; root.itemEdition = "Uncertified Copy"; + errorText.text = "The certificate associated with this entity is invalid."; - errorText.color = hifi.colors.redHighlight; + errorText.color = hifi.colors.baseGray; } else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED + root.isCertificateInvalid = true; titleBarText.text = "Invalid Certificate"; titleBarText.color = hifi.colors.redHighlight; + + popText.text = ""; + root.itemOwner = ""; + dateOfPurchaseHeader.text = ""; + root.dateOfPurchase = ""; root.itemEdition = "Uncertified Copy"; + errorText.text = "The certificate associated with this entity is invalid."; - errorText.color = hifi.colors.redHighlight; + errorText.color = hifi.colors.baseGray; } else { console.log("Unknown certificate status received from ledger signal!"); } @@ -239,7 +256,7 @@ Rectangle { } AnonymousProRegular { id: isMyCertText; - visible: root.isMyCert; + visible: root.isMyCert && !root.isCertificateInvalid; text: "(Private)"; size: 18; // Anchors diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index f83427a1a1..b5af529f2b 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -304,9 +304,9 @@ void ContextOverlayInterface::openInspectionCertificate() { if (!jsonObject["invalid_reason"].toString().isEmpty()) { qCDebug(entities) << "invalid_reason not empty"; } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { - qCDebug(entities) << "'transfer_status' is 'failed'";; + qCDebug(entities) << "'transfer_status' is 'failed'"; } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { - qCDebug(entities) << "'transfer_status' is 'pending'";; + qCDebug(entities) << "'transfer_status' is 'pending'"; } else { QString ownerKey = jsonObject["transfer_recipient_key"].toString(); From e77b9e0e97786015e39989155ff5f11f77a14f7f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 1 Nov 2017 17:26:00 -0700 Subject: [PATCH 28/42] stop drawing ignored avatars, even if PAL is still open --- interface/src/avatar/AvatarManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e8b800db69..4cf8ba6d4e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -179,6 +179,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); + bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); + if (ignoring) { + sortedAvatars.pop(); + continue; + } + // for ALL avatars... if (_shouldRender) { avatar->ensureInScene(avatar, qApp->getMain3DScene()); From db9c3cc103ef37f9a40c4e404fd03de0b0e865f8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Nov 2017 12:31:36 -0700 Subject: [PATCH 29/42] make Model::scaleToFit() public not protected --- libraries/render-utils/src/Model.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 8bce976b4e..3abf7e2758 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -262,6 +262,8 @@ public: Q_INVOKABLE MeshProxyList getMeshes() const; + void scaleToFit(); + public slots: void loadURLFinished(bool success); @@ -320,7 +322,6 @@ protected: virtual void initJointStates(); void setScaleInternal(const glm::vec3& scale); - void scaleToFit(); void snapToRegistrationPoint(); void computeMeshPartLocalBounds(); From 490483fde889e31ddee4c2697e4716eccc4bb792 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Nov 2017 12:32:51 -0700 Subject: [PATCH 30/42] call Model::scaleToFit() before update render items --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7db19704b4..03380ad321 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -215,6 +215,7 @@ void RenderableModelEntityItem::updateModelBounds() { model->setScaleToFit(true, getDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); updateRenderItems = true; + model->scaleToFit(); } bool success; From 60fce3d4f712c079aa373dd868f9eb372d4ef5c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Nov 2017 12:31:36 -0700 Subject: [PATCH 31/42] make Model::scaleToFit() public not protected --- libraries/render-utils/src/Model.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 8bce976b4e..3abf7e2758 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -262,6 +262,8 @@ public: Q_INVOKABLE MeshProxyList getMeshes() const; + void scaleToFit(); + public slots: void loadURLFinished(bool success); @@ -320,7 +322,6 @@ protected: virtual void initJointStates(); void setScaleInternal(const glm::vec3& scale); - void scaleToFit(); void snapToRegistrationPoint(); void computeMeshPartLocalBounds(); From 2b06df1c335224fefd9272d518584bdb3319a3be Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Nov 2017 12:32:51 -0700 Subject: [PATCH 32/42] call Model::scaleToFit() before update render items --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7db19704b4..03380ad321 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -215,6 +215,7 @@ void RenderableModelEntityItem::updateModelBounds() { model->setScaleToFit(true, getDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); updateRenderItems = true; + model->scaleToFit(); } bool success; From 23e627a46f740cb3f4e5ccb2384cde0876c6799f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 2 Nov 2017 13:46:24 -0700 Subject: [PATCH 33/42] Send empty decrypted text if impossible to decrypt --- interface/src/commerce/Wallet.cpp | 92 ++++++++++++++++--------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index c6d77982b8..85632ff8f1 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -718,6 +718,8 @@ bool Wallet::changePassphrase(const QString& newPassphrase) { } void Wallet::handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + auto nodeList = DependencyManager::get(); + bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest; unsigned char decryptedText[64]; int certIDByteArraySize; @@ -738,62 +740,64 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack } RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); + int decryptionStatus = -1; if (rsa) { - auto nodeList = DependencyManager::get(); - ERR_clear_error(); - const int decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, + decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, reinterpret_cast(encryptedText.constData()), decryptedText, rsa, RSA_PKCS1_OAEP_PADDING); RSA_free(rsa); - - 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); - - 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); - } - - if (decryptionStatus == -1) { - qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; - long error = ERR_get_error(); - if (error != 0) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "RSA error:" << error_str; - } - } } else { qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed."; } + + QByteArray decryptedTextByteArray; + if (decryptionStatus > -1) { + 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); + + 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); + } + + if (decryptionStatus == -1) { + qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; + long error = ERR_get_error(); + if (error != 0) { + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "RSA error:" << error_str; + } + } } void Wallet::account() { From 56b1c7d0eeb03bc6ba1504ac71dd1ebbc26b2bec Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 2 Nov 2017 14:51:40 -0700 Subject: [PATCH 34/42] Fix finding the SSL binary path --- cmake/modules/FindOpenSSL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 338dee7bc8..0619c4d587 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -60,7 +60,7 @@ if (WIN32 AND NOT CYGWIN) select_library_configurations(LIB_EAY) select_library_configurations(SSL_EAY) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) - find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) + find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} NO_DEFAULT_PATH) endif() else() From 6173ad810b3c9207d649734a741c062459f99a53 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 2 Nov 2017 15:48:59 -0700 Subject: [PATCH 35/42] Reset wallet passphrase when login username changes --- interface/src/commerce/QmlCommerce.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index ac5d0e6a2d..9d07ddb4ab 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -31,6 +31,11 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult); connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult); connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus); + + auto accountManager = DependencyManager::get(); + connect(accountManager.data(), &AccountManager::usernameChanged, [&]() { + setPassphrase(""); + }); } void QmlCommerce::getWalletStatus() { From b1fe3699f99cd239b7f14aa598fe10086d1372fa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 2 Nov 2017 17:42:24 -0700 Subject: [PATCH 36/42] Fix domain id getting set to empty when adding place name --- domain-server/resources/web/js/shared.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index 4db608ddb4..66159209ea 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -299,6 +299,7 @@ function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAd }); } + // If domainID is not specified, the current domain id will be used. function finishSettingUpPlace(domainID) { sendUpdatePlaceRequest( placeID, @@ -306,9 +307,9 @@ function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAd domainID, false, function(data) { - $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); dialog.modal('hide') if (domainID) { + $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); finalizeSaveDomainID(domainID); } else { if (onSuccessfullyAdded) { From 6f3c61c4e0314baa448cc09a8ff31470f21bdae6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 2 Nov 2017 17:57:52 -0700 Subject: [PATCH 37/42] Slightly modify invalid cert language --- .../commerce/inspectionCertificate/InspectionCertificate.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index 6a7a181b92..b6c29a1fad 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -86,7 +86,7 @@ Rectangle { root.dateOfPurchase = ""; root.itemEdition = "Uncertified Copy"; - errorText.text = "The certificate associated with this entity is invalid."; + errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item."; errorText.color = hifi.colors.baseGray; } else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED root.isCertificateInvalid = true; @@ -99,7 +99,7 @@ Rectangle { root.dateOfPurchase = ""; root.itemEdition = "Uncertified Copy"; - errorText.text = "The certificate associated with this entity is invalid."; + errorText.text = "The avatar who rezzed this item doesn't own it."; errorText.color = hifi.colors.baseGray; } else { console.log("Unknown certificate status received from ledger signal!"); From babaef8399012346342f2fb5651d7ac7a1aa223c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Fri, 3 Nov 2017 05:59:59 -0700 Subject: [PATCH 38/42] Fix the audio input device peak meters --- interface/resources/qml/hifi/audio/Audio.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 12c2ec1835..87ddce49ca 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -213,8 +213,8 @@ Rectangle { anchors.right: parent.right peak: model.peak; anchors.verticalCenter: parent.verticalCenter - visible: (bar.currentIndex === 1 && selectedHMD && isVR) || - (bar.currentIndex === 0 && selectedDesktop && !isVR) && + visible: ((bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR)) && Audio.devices.input.peakValuesAvailable; } } From 317141817317668cfaa652c08a909aab0018694b Mon Sep 17 00:00:00 2001 From: Nex-Pro Date: Fri, 3 Nov 2017 17:21:35 +0000 Subject: [PATCH 39/42] Update NameCard.qml --- interface/resources/qml/hifi/NameCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b122f71760..f16b8de337 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -433,7 +433,7 @@ Item { anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter x: 240 onClicked: { - console.log("Vist user button clicked."); // Remove after debugging. + console.log("Vist user button clicked."); // Remove after debugging. AddressManager.goToUser(thisNameCard.userName, false); UserActivityLogger.palAction("go_to_user", thisNameCard.userName); } From c496429a85cad2616f6c9f696ccbae19dbad3d25 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 3 Nov 2017 10:40:25 -0700 Subject: [PATCH 40/42] Add Machine Fingerprint to receive_at endpoint txn' --- interface/src/commerce/Ledger.cpp | 10 ++++++++-- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/Wallet.cpp | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 904847cb5f..f607c923ee 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -90,7 +90,7 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure); } -bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) { +bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { qCWarning(commerce) << "Cannot set receiveAt when not logged in."; @@ -99,7 +99,13 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) { return false; // We know right away that we will fail, so tell the caller. } - signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); + QJsonObject transaction; + transaction["hfc_key"] = hfc_key; + transaction["machine_fingerprint"] = machine_fingerprint; + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + + signedSend("transaction", transactionString, old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 42eb0ffc49..54f3f780f3 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -26,7 +26,7 @@ class Ledger : public QObject, public Dependency { public: void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false); - bool receiveAt(const QString& hfc_key, const QString& old_key); + bool receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint); void balance(const QStringList& keys); void inventory(const QStringList& keys); void history(const QStringList& keys); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 85632ff8f1..9bc8dc9e43 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -16,6 +16,7 @@ #include "ui/ImageProvider.h" #include "scripting/HMDScriptingInterface.h" +#include #include #include #include @@ -541,7 +542,8 @@ bool Wallet::generateKeyPair() { // 2. It is maximally private, and we can step back from that later if desired. // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. auto ledger = DependencyManager::get(); - return ledger->receiveAt(key, oldKey); + QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + return ledger->receiveAt(key, oldKey, machineFingerprint); } QStringList Wallet::listPublicKeys() { From 6ca9cc02399f30d1034f7d945b47992573a2e99c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Fri, 3 Nov 2017 18:40:55 -0700 Subject: [PATCH 41/42] Update WASAPI audio plugin --- cmake/externals/wasapi/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt index 4437024962..4c0ffaf88f 100644 --- a/cmake/externals/wasapi/CMakeLists.txt +++ b/cmake/externals/wasapi/CMakeLists.txt @@ -6,8 +6,8 @@ if (WIN32) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi9.zip - URL_MD5 94f4765bdbcd53cd099f349ae031e769 + URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi10.zip + URL_MD5 4f40e49715a420fb67b45b9cee19052c CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" From d4b4d188ed28bdf6875dd66ef34598aa0ad2005b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 4 Nov 2017 13:40:41 -0700 Subject: [PATCH 42/42] allow splitting of edit or add entity packets across multiple edit packets when property list is larger than MTU --- .../entities/src/EntityEditPacketSender.cpp | 42 ++++++++++++------- libraries/entities/src/EntityItem.cpp | 4 +- .../entities/src/EntityItemProperties.cpp | 34 ++++++--------- libraries/entities/src/EntityItemProperties.h | 4 +- libraries/entities/src/EntityPropertyFlags.h | 29 +++++++------ libraries/octree/src/OctreePacketData.cpp | 12 +++++- libraries/octree/src/OctreePacketData.h | 1 + tests/octree/src/OctreeTests.cpp | 2 +- 8 files changed, 71 insertions(+), 57 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index e82ed82093..168b0cd446 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -93,27 +93,41 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0); - bool success; + OctreeElement::AppendState encodeResult = OctreeElement::PARTIAL; // start the loop assuming there's more to send auto nodeList = DependencyManager::get(); + + EntityPropertyFlags didntFitProperties; + EntityItemProperties propertiesCopy = properties; + if (properties.parentIDChanged() && properties.getParentID() == AVATAR_SELF_ID) { - EntityItemProperties propertiesCopy = properties; const QUuid myNodeID = nodeList->getSessionUUID(); propertiesCopy.setParentID(myNodeID); - success = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut); - } else { - success = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, properties, bufferOut); } - if (success) { - #ifdef WANT_DEBUG - qCDebug(entities) << "calling queueOctreeEditMessage()..."; - qCDebug(entities) << " id:" << entityItemID; - qCDebug(entities) << " properties:" << properties; - #endif - queueOctreeEditMessage(type, bufferOut); - if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) { - emit addingEntityWithCertificate(properties.getCertificateID(), DependencyManager::get()->getPlaceName()); + EntityPropertyFlags requestedProperties = propertiesCopy.getChangedProperties(); + + while (encodeResult == OctreeElement::PARTIAL) { + encodeResult = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut, requestedProperties, didntFitProperties); + + if (encodeResult != OctreeElement::NONE) { + #ifdef WANT_DEBUG + qCDebug(entities) << "calling queueOctreeEditMessage()..."; + qCDebug(entities) << " id:" << entityItemID; + qCDebug(entities) << " properties:" << properties; + #endif + queueOctreeEditMessage(type, bufferOut); + if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) { + emit addingEntityWithCertificate(properties.getCertificateID(), DependencyManager::get()->getPlaceName()); + } } + + // if we still have properties to send, switch the message type to edit, and request only the packets that didn't fit + if (encodeResult != OctreeElement::COMPLETED) { + type = PacketType::EntityEdit; + requestedProperties = didntFitProperties; + } + + bufferOut.resize(NLPacket::maxPayloadSize(type)); // resize our output buffer for the next packet } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f6f4e48a73..3f054e1ccb 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -83,7 +83,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_ANGULAR_VELOCITY; requestedProperties += PROP_ACCELERATION; - requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete + requestedProperties += PROP_DIMENSIONS; requestedProperties += PROP_DENSITY; requestedProperties += PROP_GRAVITY; requestedProperties += PROP_DAMPING; @@ -241,7 +241,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getLocalAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f774b208c4..108fc14e30 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1221,8 +1221,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue // // TODO: Implement support for script and visible properties. // -bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, - QByteArray& buffer) { +OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, + QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties) { + OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro @@ -1264,17 +1265,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem QByteArray encodedUpdateDelta = updateDeltaCoder; EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); - EntityPropertyFlags requestedProperties = properties.getChangedProperties(); EntityPropertyFlags propertiesDidntFit = requestedProperties; - // TODO: we need to handle the multi-pass form of this, similar to how we handle entity data - // - // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item, - // then our modelTreeElementExtraEncodeData should include data about which properties we need to append. - //if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) { - // requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID()); - //} - LevelDetails entityLevel = packetData->startLevel(); // Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this @@ -1302,7 +1294,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem int propertyCount = 0; bool headerFits = successIDFits && successTypeFits && successLastEditedFits - && successLastUpdatedFits && successPropertyFlagsFits; + && successLastUpdatedFits && successPropertyFlagsFits; int startOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -1316,7 +1308,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation()); APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, properties.getVelocity()); @@ -1472,6 +1464,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem properties.getType() == EntityTypes::Sphere) { APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); } + APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); @@ -1522,12 +1515,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // If any part of the model items didn't fit, then the element is considered partial if (appendState != OctreeElement::COMPLETED) { - // TODO: handle mechanism for handling partial fitting data! - // add this item into our list for the next appendElementData() pass - //modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit); - - // for now, if it's not complete, it's not successful - success = false; + didntFitProperties = propertiesDidntFit; } } @@ -1543,11 +1531,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem } else { qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer."; success = false; + appendState = OctreeElement::NONE; // if we got here, then we didn't include the item + // maybe we should assert!!! } } else { packetData->discardSubTree(); } - return success; + + + return appendState; } QByteArray EntityItemProperties::getPackedNormals() const { @@ -1673,7 +1665,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATION_OWNER, QByteArray, setSimulationOwner); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a8bb063934..732dbdf69f 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -262,8 +262,8 @@ public: float getLocalRenderAlpha() const { return _localRenderAlpha; } void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; } - static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, - QByteArray& buffer); + static OctreeElement::AppendState encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, + QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties); static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index f0f22b0091..35d40b669a 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -21,8 +21,7 @@ enum EntityPropertyList { // these properties are supported by the EntityItem base class PROP_VISIBLE, PROP_POSITION, - PROP_RADIUS, // NOTE: PROP_RADIUS is obsolete and only included in old format streams - PROP_DIMENSIONS = PROP_RADIUS, + PROP_DIMENSIONS, PROP_ROTATION, PROP_DENSITY, PROP_VELOCITY, @@ -47,13 +46,13 @@ enum EntityPropertyList { PROP_ANGULAR_VELOCITY, PROP_ANGULAR_DAMPING, PROP_COLLISIONLESS, - PROP_DYNAMIC, + PROP_DYNAMIC, // 24 // property used by Light entity PROP_IS_SPOTLIGHT, PROP_DIFFUSE_COLOR, - PROP_AMBIENT_COLOR_UNUSED, - PROP_SPECULAR_COLOR_UNUSED, + PROP_AMBIENT_COLOR_UNUSED, // FIXME - No longer used, can remove and bump protocol + PROP_SPECULAR_COLOR_UNUSED, // FIXME - No longer used, can remove and bump protocol PROP_INTENSITY, // Previously PROP_CONSTANT_ATTENUATION PROP_LINEAR_ATTENUATION_UNUSED, PROP_QUADRATIC_ATTENUATION_UNUSED, @@ -61,30 +60,30 @@ enum EntityPropertyList { PROP_CUTOFF, // available to all entities - PROP_LOCKED, + PROP_LOCKED, // 34 PROP_TEXTURES, // used by Model entities - PROP_ANIMATION_SETTINGS, // used by Model entities - PROP_USER_DATA, // all entities + PROP_ANIMATION_SETTINGS_UNUSED, // FIXME - No longer used, can remove and bump protocol + PROP_USER_DATA, // all entities -- 37 PROP_SHAPE_TYPE, // used by Model + zones entities // used by ParticleEffect entities - PROP_MAX_PARTICLES, - PROP_LIFESPAN, + PROP_MAX_PARTICLES, // 39 + PROP_LIFESPAN, // 40 -- used by all entities PROP_EMIT_RATE, PROP_EMIT_SPEED, PROP_EMIT_STRENGTH, - PROP_EMIT_ACCELERATION, - PROP_PARTICLE_RADIUS, + PROP_EMIT_ACCELERATION, // FIXME - doesn't seem to get set in mark all changed???? + PROP_PARTICLE_RADIUS, // 45!! PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities PROP_MARKETPLACE_ID, // all entities PROP_ACCELERATION, // all entities PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID - PROP_NAME, // all entities + PROP_NAME, // all entities -- 50 PROP_COLLISION_SOUND_URL, PROP_RESTITUTION, - PROP_FRICTION, + PROP_FRICTION, // 53 PROP_VOXEL_VOLUME_SIZE, PROP_VOXEL_DATA, @@ -96,7 +95,7 @@ enum EntityPropertyList { // used by hyperlinks PROP_HREF, - PROP_DESCRIPTION, + PROP_DESCRIPTION, // 61 PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 493dfdcff5..b5b4a161ef 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -68,8 +68,8 @@ bool OctreePacketData::append(const unsigned char* data, int length) { _dirty = true; } - const bool wantDebug = false; - if (wantDebug && !success) { + #ifdef WANT_DEBUG + if (!success) { qCDebug(octree) << "OctreePacketData::append(const unsigned char* data, int length) FAILING...."; qCDebug(octree) << " length=" << length; qCDebug(octree) << " _bytesAvailable=" << _bytesAvailable; @@ -77,6 +77,7 @@ bool OctreePacketData::append(const unsigned char* data, int length) { qCDebug(octree) << " _targetSize=" << _targetSize; qCDebug(octree) << " _bytesReserved=" << _bytesReserved; } + #endif return success; } @@ -647,6 +648,13 @@ void OctreePacketData::debugContent() { printf("\n"); } +void OctreePacketData::debugBytes() { + qCDebug(octree) << " _bytesAvailable=" << _bytesAvailable; + qCDebug(octree) << " _bytesInUse=" << _bytesInUse; + qCDebug(octree) << " _targetSize=" << _targetSize; + qCDebug(octree) << " _bytesReserved=" << _bytesReserved; +} + int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QString& result) { uint16_t length; memcpy(&length, dataBytes, sizeof(length)); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index ed6a49941b..37c171504b 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -240,6 +240,7 @@ public: /// displays contents for debugging void debugContent(); + void debugBytes(); static quint64 getCompressContentTime() { return _compressContentTime; } /// total time spent compressing content static quint64 getCompressContentCalls() { return _compressContentCalls; } /// total calls to compress content diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 64d68e8e13..81300a1293 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -74,7 +74,7 @@ void OctreeTests::propertyFlagsTests() { EntityPropertyFlags props; props.setHasProperty(PROP_VISIBLE); props.setHasProperty(PROP_POSITION); - props.setHasProperty(PROP_RADIUS); + props.setHasProperty(PROP_DIMENSIONS); props.setHasProperty(PROP_MODEL_URL); props.setHasProperty(PROP_COMPOUND_SHAPE_URL); props.setHasProperty(PROP_ROTATION);