Fix NotifyQt::askForPassword QInputDialog is not created in GUI Thread.

This commit is contained in:
Phenom 2021-10-28 18:13:25 +02:00
parent bc76b10792
commit e137c17039
4 changed files with 134 additions and 56 deletions

View File

@ -1322,16 +1322,20 @@ bool OpenPGPSDKHandler::decryptTextFromFile(const RsPgpId&,std::string& text,con
bool OpenPGPSDKHandler::SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */)
{
RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures.
// need to find the key and to decrypt it.
const ops_keydata_t *key = locked_getSecretKey(id) ;
if(!key)
ops_keydata_t *key = nullptr;
{
RsErr() << "Cannot sign: no secret key with id " << id.toStdString() ;
RS_STACK_MUTEX(pgphandlerMtx); // lock access to PGP memory structures.
const ops_keydata_t *test_key = locked_getSecretKey(id);
if(!test_key)
{
RsErr("Cannot sign: no secret key with id ", id.toStdString() );
return false ;
}
// Copy key as it may take time for user to respond.
key = ops_keydata_new();
ops_keydata_copy(key, test_key);
}
std::string uid_hint ;
if(key->nuids > 0)
@ -1346,26 +1350,31 @@ bool OpenPGPSDKHandler::SignDataBin(const RsPgpId& id,const void *data, const ui
#endif
bool last_passwd_was_wrong = false ;
ops_secret_key_t *secret_key = NULL ;
ops_secret_key_t *secret_key = nullptr ;
for(int i=0;i<3;++i)
{
bool cancelled =false;
std::string passphrase = _passphrase_callback(NULL,reason.c_str(),uid_hint.c_str(),"Please enter passwd for encrypting your key : ",last_passwd_was_wrong,&cancelled) ;//TODO reason
// Need to be outside of mutex to not block GUI.
std::string passphrase = _passphrase_callback(NULL,reason.c_str(),uid_hint.c_str(),"Please enter password for encrypting your key : ",last_passwd_was_wrong,&cancelled) ;//TODO reason
secret_key = ops_decrypt_secret_key_from_data(key,passphrase.c_str()) ;
if(cancelled)
{
RsErr() << "Key entering cancelled" ;
ops_keydata_free(key);
return false ;
}
if(secret_key)
break ;
RsErr() << "Key decryption went wrong. Wrong passwd?" ;
RsErr() << "Key decryption went wrong. Wrong password?" ;
last_passwd_was_wrong = true ;
}
// No more need of key, free it.
ops_keydata_free(key);
if(!secret_key)
{
RsErr() << "Could not obtain secret key. Signature cancelled." ;
@ -1374,6 +1383,8 @@ ops_secret_key_t *secret_key = NULL ;
// then do the signature.
RS_STACK_MUTEX(pgphandlerMtx); // lock access to PGP memory structures.
ops_boolean_t not_raw = !use_raw_signature ;
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
ops_memory_t *memres = ops_sign_buf(data,len,OPS_SIG_BINARY,OPS_HASH_SHA256,secret_key,ops_false,ops_false,not_raw,not_raw) ;

View File

@ -21,6 +21,7 @@
#include <QColorDialog>
#include <QDesktopServices>
#include <QIcon>
#include <QInputDialog>
#include <QMessageBox>
#include <QPixmap>
#include <QStatusBar>
@ -1689,3 +1690,19 @@ void MainWindow::setCompactStatusMode(bool compact)
ratesstatus->setCompactMode(compact);
//opModeStatus: TODO Show only ???
}
Gui_InputDialogReturn MainWindow::guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal)
{
QInputDialog dialog(this);
dialog.setWindowTitle(windowTitle);
dialog.setLabelText(labelText);
dialog.setTextEchoMode(textEchoMode);
dialog.setModal(modal);
Gui_InputDialogReturn ret;
ret.execReturn = dialog.exec();
ret.textValue = dialog.textValue();
return ret;
}

View File

@ -21,6 +21,7 @@
#ifndef _MainWindow_H
#define _MainWindow_H
#include <QLineEdit>
#include <QSystemTrayIcon>
#include <set>
@ -74,6 +75,14 @@ class MessengerWindow;
class ApplicationWindow;
#endif
struct Gui_InputDialogReturn
{
int execReturn;
QString textValue;
};
Q_DECLARE_METATYPE(Gui_InputDialogReturn);
class MainWindow : public RWindow
{
Q_OBJECT
@ -210,9 +219,35 @@ public slots:
void showBandwidthGraph();
void toggleStatusToolTip(bool toggle);
/**
* @brief Create a QInputDialog. This must be called in MainWindow thread because Widgets must be created in the GUI thread.
* Here an exemple how to call it:
*
* bool sameThread = QThread::currentThread() == qApp->thread();
* Gui_InputDialogReturn ret;
* qRegisterMetaType<Gui_InputDialogReturn>("Gui_InputDialogReturn");
* QMetaObject::invokeMethod( MainWindow::getInstance()
* , "guiInputDialog"
* , sameThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection
* , Q_RETURN_ARG(Gui_InputDialogReturn, ret)
* , Q_ARG(QString, windowTitle)
* , Q_ARG(QString, labelText)
* , Q_ARG(QLineEdit::EchoMode, textEchoMode)
* , Q_ARG(bool, modal)
* );
*
* @param windowTitle: the window title (caption).
* @param labelText: label's text which describes what needs to be input.
* @param textEchoMode: the echo mode for the text value.
* @param modal: pop up the dialog as modal or modeless.
* @return Gui_InputDialogReturn ( Accepted(1)|Rejected(0), text value for the input dialog)
*/
Gui_InputDialogReturn guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal);
protected:
/** Default Constructor */
MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
void closeEvent(QCloseEvent *);

View File

@ -21,12 +21,6 @@
#include "gui/common/FilesDefs.h"
#include <retroshare/rsgxsifacehelper.h>
#include <QInputDialog>
#include <QMessageBox>
#include <QTimer>
//#include <QMutexLocker>
#include <QDesktopWidget>
#include "notifyqt.h"
#include <retroshare/rsnotify.h>
#include <retroshare/rspeers.h>
@ -55,6 +49,13 @@
#include "retroshare/rsplugin.h"
#include <QDesktopWidget>
#include <QInputDialog>
#include <QMessageBox>
//#include <QMutexLocker>
#include <QThread>
#include <QTimer>
/*****
* #define NOTIFY_DEBUG
****/
@ -223,35 +224,49 @@ bool NotifyQt::askForPassword(const std::string& title, const std::string& key_d
{
RsAutoUpdatePage::lockAllEvents() ;
QInputDialog dialog;
QString windowTitle;
if (title == "") {
dialog.setWindowTitle(tr("Passphrase required"));
windowTitle = tr("Passphrase required");
} else if (title == "AuthSSLimpl::SignX509ReqWithGPG()") {
dialog.setWindowTitle(tr("You need to sign your node's certificate."));
windowTitle = tr("You need to sign your node's certificate.");
} else if (title == "p3IdService::service_CreateGroup()") {
dialog.setWindowTitle(tr("You need to sign your forum/chatrooms identity."));
windowTitle = tr("You need to sign your forum/chatrooms identity.");
} else {
dialog.setWindowTitle(QString::fromStdString(title));
windowTitle = QString::fromStdString(title);
}
dialog.setLabelText((prev_is_bad ? QString("%1<br/><br/>").arg(tr("Wrong password !")) : QString()) + QString("<b>%1</b><br/>Profile: <i>%2</i>\n").arg(tr("Please enter your Retroshare passphrase"), QString::fromUtf8(key_details.c_str())));
dialog.setTextEchoMode(QLineEdit::Password);
dialog.setModal(true);
QString labelText = ( prev_is_bad ? QString("%1<br/><br/>").arg(tr("Wrong password !")) : QString() )
+ QString("<b>%1</b><br/>Profile: <i>%2</i>\n")
.arg( tr("Please enter your Retroshare passphrase")
, QString::fromUtf8(key_details.c_str()) );
QLineEdit::EchoMode textEchoMode = QLineEdit::Password;
bool modal = true;
int ret = dialog.exec();
bool sameThread = QThread::currentThread() == qApp->thread();
Gui_InputDialogReturn ret;
qRegisterMetaType<Gui_InputDialogReturn>("Gui_InputDialogReturn");
QMetaObject::invokeMethod( MainWindow::getInstance()
, "guiInputDialog"
, sameThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection
, Q_RETURN_ARG(Gui_InputDialogReturn, ret)
, Q_ARG(QString, windowTitle)
, Q_ARG(QString, labelText)
, Q_ARG(QLineEdit::EchoMode, textEchoMode)
, Q_ARG(bool, modal)
);
cancelled = false ;
RsAutoUpdatePage::unlockAllEvents() ;
if (ret == QDialog::Rejected) {
if (ret.execReturn == QDialog::Rejected) {
password.clear() ;
cancelled = true ;
return true ;
}
if (ret == QDialog::Accepted) {
password = dialog.textValue().toUtf8().constData();
if (ret.execReturn == QDialog::Accepted) {
password = ret.textValue.toUtf8().constData();
return true;
}