mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-13 22:27:13 +02:00
Merge pull request #13859 from howard-stearns/wallet-locker2
Wallet Locker
This commit is contained in:
commit
fe3f48b194
7 changed files with 113 additions and 263 deletions
|
@ -63,47 +63,6 @@ Item {
|
|||
question: "How can I get HFC?";
|
||||
answer: "High Fidelity commerce is in open beta right now. Want more HFC? \
|
||||
Get it by going to <br><br><b><font color='#0093C5'><a href='#bank'>BankOfHighFidelity.</a></font></b> and meeting with the banker!";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What are private keys and where are they stored?";
|
||||
answer:
|
||||
"A private key is a secret piece of text that is used to prove ownership, unlock confidential information, and sign transactions. \
|
||||
In High Fidelity, your private key is used to securely access the contents of your Wallet and Purchases. \
|
||||
After wallet setup, a hifikey file is stored on your computer in High Fidelity Interface's AppData directory. \
|
||||
Your hifikey file contains your private key and is protected by your wallet passphrase. \
|
||||
<br><br>It is very important to back up your hifikey file! \
|
||||
<b><font color='#0093C5'><a href='#privateKeyPath'>Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>"
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "How do I back up my private keys?";
|
||||
answer: "You can back up your hifikey file (which contains your private key and is encrypted using your wallet passphrase) by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. \
|
||||
Restore your hifikey file by replacing the file in Interface's AppData directory with your backup copy. \
|
||||
Others with access to your back up should not be able to spend your HFC without your passphrase. \
|
||||
<b><font color='#0093C5'><a href='#privateKeyPath'>Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What happens if I lose my private keys?";
|
||||
answer: "We cannot stress enough that you should keep a backup! For security reasons, High Fidelity does not keep a copy, and cannot restore it for you. \
|
||||
If you lose your private key, you will no longer have access to the contents of your Wallet or My Purchases. \
|
||||
Here are some things to try:<ul>\
|
||||
<li>If you have backed up your hifikey file before, search your backup location</li>\
|
||||
<li>Search your AppData directory in the last machine you used to set up the Wallet</li>\
|
||||
<li>If you are a developer and have installed multiple builds of High Fidelity, your hifikey file might be in another folder</li>\
|
||||
</ul><br><br>As a last resort, you can set up your Wallet again and generate a new hifikey file. \
|
||||
Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over.";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What if I forget my wallet passphrase?";
|
||||
answer: "Your wallet passphrase is used to encrypt your private keys. Please write it down and store it securely! \
|
||||
<br><br>If you forget your passphrase, you will no longer be able to decrypt the hifikey file that the passphrase protects. \
|
||||
You will also no longer have access to the contents of your Wallet or My Purchases. \
|
||||
For security reasons, High Fidelity does not keep a copy of your passphrase, and can't restore it for you. \
|
||||
<br><br>If you still cannot remember your wallet passphrase, you can set up your Wallet again and generate a new hifikey file. \
|
||||
Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over.";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
@ -114,11 +73,9 @@ In your Wallet's Send Money tab, choose from your list of connections, or choose
|
|||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What is a Security Pic?"
|
||||
answer: "Your Security Pic is an encrypted image that you select during Wallet Setup. \
|
||||
It acts as an extra layer of Wallet security. \
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your private keys.\
|
||||
<br><br>Don't enter your passphrase anywhere that doesn't display your Security Pic! \
|
||||
If you don't see your Security Pic on a page that requests your Wallet passphrase, someone untrustworthy may be trying to access your Wallet.";
|
||||
answer: "Your Security Pic acts as an extra layer of Wallet security. \
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your account. \
|
||||
<br><br><b><font color='#0093C5'><a href='#securitypic'>Tap here to change your Security Pic.</a></font></b>";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
@ -260,6 +217,8 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta
|
|||
}
|
||||
} else if (link === "#support") {
|
||||
Qt.openUrlExternally("mailto:support@highfidelity.com");
|
||||
} else if (link === "#securitypic") {
|
||||
sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,76 +88,9 @@ Item {
|
|||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: changePassphraseContainer;
|
||||
anchors.top: securityTextSeparator.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
height: 75;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: changePassphraseImage;
|
||||
text: hifi.glyphs.passphrase;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "Passphrase";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: changePassphraseImage.right;
|
||||
anchors.leftMargin: 30;
|
||||
width: 50;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// "Change Passphrase" button
|
||||
HifiControlsUit.Button {
|
||||
id: changePassphraseButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 140;
|
||||
height: 40;
|
||||
text: "Change";
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: 'walletSecurity_changePassphrase'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: changePassphraseSeparator;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 1;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: changePassphraseContainer.bottom;
|
||||
anchors.topMargin: 8;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: changeSecurityImageContainer;
|
||||
anchors.top: changePassphraseSeparator.bottom;
|
||||
anchors.top: securityTextSeparator.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
|
@ -207,143 +140,6 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: privateKeysSeparator;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 1;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: changeSecurityImageContainer.bottom;
|
||||
anchors.topMargin: 8;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: yourPrivateKeysContainer;
|
||||
anchors.top: privateKeysSeparator.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
Commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: yourPrivateKeysImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: yourPrivateKeysText;
|
||||
text: "Private Keys";
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 32;
|
||||
anchors.left: yourPrivateKeysImage.right;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.right: parent.right;
|
||||
height: 30;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// Text below "private keys"
|
||||
RalewayRegular {
|
||||
id: explanitoryText;
|
||||
text: "Your money and purchases are secured with private keys that only you have access to.";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: yourPrivateKeysText.bottom;
|
||||
anchors.topMargin: 10;
|
||||
anchors.left: yourPrivateKeysText.left;
|
||||
anchors.right: yourPrivateKeysText.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: removeHmdContainer;
|
||||
z: 998;
|
||||
visible: false;
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0;
|
||||
color: hifi.colors.baseGrayShadow;
|
||||
}
|
||||
}
|
||||
anchors.fill: backupInstructionsButton;
|
||||
radius: 5;
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
propagateComposedEvents: false;
|
||||
hoverEnabled: true;
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
anchors.fill: parent;
|
||||
text: "INSTRUCTIONS OPEN ON DESKTOP";
|
||||
size: 15;
|
||||
color: hifi.colors.white;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: removeHmdContainerTimer;
|
||||
interval: 5000;
|
||||
onTriggered: removeHmdContainer.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: backupInstructionsButton;
|
||||
text: "View Backup Instructions";
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.left: explanitoryText.left;
|
||||
anchors.right: explanitoryText.right;
|
||||
anchors.top: explanitoryText.bottom;
|
||||
anchors.topMargin: 16;
|
||||
height: 40;
|
||||
|
||||
onClicked: {
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
removeHmdContainer.visible = true;
|
||||
removeHmdContainerTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -399,6 +399,9 @@ Rectangle {
|
|||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
|
||||
sendToScript(msg);
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -803,12 +806,24 @@ Rectangle {
|
|||
}
|
||||
|
||||
function walletResetSetup() {
|
||||
/* Bypass all this and do it automatically
|
||||
root.activeView = "walletSetup";
|
||||
var timestamp = new Date();
|
||||
walletSetup.startingTimestamp = timestamp;
|
||||
walletSetup.setupAttemptID = generateUUID();
|
||||
UserActivityLogger.commerceWalletSetupStarted(timestamp, walletSetup.setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
|
||||
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
|
||||
*/
|
||||
|
||||
var randomNumber = Math.floor(Math.random() * 34) + 1;
|
||||
var securityImagePath = "images/" + addLeadingZero(randomNumber) + ".jpg";
|
||||
Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set.
|
||||
Commerce.chooseSecurityImage(securityImagePath);
|
||||
Commerce.generateKeyPair();
|
||||
}
|
||||
|
||||
function addLeadingZero(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
function followReferrer(msg) {
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply* reply) {
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||
#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy.
|
||||
qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
// Non-200 responses are not json:
|
||||
|
@ -69,7 +71,9 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
const QString URL = "/api/v1/commerce/";
|
||||
JSONCallbackParameters callbackParams(this, success, fail);
|
||||
#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy.
|
||||
qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact);
|
||||
#endif
|
||||
accountManager->sendRequest(URL + endpoint,
|
||||
authType,
|
||||
method,
|
||||
|
@ -117,7 +121,7 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons
|
|||
signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure);
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (!accountManager->isLoggedIn()) {
|
||||
qCWarning(commerce) << "Cannot set receiveAt when not logged in.";
|
||||
|
@ -125,11 +129,25 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
|
|||
emit receiveAtResult(result);
|
||||
return false; // We know right away that we will fail, so tell the caller.
|
||||
}
|
||||
|
||||
signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
QJsonObject transaction;
|
||||
transaction["public_key"] = hfc_key;
|
||||
transaction["locker"] = QString::fromUtf8(locker);
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in.
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto keys = wallet->listPublicKeys();
|
||||
if (keys.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto key = keys.first();
|
||||
return receiveAt(key, key, wallet->getWallet());
|
||||
}
|
||||
|
||||
void Ledger::balance(const QStringList& keys) {
|
||||
keysQuery("balance", "balanceSuccess", "balanceFailure");
|
||||
}
|
||||
|
@ -283,24 +301,30 @@ 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();
|
||||
const QByteArray locker = data["locker"].toString().toUtf8();
|
||||
bool isOverride = wallet->wasSoftReset();
|
||||
|
||||
wallet->setSalt(salt);
|
||||
wallet->setIv(iv);
|
||||
wallet->setCKey(ckey);
|
||||
if (!locker.isEmpty()) {
|
||||
wallet->setWallet(locker);
|
||||
wallet->setPassphrase("ACCOUNT"); // We only locker wallets that have been converted to account-based auth.
|
||||
}
|
||||
|
||||
QString keyStatus = "ok";
|
||||
QStringList localPublicKeys = wallet->listPublicKeys();
|
||||
if (remotePublicKey.isEmpty() || isOverride) {
|
||||
if (!localPublicKeys.isEmpty()) {
|
||||
QString key = localPublicKeys.first();
|
||||
receiveAt(key, key);
|
||||
if (!localPublicKeys.isEmpty()) { // Let the metaverse know about a local wallet.
|
||||
receiveAt();
|
||||
}
|
||||
} else {
|
||||
if (localPublicKeys.isEmpty()) {
|
||||
keyStatus = "preexisting";
|
||||
} else if (localPublicKeys.first() != remotePublicKey) {
|
||||
keyStatus = "conflicting";
|
||||
} else if (locker.isEmpty()) { // Matches metaverse data, but we haven't lockered it yet.
|
||||
receiveAt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ class Ledger : public QObject, public Dependency {
|
|||
|
||||
public:
|
||||
void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false);
|
||||
bool receiveAt(const QString& hfc_key, const QString& signing_key);
|
||||
bool receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker);
|
||||
bool receiveAt();
|
||||
void balance(const QStringList& keys);
|
||||
void inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage);
|
||||
void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage);
|
||||
|
|
|
@ -131,7 +131,7 @@ bool Wallet::writeBackupInstructions() {
|
|||
QFile outputFile(outputFilename);
|
||||
bool retval = false;
|
||||
|
||||
if (getKeyFilePath() == "")
|
||||
if (getKeyFilePath().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -190,6 +190,30 @@ bool writeKeys(const char* filename, EC_KEY* keys) {
|
|||
return retval;
|
||||
}
|
||||
|
||||
bool Wallet::setWallet(const QByteArray& wallet) {
|
||||
QFile file(keyFilePath());
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
qCCritical(commerce) << "Unable to open wallet for write in" << keyFilePath();
|
||||
return false;
|
||||
}
|
||||
if (file.write(wallet) != wallet.count()) {
|
||||
qCCritical(commerce) << "Unable to write wallet in" << keyFilePath();
|
||||
return false;
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
QByteArray Wallet::getWallet() {
|
||||
QFile file(keyFilePath());
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qCInfo(commerce) << "No existing wallet in" << keyFilePath();
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray wallet = file.readAll();
|
||||
file.close();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
QPair<QByteArray*, QByteArray*> generateECKeypair() {
|
||||
|
||||
EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
|
@ -334,7 +358,7 @@ Wallet::Wallet() {
|
|||
uint status;
|
||||
QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : "";
|
||||
|
||||
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
|
||||
if (wallet->getKeyFilePath().isEmpty() || !wallet->getSecurityImage()) {
|
||||
if (keyStatus == "preexisting") {
|
||||
status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING;
|
||||
} else{
|
||||
|
@ -524,15 +548,23 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// FIXME: initialize OpenSSL elsewhere soon
|
||||
initialize();
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: checking" << (!_passphrase || !_passphrase->isEmpty());
|
||||
|
||||
// this should always be false if we don't have a passphrase
|
||||
// cached yet
|
||||
if (!_passphrase || _passphrase->isEmpty()) {
|
||||
return false;
|
||||
if (!getKeyFilePath().isEmpty()) { // If file exists, then it is an old school file that has not been lockered. Must get user's passphrase.
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: No passphrase, but there is an existing wallet.";
|
||||
return false;
|
||||
} else {
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: New setup.";
|
||||
setPassphrase("ACCOUNT"); // Going forward, consider this an account-based client.
|
||||
}
|
||||
}
|
||||
if (_publicKeys.count() > 0) {
|
||||
// we _must_ be authenticated if the publicKeys are there
|
||||
DependencyManager::get<WalletScriptingInterface>()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY);
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet was ready";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -545,10 +577,15 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// be sure to add the public key so we don't do this over and over
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
|
||||
if (*_passphrase != "ACCOUNT") {
|
||||
changePassphrase("ACCOUNT"); // Rewrites with salt and constant, and will be lockered that way.
|
||||
}
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet now ready";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet not ready";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -559,6 +596,7 @@ bool Wallet::generateKeyPair() {
|
|||
qCInfo(commerce) << "Generating keypair.";
|
||||
auto keyPair = generateECKeypair();
|
||||
if (!keyPair.first) {
|
||||
qCWarning(commerce) << "Empty keypair";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -576,7 +614,7 @@ bool Wallet::generateKeyPair() {
|
|||
// 2. It is maximally private, and we can step back from that later if desired.
|
||||
// 3. It maximally exercises all the machinery, so we are most likely to surface issues now.
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
return ledger->receiveAt(key, key);
|
||||
return ledger->receiveAt(key, key, getWallet());
|
||||
}
|
||||
|
||||
QStringList Wallet::listPublicKeys() {
|
||||
|
@ -666,11 +704,13 @@ void Wallet::chooseSecurityImage(const QString& filename) {
|
|||
// there _is_ a keyfile, we need to update it (similar to changing the
|
||||
// passphrase, we need to do so into a temp file and move it).
|
||||
if (!QFile(keyFilePath()).exists()) {
|
||||
qCDebug(commerce) << "initial security pic set for empty wallet";
|
||||
emit securityImageResult(true);
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = writeWallet();
|
||||
qCDebug(commerce) << "updated security pic" << success;
|
||||
emit securityImageResult(success);
|
||||
}
|
||||
|
||||
|
@ -715,6 +755,11 @@ QString Wallet::getKeyFilePath() {
|
|||
|
||||
bool Wallet::writeWallet(const QString& newPassphrase) {
|
||||
EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
// Remove any existing locker, because it will be out of date.
|
||||
if (!_publicKeys.isEmpty() && !ledger->receiveAt(_publicKeys.first(), _publicKeys.first(), QByteArray())) {
|
||||
return false; // FIXME: receiveAt could fail asynchronously.
|
||||
}
|
||||
if (keys) {
|
||||
// we read successfully, so now write to a new temp file
|
||||
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
|
||||
|
@ -722,6 +767,7 @@ bool Wallet::writeWallet(const QString& newPassphrase) {
|
|||
if (!newPassphrase.isEmpty()) {
|
||||
setPassphrase(newPassphrase);
|
||||
}
|
||||
|
||||
if (writeKeys(tempFileName.toStdString().c_str(), keys)) {
|
||||
if (writeSecurityImage(_securityImage, tempFileName)) {
|
||||
// ok, now move the temp file to the correct spot
|
||||
|
@ -729,6 +775,11 @@ bool Wallet::writeWallet(const QString& newPassphrase) {
|
|||
QFile(tempFileName).rename(QString(keyFilePath()));
|
||||
qCDebug(commerce) << "wallet written successfully";
|
||||
emit keyFilePathIfExistsResult(getKeyFilePath());
|
||||
if (!walletIsAuthenticatedWithPassphrase() || !ledger->receiveAt()) {
|
||||
// FIXME: Should we fail the whole operation?
|
||||
// Tricky, because we'll need the the key and file from the TEMP location...
|
||||
qCWarning(commerce) << "Failed to update locker";
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
qCDebug(commerce) << "couldn't write security image to temp wallet";
|
||||
|
|
|
@ -73,6 +73,7 @@ private slots:
|
|||
void handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
friend class Ledger;
|
||||
QStringList _publicKeys{};
|
||||
QPixmap* _securityImage { nullptr };
|
||||
QByteArray _salt;
|
||||
|
@ -87,6 +88,9 @@ private:
|
|||
bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen);
|
||||
bool writeBackupInstructions();
|
||||
|
||||
bool setWallet(const QByteArray& wallet);
|
||||
QByteArray getWallet();
|
||||
|
||||
void account();
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue