From 138534c3ff59823d685d699c2b51d46752c18b39 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 23 Aug 2017 15:01:09 -0700 Subject: [PATCH] encrypt security image --- .../commerce/wallet/PassphraseSelection.qml | 10 +++--- .../qml/hifi/commerce/wallet/Security.qml | 16 +++++++-- .../wallet/SecurityImageSelection.qml | 11 ------- .../wallet/SecurityImageSelectionLightbox.qml | 5 +-- .../qml/hifi/commerce/wallet/Wallet.qml | 10 +++--- .../qml/hifi/commerce/wallet/WalletHome.qml | 33 ++++++++++--------- .../commerce/wallet/WalletSetupLightbox.qml | 5 +-- interface/src/Application.cpp | 10 ++++-- interface/src/commerce/QmlCommerce.h | 4 +-- interface/src/commerce/Wallet.cpp | 26 ++++++++++++--- interface/src/commerce/Wallet.h | 2 +- interface/src/ui/ImageProvider.cpp | 29 ++++++++++++++++ interface/src/ui/ImageProvider.h | 33 +++++++++++++++++++ 13 files changed, 141 insertions(+), 53 deletions(-) create mode 100644 interface/src/ui/ImageProvider.cpp create mode 100644 interface/src/ui/ImageProvider.h diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 7f098beaca..89ef851b06 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -24,7 +24,7 @@ Item { HifiConstants { id: hifi; } id: root; - + // This object is always used in a popup. // This MouseArea is used to prevent a user from being // able to click on a button/mouseArea underneath the popup. @@ -36,7 +36,8 @@ Item { Hifi.QmlCommerce { id: commerce; onSecurityImageResult: { - //passphrasePageSecurityImage.source = gridModel.getImagePathFromImageID(imageID); + passphrasePageSecurityImage.source = ""; + passphrasePageSecurityImage.source = "image://security/securityImage"; } onPassphraseSetupStatusResult: { @@ -104,7 +105,8 @@ Item { width: height; fillMode: Image.PreserveAspectFit; mipmap: true; - + source: "image://security/securityImage"; + cache: false; onVisibleChanged: { commerce.getSecurityImage(); } @@ -124,7 +126,7 @@ Item { color: hifi.colors.faintGray; // Alignment horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 85763788af..3f3d00b401 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -29,10 +29,14 @@ Item { id: commerce; onSecurityImageResult: { - if (image) { // "If security image is set up" - var path = securityImageModel.getImagePathFromImageID(1); + if (exists) { // "If security image is set up" + var path = "image://security/securityImage"; + topSecurityImage.source = ""; topSecurityImage.source = path; + changeSecurityImageImage.source = ""; changeSecurityImageImage.source = path; + changePassphraseImage.source = ""; + changePassphraseImage.source = path; } } @@ -87,6 +91,8 @@ Item { width: height; fillMode: Image.PreserveAspectFit; mipmap: true; + source: "image://security/securityImage"; + cache: false; } // "Security picture" text below pic RalewayRegular { @@ -103,7 +109,7 @@ Item { color: hifi.colors.faintGray; // Alignment horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } @@ -144,8 +150,10 @@ Item { anchors.left: parent.left; height: parent.height; width: height; + source: "image://security/securityImage"; fillMode: Image.PreserveAspectFit; mipmap: true; + cache: false; } // "Change Passphrase" button HifiControlsUit.Button { @@ -181,6 +189,8 @@ Item { width: height; fillMode: Image.PreserveAspectFit; mipmap: true; + cache: false; + source: "image://security/securityImage"; } // "Change Security Image" button HifiControlsUit.Button { diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index fb6edeb404..7ab52b7551 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -28,17 +28,6 @@ Item { Hifi.QmlCommerce { id: commerce; onSecurityImageResult: { - // for now just hardwire the index - securityImageGrid.currentIndex = 1; - //if (imageID > 0) { - // for (var itr = 0; itr < gridModel.count; itr++) { - // var thisValue = gridModel.get(itr).securityImageEnumValue; - // if (thisValue === imageID) { - // securityImageGrid.currentIndex = itr; - // break; - // } - // } - //} } } diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml index c5b59e7467..d4b0b82ed3 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml @@ -38,7 +38,7 @@ Rectangle { id: commerce; onSecurityImageResult: { - if (image) { // Success submitting new security image + if (exists) { // Success submitting new security image if (root.justSubmitted) { root.resetSubmitButton(); root.visible = false; @@ -183,7 +183,8 @@ Rectangle { root.justSubmitted = true; securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; - commerce.chooseSecurityImage(securityImageSelection.getImagePathFromImageID(1)); + var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) + commerce.chooseSecurityImage(securityImagePath); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 1ef8000d1e..ac5d851bbc 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -33,7 +33,7 @@ Rectangle { id: commerce; onSecurityImageResult: { - if (!image) { // "If security image is not set up" + if (!exists) { // "If security image is not set up" if (root.activeView !== "notSetUp") { root.activeView = "notSetUp"; } @@ -104,7 +104,7 @@ Rectangle { width: walletSetupLightboxContainer.width - 50; height: walletSetupLightboxContainer.height - 50; } - + // // TITLE BAR START @@ -226,7 +226,7 @@ Rectangle { // // TAB CONTENTS END // - + // // TAB BUTTONS START // @@ -283,7 +283,7 @@ Rectangle { onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; } - + onVisibleChanged: { if (visible) { commerce.getSecurityImage(); @@ -382,7 +382,7 @@ Rectangle { onEntered: parent.color = hifi.colors.blueHighlight; onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; } - + onVisibleChanged: { if (visible) { commerce.getSecurityImage(); diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 0e1310bce3..88f939d393 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -22,16 +22,17 @@ import "../../../controls" as HifiControls Item { HifiConstants { id: hifi; } - + id: root; Hifi.QmlCommerce { id: commerce; onSecurityImageResult: { - if (image) { // "If security image is set up" - var path = securityImageModel.getImagePathFromImageID(1); - securityImage.source = path; + if (exists) { + // just set the source again (to be sure the change was noticed) + securityImage.source = ""; + securityImage.source = "image://security/securityImage"; } } @@ -43,7 +44,7 @@ Item { SecurityImageModel { id: securityImageModel; } - + Connections { target: GlobalServices onMyUsernameChanged: { @@ -66,7 +67,7 @@ Item { anchors.left: parent.left; anchors.right: hfcBalanceContainer.left; } - + // HFC Balance Container Item { id: hfcBalanceContainer; @@ -99,8 +100,8 @@ Item { color: hifi.colors.darkGray; // Alignment horizontalAlignment: Text.AlignRight; - verticalAlignment: Text.AlignVCenter; - + verticalAlignment: Text.AlignVCenter; + onVisibleChanged: { if (visible) { commerce.balance(); @@ -124,7 +125,7 @@ Item { color: hifi.colors.darkGray; // Alignment horizontalAlignment: Text.AlignRight; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } // "balance" text above field @@ -142,7 +143,7 @@ Item { color: hifi.colors.faintGray; // Alignment horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } @@ -170,6 +171,8 @@ Item { width: height; fillMode: Image.PreserveAspectFit; mipmap: true; + cache: false; + source: "image://security/securityImage"; } // "Security picture" text below pic RalewayRegular { @@ -186,7 +189,7 @@ Item { color: hifi.colors.faintGray; // Alignment horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } @@ -222,7 +225,7 @@ Item { anchors.bottomMargin: 8; anchors.left: parent.left; anchors.right: parent.right; - + // some placeholder stuff RalewayRegular { text: homeMessage.visible ? "you CANNOT scroll through this." : "you CAN scroll through this"; @@ -234,10 +237,10 @@ Item { color: hifi.colors.darkGray; // Alignment horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignVCenter; } } - + HifiControlsUit.Button { id: toggleFullHistoryButton; color: hifi.buttons.black; @@ -322,7 +325,7 @@ Item { homeMessageButtons.visible = false; } } - } + } } // diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml index 3494b18edc..474322062e 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml @@ -40,7 +40,7 @@ Rectangle { } onSecurityImageResult: { - if (!image && root.lastPage === "securityImage") { + if (!exists && root.lastPage === "securityImage") { // ERROR! Invalid security image. securityImageContainer.visible = true; choosePassphraseContainer.visible = false; @@ -327,7 +327,8 @@ Rectangle { text: "Next"; onClicked: { root.lastPage = "securityImage"; - commerce.chooseSecurityImage(securityImageSelection.getImagePathFromImageID(1)); + var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) + commerce.chooseSecurityImage(securityImagePath); securityImageContainer.visible = false; choosePassphraseContainer.visible = true; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 398b2dbdb4..f7e664476b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -183,6 +183,7 @@ #include "ui/UpdateDialog.h" #include "ui/overlays/Overlays.h" #include "ui/DomainConnectionModel.h" +#include "ui/ImageProvider.h" #include "Util.h" #include "InterfaceParentFinder.h" #include "ui/OctreeStatsProvider.h" @@ -2144,6 +2145,9 @@ void Application::initializeUi() { qApp->quit(); }); + // register the pixmap image provider (used only for security image, for now) + engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider()); + setupPreferences(); // For some reason there is already an "Application" object in the QML context, @@ -3736,7 +3740,7 @@ bool Application::shouldPaint() { (float)paintDelaySamples / paintDelayUsecs << "us"; } #endif - + // Throttle if requested if (displayPlugin->isThrottled() && (_lastTimeUpdated.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { return false; @@ -6276,7 +6280,7 @@ bool Application::askToReplaceDomainContent(const QString& url) { OffscreenUi::warning("Unable to replace content", "You do not have permissions to replace domain content", QMessageBox::Ok, QMessageBox::Ok); } - QJsonObject messageProperties = { + QJsonObject messageProperties = { { "status", methodDetails }, { "content_set_url", url } }; @@ -6359,7 +6363,7 @@ void Application::showAssetServerWidget(QString filePath) { void Application::addAssetToWorldFromURL(QString url) { qInfo(interfaceapp) << "Download model and add to world from" << url; - + QString filename; if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index ae606f80de..d7a892cf1f 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -29,11 +29,11 @@ public: signals: void buyResult(QJsonObject result); - // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and + // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and // because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain). void balanceResult(QJsonObject result); void inventoryResult(QJsonObject result); - void securityImageResult(QPixmap* image); + void securityImageResult(bool exists); void loginStatusResult(bool isLoggedIn); void passphraseSetupStatusResult(bool passphraseIsSetup); void keyFilePathResult(const QString& path); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 68fdecca4a..b003492e5c 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -13,11 +13,14 @@ #include "Ledger.h" #include "Wallet.h" #include "Application.h" +#include "ui/ImageProvider.h" #include +#include #include #include +#include #include #include @@ -402,10 +405,17 @@ void Wallet::chooseSecurityImage(const QString& filename) { // encrypt it and save. if (encryptFile(path, imageFilePath())) { - emit securityImageResult(_securityImage); + qCDebug(commerce) << "emitting pixmap"; + + // inform the image provider + auto engine = DependencyManager::get()->getSurfaceContext()->engine(); + auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); + imageProvider->setSecurityImage(_securityImage); + + emit securityImageResult(true); } else { qCDebug(commerce) << "failed to encrypt security image"; - emit securityImageResult(nullptr); + emit securityImageResult(false); } } void Wallet::getSecurityImage() { @@ -414,7 +424,7 @@ void Wallet::getSecurityImage() { // if already decrypted, don't do it again if (_securityImage) { - emit securityImageResult(_securityImage); + emit securityImageResult(true); return; } @@ -424,10 +434,16 @@ void Wallet::getSecurityImage() { _securityImage = new QPixmap(); _securityImage->loadFromData(data, dataLen, "jpg"); qCDebug(commerce) << "created pixmap from encrypted file"; - emit securityImageResult(_securityImage); + + // inform the image provider + auto engine = DependencyManager::get()->getSurfaceContext()->engine(); + auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); + imageProvider->setSecurityImage(_securityImage); + + emit securityImageResult(true); } else { qCDebug(commerce) << "failed to decrypt security image (maybe none saved yet?)"; - emit securityImageResult(nullptr); + emit securityImageResult(false); } } void Wallet::getKeyFilePath() { diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 8f962a1bc9..f7649aa4ca 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -36,7 +36,7 @@ public: QByteArray getSalt() { return _salt; } signals: - void securityImageResult(QPixmap* image); + void securityImageResult(bool exists) ; void keyFilePathResult(const QString& path); protected: diff --git a/interface/src/ui/ImageProvider.cpp b/interface/src/ui/ImageProvider.cpp new file mode 100644 index 0000000000..4925cdf1e9 --- /dev/null +++ b/interface/src/ui/ImageProvider.cpp @@ -0,0 +1,29 @@ +// +// ImageProvider.cpp +// interface/src/ui +// +// Created by David Kelly on 8/23/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ImageProvider.h" +#include + +const QString ImageProvider::PROVIDER_NAME = "security"; + +QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { + + // adjust the internal pixmap to have the requested size + if (id == "securityImage" && _securityImage) { + *size = _securityImage->size(); + if (requestedSize.width() > 0 && requestedSize.height() > 0) { + return _securityImage->scaled(requestedSize.width(), requestedSize.height(), Qt::KeepAspectRatio); + } else { + return _securityImage->copy(); + } + } + return QPixmap(); +} diff --git a/interface/src/ui/ImageProvider.h b/interface/src/ui/ImageProvider.h new file mode 100644 index 0000000000..b09d32c8a8 --- /dev/null +++ b/interface/src/ui/ImageProvider.h @@ -0,0 +1,33 @@ +// +// ImageProvider.h +// +// Created by David Kelly on 2017/08/23 +// Copyright 2017 High Fidelity, Inc. + +// Distributed under the Apache License, Version 2.0 +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_ImageProvider_h +#define hifi_ImageProvider_h + +#include + +class ImageProvider: public QQuickImageProvider { +public: + static const QString PROVIDER_NAME; + + ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} + + QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize); + + void setSecurityImage(QPixmap* pixmap) { _securityImage = pixmap; } + +protected: + QPixmap* _securityImage; + +}; + +#endif //hifi_ImageProvider_h +