From 969b79a40d80a6369fe0bd9677e092b9e5eaa500 Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sun, 21 Jun 2020 01:20:26 +0200 Subject: [PATCH] add request Hush via chat --- application.qrc | 1 + res/hush-money-white.png | Bin 0 -> 1223 bytes res/hush-money.png | Bin 0 -> 1123 bytes src/Model/ChatItem.cpp | 36 ++++- src/mainwindow.cpp | 304 ++++++++++++++++++++++++++++++++++++++- src/mainwindow.h | 3 + 6 files changed, 337 insertions(+), 7 deletions(-) create mode 100644 res/hush-money-white.png create mode 100644 res/hush-money.png diff --git a/application.qrc b/application.qrc index 0332b5f..9ff3227 100644 --- a/application.qrc +++ b/application.qrc @@ -50,6 +50,7 @@ res/dark-01.png res/money-mouth.png res/money-outgoing.png + res/hush-money-white.png res/hushdlogo.gif diff --git a/res/hush-money-white.png b/res/hush-money-white.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee8d9a57d4fe8dd6f07285bf61ff8648a3d1b87 GIT binary patch literal 1223 zcmV;&1UUPNP)I0004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmP!xqvQ?()$2aAX}WT;LSL`5963Pq?8YK2xEOkVm2O&XFE z7e~Rh;NZ_<)xpJCR|i)?5c~mga&%I3krMAq3N2!MaCsl+y>qzlK0v6KnPzp21DbA| zsYG1NWLL$|E4mQD0F@{+%b1g-Bz)J`Jpz2ci}5V~dw;H8HD@s(AQI0q!?cMvh^IGg zgY!OdgcW6#_?&pmqy~u}xvqHp#<}3Kz%wIeIyFxmAr=d5th6yJni}yGaa7fG$`>*o ztDLtuYvn3y_Q_uu&gm=5T&EgF0*hFJ1Q80VD4`4+G1_%fETrf>?&BYF{Svtpa+Scy zv49FR$gUs!4}Q(v&^mat9cEGGtSBr684%&jasg^i5fy{}$+3^XAq($LRx*rdcI#fP+I| zv_RSGKJV^spWDB8n)CYsWE*m!LbA=l00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNlirunu~K~z}7<(WBXRY4Snzj=Aa z9YIBH+z>=@LlF_J#L~j85R8Rjw7Qgsm|R0&YAzroH=vmUML{yT=l;CT5X|`qF(T~yjPow*em4>7S!G9 zS#?b>uZ)lMk-&(g|2XxidR(1a)bp0e^B?Mr1ixud8I|DYBJ5V7nE~cSdJ{0WN`Dqc z`ux0Q%p((W+SNE4^7@z6A;3D|GteGF=&s`iXad#(Lx3}7;54u@!w&&FtFZS5Xazn2 zoBF}04cMOPt5Cm1LH00VzCQ`jbqPKp(nqU<6Z~b;zntKYBkXG#7!={n)wmTx=!*2W z{g{~^W0x2}QYsjL!_-#wpgN@}nR3DY`=S6`4$NuT%m9lbeYQHXkz`6a?QfC(9q6tl znLN1|=^c3qwOnH|yMP(12``a{RB?cD`xHwm^=e)1+LeN%;%*2DOrXuz-r)G zA4zendO$t)M@ca`$et(I4E1e>-BXA6VPl$lL@g!H+bdOi>Wg^rie$15W7MTt-Bayx z@iemComP4&nerd(h&RC1zYqqwmEJ#fYVTE-)P;;XR6U_SQ1|rm%4*Q-Sj}z1~(SOR_7+fFRTGvuQw)`H)m~ zUmHp0a8z2hg%Ex;>~;`BXjdlzBSHv|8+}zFgzyS@^|xZ?QPh4|=a`Mh?koW=LR(*LR@>BT>b73+yUD3MI>D!_9qJWzajn0}RV4FYpG{qn{t50004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ?()$2P=ql$WWauh>AFB6^c+H)C#RSm|XfHG-*gu zTpR`0f`cE6RRL;k>@Q#C4icB(Z=+ND!f*iVc)uBTlPMiiI@oCw%-vu3sXTLaq%k za?GOw4YKP8|AXJ%T7`*mFDaY=I$s>;V;BhS0*#vEd>=bb;{*sk16O*>U#SDrpQP7X zTI>ku+XgPKTbi;5T00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliruJMCT% zB$!J`^0Qg+?PG7(y}jKy)jVe2oA3SmX5N!>2rvSC09wFB6)nJ4Uo)AriG zy_r7>5AmlCSHA|F10&FaVtK%LL%QGxocfejnZ7iC}tA z3(cmag9wuUtaX)z$1_szCsUhjJq?bU=b2%jG7I2}Am8nbW5A{8g zhC38smw;<|>)bRjeHlpdw4_b{b8adX%#x$8NLpU&dgi;N1xe#(wwPzIT#3@mrX)=P zW@hwan|?a&R+pf<1rmuJgb%H0Np~cj%1HOS9epQ|^)`)$ai_fpUu>|6l&8uo;05p) zSnx?PEjML7Gjm=$u67yx$Nuw@R`X=t8gLzW7UrQKW@TLQS7r!!0L%bKi~cT21XDK8 pxV*CJkzlz390`A}n!WhB`U7D3TiKFwpd$bP002ovPDHLkV1iC8^b!C7 literal 0 HcmV?d00001 diff --git a/src/Model/ChatItem.cpp b/src/Model/ChatItem.cpp index 3a190f0..34d1992 100644 --- a/src/Model/ChatItem.cpp +++ b/src/Model/ChatItem.cpp @@ -158,6 +158,8 @@ QString ChatItem::toChatLine() { QDateTime myDateTime; QString lock; + QString money; + QString moneyText; myDateTime.setTime_t(_timestamp); if (_notarize == true) @@ -176,10 +178,42 @@ QString ChatItem::toChatLine() lock = " "; } + + if (_memo.startsWith("Money transaction of :")) + { + if (_outgoing == true) + { + + moneyText = QString("

Outgoing Money Transaction

") + QString(" "); + }else{ + + + moneyText = QString("

Incoming Money Transaction

") + QString(" "); + + } + }else{money = ""; + moneyText = ""; } + + if (_memo.startsWith("Request of :")) + { + if (_outgoing == true) + { + + moneyText = QString("

Outgoing Hush Request

") + QString(" "); + }else{ + + + moneyText = QString("

Incoming Hush Request

") + QString(" "); + + } + }else{money = ""; + moneyText = ""; } + + QString line = QString("") + myDateTime.toString("yyyy-MM-dd hh:mm"); - line += QString(lock) + QString(""); + line += QString(lock) + QString(moneyText) + QString(""); line +=QString("

") + _memo.toHtmlEscaped() + QString("

"); return line; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a2dda35..d5e979d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1488,9 +1488,8 @@ void MainWindow::setupchatTab() { QAction* requestHushAction; QAction* subatomicAction; contextMenu = new QMenu(ui->listContactWidget); - HushAction = new QAction("Send this contact Hush ",contextMenu); + HushAction = new QAction("Send or Request Hush ",contextMenu); editAction = new QAction("Delete this contact",contextMenu); - requestAction = new QAction("Send a contact request - coming soon",contextMenu); subatomicAction = new QAction("Make a subatomic swap with a friend- coming soon",contextMenu); @@ -1500,8 +1499,7 @@ void MainWindow::setupchatTab() { ui->listContactWidget->setContextMenuPolicy(Qt::ActionsContextMenu); ui->listContactWidget->addAction(HushAction); - ui->listContactWidget->addAction(editAction); - ui->listContactWidget->addAction(requestAction); + ui->listContactWidget->addAction(editAction); ui->listContactWidget->addAction(subatomicAction); ui->memoTxtChat->setEnabled(true); @@ -1525,9 +1523,12 @@ void MainWindow::setupchatTab() { QDialog transactionDialog(this); transaction.setupUi(&transactionDialog); Settings::saveRestore(&transactionDialog); - transaction.requestHush->setEnabled(false); - transaction.requestHush->setVisible(false); + // transaction.requestHush->setEnabled(false); + // transaction.requestHush->setVisible(false); transaction.amountChat->setValidator(this->getAmountValidator()); + QString icon = ":icons/res/hush-money-white.png"; + QPixmap hush(icon); + transaction.label_3->setPixmap(hush); @@ -1559,6 +1560,19 @@ void MainWindow::setupchatTab() { QObject::connect(transaction.sendHush, &QPushButton::clicked, this , &MainWindow::sendMoneyChat); + + + QObject::connect(transaction.requestHush, &QPushButton::clicked, [&] (){ + + QString amt = transaction.amountChat->text(); + QString memo = transaction.MemoMoney->text(); + this->setAmt(amt); + this->setMoneyMemo(memo); + transactionDialog.close(); + }); + + QObject::connect(transaction.requestHush, &QPushButton::clicked, this , &MainWindow::sendMoneyRequestChat); + transactionDialog.exec(); @@ -1869,6 +1883,284 @@ QString MainWindow::doSendChatMoneyTxValidations(Tx tx) { return ""; } +// Create a Tx from the current state of the Chat page. +Tx MainWindow::createTxFromSendRequestChatPage() { + Tx tx; + CAmount totalAmt; + // For each addr/amt in the Chat tab + { + + QString amtStr = this->getAmt(); + CAmount amt; + CAmount amtHm; + + amt = CAmount::fromDecimalString("0"); + amtHm = CAmount::fromDecimalString("0"); + totalAmt = totalAmt + amt; + + QModelIndex index = ui->listContactWidget->currentIndex(); + QString label_contact = index.data(Qt::DisplayRole).toString(); + + for(auto &c : AddressBook::getInstance()->getAllAddressLabels()) + + if (label_contact == c.getName()) { + + QString cid = c.getCid(); + QString myAddr = c.getMyAddress(); + QString type = "Money"; + QString addr = c.getPartnerAddress(); + QString moneymemo = this->getMoneyMemo(); + + /////////User input for chatmemos + QString memoplain = QString("Request of : ") + amtStr + QString(" HUSH ") + QString("\n") + QString("\n") + moneymemo; + + /////////We convert the user input from QString to unsigned char*, so we can encrypt it later + int lengthmemo = memoplain.length(); + + char *memoplainchar = NULL; + memoplainchar = new char[lengthmemo+2]; + strncpy(memoplainchar, memoplain.toUtf8(), lengthmemo +1); + + QString pubkey = this->getPubkeyByAddress(addr); + QString passphraseHash = DataStore::getChatDataStore()->getPassword(); + int length = passphraseHash.length(); + + ////////////////Generate the secretkey for our message encryption + + char *hashEncryptionKeyraw = NULL; + hashEncryptionKeyraw = new char[length+1]; + strncpy(hashEncryptionKeyraw, passphraseHash.toUtf8(), length+1); + + #define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw) + #define MESSAGEAS1_LEN length + + + unsigned char sk[crypto_kx_SECRETKEYBYTES]; + unsigned char pk[crypto_kx_PUBLICKEYBYTES]; + unsigned char server_rx[crypto_kx_SESSIONKEYBYTES], server_tx[crypto_kx_SESSIONKEYBYTES]; + + if (crypto_kx_seed_keypair(pk,sk, + MESSAGEAS1) !=0) { + + this->logger->write("Suspicious keypair, bail out "); + } + ////////////////Get the pubkey from Bob, so we can create the share key + + const QByteArray pubkeyBobArray = QByteArray::fromHex(pubkey.toLatin1()); + const unsigned char *pubkeyBob = reinterpret_cast(pubkeyBobArray.constData()); + /////Create the shared key for sending the message + + if (crypto_kx_server_session_keys(server_rx, server_tx, + pk, sk, pubkeyBob) != 0) { + this->logger->write("Suspicious client public send key, bail out "); + } + + + // Let's try to preserve Unicode characters + QByteArray ba_memo = memoplain.toUtf8(); + int ba_memo_length = ba_memo.size(); + + #define MESSAGEMoney (const unsigned char *) ba_memo.data() + #define MESSAGE_LENMoney ba_memo_length + + + ////////////Now lets encrypt the message Alice send to Bob////////////////////////////// + //#define MESSAGE (const unsigned char *) memoplainchar + //#define MESSAGE_LEN lengthmemo + #define CIPHERTEXT_LEN (crypto_secretstream_xchacha20poly1305_ABYTES + MESSAGE_LENMoney) + unsigned char ciphertext[CIPHERTEXT_LEN]; + unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; + + crypto_secretstream_xchacha20poly1305_state state; + + /* Set up a new stream: initialize the state and create the header */ + crypto_secretstream_xchacha20poly1305_init_push(&state, header, server_tx); + + + /* Now, encrypt the first chunk. `c1` will contain an encrypted, + * authenticated representation of `MESSAGE_PART1`. */ + crypto_secretstream_xchacha20poly1305_push + (&state, ciphertext, NULL, MESSAGEMoney, MESSAGE_LENMoney, NULL, 0, crypto_secretstream_xchacha20poly1305_TAG_FINAL); + + ////Create the HM for this message + QString headerbytes = QByteArray(reinterpret_cast(header), crypto_secretstream_xchacha20poly1305_HEADERBYTES).toHex(); + QString publickeyAlice = QByteArray(reinterpret_cast(pk), crypto_kx_PUBLICKEYBYTES).toHex(); + + + QString hmemo= createHeaderMemo(type,cid,myAddr,headerbytes,publickeyAlice,1,0); + + /////Ciphertext Memo + QString memo = QByteArray(reinterpret_cast(ciphertext), CIPHERTEXT_LEN).toHex(); + + + tx.toAddrs.push_back(ToFields{addr, amtHm, hmemo}); + tx.toAddrs.push_back(ToFields{addr, amt, memo}); + + } + } + + tx.fee = Settings::getMinerFee(); + + return tx; + +} + +void MainWindow::sendMoneyRequestChat() { + +////////////////////////////Todo: Check if a Contact is selected////////// + + // Create a Tx from the values on the send tab. Note that this Tx object + // might not be valid yet. + + /* QString Name = ui->contactNameMemo->text(); + + if ((ui->contactNameMemo->text().isEmpty()) || (ui->memoTxtChat->toPlainText().trimmed().isEmpty())) { + + QMessageBox msg(QMessageBox::Critical, tr("You have to select a contact and insert a Memo"), + tr("You have selected no Contact from Contactlist,\n") + tr("\nor your Memo is empty"), + QMessageBox::Ok, this); + + msg.exec(); + return; + }*/ + + + Tx tx = createTxFromSendRequestChatPage(); + + QString error = doSendChatMoneyRequestTxValidations(tx); + + if (!error.isEmpty()) { + // Something went wrong, so show an error and exit + QMessageBox msg(QMessageBox::Critical, tr("Message Error"), error, + QMessageBox::Ok, this); + + msg.exec(); + + // abort the Tx + return; + } + + auto movie = new QMovie(this); + auto movie1 = new QMovie(this); + movie->setFileName(":/img/res/loaderblack.gif"); + movie1->setFileName(":/img/res/loaderwhite.gif"); + + auto theme = Settings::getInstance()->get_theme_name(); + if (theme == "Dark" || theme == "Midnight") { + + connect(movie, &QMovie::frameChanged, [=]{ + ui->sendChatButton->setIcon(movie->currentPixmap()); + }); + movie->start(); + ui->sendChatButton->show(); + ui->sendChatButton->setEnabled(false); + + } else { + + connect(movie1, &QMovie::frameChanged, [=]{ + ui->sendChatButton->setIcon(movie1->currentPixmap()); + }); + movie1->start(); + ui->sendChatButton->show(); + ui->sendChatButton->setEnabled(false); + } + + ui->memoTxtChat->clear(); + + // And send the Tx + rpc->executeTransaction(tx, + [=] (QString txid) { + ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); + + + QTimer::singleShot(1000, [=]() { + + if (theme == "Dark" || theme == "Midnight") { + QPixmap send(":/icons/res/send-white.png"); + QIcon sendIcon(send); + ui->sendChatButton->setIcon(sendIcon); + movie->stop(); + ui->sendChatButton->setEnabled(true); + }else{ + + QPixmap send(":/icons/res/sendBlack.png"); + QIcon sendIcon(send); + ui->sendChatButton->setIcon(sendIcon); + movie1->stop(); + ui->sendChatButton->setEnabled(true); + } + + }); + + // Force a UI update so we get the unconfirmed Tx + rpc->refresh(true); + ui->memoTxtChat->clear(); + + }, + // Errored out + [=] (QString opid, QString errStr) { + ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000); + + if (!opid.isEmpty()) + errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr; + + QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); + movie->stop(); + + + if (theme == "Dark" || theme == "Midnight") { + QPixmap send(":/icons/res/send-white.png"); + QIcon sendIcon(send); + ui->sendChatButton->setIcon(sendIcon); + movie->stop(); + ui->sendChatButton->setEnabled(true); + }else{ + + QPixmap send(":/icons/res/sendBlack.png"); + QIcon sendIcon(send); + ui->sendChatButton->setIcon(sendIcon); + movie1->stop(); + ui->sendChatButton->setEnabled(true); + } + + + + } + ); + + } + +QString MainWindow::doSendChatMoneyRequestTxValidations(Tx tx) { + // Check to see if we have enough verified funds to send the Tx. + + CAmount total; + for (auto toAddr : tx.toAddrs) { + if (!Settings::isValidAddress(toAddr.addr)) { + QString addr = (toAddr.addr.length() > 100 ? toAddr.addr.left(100) + "..." : toAddr.addr); + return QString(tr("Recipient Address ")) % addr % tr(" is Invalid"); + } + + // This technically shouldn't be possible, but issue #62 seems to have discovered a bug + // somewhere, so just add a check to make sure. + if (toAddr.amount.toqint64() < 0) { + return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr)); + } + + total = total + toAddr.amount; + } + total = total + tx.fee; + + auto available = rpc->getModel()->getAvailableBalance(); + + if (available < total) { + return tr("Not enough available funds to send this transaction\n\nHave: %1\nNeed: %2\n\nNote: Funds need 1 confirmations before they can be spent") + .arg(available.toDecimalhushString(), total.toDecimalhushString()); + } + + return ""; +} + + void MainWindow::updateChat() { rpc->refreshChat(ui->listChat,ui->memoSizeChat); diff --git a/src/mainwindow.h b/src/mainwindow.h index 3867de6..ca4d8cc 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -51,6 +51,7 @@ public: QString doSendChatTxValidations(Tx tx); QString doSendChatMoneyTxValidations(Tx tx); QString doSendRequestTxValidations(Tx tx); + QString doSendChatMoneyRequestTxValidations(Tx tx); QString getCid(); QString getAmt(); QString getMoneyMemo(); @@ -143,6 +144,7 @@ private: Tx createTxFromChatPage(); Tx createTxForSafeContactRequest(); Tx createTxFromSendChatPage(); + Tx createTxFromSendRequestChatPage(); void encryptWallet(); void removeWalletEncryption(); @@ -152,6 +154,7 @@ private: void sendButton(); void sendChat(); void sendMoneyChat(); + void sendMoneyRequestChat(); void addContact(); void ContactRequest();