diff --git a/CMakeLists.txt b/CMakeLists.txt index 4527e06418..e67002b89d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -247,6 +247,9 @@ endif() set_packaging_parameters() +option(BUILD_TESTS "Build tests" ON) +MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) + # add subdirectories for all targets if (NOT ANDROID) add_subdirectory(assignment-client) @@ -259,7 +262,9 @@ if (NOT ANDROID) if (NOT SERVER_ONLY) add_subdirectory(interface) set_target_properties(interface PROPERTIES FOLDER "Apps") - add_subdirectory(tests) + if (BUILD_TESTS) + add_subdirectory(tests) + endif() endif() add_subdirectory(plugins) add_subdirectory(tools) diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 3f3d00b401..d0a96db3f2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -40,10 +40,8 @@ Item { } } - onKeyFilePathResult: { - if (path !== "") { - keyFilePath.text = path; - } + onKeyFilePathIfExistsResult: { + keyFilePath.text = path; } } @@ -264,7 +262,7 @@ Item { onVisibleChanged: { if (visible) { - commerce.getKeyFilePath(); + commerce.getKeyFilePathIfExists(); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index ac5d851bbc..ae2606c0f6 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -25,7 +25,9 @@ Rectangle { id: root; - property string activeView: "walletHome"; + property string activeView: "initialize"; + property bool securityImageResultReceived: false; + property bool keyFilePathIfExistsResultReceived: false; // Style color: hifi.colors.baseGray; @@ -33,16 +35,20 @@ Rectangle { id: commerce; onSecurityImageResult: { - if (!exists) { // "If security image is not set up" - if (root.activeView !== "notSetUp") { - root.activeView = "notSetUp"; - } + securityImageResultReceived = true; + if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" + root.activeView = "notSetUp"; + } else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") { + root.activeView = "walletHome"; } } - onKeyFilePathResult: { + onKeyFilePathIfExistsResult: { + keyFilePathIfExistsResultReceived = true; if (path === "" && root.activeView !== "notSetUp") { root.activeView = "notSetUp"; + } else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") { + root.activeView = "walletHome"; } } } @@ -151,6 +157,22 @@ Rectangle { // // TAB CONTENTS START // + + Rectangle { + id: initialize; + visible: root.activeView === "initialize"; + anchors.top: titleBarContainer.bottom; + anchors.bottom: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + color: hifi.colors.baseGray; + + Component.onCompleted: { + commerce.getSecurityImage(); + commerce.getKeyFilePathIfExists(); + } + } + NotSetUp { id: notSetUp; visible: root.activeView === "notSetUp"; @@ -283,13 +305,6 @@ Rectangle { onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; } - - onVisibleChanged: { - if (visible) { - commerce.getSecurityImage(); - commerce.balance(); - } - } } // "SEND MONEY" tab button @@ -382,13 +397,6 @@ Rectangle { onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; } - - onVisibleChanged: { - if (visible) { - commerce.getSecurityImage(); - commerce.getKeyFilePath(); - } - } } // "HELP" tab button diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml index 474322062e..bbeb77f6fa 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml @@ -56,10 +56,8 @@ Rectangle { } } - onKeyFilePathResult: { - if (path !== "") { - keyFilePath.text = path; - } + onKeyFilePathIfExistsResult: { + keyFilePath.text = path; } } @@ -455,10 +453,10 @@ Rectangle { text: "Next"; onClicked: { if (passphraseSelection.validateAndSubmitPassphrase()) { - root.lastPage = "passphrase"; + root.lastPage = "choosePassphrase"; + commerce.balance(); // Do this here so that keys are generated. Order might change as backend changes? choosePassphraseContainer.visible = false; privateKeysReadyContainer.visible = true; - commerce.balance(); // Do this here so that keys are generated. Order might change as backend changes? } } } @@ -562,7 +560,7 @@ Rectangle { onVisibleChanged: { if (visible) { - commerce.getKeyFilePath(); + commerce.getKeyFilePathIfExists(); } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 9676c821be..c7f83ad28f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -702,8 +702,8 @@ private: bool _saveAvatarOverrideUrl { false }; QObject* _renderEventHandler{ nullptr }; - LaserPointerManager _laserPointerManager; RayPickManager _rayPickManager; + LaserPointerManager _laserPointerManager; friend class RenderEventHandler; }; diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index c2103c89ce..bf6bcc221c 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -25,8 +25,8 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { connect(ledger.data(), &Ledger::balanceResult, this, &QmlCommerce::balanceResult); connect(ledger.data(), &Ledger::inventoryResult, this, &QmlCommerce::inventoryResult); connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult); - connect(wallet.data(), &Wallet::keyFilePathResult, this, &QmlCommerce::keyFilePathResult); connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult); + connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); } void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) { @@ -81,8 +81,7 @@ void QmlCommerce::setPassphrase(const QString& passphrase) { void QmlCommerce::getPassphraseSetupStatus() { emit passphraseSetupStatusResult(false); } - -void QmlCommerce::getKeyFilePath() { +void QmlCommerce::getKeyFilePathIfExists() { auto wallet = DependencyManager::get(); - wallet->getKeyFilePath(); + wallet->sendKeyFilePathIfExists(); } diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 9438d4f696..fd913ae4b7 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -36,8 +36,8 @@ signals: void securityImageResult(bool exists); void loginStatusResult(bool isLoggedIn); void passphraseSetupStatusResult(bool passphraseIsSetup); - void keyFilePathResult(const QString& path); void historyResult(QJsonObject result); + void keyFilePathIfExistsResult(const QString& path); protected: Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = ""); @@ -49,7 +49,7 @@ protected: Q_INVOKABLE void getLoginStatus(); Q_INVOKABLE void setPassphrase(const QString& passphrase); Q_INVOKABLE void getPassphraseSetupStatus(); - Q_INVOKABLE void getKeyFilePath(); + Q_INVOKABLE void getKeyFilePathIfExists(); }; #endif // hifi_QmlCommerce_h diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 5fefd0c43b..1d64733f49 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -220,8 +220,8 @@ static const unsigned char IVEC[16] = "IAmAnIVecYay123"; void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) { // first ivec memcpy(ivec, IVEC, 16); - auto hash = QCryptographicHash::hash(salt, QCryptographicHash::Md5); - memcpy(ckey, hash.data(), 16); + auto hash = QCryptographicHash::hash(salt, QCryptographicHash::Sha256); + memcpy(ckey, hash.data(), 32); } void Wallet::setPassphrase(const QString& passphrase) { @@ -238,7 +238,7 @@ bool Wallet::encryptFile(const QString& inputFilePath, const QString& outputFile // a constant. We can review this later - there are ways to generate keys // from a password that may be better. unsigned char ivec[16]; - unsigned char ckey[16]; + unsigned char ckey[32]; initializeAESKeys(ivec, ckey, _salt); @@ -292,7 +292,7 @@ bool Wallet::encryptFile(const QString& inputFilePath, const QString& outputFile bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferSize) { unsigned char ivec[16]; - unsigned char ckey[16]; + unsigned char ckey[32]; initializeAESKeys(ivec, ckey, _salt); // read encrypted file @@ -331,7 +331,6 @@ bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBuf *outputBufferSize += tempSize; *outputBufferPtr = outputBuffer; qCDebug(commerce) << "decrypted buffer size" << *outputBufferSize; - delete[] outputBuffer; return true; } @@ -359,6 +358,7 @@ bool Wallet::createIfNeeded() { bool Wallet::generateKeyPair() { qCInfo(commerce) << "Generating keypair."; auto keyPair = generateRSAKeypair(); + sendKeyFilePathIfExists(); QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last(); QString key = keyPair.first->toBase64(); _publicKeys.push_back(key); @@ -465,12 +465,19 @@ void Wallet::getSecurityImage() { auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); imageProvider->setSecurityImage(_securityImage); + delete[] data; emit securityImageResult(true); } else { qCDebug(commerce) << "failed to decrypt security image (maybe none saved yet?)"; emit securityImageResult(false); } } -void Wallet::getKeyFilePath() { - emit keyFilePathResult(keyFilePath()); +void Wallet::sendKeyFilePathIfExists() { + QString filePath(keyFilePath()); + QFileInfo fileInfo(filePath); + if (fileInfo.exists()) { + emit keyFilePathIfExistsResult(filePath); + } else { + emit keyFilePathIfExistsResult(""); + } } diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 4c0d7190bb..b13d4368d9 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -30,7 +30,7 @@ public: QString signWithKey(const QByteArray& text, const QString& key); void chooseSecurityImage(const QString& imageFile); void getSecurityImage(); - void getKeyFilePath(); + void sendKeyFilePathIfExists(); void setSalt(const QByteArray& salt) { _salt = salt; } QByteArray getSalt() { return _salt; } @@ -40,7 +40,7 @@ public: signals: void securityImageResult(bool exists) ; - void keyFilePathResult(const QString& path); + void keyFilePathIfExistsResult(const QString& path); protected: enum SecurityImage { diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 2285337f41..f892a5ec78 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -24,12 +24,12 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/makeUserConnection.js", "system/tablet-goto.js", "system/marketplaces/marketplaces.js", + "system/commerce/wallet.js", "system/edit.js", "system/notifications.js", "system/dialTone.js", "system/firstPersonHMD.js", - "system/tablet-ui/tabletUI.js", - "system/commerce/wallet.js" + "system/tablet-ui/tabletUI.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ "system/controllers/controllerScripts.js", diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 14954e5df6..4b758f0add 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -126,7 +126,8 @@ button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/wallet-i.svg", - activeIcon: "icons/tablet-icons/wallet-a.svg" + activeIcon: "icons/tablet-icons/wallet-a.svg", + sortOrder: 10 }); button.clicked.connect(onButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged);