Merge pull request #12497 from howard-stearns/end-seeding

End seeding
This commit is contained in:
Howard Stearns 2018-02-27 13:18:13 -08:00 committed by GitHub
commit 0e4f3460b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 518 additions and 63 deletions

View file

@ -59,17 +59,17 @@ Rectangle {
if (root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
}
} else if (walletStatus === 1) {
} else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) {
if (root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
}
} else if (walletStatus === 2) {
} else if (walletStatus === 4) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
UserActivityLogger.commercePassphraseEntry("marketplace checkout");
}
} else if (walletStatus === 3) {
} else if (walletStatus === 5) {
authSuccessStep();
} else {
console.log("ERROR in Checkout.qml: Unknown wallet status: " + walletStatus);

View file

@ -25,10 +25,13 @@ Rectangle {
property string titleText;
property string bodyImageSource;
property string bodyText;
property string button1color: hifi.buttons.noneBorderlessGray;
property string button1text;
property string button1method;
property string button2color: hifi.buttons.noneBorderless;
property string button2text;
property string button2method;
property string buttonLayout: "leftright";
readonly property string securityPicBodyText: "When you see your Security Pic, your actions and data are securely making use of your " +
"Wallet's private keys.<br><br>You can change your Security Pic in your Wallet.";
@ -39,6 +42,12 @@ Rectangle {
color: Qt.rgba(0, 0, 0, 0.5);
z: 999;
onVisibleChanged: {
if (!visible) {
resetLightbox();
}
}
// 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.
@ -112,18 +121,21 @@ Rectangle {
anchors.topMargin: 30;
anchors.left: parent.left;
anchors.right: parent.right;
height: 70;
height: root.buttonLayout === "leftright" ? 70 : 150;
// Button 1
HifiControlsUit.Button {
color: hifi.buttons.noneBorderlessGray;
id: button1;
color: root.button1color;
colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 20;
anchors.top: root.buttonLayout === "leftright" ? parent.top : parent.top;
anchors.left: parent.left;
anchors.leftMargin: 10;
width: root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2;
anchors.right: root.buttonLayout === "leftright" ? undefined : parent.right;
anchors.rightMargin: root.buttonLayout === "leftright" ? undefined : 10;
width: root.buttonLayout === "leftright" ? (root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2) :
(undefined);
height: 50;
text: root.button1text;
onClicked: {
eval(button1method);
@ -132,15 +144,18 @@ Rectangle {
// Button 2
HifiControlsUit.Button {
id: button2;
visible: root.button2text;
color: hifi.buttons.noneBorderless;
color: root.button2color;
colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 20;
anchors.top: root.buttonLayout === "leftright" ? parent.top : button1.bottom;
anchors.topMargin: root.buttonLayout === "leftright" ? undefined : 20;
anchors.left: root.buttonLayout === "leftright" ? undefined : parent.left;
anchors.leftMargin: root.buttonLayout === "leftright" ? undefined : 10;
anchors.right: parent.right;
anchors.rightMargin: 10;
width: parent.width/2 - anchors.rightMargin*2;
width: root.buttonLayout === "leftright" ? parent.width/2 - anchors.rightMargin*2 : undefined;
height: 50;
text: root.button2text;
onClicked: {
eval(button2method);
@ -153,6 +168,19 @@ Rectangle {
// FUNCTION DEFINITIONS START
//
signal sendToParent(var msg);
function resetLightbox() {
root.titleText = "";
root.bodyImageSource = "";
root.bodyText = "";
root.button1color = hifi.buttons.noneBorderlessGray;
root.button1text = "";
root.button1method = "";
root.button2color = hifi.buttons.noneBorderless;
root.button2text = "";
root.button2method = "";
root.buttonLayout = "leftright";
}
//
// FUNCTION DEFINITIONS END
//

View file

@ -37,9 +37,9 @@ Item {
onWalletStatusResult: {
if (walletStatus === 0) {
sendToParent({method: "needsLogIn"});
} else if (walletStatus === 3) {
} else if (walletStatus === 5) {
Commerce.getSecurityImage();
} else if (walletStatus > 3) {
} else if (walletStatus > 5) {
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
}
}

View file

@ -47,17 +47,17 @@ Rectangle {
if (root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
}
} else if (walletStatus === 1) {
} else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) {
if (root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
}
} else if (walletStatus === 2) {
} else if (walletStatus === 4) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
UserActivityLogger.commercePassphraseEntry("marketplace purchases");
}
} else if (walletStatus === 3) {
} else if (walletStatus === 5) {
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
root.activeView = "firstUseTutorial";
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {

View file

@ -47,20 +47,22 @@ Rectangle {
}
} else if (walletStatus === 1) {
if (root.activeView !== "walletSetup") {
root.activeView = "walletSetup";
Commerce.resetLocalWalletOnly();
var timestamp = new Date();
walletSetup.startingTimestamp = timestamp;
walletSetup.setupAttemptID = generateUUID();
UserActivityLogger.commerceWalletSetupStarted(timestamp, setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
walletResetSetup();
}
} else if (walletStatus === 2) {
if (root.activeView != "preexisting") {
root.activeView = "preexisting";
}
} else if (walletStatus === 3) {
if (root.activeView != "conflicting") {
root.activeView = "conflicting";
}
} else if (walletStatus === 4) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
UserActivityLogger.commercePassphraseEntry("wallet app");
}
} else if (walletStatus === 3) {
} else if (walletStatus === 5) {
if (root.activeView !== "walletSetup") {
root.activeView = "walletHome";
Commerce.getSecurityImage();
@ -169,6 +171,25 @@ Rectangle {
// TITLE BAR END
//
WalletChoice {
id: walletChoice;
proceedFunction: function (isReset) {
console.log(isReset ? "Reset wallet." : "Trying again with new wallet.");
Commerce.setSoftReset();
if (isReset) {
walletResetSetup();
} else {
var msg = { referrer: walletChoice.referrer }
followReferrer(msg);
}
}
copyFunction: Commerce.copyKeyFileFrom;
z: 997;
visible: (root.activeView === "preexisting") || (root.activeView === "conflicting");
activeView: root.activeView;
anchors.fill: parent;
}
WalletSetup {
id: walletSetup;
visible: root.activeView === "walletSetup";
@ -178,14 +199,7 @@ Rectangle {
Connections {
onSendSignalToWallet: {
if (msg.method === 'walletSetup_finished') {
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
root.activeView = "initialize";
Commerce.getWalletStatus();
} else if (msg.referrer === 'purchases') {
sendToScript({method: 'goToPurchases'});
} else {
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
}
followReferrer(msg);
} else if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true;
root.isPassword = msg.isPasswordField;
@ -738,6 +752,7 @@ Rectangle {
switch (message.method) {
case 'updateWalletReferrer':
walletSetup.referrer = message.referrer;
walletChoice.referrer = message.referrer;
break;
case 'inspectionCertificate_resetCert':
// NOP
@ -768,6 +783,28 @@ Rectangle {
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
function walletResetSetup() {
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] : ''));
}
function followReferrer(msg) {
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
root.activeView = "initialize";
Commerce.getWalletStatus();
} else if (msg.referrer === 'purchases') {
sendToScript({method: 'goToPurchases'});
} else if (msg.referrer === 'marketplace cta' || msg.referrer === 'mainPage') {
sendToScript({method: 'goToMarketplaceMainPage', itemId: msg.referrer});
} else {
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
}
}
//
// FUNCTION DEFINITIONS END
//

View file

@ -0,0 +1,297 @@
//
// WalletChoice.qml
// qml/hifi/commerce/wallet
//
// WalletChoice
//
// Created by Howard Stearns
// Copyright 2018 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 "../common" as HifiCommerceCommon
import "../../../styles-uit"
import "../../../controls-uit" as HifiControlsUit
Item {
HifiConstants { id: hifi; }
id: root;
property string activeView: "conflict";
property var proceedFunction: nil;
property var copyFunction: nil;
property string referrer: "";
Image {
anchors.fill: parent;
source: "images/wallet-bg.jpg";
}
HifiCommerceCommon.CommerceLightbox {
id: lightboxPopup;
visible: false;
anchors.fill: parent;
}
// 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;
hoverEnabled: true;
}
//
// TITLE BAR START
//
Item {
id: titleBarContainer;
// Size
height: 50;
// Anchors
anchors.left: parent.left;
anchors.top: parent.top;
anchors.right: parent.right;
// Wallet icon
HiFiGlyphs {
id: walletIcon;
text: hifi.glyphs.wallet;
// Size
size: parent.height * 0.8;
// Anchors
anchors.left: parent.left;
anchors.leftMargin: 8;
anchors.verticalCenter: parent.verticalCenter;
// Style
color: hifi.colors.blueHighlight;
}
// Title Bar text
RalewayRegular {
id: titleBarText;
text: "Wallet Setup";
// Text size
size: hifi.fontSizes.overlayTitle;
// Anchors
anchors.top: parent.top;
anchors.left: walletIcon.right;
anchors.leftMargin: 8;
anchors.bottom: parent.bottom;
width: paintedWidth;
// Style
color: hifi.colors.white;
// Alignment
horizontalAlignment: Text.AlignHLeft;
verticalAlignment: Text.AlignVCenter;
}
}
//
// TITLE BAR END
//
//
// MAIN PAGE START
//
Item {
id: preexistingContainer;
// Anchors
anchors.top: titleBarContainer.bottom;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
HiFiGlyphs {
id: bigKeyIcon;
text: hifi.glyphs.walletKey;
// Size
size: 180;
// Anchors
anchors.top: parent.top;
anchors.topMargin: 40;
anchors.horizontalCenter: parent.horizontalCenter;
// Style
color: hifi.colors.white;
}
RalewayRegular {
id: text01;
text: root.activeView === "preexisting" ?
"Where are your private keys?" :
"Hmm, your keys are different"
// Text size
size: 26;
// Anchors
anchors.top: bigKeyIcon.bottom;
anchors.left: parent.left;
anchors.leftMargin: 16;
anchors.right: parent.right;
anchors.rightMargin: 16;
height: paintedHeight;
width: paintedWidth;
// Style
color: hifi.colors.white;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
RalewayRegular {
id: text02;
text: root.activeView === "preexisting" ?
"Our records indicate that you created a wallet, but the private keys are not in the folder where we checked." :
"Our records indicate that you created a wallet with different keys than the keys you're providing."
// Text size
size: 18;
// Anchors
anchors.top: text01.bottom;
anchors.topMargin: 40;
anchors.left: parent.left;
anchors.leftMargin: 65;
anchors.right: parent.right;
anchors.rightMargin: 65;
height: paintedHeight;
width: paintedWidth;
// Style
color: hifi.colors.white;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
// "Locate" button
HifiControlsUit.Button {
id: locateButton;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: text02.bottom;
anchors.topMargin: 40;
anchors.horizontalCenter: parent.horizontalCenter;
width: parent.width/2;
height: 50;
text: root.activeView === "preexisting" ?
"LOCATE MY KEYS" :
"LOCATE OTHER KEYS"
onClicked: {
walletChooser();
}
}
// "Create New" OR "Continue" button
HifiControlsUit.Button {
id: button02;
color: hifi.buttons.none;
colorScheme: hifi.colorSchemes.dark;
anchors.top: locateButton.bottom;
anchors.topMargin: 20;
anchors.horizontalCenter: parent.horizontalCenter;
width: parent.width/2;
height: 50;
text: root.activeView === "preexisting" ?
"CREATE NEW WALLET" :
"CONTINUE WITH THESE KEYS"
onClicked: {
lightboxPopup.titleText = "Are you sure?";
lightboxPopup.bodyText = "Taking this step will abandon your old wallet and you will no " +
"longer be able to access your money and your past purchases.<br><br>" +
"This step should only be used if you cannot find your keys.<br><br>" +
"This step cannot be undone.";
lightboxPopup.button1color = hifi.buttons.red;
lightboxPopup.button1text = "YES, CREATE NEW WALLET";
lightboxPopup.button1method = "root.visible = false;proceed(true);";
lightboxPopup.button2text = "CANCEL";
lightboxPopup.button2method = "root.visible = false;"
lightboxPopup.buttonLayout = "topbottom";
lightboxPopup.visible = true;
}
}
// "What's This?" link
RalewayRegular {
id: whatsThisLink;
text: '<font color="#FFFFFF"><a href="#whatsthis">What\'s this?</a></font>';
// Anchors
anchors.bottom: parent.bottom;
anchors.bottomMargin: 48;
anchors.horizontalCenter: parent.horizontalCenter;
width: paintedWidth;
height: paintedHeight;
// Text size
size: 18;
// Style
color: hifi.colors.white;
MouseArea {
anchors.fill: parent;
onClicked: {
if (root.activeView === "preexisting") {
lightboxPopup.titleText = "Your wallet's private keys are not in the folder we expected";
lightboxPopup.bodyText = "We see that you have created a wallet but the private keys " +
"for it seem to have been moved to a different folder.<br><br>" +
"To tell us where the keys are, click 'Locate My Keys'. <br><br>" +
"If you'd prefer to create a new wallet (not recommended - you will lose your money and past " +
"purchases), click 'Create New Wallet'.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.visible = true;
} else {
lightboxPopup.titleText = "You may have set up more than one wallet";
lightboxPopup.bodyText = "We see that the private keys stored on your computer are different " +
"from the ones you used last time. This may mean that you set up more than one wallet. " +
"If you would like to use these keys, click 'Continue With These Keys'.<br><br>" +
"If you would prefer to use another wallet, click 'Locate Other Keys' to show us where " +
"you've stored the private keys for that wallet.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.visible = true;
}
}
}
}
}
//
// MAIN PAGE END
//
//
// FUNCTION DEFINITIONS START
//
function onFileOpenChanged(filename) {
// disconnect the event, otherwise the requests will stack up
try { // Not all calls to onFileOpenChanged() connect an event.
Window.browseChanged.disconnect(onFileOpenChanged);
} catch (e) {
console.log('WalletChoice.qml ignoring', e);
}
if (filename) {
if (copyFunction && copyFunction(filename)) {
proceed(false);
} else {
console.log("WalletChoice.qml copyFunction", copyFunction, "failed.");
}
} // Else we're still at WalletChoice
}
function walletChooser() {
Window.browseChanged.connect(onFileOpenChanged);
Window.browseAsync("Locate your .hifikey file", "", "*.hifikey");
}
function proceed(isReset) {
if (!proceedFunction) {
console.log("Provide a function of no arguments to WalletChoice.qml.");
} else {
proceedFunction(isReset);
}
}
//
// FUNCTION DEFINITIONS END
//
}

View file

@ -310,7 +310,7 @@ Item {
height: parent.height;
HifiControlsUit.Separator {
colorScheme: 1;
colorScheme: 1;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: parent.top;
@ -318,20 +318,42 @@ Item {
RalewayRegular {
id: noActivityText;
text: "<b>The Wallet app is in closed Beta.</b><br><br>To request entry and <b>receive free HFC</b>, please contact " +
"<b>info@highfidelity.com</b> with your High Fidelity account username and the email address registered to that account.";
// Text size
size: 24;
// Style
color: hifi.colors.blueAccent;
anchors.left: parent.left;
anchors.leftMargin: 12;
anchors.right: parent.right;
anchors.rightMargin: 12;
anchors.verticalCenter: parent.verticalCenter;
height: paintedHeight;
wrapMode: Text.WordWrap;
horizontalAlignment: Text.AlignHCenter;
text: "Congrats! Your wallet is all set!<br><br>" +
"<b>Where's my HFC?</b><br>" +
"High Fidelity commerce is in open beta right now. Want more HFC? Get it by meeting with a banker at " +
"<a href='#goToBank'>BankOfHighFidelity</a>!"
// Text size
size: 22;
// Style
color: hifi.colors.blueAccent;
anchors.top: parent.top;
anchors.topMargin: 36;
anchors.left: parent.left;
anchors.leftMargin: 12;
anchors.right: parent.right;
anchors.rightMargin: 12;
height: paintedHeight;
wrapMode: Text.WordWrap;
horizontalAlignment: Text.AlignHCenter;
onLinkActivated: {
sendSignalToWallet({ method: "transactionHistory_goToBank" });
}
}
HifiControlsUit.Button {
id: bankButton;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: noActivityText.bottom;
anchors.topMargin: 30;
anchors.horizontalCenter: parent.horizontalCenter;
width: parent.width/2;
height: 50;
text: "VISIT BANK OF HIGH FIDELITY";
onClicked: {
sendSignalToWallet({ method: "transactionHistory_goToBank" });
}
}
}

View file

@ -22,6 +22,8 @@
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
// balance answers {status: 'success', data: {balance: integer}}
// buy and receive_at answer {status: 'success'}
// account synthesizes a result {status: 'success', data: {keyStatus: "preexisting"|"conflicting"|"ok"}}
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply& reply) {
QByteArray response = reply.readAll();
@ -99,7 +101,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& old_key) {
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
auto accountManager = DependencyManager::get<AccountManager>();
if (!accountManager->isLoggedIn()) {
qCWarning(commerce) << "Cannot set receiveAt when not logged in.";
@ -108,7 +110,7 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) {
return false; // We know right away that we will fail, so tell the caller.
}
signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
signedSend("public_key", hfc_key.toUtf8(), 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.
}
@ -179,7 +181,7 @@ QString transactionString(const QJsonObject& valueObject) {
} else {
result += valueObject["message"].toString();
}
// no matter what we append a smaller date to the bottom of this...
result += QString("<br><font size='-2' color='#1080B8'>%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate));
return result;
@ -246,18 +248,33 @@ void Ledger::accountSuccess(QNetworkReply& reply) {
auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8());
auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8());
QString remotePublicKey = data["public_key"].toString();
bool isOverride = wallet->wasSoftReset();
wallet->setSalt(salt);
wallet->setIv(iv);
wallet->setCKey(ckey);
QString keyStatus = "ok";
QStringList localPublicKeys = wallet->listPublicKeys();
if (remotePublicKey.isEmpty() && !localPublicKeys.isEmpty()) {
receiveAt(localPublicKeys.first(), "");
if (remotePublicKey.isEmpty() || isOverride) {
if (!localPublicKeys.isEmpty()) {
QString key = localPublicKeys.first();
receiveAt(key, key);
}
} else {
if (localPublicKeys.isEmpty()) {
keyStatus = "preexisting";
} else if (localPublicKeys.first() != remotePublicKey) {
keyStatus = "conflicting";
}
}
// none of the hfc account info should be emitted
emit accountResult(QJsonObject{ {"status", "success"} });
QJsonObject json;
QJsonObject responseData{ { "status", "success"} };
json["keyStatus"] = keyStatus;
responseData["data"] = json;
emit accountResult(responseData);
}
void Ledger::accountFailure(QNetworkReply& reply) {

View file

@ -26,7 +26,7 @@ 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& old_key);
bool receiveAt(const QString& hfc_key, const QString& signing_key);
void balance(const QStringList& keys);
void inventory(const QStringList& keys);
void history(const QStringList& keys, const int& pageNumber);

View file

@ -62,6 +62,11 @@ void QmlCommerce::getKeyFilePathIfExists() {
emit keyFilePathIfExistsResult(wallet->getKeyFilePath());
}
bool QmlCommerce::copyKeyFileFrom(const QString& pathname) {
auto wallet = DependencyManager::get<Wallet>();
return wallet->copyKeyFileFrom(pathname);
}
void QmlCommerce::getWalletAuthenticatedStatus() {
auto wallet = DependencyManager::get<Wallet>();
emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());
@ -128,6 +133,11 @@ void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString&
}
}
void QmlCommerce::setSoftReset() {
auto wallet = DependencyManager::get<Wallet>();
wallet->setSoftReset();
}
void QmlCommerce::setPassphrase(const QString& passphrase) {
auto wallet = DependencyManager::get<Wallet>();
wallet->setPassphrase(passphrase);

View file

@ -61,10 +61,12 @@ protected:
Q_INVOKABLE void getKeyFilePathIfExists();
Q_INVOKABLE void getSecurityImage();
Q_INVOKABLE void getWalletAuthenticatedStatus();
Q_INVOKABLE bool copyKeyFileFrom(const QString& pathname);
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
Q_INVOKABLE void setPassphrase(const QString& passphrase);
Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase);
Q_INVOKABLE void setSoftReset();
Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false);
Q_INVOKABLE void balance();

View file

@ -59,6 +59,23 @@ QString keyFilePath() {
auto accountManager = DependencyManager::get<AccountManager>();
return PathUtils::getAppDataFilePath(QString("%1.%2").arg(accountManager->getAccountInfo().getUsername(), KEY_FILE));
}
bool Wallet::copyKeyFileFrom(const QString& pathname) {
QString existing = getKeyFilePath();
qCDebug(commerce) << "Old keyfile" << existing;
if (!existing.isEmpty()) {
QString backup = QString(existing).insert(existing.indexOf(KEY_FILE) - 1,
QDateTime::currentDateTime().toString(Qt::ISODate).replace(":", ""));
qCDebug(commerce) << "Renaming old keyfile to" << backup;
if (!QFile::rename(existing, backup)) {
qCCritical(commerce) << "Unable to backup" << existing << "to" << backup;
return false;
}
}
QString destination = keyFilePath();
bool result = QFile::copy(pathname, destination);
qCDebug(commerce) << "copy" << pathname << "to" << destination << "=>" << result;
return result;
}
// use the cached _passphrase if it exists, otherwise we need to prompt
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
@ -300,17 +317,24 @@ Wallet::Wallet() {
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket");
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
connect(ledger.data(), &Ledger::accountResult, this, [&](QJsonObject result) {
auto wallet = DependencyManager::get<Wallet>();
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
uint status;
QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : "";
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP;
if (keyStatus == "preexisting") {
status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING;
} else{
status = (uint) WalletStatus::WALLET_STATUS_NOT_SET_UP;
}
} else if (!wallet->walletIsAuthenticatedWithPassphrase()) {
status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
status = (uint) WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
} else if (keyStatus == "conflicting") {
status = (uint) WalletStatus::WALLET_STATUS_CONFLICTING;
} else {
status = (uint)WalletStatus::WALLET_STATUS_READY;
status = (uint) WalletStatus::WALLET_STATUS_READY;
}
walletScriptingInterface->setWalletStatus(status);
@ -524,17 +548,17 @@ bool Wallet::generateKeyPair() {
// TODO: redo this soon -- need error checking and so on
writeSecurityImage(_securityImage, keyFilePath());
QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last();
QString key = keyPair.first->toBase64();
_publicKeys.push_back(key);
qCDebug(commerce) << "public key:" << key;
_isOverridingServer = false;
// It's arguable whether we want to change the receiveAt every time, but:
// 1. It's certainly needed the first time, when createIfNeeded answers true.
// 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<Ledger>();
return ledger->receiveAt(key, oldKey);
return ledger->receiveAt(key, key);
}
QStringList Wallet::listPublicKeys() {

View file

@ -35,6 +35,7 @@ public:
void chooseSecurityImage(const QString& imageFile);
bool getSecurityImage();
QString getKeyFilePath();
bool copyKeyFileFrom(const QString& pathname);
void setSalt(const QByteArray& salt) { _salt = salt; }
QByteArray getSalt() { return _salt; }
@ -48,11 +49,15 @@ public:
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
bool walletIsAuthenticatedWithPassphrase();
bool changePassphrase(const QString& newPassphrase);
void setSoftReset() { _isOverridingServer = true; }
bool wasSoftReset() { bool was = _isOverridingServer; _isOverridingServer = false; return was; }
void getWalletStatus();
enum WalletStatus {
WALLET_STATUS_NOT_LOGGED_IN = 0,
WALLET_STATUS_NOT_SET_UP,
WALLET_STATUS_PREEXISTING,
WALLET_STATUS_CONFLICTING,
WALLET_STATUS_NOT_AUTHENTICATED,
WALLET_STATUS_READY
};
@ -73,6 +78,7 @@ private:
QByteArray _iv;
QByteArray _ckey;
QString* _passphrase { new QString("") };
bool _isOverridingServer { false };
bool writeWallet(const QString& newPassphrase = QString(""));
void updateImageProvider();

View file

@ -26,6 +26,7 @@
#include <GeometryUtil.h>
#include <gl/GLHelpers.h>
#include <scripting/HMDScriptingInterface.h>
#include <scripting/WindowScriptingInterface.h>
#include <ui/OffscreenQmlSurface.h>
#include <ui/OffscreenQmlSurfaceCache.h>
#include <ui/TabletScriptingInterface.h>
@ -233,6 +234,7 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");

View file

@ -655,6 +655,9 @@
case 'goToPurchases':
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
break;
case 'goToMarketplaceMainPage':
tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
break;
case 'goToMarketplaceItemPage':
tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL);
break;
@ -688,6 +691,13 @@
updateSendMoneyParticleEffect();
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
break;
case 'transactionHistory_goToBank':
if (Account.metaverseServerURL.indexOf("staging") >= 0) {
Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging.
} else {
Window.location = "hifi://BankOfHighFidelity";
}
break;
default:
print('Unrecognized message from QML:', JSON.stringify(message));
}