From 73cca4294002f99c8cc782ca0439787ac5c8966c Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 13 Aug 2018 12:35:26 -0700 Subject: [PATCH 01/10] initial prototype --- interface/src/commerce/Ledger.cpp | 23 +++++++++++++++++++++-- interface/src/commerce/Wallet.cpp | 26 ++++++++++++++++++++++++++ interface/src/commerce/Wallet.h | 4 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 702251f867..bcd96fdb06 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -125,8 +125,19 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) { emit receiveAtResult(result); return false; // We know right away that we will fail, so tell the caller. } - - signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); + auto wallet = DependencyManager::get(); + QByteArray locker = wallet->getWallet(); + if (locker.isEmpty()) { + signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); + } else { + QJsonObject transaction; + transaction["public_key"] = hfc_key; + transaction["locker"] = QString::fromUtf8(locker); + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + qCDebug(commerce) << "FIXME transactionString" << transactionString; + signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); + } return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } @@ -277,17 +288,22 @@ void Ledger::accountSuccess(QNetworkReply* reply) { // lets set the appropriate stuff in the wallet now auto wallet = DependencyManager::get(); QByteArray response = reply->readAll(); + qCDebug(commerce) << "FIXME accountSuccess got" << response; QJsonObject data = QJsonDocument::fromJson(response).object()["data"].toObject(); auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8()); auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8()); auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8()); QString remotePublicKey = data["public_key"].toString(); + const QByteArray locker = data["locker"].toString().toUtf8(); bool isOverride = wallet->wasSoftReset(); wallet->setSalt(salt); wallet->setIv(iv); wallet->setCKey(ckey); + if (!locker.isEmpty()) { + wallet->setWallet(locker); + } QString keyStatus = "ok"; QStringList localPublicKeys = wallet->listPublicKeys(); @@ -301,6 +317,9 @@ void Ledger::accountSuccess(QNetworkReply* reply) { keyStatus = "preexisting"; } else if (localPublicKeys.first() != remotePublicKey) { keyStatus = "conflicting"; + } else if (locker.isEmpty()) { + QString key = localPublicKeys.first(); + receiveAt(key, key); } } diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index ef6b4654f5..197e6f60b9 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -190,6 +190,32 @@ bool writeKeys(const char* filename, EC_KEY* keys) { return retval; } +bool Wallet::setWallet(const QByteArray& wallet) { + QFile file(keyFilePath()); + if (!file.open(QIODevice::WriteOnly)) { + qCCritical(commerce) << "Unable to open wallet for write in" << keyFilePath(); + return false; + } + if (file.write(wallet) != wallet.count()) { + qCCritical(commerce) << "Unable to write wallet in" << keyFilePath(); + return false; + } + file.close(); + qCDebug(commerce) << "FIXME wrote" << wallet.count() << "to" << keyFilePath(); + return true; +} +QByteArray Wallet::getWallet() { + QFile file(keyFilePath()); + if (!file.open(QIODevice::ReadOnly)) { + qCInfo(commerce) << "No existing wallet in" << keyFilePath(); + return QByteArray(); + } + QByteArray wallet = file.readAll(); + file.close(); + qCDebug(commerce) << "FIXME read" << wallet.count() << "from" << keyFilePath(); + return wallet; +} + QPair generateECKeypair() { EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1); diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 665afd9a23..4e7608b096 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -44,6 +44,10 @@ public: void setCKey(const QByteArray& ckey) { _ckey = ckey; } QByteArray getCKey() { return _ckey; } + // FIXME protect more + bool setWallet(const QByteArray& wallet); + QByteArray getWallet(); + bool setPassphrase(const QString& passphrase); QString* getPassphrase() { return _passphrase; } bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); } From ef9cc782b91bba76aa31a629a1a6ba3beb6c6f3e Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 13 Aug 2018 14:30:36 -0700 Subject: [PATCH 02/10] no need to keep old format in client --- interface/src/commerce/Ledger.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index bcd96fdb06..c0bda8493a 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -127,17 +127,13 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) { } auto wallet = DependencyManager::get(); QByteArray locker = wallet->getWallet(); - if (locker.isEmpty()) { - signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); - } else { - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["locker"] = QString::fromUtf8(locker); - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - qCDebug(commerce) << "FIXME transactionString" << transactionString; - signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); - } + QJsonObject transaction; + transaction["public_key"] = hfc_key; + transaction["locker"] = QString::fromUtf8(locker); + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + qCDebug(commerce) << "FIXME transactionString" << transactionString; + signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } From ef1aacd226b96eb3d88ce7b1826a9d1f74a3d83c Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Tue, 14 Aug 2018 13:14:48 -0700 Subject: [PATCH 03/10] handle password changes --- interface/src/commerce/Ledger.cpp | 24 +++++++++++++++--------- interface/src/commerce/Ledger.h | 3 ++- interface/src/commerce/Wallet.cpp | 13 ++++++++++++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index c0bda8493a..4ab76c42f5 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -117,7 +117,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& signing_key) { +bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { qCWarning(commerce) << "Cannot set receiveAt when not logged in."; @@ -125,8 +125,6 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) { emit receiveAtResult(result); return false; // We know right away that we will fail, so tell the caller. } - auto wallet = DependencyManager::get(); - QByteArray locker = wallet->getWallet(); QJsonObject transaction; transaction["public_key"] = hfc_key; transaction["locker"] = QString::fromUtf8(locker); @@ -137,6 +135,16 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) { return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } +bool Ledger::receiveAt() { + auto wallet = DependencyManager::get(); + auto keys = wallet->listPublicKeys(); + if (keys.isEmpty()) { + return false; + } + auto key = keys.first(); + return receiveAt(key, key, wallet->getWallet()); +} + void Ledger::balance(const QStringList& keys) { keysQuery("balance", "balanceSuccess", "balanceFailure"); } @@ -304,18 +312,16 @@ void Ledger::accountSuccess(QNetworkReply* reply) { QString keyStatus = "ok"; QStringList localPublicKeys = wallet->listPublicKeys(); if (remotePublicKey.isEmpty() || isOverride) { - if (!localPublicKeys.isEmpty()) { - QString key = localPublicKeys.first(); - receiveAt(key, key); + if (!localPublicKeys.isEmpty()) { // Let the metaverse know about a local wallet. + receiveAt(); } } else { if (localPublicKeys.isEmpty()) { keyStatus = "preexisting"; } else if (localPublicKeys.first() != remotePublicKey) { keyStatus = "conflicting"; - } else if (locker.isEmpty()) { - QString key = localPublicKeys.first(); - receiveAt(key, key); + } else if (locker.isEmpty()) { // Matches metaverse data, but we haven't lockered it yet. + receiveAt(); } } diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index ba2f167f4b..427395ee11 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -26,7 +26,8 @@ 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& signing_key); + bool receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker); + bool receiveAt(); void balance(const QStringList& keys); void inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage); void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 197e6f60b9..fb6a0c9b03 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -602,7 +602,7 @@ 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, key); + return ledger->receiveAt(key, key, getWallet()); } QStringList Wallet::listPublicKeys() { @@ -741,6 +741,11 @@ QString Wallet::getKeyFilePath() { bool Wallet::writeWallet(const QString& newPassphrase) { EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str()); + auto ledger = DependencyManager::get(); + // Remove any existing locker, because it will be out of date. + if (!_publicKeys.isEmpty() && !ledger->receiveAt(_publicKeys.first(), _publicKeys.first(), QByteArray())) { + return false; // FIXME: receiveAt could fail asynchronously. + } if (keys) { // we read successfully, so now write to a new temp file QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp")); @@ -748,6 +753,7 @@ bool Wallet::writeWallet(const QString& newPassphrase) { if (!newPassphrase.isEmpty()) { setPassphrase(newPassphrase); } + if (writeKeys(tempFileName.toStdString().c_str(), keys)) { if (writeSecurityImage(_securityImage, tempFileName)) { // ok, now move the temp file to the correct spot @@ -755,6 +761,11 @@ bool Wallet::writeWallet(const QString& newPassphrase) { QFile(tempFileName).rename(QString(keyFilePath())); qCDebug(commerce) << "wallet written successfully"; emit keyFilePathIfExistsResult(getKeyFilePath()); + if (!walletIsAuthenticatedWithPassphrase() || !ledger->receiveAt()) { + // FIXME: Should we fail the whole operation? + // Tricky, because we'll need the the key and file from the TEMP location... + qCWarning(commerce) << "Failed to update locker"; + } return true; } else { qCDebug(commerce) << "couldn't write security image to temp wallet"; From 13629f6870fe60b0f094c316b0b2f04e200602bc Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 15 Aug 2018 11:23:50 -0700 Subject: [PATCH 04/10] bypass setup and password, and convert old wallets to account based before lockering --- .../qml/hifi/commerce/wallet/Help.qml | 11 +++++---- .../qml/hifi/commerce/wallet/Wallet.qml | 24 ++++++++++++++++--- interface/src/commerce/Ledger.cpp | 1 + interface/src/commerce/Wallet.cpp | 24 +++++++++++++++---- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index b453509712..e38f23e5a5 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -114,11 +114,9 @@ In your Wallet's Send Money tab, choose from your list of connections, or choose ListElement { isExpanded: false; question: "What is a Security Pic?" - answer: "Your Security Pic is an encrypted image that you select during Wallet Setup. \ -It acts as an extra layer of Wallet security. \ -When you see your Security Pic, you know that your actions and data are securely making use of your private keys.\ -

Don't enter your passphrase anywhere that doesn't display your Security Pic! \ -If you don't see your Security Pic on a page that requests your Wallet passphrase, someone untrustworthy may be trying to access your Wallet."; + answer: "Your Security Pic acts as an extra layer of Wallet security. \ +When you see your Security Pic, you know that your actions and data are securely making use of your account. \ +Tap here to change your Security Pic."; } ListElement { isExpanded: false; @@ -260,6 +258,9 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta } } else if (link === "#support") { Qt.openUrlExternally("mailto:support@highfidelity.com"); + } else if (link === "#securitypic") { + console.log("HRS FIXME here"); + sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'}); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 603d7fb676..f48553a4d0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -257,9 +257,9 @@ Rectangle { Connections { onSendSignalToWallet: { if (msg.method === 'walletSecurity_changeSecurityImageCancelled') { - root.activeView = "security"; + root.activeView = "walletHome"; // was "security"; } else if (msg.method === 'walletSecurity_changeSecurityImageSuccess') { - root.activeView = "security"; + root.activeView = "walletHome"; // was "security"; } else { sendToScript(msg); } @@ -399,6 +399,9 @@ Rectangle { onSendSignalToWallet: { if (msg.method === 'walletReset' || msg.method === 'passphraseReset') { sendToScript(msg); + } else if (msg.method === 'walletSecurity_changeSecurityImage') { + securityImageChange.initModel(); + root.activeView = "securityImageChange"; } } } @@ -607,7 +610,7 @@ Rectangle { } RalewaySemiBold { - text: "SECURITY"; + text: "PURCHASES"; // was "SECURITY"; // Text size size: 16; // Anchors @@ -629,8 +632,11 @@ Rectangle { anchors.fill: parent; hoverEnabled: enabled; onClicked: { + sendToScript({method: 'goToPurchases_fromWalletHome'}); + /* was root.activeView = "security"; tabButtonsContainer.resetTabButtonColors(); + */ } onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; @@ -803,12 +809,24 @@ Rectangle { } function walletResetSetup() { + /* Bypass all this and do it automatically root.activeView = "walletSetup"; var timestamp = new Date(); walletSetup.startingTimestamp = timestamp; walletSetup.setupAttemptID = generateUUID(); UserActivityLogger.commerceWalletSetupStarted(timestamp, walletSetup.setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app", (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : '')); + */ + + var randomNumber = Math.floor(Math.random() * 34) + 1; + var securityImagePath = "images/" + addLeadingZero(randomNumber) + ".jpg"; + Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set. + Commerce.chooseSecurityImage(securityImagePath); + Commerce.generateKeyPair(); + } + + function addLeadingZero(n) { + return n < 10 ? '0' + n : '' + n; } function followReferrer(msg) { diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 4ab76c42f5..18d22057fd 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -307,6 +307,7 @@ void Ledger::accountSuccess(QNetworkReply* reply) { wallet->setCKey(ckey); if (!locker.isEmpty()) { wallet->setWallet(locker); + wallet->setPassphrase("ACCOUNT"); // We only locker wallets that have been converted to account-based auth. } QString keyStatus = "ok"; diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index fb6a0c9b03..84e90544ff 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -131,7 +131,7 @@ bool Wallet::writeBackupInstructions() { QFile outputFile(outputFilename); bool retval = false; - if (getKeyFilePath() == "") + if (getKeyFilePath().isEmpty()) { return false; } @@ -360,7 +360,7 @@ Wallet::Wallet() { uint status; QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : ""; - if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { + if (wallet->getKeyFilePath().isEmpty() || !wallet->getSecurityImage()) { if (keyStatus == "preexisting") { status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING; } else{ @@ -550,15 +550,23 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() { // FIXME: initialize OpenSSL elsewhere soon initialize(); + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: checking" << (!_passphrase || !_passphrase->isEmpty()); // this should always be false if we don't have a passphrase // cached yet if (!_passphrase || _passphrase->isEmpty()) { - return false; + if (!getKeyFilePath().isEmpty()) { // If file exists, then it is an old school file that has not been lockered. Must get user's passphrase. + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: No passphrase, but there is an existing wallet."; + return false; + } else { + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: New setup."; + setPassphrase("ACCOUNT"); // Going forward, consider this an account-based client. + } } if (_publicKeys.count() > 0) { // we _must_ be authenticated if the publicKeys are there DependencyManager::get()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY); + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet was ready"; return true; } @@ -571,10 +579,15 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() { // be sure to add the public key so we don't do this over and over _publicKeys.push_back(publicKey.toBase64()); + + if (*_passphrase != "ACCOUNT") { + changePassphrase("ACCOUNT"); // Rewrites with salt and constant, and will be lockered that way. + } + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet now ready"; return true; } } - + qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet not ready"; return false; } @@ -585,6 +598,7 @@ bool Wallet::generateKeyPair() { qCInfo(commerce) << "Generating keypair."; auto keyPair = generateECKeypair(); if (!keyPair.first) { + qCWarning(commerce) << "Empty keypair"; return false; } @@ -692,11 +706,13 @@ void Wallet::chooseSecurityImage(const QString& filename) { // there _is_ a keyfile, we need to update it (similar to changing the // passphrase, we need to do so into a temp file and move it). if (!QFile(keyFilePath()).exists()) { + qCDebug(commerce) << "initial security pic set for empty wallet"; emit securityImageResult(true); return; } bool success = writeWallet(); + qCDebug(commerce) << "updated security pic" << success; emit securityImageResult(success); } From 88a3505b6a308cf53d3ad0b63af42f506df1e260 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 22 Aug 2018 12:59:43 -0700 Subject: [PATCH 05/10] cleanup --- .../qml/hifi/commerce/wallet/Help.qml | 19 +++++++++---------- .../qml/hifi/commerce/wallet/Security.qml | 7 +++++-- .../qml/hifi/commerce/wallet/Wallet.qml | 9 +++------ interface/src/commerce/Ledger.cpp | 6 ++++-- interface/src/commerce/Wallet.cpp | 2 -- interface/src/commerce/Wallet.h | 8 ++++---- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index e38f23e5a5..1c37ded4ee 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -64,7 +64,7 @@ Item { answer: "High Fidelity commerce is in open beta right now. Want more HFC? \ Get it by going to

BankOfHighFidelity. and meeting with the banker!"; } - ListElement { + /* ListElement { isExpanded: false; question: "What are private keys and where are they stored?"; answer: @@ -74,16 +74,16 @@ After wallet setup, a hifikey file is stored on your computer in High Fidelity I Your hifikey file contains your private key and is protected by your wallet passphrase. \

It is very important to back up your hifikey file! \ Tap here to open the folder where your HifiKeys are stored on your main display." - } - ListElement { + }*/ + /*ListElement { isExpanded: false; question: "How do I back up my private keys?"; answer: "You can back up your hifikey file (which contains your private key and is encrypted using your wallet passphrase) by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. \ Restore your hifikey file by replacing the file in Interface's AppData directory with your backup copy. \ Others with access to your back up should not be able to spend your HFC without your passphrase. \ Tap here to open the folder where your HifiKeys are stored on your main display."; - } - ListElement { + }*/ + /*ListElement { isExpanded: false; question: "What happens if I lose my private keys?"; answer: "We cannot stress enough that you should keep a backup! For security reasons, High Fidelity does not keep a copy, and cannot restore it for you. \ @@ -94,8 +94,8 @@ Here are some things to try:
    \
  • If you are a developer and have installed multiple builds of High Fidelity, your hifikey file might be in another folder
  • \


As a last resort, you can set up your Wallet again and generate a new hifikey file. \ Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over."; - } - ListElement { + }*/ + /*ListElement { isExpanded: false; question: "What if I forget my wallet passphrase?"; answer: "Your wallet passphrase is used to encrypt your private keys. Please write it down and store it securely! \ @@ -104,7 +104,7 @@ You will also no longer have access to the contents of your Wallet or My Purchas For security reasons, High Fidelity does not keep a copy of your passphrase, and can't restore it for you. \

If you still cannot remember your wallet passphrase, you can set up your Wallet again and generate a new hifikey file. \ Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over."; - } + }*/ ListElement { isExpanded: false; question: "How do I send HFC to other people?"; @@ -116,7 +116,7 @@ In your Wallet's Send Money tab, choose from your list of connections, or choose question: "What is a Security Pic?" answer: "Your Security Pic acts as an extra layer of Wallet security. \ When you see your Security Pic, you know that your actions and data are securely making use of your account. \ -Tap here to change your Security Pic."; +

Tap here to change your Security Pic."; } ListElement { isExpanded: false; @@ -259,7 +259,6 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta } else if (link === "#support") { Qt.openUrlExternally("mailto:support@highfidelity.com"); } else if (link === "#securitypic") { - console.log("HRS FIXME here"); sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'}); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 216d621bf8..08eb94a23c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -88,6 +88,7 @@ Item { color: hifi.colors.faintGray; } + /* Item { id: changePassphraseContainer; anchors.top: securityTextSeparator.bottom; @@ -154,10 +155,11 @@ Item { // Style color: hifi.colors.faintGray; } + */ Item { id: changeSecurityImageContainer; - anchors.top: changePassphraseSeparator.bottom; + anchors.top: securityTextSeparator.bottom; // changePassphraseSeparator.bottom; anchors.topMargin: 8; anchors.left: parent.left; anchors.leftMargin: 40; @@ -207,7 +209,7 @@ Item { } } } - + /* Rectangle { id: privateKeysSeparator; // Size @@ -344,6 +346,7 @@ Item { } } } + */ } // diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index f48553a4d0..ffd06cb4a8 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -257,9 +257,9 @@ Rectangle { Connections { onSendSignalToWallet: { if (msg.method === 'walletSecurity_changeSecurityImageCancelled') { - root.activeView = "walletHome"; // was "security"; + root.activeView = "security"; } else if (msg.method === 'walletSecurity_changeSecurityImageSuccess') { - root.activeView = "walletHome"; // was "security"; + root.activeView = "security"; } else { sendToScript(msg); } @@ -610,7 +610,7 @@ Rectangle { } RalewaySemiBold { - text: "PURCHASES"; // was "SECURITY"; + text: "SECURITY"; // Text size size: 16; // Anchors @@ -632,11 +632,8 @@ Rectangle { anchors.fill: parent; hoverEnabled: enabled; onClicked: { - sendToScript({method: 'goToPurchases_fromWalletHome'}); - /* was root.activeView = "security"; tabButtonsContainer.resetTabButtonColors(); - */ } onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 18d22057fd..67303f2a9b 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -31,7 +31,9 @@ QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply* reply) { QByteArray response = reply->readAll(); QJsonObject data = QJsonDocument::fromJson(response).object(); +#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy. qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact); +#endif return data; } // Non-200 responses are not json: @@ -69,7 +71,9 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString auto accountManager = DependencyManager::get(); const QString URL = "/api/v1/commerce/"; JSONCallbackParameters callbackParams(this, success, fail); +#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy. qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact); +#endif accountManager->sendRequest(URL + endpoint, authType, method, @@ -130,7 +134,6 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key, const transaction["locker"] = QString::fromUtf8(locker); QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - qCDebug(commerce) << "FIXME transactionString" << transactionString; signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } @@ -292,7 +295,6 @@ void Ledger::accountSuccess(QNetworkReply* reply) { // lets set the appropriate stuff in the wallet now auto wallet = DependencyManager::get(); QByteArray response = reply->readAll(); - qCDebug(commerce) << "FIXME accountSuccess got" << response; QJsonObject data = QJsonDocument::fromJson(response).object()["data"].toObject(); auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8()); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 84e90544ff..5b8417be7c 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -201,7 +201,6 @@ bool Wallet::setWallet(const QByteArray& wallet) { return false; } file.close(); - qCDebug(commerce) << "FIXME wrote" << wallet.count() << "to" << keyFilePath(); return true; } QByteArray Wallet::getWallet() { @@ -212,7 +211,6 @@ QByteArray Wallet::getWallet() { } QByteArray wallet = file.readAll(); file.close(); - qCDebug(commerce) << "FIXME read" << wallet.count() << "from" << keyFilePath(); return wallet; } diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 4e7608b096..c096713058 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -44,10 +44,6 @@ public: void setCKey(const QByteArray& ckey) { _ckey = ckey; } QByteArray getCKey() { return _ckey; } - // FIXME protect more - bool setWallet(const QByteArray& wallet); - QByteArray getWallet(); - bool setPassphrase(const QString& passphrase); QString* getPassphrase() { return _passphrase; } bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); } @@ -77,6 +73,7 @@ private slots: void handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode); private: + friend class Ledger; QStringList _publicKeys{}; QPixmap* _securityImage { nullptr }; QByteArray _salt; @@ -91,6 +88,9 @@ private: bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen); bool writeBackupInstructions(); + bool setWallet(const QByteArray& wallet); + QByteArray getWallet(); + void account(); }; From b7fa47da359dbc2394c85a82280b817ed14197f7 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 23 Aug 2018 10:37:55 -0700 Subject: [PATCH 06/10] cr feedback --- .../qml/hifi/commerce/wallet/Help.qml | 41 ---- .../qml/hifi/commerce/wallet/Security.qml | 207 ------------------ 2 files changed, 248 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 1c37ded4ee..6d8fc3c33f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -64,47 +64,6 @@ Item { answer: "High Fidelity commerce is in open beta right now. Want more HFC? \ Get it by going to

BankOfHighFidelity. and meeting with the banker!"; } - /* ListElement { - isExpanded: false; - question: "What are private keys and where are they stored?"; - answer: - "A private key is a secret piece of text that is used to prove ownership, unlock confidential information, and sign transactions. \ -In High Fidelity, your private key is used to securely access the contents of your Wallet and Purchases. \ -After wallet setup, a hifikey file is stored on your computer in High Fidelity Interface's AppData directory. \ -Your hifikey file contains your private key and is protected by your wallet passphrase. \ -

It is very important to back up your hifikey file! \ -Tap here to open the folder where your HifiKeys are stored on your main display." - }*/ - /*ListElement { - isExpanded: false; - question: "How do I back up my private keys?"; - answer: "You can back up your hifikey file (which contains your private key and is encrypted using your wallet passphrase) by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. \ -Restore your hifikey file by replacing the file in Interface's AppData directory with your backup copy. \ -Others with access to your back up should not be able to spend your HFC without your passphrase. \ -Tap here to open the folder where your HifiKeys are stored on your main display."; - }*/ - /*ListElement { - isExpanded: false; - question: "What happens if I lose my private keys?"; - answer: "We cannot stress enough that you should keep a backup! For security reasons, High Fidelity does not keep a copy, and cannot restore it for you. \ -If you lose your private key, you will no longer have access to the contents of your Wallet or My Purchases. \ -Here are some things to try:
    \ -
  • If you have backed up your hifikey file before, search your backup location
  • \ -
  • Search your AppData directory in the last machine you used to set up the Wallet
  • \ -
  • If you are a developer and have installed multiple builds of High Fidelity, your hifikey file might be in another folder
  • \ -


As a last resort, you can set up your Wallet again and generate a new hifikey file. \ -Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over."; - }*/ - /*ListElement { - isExpanded: false; - question: "What if I forget my wallet passphrase?"; - answer: "Your wallet passphrase is used to encrypt your private keys. Please write it down and store it securely! \ -

If you forget your passphrase, you will no longer be able to decrypt the hifikey file that the passphrase protects. \ -You will also no longer have access to the contents of your Wallet or My Purchases. \ -For security reasons, High Fidelity does not keep a copy of your passphrase, and can't restore it for you. \ -

If you still cannot remember your wallet passphrase, you can set up your Wallet again and generate a new hifikey file. \ -Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over."; - }*/ ListElement { isExpanded: false; question: "How do I send HFC to other people?"; diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 08eb94a23c..da3331ebfc 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -88,75 +88,6 @@ Item { color: hifi.colors.faintGray; } - /* - Item { - id: changePassphraseContainer; - anchors.top: securityTextSeparator.bottom; - anchors.topMargin: 8; - anchors.left: parent.left; - anchors.leftMargin: 40; - anchors.right: parent.right; - anchors.rightMargin: 55; - height: 75; - - HiFiGlyphs { - id: changePassphraseImage; - text: hifi.glyphs.passphrase; - // Size - size: 80; - // Anchors - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - // Style - color: hifi.colors.white; - } - - RalewaySemiBold { - text: "Passphrase"; - // Anchors - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: changePassphraseImage.right; - anchors.leftMargin: 30; - width: 50; - // Text size - size: 18; - // Style - color: hifi.colors.white; - } - - // "Change Passphrase" button - HifiControlsUit.Button { - id: changePassphraseButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter; - width: 140; - height: 40; - text: "Change"; - onClicked: { - sendSignalToWallet({method: 'walletSecurity_changePassphrase'}); - } - } - } - - Rectangle { - id: changePassphraseSeparator; - // Size - width: parent.width; - height: 1; - // Anchors - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: changePassphraseContainer.bottom; - anchors.topMargin: 8; - // Style - color: hifi.colors.faintGray; - } - */ - Item { id: changeSecurityImageContainer; anchors.top: securityTextSeparator.bottom; // changePassphraseSeparator.bottom; @@ -209,144 +140,6 @@ Item { } } } - /* - Rectangle { - id: privateKeysSeparator; - // Size - width: parent.width; - height: 1; - // Anchors - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: changeSecurityImageContainer.bottom; - anchors.topMargin: 8; - // Style - color: hifi.colors.faintGray; - } - - Item { - id: yourPrivateKeysContainer; - anchors.top: privateKeysSeparator.bottom; - anchors.left: parent.left; - anchors.leftMargin: 40; - anchors.right: parent.right; - anchors.rightMargin: 55; - anchors.bottom: parent.bottom; - - onVisibleChanged: { - if (visible) { - Commerce.getKeyFilePathIfExists(); - } - } - - HiFiGlyphs { - id: yourPrivateKeysImage; - text: hifi.glyphs.walletKey; - // Size - size: 80; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 20; - anchors.left: parent.left; - // Style - color: hifi.colors.white; - } - - RalewaySemiBold { - id: yourPrivateKeysText; - text: "Private Keys"; - size: 18; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 32; - anchors.left: yourPrivateKeysImage.right; - anchors.leftMargin: 30; - anchors.right: parent.right; - height: 30; - // Style - color: hifi.colors.white; - } - - // Text below "private keys" - RalewayRegular { - id: explanitoryText; - text: "Your money and purchases are secured with private keys that only you have access to."; - // Text size - size: 18; - // Anchors - anchors.top: yourPrivateKeysText.bottom; - anchors.topMargin: 10; - anchors.left: yourPrivateKeysText.left; - anchors.right: yourPrivateKeysText.right; - height: paintedHeight; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - } - - Rectangle { - id: removeHmdContainer; - z: 998; - visible: false; - - gradient: Gradient { - GradientStop { - position: 0.2; - color: hifi.colors.baseGrayHighlight; - } - GradientStop { - position: 1.0; - color: hifi.colors.baseGrayShadow; - } - } - anchors.fill: backupInstructionsButton; - radius: 5; - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - RalewayBold { - anchors.fill: parent; - text: "INSTRUCTIONS OPEN ON DESKTOP"; - size: 15; - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - horizontalAlignment: Text.AlignHCenter; - } - - Timer { - id: removeHmdContainerTimer; - interval: 5000; - onTriggered: removeHmdContainer.visible = false - } - } - - HifiControlsUit.Button { - id: backupInstructionsButton; - text: "View Backup Instructions"; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.left: explanitoryText.left; - anchors.right: explanitoryText.right; - anchors.top: explanitoryText.bottom; - anchors.topMargin: 16; - height: 40; - - onClicked: { - var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')); - Qt.openUrlExternally(keyPath + "/backup_instructions.html"); - Qt.openUrlExternally(keyPath); - removeHmdContainer.visible = true; - removeHmdContainerTimer.start(); - } - } - } - */ } // From b7d074aaa4e23efe8c50c5f5c5b23f6c35bbc764 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 23 Aug 2018 10:41:19 -0700 Subject: [PATCH 07/10] remove comment --- interface/resources/qml/hifi/commerce/wallet/Security.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index da3331ebfc..e021328ebe 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -90,7 +90,7 @@ Item { Item { id: changeSecurityImageContainer; - anchors.top: securityTextSeparator.bottom; // changePassphraseSeparator.bottom; + anchors.top: securityTextSeparator.bottom; anchors.topMargin: 8; anchors.left: parent.left; anchors.leftMargin: 40; From 36784b0039058ce30e8d165e25379431ed37c766 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Aug 2018 10:21:59 -0700 Subject: [PATCH 08/10] reset sent trait data when re-send required --- assignment-client/src/avatars/AvatarMixer.cpp | 23 ++++++++++++------- .../src/avatars/AvatarMixerClientData.cpp | 8 +++++++ .../src/avatars/AvatarMixerClientData.h | 2 ++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 167c1cd29c..edbba20dc7 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -541,7 +541,8 @@ void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointersetLastBroadcastTime(node->getUUID(), 0); + nodeData->setLastBroadcastTime(node->getUUID(), 0); + nodeData->resetSentTraitData(node->getLocalID()); } ); } @@ -588,10 +589,10 @@ void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointergetMessage()) ); if (!avatarID.isNull()) { auto nodeList = DependencyManager::get(); - auto node = nodeList->nodeWithUUID(avatarID); - if (node) { - QMutexLocker lock(&node->getMutex()); - AvatarMixerClientData* avatarClientData = dynamic_cast(node->getLinkedData()); + auto requestedNode = nodeList->nodeWithUUID(avatarID); + + if (requestedNode) { + AvatarMixerClientData* avatarClientData = static_cast(requestedNode->getLinkedData()); if (avatarClientData) { const AvatarData& avatarData = avatarClientData->getAvatar(); QByteArray serializedAvatar = avatarData.identityByteArray(); @@ -600,6 +601,11 @@ void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointersendPacketList(std::move(identityPackets), *senderNode); ++_sumIdentityPackets; } + + AvatarMixerClientData* senderData = static_cast(senderNode->getLinkedData()); + if (senderData) { + senderData->resetSentTraitData(requestedNode->getLocalID()); + } } } } @@ -625,23 +631,24 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer while (message->getBytesLeftToRead()) { // parse out the UUID being ignored from the packet QUuid ignoredUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - - if (nodeList->nodeWithUUID(ignoredUUID)) { + auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID); + if (ignoredNode) { if (nodeData) { // Reset the lastBroadcastTime for the ignored avatar to 0 // so the AvatarMixer knows it'll have to send identity data about the ignored avatar // to the ignorer if the ignorer unignores. nodeData->setLastBroadcastTime(ignoredUUID, 0); + nodeData->resetSentTraitData(ignoredNode->getLocalID()); } // Reset the lastBroadcastTime for the ignorer (FROM THE PERSPECTIVE OF THE IGNORED) to 0 // so the AvatarMixer knows it'll have to send identity data about the ignorer // to the ignored if the ignorer unignores. - auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID); AvatarMixerClientData* ignoredNodeData = reinterpret_cast(ignoredNode->getLinkedData()); if (ignoredNodeData) { ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0); + ignoredNodeData->resetSentTraitData(senderNode->getLocalID()); } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index b2490fc7b4..f524c071ec 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -228,6 +228,9 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble); } setLastBroadcastTime(other->getUUID(), 0); + + resetSentTraitData(other->getLocalID()); + DependencyManager::get()->sendPacket(std::move(killPacket), *self); } } @@ -238,6 +241,11 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self, } } +void AvatarMixerClientData::resetSentTraitData(Node::LocalID nodeLocalID) { + _lastSentTraitsTimestamps[nodeLocalID] = TraitsCheckTimestamp(); + _sentTraitVersions[nodeLocalID].reset(); +} + void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) { _currentViewFrustums.clear(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 1c2694af48..a892455fe3 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -135,6 +135,8 @@ public: AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _sentTraitVersions[otherAvatar]; } + void resetSentTraitData(Node::LocalID nodeID); + private: struct PacketQueue : public std::queue> { QWeakPointer node; From 09065cf19aaa47eedbca871c3a5b7ae75b399e17 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Aug 2018 10:37:41 -0700 Subject: [PATCH 09/10] provide assignment dynamic factory to agent --- assignment-client/src/Agent.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 06a14927d3..2f03f15da7 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -53,6 +53,7 @@ #include // TODO: consider moving to scriptengine.h #include "entities/AssignmentParentFinder.h" +#include "AssignmentDynamicFactory.h" #include "RecordingScriptingInterface.h" #include "AbstractAudioInterface.h" #include "AgentScriptingInterface.h" @@ -67,6 +68,9 @@ Agent::Agent(ReceivedMessage& message) : { DependencyManager::set(); + DependencyManager::registerInheritance(); + DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(false); @@ -860,6 +864,8 @@ void Agent::aboutToFinish() { DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); + DependencyManager::destroy(); QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); From e1879bf26ac5bd87996ed5d701a9ea69482aa3a8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Aug 2018 13:55:17 -0700 Subject: [PATCH 10/10] add assignment dynamic factory to ESS --- assignment-client/src/scripts/EntityScriptServer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 586931d403..272985093c 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -33,6 +33,7 @@ #include // for EntityScriptServerServices +#include "../AssignmentDynamicFactory.h" #include "EntityScriptServerLogging.h" #include "../entities/AssignmentParentFinder.h" @@ -56,6 +57,9 @@ int EntityScriptServer::_entitiesScriptEngineCount = 0; EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { qInstallMessageHandler(messageHandler); + DependencyManager::registerInheritance(); + DependencyManager::set(); + DependencyManager::set(false)->setPacketSender(&_entityEditSender); DependencyManager::set(); @@ -579,6 +583,7 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer mess void EntityScriptServer::aboutToFinish() { shutdownScriptEngine(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::get()->cleanup();