From 1fa9bd8fc6c169454296e97aceb956a76deb5e1d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 6 Oct 2017 10:47:06 -0700 Subject: [PATCH] Better implementation of location change and bugfixes --- .../qml/hifi/commerce/checkout/Checkout.qml | 1 - .../hifi/commerce/purchases/PurchasedItem.qml | 1 - .../qml/hifi/commerce/wallet/Wallet.qml | 2 +- interface/src/Application.cpp | 6 +++ interface/src/Application.h | 1 + interface/src/commerce/Ledger.cpp | 24 ++++++++---- interface/src/commerce/QmlCommerce.cpp | 38 ++----------------- interface/src/commerce/QmlCommerce.h | 9 ----- interface/src/commerce/Wallet.cpp | 38 +++++++++++++++++++ interface/src/commerce/Wallet.h | 13 +++++++ .../scripting/WalletScriptingInterface.cpp | 5 +++ .../src/scripting/WalletScriptingInterface.h | 3 ++ .../entities/src/EntityEditPacketSender.cpp | 5 ++- .../entities/src/EntityEditPacketSender.h | 3 ++ libraries/entities/src/EntityTree.cpp | 33 ++++++++++------ libraries/entities/src/EntityTree.h | 1 + scripts/system/marketplaces/marketplaces.js | 11 ++++-- scripts/system/notifications.js | 9 ++++- 18 files changed, 131 insertions(+), 72 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index e7bbaec755..09c2f6fa76 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -579,7 +579,6 @@ Rectangle { } rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); - commerce.updatePopLocation(root.itemId); } } RalewaySemiBold { diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index e343b93117..5eb5516519 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -347,7 +347,6 @@ Item { if (urlHandler.canHandleUrl(root.itemHref)) { urlHandler.handleUrl(root.itemHref); } - commerce.updatePopLocation(root.itemId); rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); } diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 9056d5bed3..0bc444efb5 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -283,7 +283,7 @@ Rectangle { Connections { onSendSignalToParent: { if (msg.method === "authSuccess") { - root.activeView = "walletHome"; + commerce.getWalletStatus(); } else { sendToScript(msg); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0fc8c46cdc..6608cfe5fc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1006,6 +1006,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // connect to the packet sent signal of the _entityEditSender connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); + connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); const char** constArgv = const_cast(argv); QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); @@ -5735,6 +5736,11 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer void Application::packetSent(quint64 length) { } +void Application::addingEntityWithCertificate(const QString& certificateID, const QString& domainID) { + auto ledger = DependencyManager::get(); + ledger->updateLocation(certificateID, domainID); +} + void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) { scriptEngine->setEmitScriptUpdatesFunction([this]() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 478642e2da..061fae5bcd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -440,6 +440,7 @@ private slots: void nodeActivated(SharedNodePointer node); void nodeKilled(SharedNodePointer node); static void packetSent(quint64 length); + static void addingEntityWithCertificate(const QString& certificateID, const QString& domainID); void updateDisplayMode(); void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo); diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index e926d8918e..2f5e79f28b 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -225,12 +225,20 @@ void Ledger::updateLocationSuccess(QNetworkReply& reply) { apiResponse("updateLo void Ledger::updateLocationFailure(QNetworkReply& reply) { failResponse("updateLocation", reply); } void Ledger::updateLocation(const QString& asset_id, const QString location, const bool controlledFailure) { auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - QString key = keys[0]; - QJsonObject transaction; - transaction["asset_id"] = asset_id; - transaction["location"] = location; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + auto walletScriptingInterface = DependencyManager::get(); + uint walletStatus = walletScriptingInterface->getWalletStatus(); + + if (walletStatus != wallet->WALLET_STATUS_READY) { + emit walletScriptingInterface->walletNotSetup(); + qDebug(commerce) << "User attempted to update the location of a certificate, but their wallet wasn't ready. Status:" << walletStatus; + } else { + QStringList keys = wallet->listPublicKeys(); + QString key = keys[0]; + QJsonObject transaction; + transaction["asset_id"] = asset_id; + transaction["location"] = location; + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + } } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 46c73708de..ee75bc59e3 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -15,7 +15,6 @@ #include "Ledger.h" #include "Wallet.h" #include -#include "scripting/WalletScriptingInterface.h" HIFI_QML_DEF(QmlCommerce) @@ -29,37 +28,12 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult); connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult); - connect(ledger.data(), &Ledger::accountResult, this, [&]() { - auto wallet = DependencyManager::get(); - auto walletScriptingInterface = DependencyManager::get(); - uint status; - - if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { - status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP; - } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { - status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED; - } else { - status = (uint)WalletStatus::WALLET_STATUS_READY; - } - - walletScriptingInterface->setWalletStatus(status); - emit walletStatusResult(status); - }); + connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult); } void QmlCommerce::getWalletStatus() { - auto walletScriptingInterface = DependencyManager::get(); - uint status; - - if (DependencyManager::get()->isLoggedIn()) { - // This will set account info for the wallet, allowing us to decrypt and display the security image. - account(); - } else { - status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN; - emit walletStatusResult(status); - walletScriptingInterface->setWalletStatus(status); - return; - } + auto wallet = DependencyManager::get(); + wallet->getWalletStatus(); } void QmlCommerce::getLoginStatus() { @@ -151,9 +125,3 @@ void QmlCommerce::account() { auto ledger = DependencyManager::get(); ledger->account(); } - -void QmlCommerce::updatePopLocation(const QString& popId, const bool controlledFailure) { - auto ledger = DependencyManager::get(); - auto nodeList = DependencyManager::get(); - ledger->updateLocation(popId, nodeList->getDomainHandler().getUUID().toString(), controlledFailure); -} diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index b1d179aae8..45a5360680 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -27,13 +27,6 @@ class QmlCommerce : public OffscreenQmlDialog { public: QmlCommerce(QQuickItem* parent = nullptr); - enum WalletStatus { - WALLET_STATUS_NOT_LOGGED_IN = 0, - WALLET_STATUS_NOT_SET_UP, - WALLET_STATUS_NOT_AUTHENTICATED, - WALLET_STATUS_READY - }; - signals: void walletStatusResult(uint walletStatus); @@ -70,8 +63,6 @@ protected: Q_INVOKABLE void generateKeyPair(); Q_INVOKABLE void reset(); Q_INVOKABLE void account(); - - Q_INVOKABLE void updatePopLocation(const QString& popId, const bool controlledFailure = false); }; #endif // hifi_QmlCommerce_h diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 8b6f2785f1..34e266b32c 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -282,9 +282,27 @@ void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArra Wallet::Wallet() { auto nodeList = DependencyManager::get(); + auto ledger = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket"); + + connect(ledger.data(), &Ledger::accountResult, this, [&]() { + auto wallet = DependencyManager::get(); + auto walletScriptingInterface = DependencyManager::get(); + uint status; + + if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { + status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP; + } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { + status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED; + } else { + status = (uint)WalletStatus::WALLET_STATUS_READY; + } + + walletScriptingInterface->setWalletStatus(status); + emit walletStatusResult(status); + }); } Wallet::~Wallet() { @@ -695,3 +713,23 @@ bool Wallet::verifyOwnerChallenge(const QByteArray& encryptedText, const QString decryptedText = QString("fail"); return true; } + +void Wallet::account() { + auto ledger = DependencyManager::get(); + ledger->account(); +} + +void Wallet::getWalletStatus() { + auto walletScriptingInterface = DependencyManager::get(); + uint status; + + if (DependencyManager::get()->isLoggedIn()) { + // This will set account info for the wallet, allowing us to decrypt and display the security image. + account(); + } else { + status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN; + emit walletStatusResult(status); + walletScriptingInterface->setWalletStatus(status); + return; + } +} diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index acf9f8e45e..38c5299810 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -17,6 +17,7 @@ #include #include #include +#include "scripting/WalletScriptingInterface.h" #include @@ -50,10 +51,20 @@ public: void reset(); + void getWalletStatus(); + enum WalletStatus { + WALLET_STATUS_NOT_LOGGED_IN = 0, + WALLET_STATUS_NOT_SET_UP, + WALLET_STATUS_NOT_AUTHENTICATED, + WALLET_STATUS_READY + }; + signals: void securityImageResult(bool exists); void keyFilePathIfExistsResult(const QString& path); + void walletStatusResult(uint walletStatus); + private slots: void handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode); @@ -71,6 +82,8 @@ private: bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen); bool verifyOwnerChallenge(const QByteArray& encryptedText, const QString& publicKey, QString& decryptedText); + + void account(); }; #endif // hifi_Wallet_h diff --git a/interface/src/scripting/WalletScriptingInterface.cpp b/interface/src/scripting/WalletScriptingInterface.cpp index 555e9477b0..99fdd5fbde 100644 --- a/interface/src/scripting/WalletScriptingInterface.cpp +++ b/interface/src/scripting/WalletScriptingInterface.cpp @@ -18,6 +18,11 @@ CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(q WalletScriptingInterface::WalletScriptingInterface() { } +void WalletScriptingInterface::refreshWalletStatus() { + auto wallet = DependencyManager::get(); + wallet->getWalletStatus(); +} + static const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml"; void WalletScriptingInterface::buy(const QString& name, const QString& id, const int& price, const QString& href) { if (QThread::currentThread() != thread()) { diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h index 31b42094cf..038c580197 100644 --- a/interface/src/scripting/WalletScriptingInterface.h +++ b/interface/src/scripting/WalletScriptingInterface.h @@ -20,6 +20,7 @@ #include #include #include "Application.h" +#include "commerce/Wallet.h" class CheckoutProxy : public QmlWrapper { Q_OBJECT @@ -36,6 +37,7 @@ class WalletScriptingInterface : public QObject, public Dependency { public: WalletScriptingInterface(); + Q_INVOKABLE void refreshWalletStatus(); Q_INVOKABLE uint getWalletStatus() { return _walletStatus; } void setWalletStatus(const uint& status) { _walletStatus = status; } @@ -43,6 +45,7 @@ public: signals: void walletStatusChanged(); + void walletNotSetup(); private: uint _walletStatus; diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index ee0fcf8218..2f8b796c93 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -93,9 +93,9 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0); bool success; + auto nodeList = DependencyManager::get(); if (properties.parentIDChanged() && properties.getParentID() == AVATAR_SELF_ID) { EntityItemProperties propertiesCopy = properties; - auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); propertiesCopy.setParentID(myNodeID); success = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut); @@ -110,6 +110,9 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, qCDebug(entities) << " properties:" << properties; #endif queueOctreeEditMessage(type, bufferOut); + if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) { + emit addingEntityWithCertificate(properties.getCertificateID(), nodeList->getDomainHandler().getUUID().toString()); + } } } diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index 81efaa865c..4e5b62e206 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -43,6 +43,9 @@ public: virtual char getMyNodeType() const override { return NodeType::EntityServer; } virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew) override; +signals: + void addingEntityWithCertificate(const QString& certificateID, const QString& domainID); + public slots: void processEntityEditNackPacket(QSharedPointer message, SharedNodePointer sendingNode); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 7322378b5f..35c47e48c9 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1099,10 +1099,10 @@ bool EntityTree::isScriptInWhitelist(const QString& scriptProperty) { void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID) { QTimer* _challengeOwnershipTimeoutTimer = new QTimer(this); - connect(this, &EntityTree::killChallengeOwnershipTimeoutTimer, this, [&](const QString& certID) { + connect(this, &EntityTree::killChallengeOwnershipTimeoutTimer, this, [=](const QString& certID) { QReadLocker locker(&_entityCertificateIDMapLock); EntityItemID id = _entityCertificateIDMap.value(certID); - if (entityItemID == id) { + if (entityItemID == id && _challengeOwnershipTimeoutTimer) { _challengeOwnershipTimeoutTimer->stop(); _challengeOwnershipTimeoutTimer->deleteLater(); } @@ -1112,8 +1112,10 @@ void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID) deleteEntity(entityItemID, true); QWriteLocker locker(&_recentlyDeletedEntitiesLock); _recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), entityItemID); - _challengeOwnershipTimeoutTimer->stop(); - _challengeOwnershipTimeoutTimer->deleteLater(); + if (_challengeOwnershipTimeoutTimer) { + _challengeOwnershipTimeoutTimer->stop(); + _challengeOwnershipTimeoutTimer->deleteLater(); + } }); _challengeOwnershipTimeoutTimer->setInterval(5000); _challengeOwnershipTimeoutTimer->start(); @@ -1134,14 +1136,18 @@ void EntityTree::processChallengeOwnershipPacket(ReceivedMessage& message, const emit killChallengeOwnershipTimeoutTimer(certID); if (decryptedText == "fail") { - QReadLocker certIdMapLocker(&_entityCertificateIDMapLock); - EntityItemID id = _entityCertificateIDMap.value(certID); - - qCDebug(entities) << "Ownership challenge failed, deleting entity" << id; - deleteEntity(id, true); - QWriteLocker recentlyDeletedLocker(&_recentlyDeletedEntitiesLock); - _recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), id); - } else { + EntityItemID id; + { + QReadLocker certIdMapLocker(&_entityCertificateIDMapLock); + id = _entityCertificateIDMap.value(certID); + } + + if (!id.isNull()) { + qCDebug(entities) << "Ownership challenge failed, deleting entity" << id; + deleteEntity(id, true); + QWriteLocker recentlyDeletedLocker(&_recentlyDeletedEntitiesLock); + _recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), id); + } } } @@ -2173,3 +2179,6 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } +void EntityTree::startDynamicDomainVerification() { + +} diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 210a35d407..85ce6a2ed5 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -369,6 +369,7 @@ protected: QHash _entitiesToAdd; Q_INVOKABLE void startChallengeOwnershipTimer(const EntityItemID& entityItemID); + void startDynamicDomainVerification(); }; #endif // hifi_EntityTree_h diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index e94b227a4a..0bee540a9d 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -129,6 +129,10 @@ } } + function openWallet() { + tablet.pushOntoStack(MARKETPLACE_WALLET_QML_PATH); + } + function setCertificateInfo(currentEntityWithContextOverlay, itemMarketplaceId) { wireEventBridge(true); tablet.sendToQml({ @@ -158,6 +162,7 @@ Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); ContextOverlay.contextOverlayClicked.connect(setCertificateInfo); GlobalServices.myUsernameChanged.connect(onUsernameChanged); + Wallet.refreshWalletStatus(); function onMessage(message) { @@ -214,7 +219,7 @@ } else if (parsedJsonMessage.type === "LOGIN") { openLoginWindow(); } else if (parsedJsonMessage.type === "WALLET_SETUP") { - tablet.pushOntoStack(MARKETPLACE_WALLET_QML_PATH); + openWallet(); } else if (parsedJsonMessage.type === "MY_ITEMS") { referrerURL = MARKETPLACE_URL_INITIAL; filterText = ""; @@ -281,7 +286,7 @@ case 'purchases_openWallet': case 'checkout_openWallet': case 'checkout_setUpClicked': - tablet.pushOntoStack(MARKETPLACE_WALLET_QML_PATH); + openWallet(); break; case 'purchases_walletNotSetUp': case 'checkout_walletNotSetUp': @@ -290,7 +295,7 @@ method: 'updateWalletReferrer', referrer: "purchases" }); - tablet.pushOntoStack(MARKETPLACE_WALLET_QML_PATH); + openWallet(); break; case 'checkout_cancelClicked': tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.params, MARKETPLACES_INJECT_SCRIPT_URL); diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index ffe93d13e8..a23a390e9b 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -94,13 +94,15 @@ EDIT_ERROR: 4, TABLET: 5, CONNECTION: 6, + WALLET: 7, properties: [ { text: "Snapshot" }, { text: "Level of Detail" }, { text: "Connection Refused" }, { text: "Edit error" }, { text: "Tablet" }, - { text: "Connection" } + { text: "Connection" }, + { text: "Wallet" } ], getTypeFromMenuItem: function (menuItemName) { var type; @@ -574,6 +576,10 @@ createNotification(wordWrap("Error trying to make connection: " + error), NotificationType.CONNECTION); } + function walletNotSetup() { + createNotification("The action you performed requires you to set up your Wallet. Open the Wallet app.", NotificationType.SNAPSHOT); + } + // handles mouse clicks on buttons function mousePressEvent(event) { var pickRay, @@ -682,6 +688,7 @@ Window.notifyEditError = onEditError; Window.notify = onNotify; Tablet.tabletNotification.connect(tabletNotification); + Wallet.walletNotSetup.connect(walletNotSetup); setup(); }()); // END LOCAL_SCOPE