mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 06:38:29 +02:00
Merge pull request #11294 from zfox23/commerce_walletPassphraseModal
Commerce: Wallet Passphrase Input Modal
This commit is contained in:
commit
8723ff2df2
14 changed files with 602 additions and 125 deletions
|
@ -29,7 +29,6 @@ Rectangle {
|
||||||
property bool purchasesReceived: false;
|
property bool purchasesReceived: false;
|
||||||
property bool balanceReceived: false;
|
property bool balanceReceived: false;
|
||||||
property bool securityImageResultReceived: false;
|
property bool securityImageResultReceived: false;
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property string itemId: "";
|
property string itemId: "";
|
||||||
property string itemHref: "";
|
property string itemHref: "";
|
||||||
property double balanceAfterPurchase: 0;
|
property double balanceAfterPurchase: 0;
|
||||||
|
@ -46,10 +45,15 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
commerce.balance();
|
}
|
||||||
commerce.inventory();
|
}
|
||||||
|
|
||||||
|
onKeyFilePathIfExistsResult: {
|
||||||
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
|
root.activeView = "notSetUp";
|
||||||
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +61,8 @@ Rectangle {
|
||||||
securityImageResultReceived = true;
|
securityImageResultReceived = true;
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
root.activeView = "checkoutMain";
|
commerce.getWalletAuthenticatedStatus();
|
||||||
} else if (exists) {
|
} else if (exists) {
|
||||||
// just set the source again (to be sure the change was noticed)
|
// just set the source again (to be sure the change was noticed)
|
||||||
securityImage.source = "";
|
securityImage.source = "";
|
||||||
|
@ -66,12 +70,17 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!isAuthenticated && !passphraseModal.visible) {
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
passphraseModal.visible = true;
|
||||||
root.activeView = "notSetUp";
|
} else if (isAuthenticated) {
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
|
||||||
root.activeView = "checkoutMain";
|
root.activeView = "checkoutMain";
|
||||||
|
if (!balanceReceived) {
|
||||||
|
commerce.balance();
|
||||||
|
}
|
||||||
|
if (!purchasesReceived) {
|
||||||
|
commerce.inventory();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +119,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiWallet.SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// TITLE BAR START
|
// TITLE BAR START
|
||||||
//
|
//
|
||||||
|
@ -195,11 +200,10 @@ Rectangle {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
balanceReceived = false;
|
balanceReceived = false;
|
||||||
keyFilePathIfExistsResultReceived = false;
|
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiWallet.NeedsLogIn {
|
HifiWallet.NeedsLogIn {
|
||||||
id: needsLogIn;
|
id: needsLogIn;
|
||||||
visible: root.activeView === "needsLogIn";
|
visible: root.activeView === "needsLogIn";
|
||||||
|
@ -221,8 +225,21 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HifiWallet.PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// "WALLET NOT SET UP" START
|
// "WALLET NOT SET UP" START
|
||||||
//
|
//
|
||||||
|
@ -233,7 +250,7 @@ Rectangle {
|
||||||
anchors.bottom: parent.bottom;
|
anchors.bottom: parent.bottom;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: notSetUpText;
|
id: notSetUpText;
|
||||||
text: "<b>Your wallet isn't set up.</b><br><br>Set up your Wallet (no credit card necessary) to claim your <b>free HFC</b> " +
|
text: "<b>Your wallet isn't set up.</b><br><br>Set up your Wallet (no credit card necessary) to claim your <b>free HFC</b> " +
|
||||||
|
@ -264,7 +281,7 @@ Rectangle {
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.bottom: parent.bottom;
|
anchors.bottom: parent.bottom;
|
||||||
anchors.bottomMargin: 24;
|
anchors.bottomMargin: 24;
|
||||||
|
|
||||||
// "Cancel" button
|
// "Cancel" button
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
id: cancelButton;
|
id: cancelButton;
|
||||||
|
|
|
@ -28,7 +28,6 @@ Rectangle {
|
||||||
property string activeView: "initialize";
|
property string activeView: "initialize";
|
||||||
property string referrerURL: "";
|
property string referrerURL: "";
|
||||||
property bool securityImageResultReceived: false;
|
property bool securityImageResultReceived: false;
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property bool purchasesReceived: false;
|
property bool purchasesReceived: false;
|
||||||
property bool punctuationMode: false;
|
property bool punctuationMode: false;
|
||||||
// Style
|
// Style
|
||||||
|
@ -41,9 +40,15 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
commerce.inventory();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyFilePathIfExistsResult: {
|
||||||
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
|
root.activeView = "notSetUp";
|
||||||
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +56,8 @@ Rectangle {
|
||||||
securityImageResultReceived = true;
|
securityImageResultReceived = true;
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
root.activeView = "purchasesMain";
|
commerce.getWalletAuthenticatedStatus();
|
||||||
} else if (exists) {
|
} else if (exists) {
|
||||||
// just set the source again (to be sure the change was noticed)
|
// just set the source again (to be sure the change was noticed)
|
||||||
securityImage.source = "";
|
securityImage.source = "";
|
||||||
|
@ -60,12 +65,12 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!isAuthenticated && !passphraseModal.visible) {
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
passphraseModal.visible = true;
|
||||||
root.activeView = "notSetUp";
|
} else if (isAuthenticated) {
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
|
||||||
root.activeView = "purchasesMain";
|
root.activeView = "purchasesMain";
|
||||||
|
commerce.inventory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +171,6 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
keyFilePathIfExistsResultReceived = false;
|
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +195,21 @@ Rectangle {
|
||||||
commerce.getLoginStatus();
|
commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HifiWallet.PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// "WALLET NOT SET UP" START
|
// "WALLET NOT SET UP" START
|
||||||
|
|
|
@ -47,11 +47,26 @@ Item {
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
color: hifi.buttons.black;
|
color: hifi.buttons.black;
|
||||||
colorScheme: hifi.colorSchemes.dark;
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
anchors.bottom: helpText.bottom;
|
anchors.bottom: resetButton.top;
|
||||||
|
anchors.bottomMargin: 15;
|
||||||
anchors.horizontalCenter: parent.horizontalCenter;
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
height: 50;
|
height: 50;
|
||||||
width: 250;
|
width: 250;
|
||||||
text: "Testing: Reset Wallet!";
|
text: "DEBUG: Clear Cached Passphrase";
|
||||||
|
onClicked: {
|
||||||
|
commerce.setPassphrase("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: resetButton;
|
||||||
|
color: hifi.buttons.red;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.bottom: helpText.bottom;
|
||||||
|
anchors.bottomMargin: 15;
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
height: 50;
|
||||||
|
width: 250;
|
||||||
|
text: "DEBUG: Reset Wallet!";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
commerce.reset();
|
commerce.reset();
|
||||||
sendSignalToWallet({method: 'walletReset'});
|
sendSignalToWallet({method: 'walletReset'});
|
||||||
|
|
304
interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
Normal file
304
interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
//
|
||||||
|
// PassphraseModal.qml
|
||||||
|
// qml/hifi/commerce/wallet
|
||||||
|
//
|
||||||
|
// PassphraseModal
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-08-31
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
import Hifi 1.0 as Hifi
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import "../../../styles-uit"
|
||||||
|
import "../../../controls-uit" as HifiControlsUit
|
||||||
|
import "../../../controls" as HifiControls
|
||||||
|
|
||||||
|
// references XXX from root context
|
||||||
|
|
||||||
|
Item {
|
||||||
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
|
id: root;
|
||||||
|
z: 998;
|
||||||
|
property bool keyboardRaised: false;
|
||||||
|
|
||||||
|
Hifi.QmlCommerce {
|
||||||
|
id: commerce;
|
||||||
|
|
||||||
|
onSecurityImageResult: {
|
||||||
|
passphraseModalSecurityImage.source = "";
|
||||||
|
passphraseModalSecurityImage.source = "image://security/securityImage";
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletAuthenticatedStatusResult: {
|
||||||
|
submitPassphraseInputButton.enabled = true;
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
errorText.text = "Authentication failed - please try again.";
|
||||||
|
} else {
|
||||||
|
root.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
propagateComposedEvents: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will cause a bug -- if you bring up passphrase selection in HUD mode while
|
||||||
|
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
|
||||||
|
// HMD preview will stay off.
|
||||||
|
// TODO: Fix this unlikely bug
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (visible) {
|
||||||
|
passphraseField.focus = true;
|
||||||
|
sendSignalToParent({method: 'disableHmdPreview'});
|
||||||
|
} else {
|
||||||
|
sendSignalToParent({method: 'maybeEnableHmdPreview'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background rectangle
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent;
|
||||||
|
color: "black";
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
height: 250;
|
||||||
|
color: hifi.colors.baseGray;
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: instructionsText;
|
||||||
|
text: "Enter Wallet Passphrase";
|
||||||
|
size: 16;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.topMargin: 30;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 16;
|
||||||
|
width: passphraseField.width;
|
||||||
|
height: paintedHeight;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.faintGray;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.TextField {
|
||||||
|
id: passphraseField;
|
||||||
|
anchors.top: instructionsText.bottom;
|
||||||
|
anchors.topMargin: 4;
|
||||||
|
anchors.left: instructionsText.left;
|
||||||
|
width: 280;
|
||||||
|
height: 50;
|
||||||
|
echoMode: TextInput.Password;
|
||||||
|
placeholderText: "passphrase";
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
root.keyboardRaised = focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
parent.focus = true;
|
||||||
|
root.keyboardRaised = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
submitPassphraseInputButton.enabled = false;
|
||||||
|
commerce.setPassphrase(passphraseField.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show passphrase text
|
||||||
|
HifiControlsUit.CheckBox {
|
||||||
|
id: showPassphrase;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.left: passphraseField.left;
|
||||||
|
anchors.top: passphraseField.bottom;
|
||||||
|
anchors.topMargin: 8;
|
||||||
|
height: 30;
|
||||||
|
text: "Show passphrase as plain text";
|
||||||
|
boxSize: 24;
|
||||||
|
onClicked: {
|
||||||
|
passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security Image
|
||||||
|
Item {
|
||||||
|
id: securityImageContainer;
|
||||||
|
// Anchors
|
||||||
|
anchors.top: instructionsText.top;
|
||||||
|
anchors.left: passphraseField.right;
|
||||||
|
anchors.leftMargin: 12;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
Image {
|
||||||
|
id: passphraseModalSecurityImage;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
height: 75;
|
||||||
|
width: height;
|
||||||
|
fillMode: Image.PreserveAspectFit;
|
||||||
|
mipmap: true;
|
||||||
|
source: "image://security/securityImage";
|
||||||
|
cache: false;
|
||||||
|
onVisibleChanged: {
|
||||||
|
commerce.getSecurityImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
id: passphraseModalSecurityImageOverlay;
|
||||||
|
source: "images/lockOverlay.png";
|
||||||
|
width: passphraseModalSecurityImage.width * 0.45;
|
||||||
|
height: passphraseModalSecurityImage.height * 0.45;
|
||||||
|
anchors.bottom: passphraseModalSecurityImage.bottom;
|
||||||
|
anchors.right: passphraseModalSecurityImage.right;
|
||||||
|
mipmap: true;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
// "Security image" text below pic
|
||||||
|
RalewayRegular {
|
||||||
|
text: "security image";
|
||||||
|
// Text size
|
||||||
|
size: 12;
|
||||||
|
// Anchors
|
||||||
|
anchors.top: passphraseModalSecurityImage.bottom;
|
||||||
|
anchors.topMargin: 4;
|
||||||
|
anchors.left: securityImageContainer.left;
|
||||||
|
anchors.right: securityImageContainer.right;
|
||||||
|
height: paintedHeight;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.faintGray;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error text above buttons
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: errorText;
|
||||||
|
text: "";
|
||||||
|
// Text size
|
||||||
|
size: 16;
|
||||||
|
// Anchors
|
||||||
|
anchors.bottom: passphrasePopupActionButtonsContainer.top;
|
||||||
|
anchors.bottomMargin: 4;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 16;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.rightMargin: 16;
|
||||||
|
height: 30;
|
||||||
|
// Style
|
||||||
|
color: hifi.colors.redHighlight;
|
||||||
|
// Alignment
|
||||||
|
horizontalAlignment: Text.AlignHCenter;
|
||||||
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ACTION BUTTONS START
|
||||||
|
//
|
||||||
|
Item {
|
||||||
|
id: passphrasePopupActionButtonsContainer;
|
||||||
|
// Size
|
||||||
|
width: root.width;
|
||||||
|
height: 50;
|
||||||
|
// Anchors
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.bottomMargin: 10;
|
||||||
|
|
||||||
|
// "Cancel" button
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: cancelPassphraseInputButton;
|
||||||
|
color: hifi.buttons.black;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
height: 40;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 20;
|
||||||
|
width: parent.width/2 - anchors.leftMargin*2;
|
||||||
|
text: "Cancel"
|
||||||
|
onClicked: {
|
||||||
|
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Submit" button
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: submitPassphraseInputButton;
|
||||||
|
color: hifi.buttons.blue;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
height: 40;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.rightMargin: 20;
|
||||||
|
width: parent.width/2 - anchors.rightMargin*2;
|
||||||
|
text: "Submit"
|
||||||
|
onClicked: {
|
||||||
|
submitPassphraseInputButton.enabled = false;
|
||||||
|
commerce.setPassphrase(passphraseField.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: keyboardContainer;
|
||||||
|
z: 999;
|
||||||
|
visible: keyboard.raised;
|
||||||
|
property bool punctuationMode: false;
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom;
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: lowerKeyboardButton;
|
||||||
|
source: "images/lowerKeyboard.png";
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
|
anchors.bottom: keyboard.top;
|
||||||
|
height: 30;
|
||||||
|
width: 120;
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.keyboardRaised = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.Keyboard {
|
||||||
|
id: keyboard;
|
||||||
|
raised: HMD.mounted && root.keyboardRaised;
|
||||||
|
numeric: parent.punctuationMode;
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom;
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signal sendSignalToParent(var msg);
|
||||||
|
}
|
|
@ -40,8 +40,8 @@ Item {
|
||||||
passphrasePageSecurityImage.source = "image://security/securityImage";
|
passphrasePageSecurityImage.source = "image://security/securityImage";
|
||||||
}
|
}
|
||||||
|
|
||||||
onPassphraseSetupStatusResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
sendMessageToLightbox({method: 'statusResult', status: passphraseIsSetup});
|
sendMessageToLightbox({method: 'statusResult', status: isAuthenticated});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +58,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: gridModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.TextField {
|
HifiControlsUit.TextField {
|
||||||
id: passphraseField;
|
id: passphraseField;
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
|
@ -199,7 +195,7 @@ Item {
|
||||||
// Text below TextFields
|
// Text below TextFields
|
||||||
RalewaySemiBold {
|
RalewaySemiBold {
|
||||||
id: passwordReqs;
|
id: passwordReqs;
|
||||||
text: "Passphrase must be at least 4 characters";
|
text: "Passphrase must be at least 3 characters";
|
||||||
// Text size
|
// Text size
|
||||||
size: 16;
|
size: 16;
|
||||||
// Anchors
|
// Anchors
|
||||||
|
@ -256,7 +252,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAndSubmitPassphrase() {
|
function validateAndSubmitPassphrase() {
|
||||||
if (passphraseField.text.length < 4) {
|
if (passphraseField.text.length < 3) {
|
||||||
setErrorText("Passphrase too short.");
|
setErrorText("Passphrase too short.");
|
||||||
return false;
|
return false;
|
||||||
} else if (passphraseField.text !== passphraseFieldAgain.text) {
|
} else if (passphraseField.text !== passphraseFieldAgain.text) {
|
||||||
|
|
|
@ -26,8 +26,6 @@ Rectangle {
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
property string activeView: "initialize";
|
property string activeView: "initialize";
|
||||||
property bool securityImageResultReceived: false;
|
|
||||||
property bool keyFilePathIfExistsResultReceived: false;
|
|
||||||
property bool keyboardRaised: false;
|
property bool keyboardRaised: false;
|
||||||
|
|
||||||
// Style
|
// Style
|
||||||
|
@ -40,25 +38,30 @@ Rectangle {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getSecurityImage();
|
|
||||||
commerce.getKeyFilePathIfExists();
|
commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSecurityImageResult: {
|
onKeyFilePathIfExistsResult: {
|
||||||
securityImageResultReceived = true;
|
if (path === "" && root.activeView !== "notSetUp") {
|
||||||
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
|
} else if (path !== "" && root.activeView === "initialize") {
|
||||||
root.activeView = "walletHome";
|
commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onSecurityImageResult: {
|
||||||
keyFilePathIfExistsResultReceived = true;
|
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
|
||||||
if (path === "" && root.activeView !== "notSetUp") {
|
|
||||||
root.activeView = "notSetUp";
|
root.activeView = "notSetUp";
|
||||||
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
|
} else if (exists && root.activeView === "initialize") {
|
||||||
|
commerce.getWalletAuthenticatedStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletAuthenticatedStatusResult: {
|
||||||
|
if (!isAuthenticated && !passphraseModal.visible) {
|
||||||
|
passphraseModal.visible = true;
|
||||||
|
} else if (isAuthenticated) {
|
||||||
root.activeView = "walletHome";
|
root.activeView = "walletHome";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +92,8 @@ Rectangle {
|
||||||
if (msg.method === 'walletSetup_cancelClicked') {
|
if (msg.method === 'walletSetup_cancelClicked') {
|
||||||
walletSetupLightbox.visible = false;
|
walletSetupLightbox.visible = false;
|
||||||
} else if (msg.method === 'walletSetup_finished') {
|
} else if (msg.method === 'walletSetup_finished') {
|
||||||
root.activeView = "walletHome";
|
root.activeView = "initialize";
|
||||||
|
commerce.getLoginStatus();
|
||||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||||
root.keyboardRaised = true;
|
root.keyboardRaised = true;
|
||||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||||
|
@ -218,6 +222,21 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PassphraseModal {
|
||||||
|
id: passphraseModal;
|
||||||
|
visible: false;
|
||||||
|
anchors.top: titleBarContainer.bottom;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onSendSignalToParent: {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotSetUp {
|
NotSetUp {
|
||||||
id: notSetUp;
|
id: notSetUp;
|
||||||
visible: root.activeView === "notSetUp";
|
visible: root.activeView === "notSetUp";
|
||||||
|
|
|
@ -88,13 +88,14 @@ Item {
|
||||||
height: 60;
|
height: 60;
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: hfcBalanceField;
|
id: hfcBalanceField;
|
||||||
|
color: hifi.colors.darkGray;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.bottom: parent.bottom;
|
anchors.bottom: parent.bottom;
|
||||||
height: parent.height - 15;
|
height: parent.height - 15;
|
||||||
|
|
||||||
// "HFC" balance label
|
// "HFC" balance label
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: balanceLabel;
|
id: balanceLabel;
|
||||||
text: "HFC";
|
text: "HFC";
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -106,7 +107,7 @@ Item {
|
||||||
anchors.rightMargin: 4;
|
anchors.rightMargin: 4;
|
||||||
width: paintedWidth;
|
width: paintedWidth;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.darkGray;
|
color: hifi.colors.lightGrayText;
|
||||||
// Alignment
|
// Alignment
|
||||||
horizontalAlignment: Text.AlignRight;
|
horizontalAlignment: Text.AlignRight;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
@ -121,7 +122,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balance Text
|
// Balance Text
|
||||||
FiraSansRegular {
|
FiraSansSemiBold {
|
||||||
id: balanceText;
|
id: balanceText;
|
||||||
text: "--";
|
text: "--";
|
||||||
// Text size
|
// Text size
|
||||||
|
@ -133,7 +134,7 @@ Item {
|
||||||
anchors.right: balanceLabel.left;
|
anchors.right: balanceLabel.left;
|
||||||
anchors.rightMargin: 4;
|
anchors.rightMargin: 4;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.darkGray;
|
color: hifi.colors.lightGrayText;
|
||||||
// Alignment
|
// Alignment
|
||||||
horizontalAlignment: Text.AlignRight;
|
horizontalAlignment: Text.AlignRight;
|
||||||
verticalAlignment: Text.AlignVCenter;
|
verticalAlignment: Text.AlignVCenter;
|
||||||
|
@ -258,7 +259,7 @@ Item {
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
height: transactionText.height + 30;
|
height: transactionText.height + 30;
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: transactionText;
|
id: transactionText;
|
||||||
text: model.text;
|
text: model.text;
|
||||||
// Style
|
// Style
|
||||||
|
@ -288,7 +289,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should never be visible (since you immediately get 100 HFC)
|
// This should never be visible (since you immediately get 100 HFC)
|
||||||
RalewayRegular {
|
FiraSansRegular {
|
||||||
id: emptyTransationHistory;
|
id: emptyTransationHistory;
|
||||||
size: 24;
|
size: 24;
|
||||||
visible: !transactionHistory.visible && root.historyReceived;
|
visible: !transactionHistory.visible && root.historyReceived;
|
||||||
|
|
|
@ -39,9 +39,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPassphraseSetupStatusResult: {
|
onWalletAuthenticatedStatusResult: {
|
||||||
securityImageContainer.visible = false;
|
securityImageContainer.visible = false;
|
||||||
if (passphraseIsSetup) {
|
if (isAuthenticated) {
|
||||||
privateKeysReadyContainer.visible = true;
|
privateKeysReadyContainer.visible = true;
|
||||||
} else {
|
} else {
|
||||||
choosePassphraseContainer.visible = true;
|
choosePassphraseContainer.visible = true;
|
||||||
|
@ -117,7 +117,7 @@ Rectangle {
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 16;
|
anchors.rightMargin: 16;
|
||||||
height: 280;
|
height: 280;
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
sendSignalToWallet(msg);
|
sendSignalToWallet(msg);
|
||||||
|
@ -210,7 +210,7 @@ Rectangle {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getPassphraseSetupStatus();
|
commerce.getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,30 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||||
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
|
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getLoginStatus() {
|
||||||
|
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getKeyFilePathIfExists() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->sendKeyFilePathIfExists();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getWalletAuthenticatedStatus() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::getSecurityImage() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->getSecurityImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->chooseSecurityImage(imageFile);
|
||||||
|
}
|
||||||
|
|
||||||
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
|
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
@ -60,30 +84,14 @@ void QmlCommerce::history() {
|
||||||
ledger->history(wallet->listPublicKeys());
|
ledger->history(wallet->listPublicKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
|
||||||
wallet->chooseSecurityImage(imageFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getSecurityImage() {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
|
||||||
wallet->getSecurityImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getLoginStatus() {
|
|
||||||
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::setPassphrase(const QString& passphrase) {
|
void QmlCommerce::setPassphrase(const QString& passphrase) {
|
||||||
emit passphraseSetupStatusResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlCommerce::getPassphraseSetupStatus() {
|
|
||||||
emit passphraseSetupStatusResult(false);
|
|
||||||
}
|
|
||||||
void QmlCommerce::getKeyFilePathIfExists() {
|
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
wallet->sendKeyFilePathIfExists();
|
if (wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty()) {
|
||||||
|
wallet->changePassphrase(passphrase);
|
||||||
|
} else {
|
||||||
|
wallet->setPassphrase(passphrase);
|
||||||
|
}
|
||||||
|
getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::reset() {
|
void QmlCommerce::reset() {
|
||||||
|
@ -91,4 +99,4 @@ void QmlCommerce::reset() {
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
ledger->reset();
|
ledger->reset();
|
||||||
wallet->reset();
|
wallet->reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,28 +28,32 @@ public:
|
||||||
QmlCommerce(QQuickItem* parent = nullptr);
|
QmlCommerce(QQuickItem* parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void loginStatusResult(bool isLoggedIn);
|
||||||
|
void keyFilePathIfExistsResult(const QString& path);
|
||||||
|
void securityImageResult(bool exists);
|
||||||
|
void walletAuthenticatedStatusResult(bool isAuthenticated);
|
||||||
|
|
||||||
void buyResult(QJsonObject result);
|
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).
|
// 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 balanceResult(QJsonObject result);
|
||||||
void inventoryResult(QJsonObject result);
|
void inventoryResult(QJsonObject result);
|
||||||
void securityImageResult(bool exists);
|
|
||||||
void loginStatusResult(bool isLoggedIn);
|
|
||||||
void passphraseSetupStatusResult(bool passphraseIsSetup);
|
|
||||||
void historyResult(QJsonObject result);
|
void historyResult(QJsonObject result);
|
||||||
void keyFilePathIfExistsResult(const QString& path);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Q_INVOKABLE void getLoginStatus();
|
||||||
|
Q_INVOKABLE void getKeyFilePathIfExists();
|
||||||
|
Q_INVOKABLE void getSecurityImage();
|
||||||
|
Q_INVOKABLE void getWalletAuthenticatedStatus();
|
||||||
|
|
||||||
|
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
|
||||||
|
Q_INVOKABLE void setPassphrase(const QString& passphrase);
|
||||||
|
|
||||||
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
|
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
|
||||||
Q_INVOKABLE void balance();
|
Q_INVOKABLE void balance();
|
||||||
Q_INVOKABLE void inventory();
|
Q_INVOKABLE void inventory();
|
||||||
Q_INVOKABLE void history();
|
Q_INVOKABLE void history();
|
||||||
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
|
|
||||||
Q_INVOKABLE void getSecurityImage();
|
|
||||||
Q_INVOKABLE void getLoginStatus();
|
|
||||||
Q_INVOKABLE void setPassphrase(const QString& passphrase);
|
|
||||||
Q_INVOKABLE void getPassphraseSetupStatus();
|
|
||||||
Q_INVOKABLE void getKeyFilePathIfExists();
|
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,16 +56,72 @@ QString imageFilePath() {
|
||||||
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
||||||
// just return a hardcoded pwd for now
|
// just return a hardcoded pwd for now
|
||||||
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
|
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
|
||||||
if (passphrase) {
|
if (passphrase && !passphrase->isEmpty()) {
|
||||||
strcpy(password, passphrase->toLocal8Bit().constData());
|
strcpy(password, passphrase->toLocal8Bit().constData());
|
||||||
return static_cast<int>(passphrase->size());
|
return static_cast<int>(passphrase->size());
|
||||||
} else {
|
} else {
|
||||||
// ok gotta bring up modal dialog... But right now lets just
|
// this shouldn't happen - so lets log it to tell us we have
|
||||||
// just keep it empty
|
// a problem with the flow...
|
||||||
|
qCCritical(commerce) << "no cached passphrase while decrypting!";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RSA* readKeys(const char* filename) {
|
||||||
|
FILE* fp;
|
||||||
|
RSA* key = NULL;
|
||||||
|
if ((fp = fopen(filename, "rt"))) {
|
||||||
|
// file opened successfully
|
||||||
|
qCDebug(commerce) << "opened key file" << filename;
|
||||||
|
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
|
||||||
|
// now read private key
|
||||||
|
|
||||||
|
qCDebug(commerce) << "read public key";
|
||||||
|
|
||||||
|
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||||
|
qCDebug(commerce) << "read private key";
|
||||||
|
fclose(fp);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
qCDebug(commerce) << "failed to read private key";
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to read public key";
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to open key file" << filename;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeKeys(const char* filename, RSA* keys) {
|
||||||
|
FILE* fp;
|
||||||
|
bool retval = false;
|
||||||
|
if ((fp = fopen(filename, "wt"))) {
|
||||||
|
if (!PEM_write_RSAPublicKey(fp, keys)) {
|
||||||
|
fclose(fp);
|
||||||
|
qCDebug(commerce) << "failed to write public key";
|
||||||
|
QFile(QString(filename)).remove();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
||||||
|
fclose(fp);
|
||||||
|
qCDebug(commerce) << "failed to write private key";
|
||||||
|
QFile(QString(filename)).remove();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = true;
|
||||||
|
qCDebug(commerce) << "wrote keys successfully";
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "failed to open key file" << filename;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// BEGIN copied code - this will be removed/changed at some point soon
|
// BEGIN copied code - this will be removed/changed at some point soon
|
||||||
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
|
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
|
||||||
// We will have a different implementation in practice, but this gives us a start for now
|
// We will have a different implementation in practice, but this gives us a start for now
|
||||||
|
@ -124,25 +180,9 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!writeKeys(keyFilePath().toStdString().c_str(), keyPair)) {
|
||||||
// now lets persist them to files
|
qCDebug(commerce) << "couldn't save keys!";
|
||||||
// FIXME: for now I'm appending to the file if it exists. As long as we always put
|
return retval;
|
||||||
// the keys in the same order, this works fine. TODO: verify this will skip over
|
|
||||||
// anything else (like an embedded image)
|
|
||||||
FILE* fp;
|
|
||||||
if ((fp = fopen(keyFilePath().toStdString().c_str(), "at"))) {
|
|
||||||
if (!PEM_write_RSAPublicKey(fp, keyPair)) {
|
|
||||||
fclose(fp);
|
|
||||||
qCDebug(commerce) << "failed to write public key";
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PEM_write_RSAPrivateKey(fp, keyPair, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
|
||||||
fclose(fp);
|
|
||||||
qCDebug(commerce) << "failed to write private key";
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RSA_free(keyPair);
|
RSA_free(keyPair);
|
||||||
|
@ -201,9 +241,6 @@ RSA* readPrivateKey(const char* filename) {
|
||||||
// file opened successfully
|
// file opened successfully
|
||||||
qCDebug(commerce) << "opened key file" << filename;
|
qCDebug(commerce) << "opened key file" << filename;
|
||||||
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||||
// cleanup
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
qCDebug(commerce) << "parsed private key file successfully";
|
qCDebug(commerce) << "parsed private key file successfully";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -215,7 +252,6 @@ RSA* readPrivateKey(const char* filename) {
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
|
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
|
||||||
|
|
||||||
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
|
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
|
||||||
|
@ -341,6 +377,24 @@ bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBuf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
||||||
|
// try to read existing keys if they exist...
|
||||||
|
|
||||||
|
// FIXME: initialize OpenSSL elsewhere soon
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
auto publicKey = readPublicKey(keyFilePath().toStdString().c_str());
|
||||||
|
|
||||||
|
if (publicKey.size() > 0) {
|
||||||
|
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) {
|
||||||
|
RSA_free(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Wallet::createIfNeeded() {
|
bool Wallet::createIfNeeded() {
|
||||||
if (_publicKeys.count() > 0) return false;
|
if (_publicKeys.count() > 0) return false;
|
||||||
|
|
||||||
|
@ -512,3 +566,30 @@ void Wallet::reset() {
|
||||||
keyFile.remove();
|
keyFile.remove();
|
||||||
imageFile.remove();
|
imageFile.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::changePassphrase(const QString& newPassphrase) {
|
||||||
|
qCDebug(commerce) << "changing passphrase";
|
||||||
|
RSA* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||||
|
if (keys) {
|
||||||
|
// we read successfully, so now write to a new temp file
|
||||||
|
// save old passphrase just in case
|
||||||
|
// TODO: force re-enter?
|
||||||
|
QString oldPassphrase = *_passphrase;
|
||||||
|
setPassphrase(newPassphrase);
|
||||||
|
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
|
||||||
|
if (writeKeys(tempFileName.toStdString().c_str(), keys)) {
|
||||||
|
// ok, now move the temp file to the correct spot
|
||||||
|
QFile(QString(keyFilePath())).remove();
|
||||||
|
QFile(tempFileName).rename(QString(keyFilePath()));
|
||||||
|
qCDebug(commerce) << "passphrase changed successfully";
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
qCDebug(commerce) << "couldn't write keys";
|
||||||
|
QFile(tempFileName).remove();
|
||||||
|
setPassphrase(oldPassphrase);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qCDebug(commerce) << "couldn't read keys";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -39,18 +39,21 @@ public:
|
||||||
|
|
||||||
void setPassphrase(const QString& passphrase);
|
void setPassphrase(const QString& passphrase);
|
||||||
QString* getPassphrase() { return _passphrase; }
|
QString* getPassphrase() { return _passphrase; }
|
||||||
|
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
|
||||||
|
bool walletIsAuthenticatedWithPassphrase();
|
||||||
|
bool changePassphrase(const QString& newPassphrase);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void securityImageResult(bool exists) ;
|
void securityImageResult(bool exists);
|
||||||
void keyFilePathIfExistsResult(const QString& path);
|
void keyFilePathIfExistsResult(const QString& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList _publicKeys{};
|
QStringList _publicKeys{};
|
||||||
QPixmap* _securityImage { nullptr };
|
QPixmap* _securityImage { nullptr };
|
||||||
QByteArray _salt {"iamsalt!"};
|
QByteArray _salt {"iamsalt!"};
|
||||||
QString* _passphrase { new QString("pwd") };
|
QString* _passphrase { new QString("") };
|
||||||
|
|
||||||
void updateImageProvider();
|
void updateImageProvider();
|
||||||
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);
|
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
var isHmdPreviewDisabled = true;
|
var isHmdPreviewDisabled = true;
|
||||||
function fromQml(message) {
|
function fromQml(message) {
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
|
case 'passphrasePopup_cancelClicked':
|
||||||
case 'walletSetup_cancelClicked':
|
case 'walletSetup_cancelClicked':
|
||||||
case 'needsLogIn_cancelClicked':
|
case 'needsLogIn_cancelClicked':
|
||||||
tablet.gotoHomeScreen();
|
tablet.gotoHomeScreen();
|
||||||
|
|
|
@ -197,6 +197,7 @@
|
||||||
// Description:
|
// Description:
|
||||||
// -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML
|
// -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML
|
||||||
// in the format "{method, params}", like json-rpc.
|
// in the format "{method, params}", like json-rpc.
|
||||||
|
var isHmdPreviewDisabled = true;
|
||||||
function fromQml(message) {
|
function fromQml(message) {
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
case 'checkout_setUpClicked':
|
case 'checkout_setUpClicked':
|
||||||
|
@ -231,12 +232,20 @@
|
||||||
case 'purchases_goToMarketplaceClicked':
|
case 'purchases_goToMarketplaceClicked':
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
break;
|
break;
|
||||||
|
case 'passphrasePopup_cancelClicked':
|
||||||
case 'needsLogIn_cancelClicked':
|
case 'needsLogIn_cancelClicked':
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
break;
|
break;
|
||||||
case 'needsLogIn_loginClicked':
|
case 'needsLogIn_loginClicked':
|
||||||
openLoginWindow();
|
openLoginWindow();
|
||||||
break;
|
break;
|
||||||
|
case 'disableHmdPreview':
|
||||||
|
isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview");
|
||||||
|
Menu.setIsOptionChecked("Disable Preview", true);
|
||||||
|
break;
|
||||||
|
case 'maybeEnableHmdPreview':
|
||||||
|
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
|
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue