From fada0ebeb028adcb5a46dab40a202f03d2c14e41 Mon Sep 17 00:00:00 2001 From: Daniel Tartavel Date: Thu, 9 Mar 2023 18:13:46 +0100 Subject: [PATCH] added storing password in a secure way --- RsyncUI.pro | 9 +++-- RsyncUI.pro.user | 2 +- main.cpp | 3 ++ mainwindow.cpp | 94 +++++++++++++++++------------------------------- mainwindow.h | 12 +++---- password.cpp | 82 ++++++++++++++++++++---------------------- password.h | 14 +++++--- tools.cpp | 3 +- 8 files changed, 101 insertions(+), 118 deletions(-) diff --git a/RsyncUI.pro b/RsyncUI.pro index 51c292f..457a665 100644 --- a/RsyncUI.pro +++ b/RsyncUI.pro @@ -6,11 +6,14 @@ QT += KConfigCore KConfigGui QT += KCoreAddons QT += KDBusAddons -#LIBS += -lKF5WindowSystem +LIBS += -lqt5keychain + greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 +DEFINES += QTKEYCHAIN_NO_EXPORT + # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 @@ -37,7 +40,8 @@ TRANSLATIONS += \ RsyncUI_fr_FR.ts INCLUDEPATH += \ - /usr/include/KF5 + /usr/include/KF5 \ + /usr/include/qt5keychain/ # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin @@ -63,3 +67,4 @@ desktopfile.path = /usr/share/applications desktopfile.files = RsyncUI.desktop icon.path = /usr/share/icons/ icon.files = RsyncUI.png +-lqt5keychain diff --git a/RsyncUI.pro.user b/RsyncUI.pro.user index 372b13c..8a96282 100644 --- a/RsyncUI.pro.user +++ b/RsyncUI.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/main.cpp b/main.cpp index 54d6085..252bec4 100644 --- a/main.cpp +++ b/main.cpp @@ -21,6 +21,9 @@ int main(int argc, char *argv[]) a.installTranslator(&myappTranslator); } + static const QString appName = "RsyncUI"; + + //Password passwdJob; MainWindow w; w.show(); w.init(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 0e6184d..10dadd0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4,9 +4,9 @@ using namespace std; bool display = false; -//extern QDialog Configuration; extern Ui::Configuration config; extern bool testRsyncReturn(QProcess *); +extern QApplication a; QMap rsyncErrorStrings { {0, QTranslator::tr("Success. The rsync command completed successfully without any errors.")}, @@ -38,9 +38,10 @@ MainWindow::MainWindow(QWidget *parent) QCoreApplication::setOrganizationName("RsyncUI"); QCoreApplication::setApplicationName("RsyncUI"); + this->setWindowTitle(a.applicationName()); + // context menu for treewidget (list of files) ui->treeWidget->addAction(ui->actionDownload); - // init configuration window config.setupUi(&Configuration); @@ -64,8 +65,6 @@ MainWindow::MainWindow(QWidget *parent) connect(this, &MainWindow::stopDownloading, this, &MainWindow::cancelled); connect(config.buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted())); connect(config.comboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::on_comboBox_currentIndexChanged); -// connect(loginD.loginBox, SIGNAL(accepted()), this, SLOT(on_loginBox_accepted())); -// connect(this, SIGNAL(passwordReady()), this, SLOT(waitPasswword())); loadSettings(); @@ -116,7 +115,7 @@ void MainWindow::init() if (this->settings.value("Downloads/rows").toInt() != 0) { // asking if we load the list and continue downloading - msgBox.setWindowTitle("RsyncUI"); + msgBox.setWindowTitle(a.applicationName()); msgBox.setInformativeText(tr("A list of interrupted downloads exists, do you want to continue downloading ? if not the list will be cleared" )); QPushButton *yes = msgBox.addButton(QMessageBox::Yes); @@ -133,7 +132,7 @@ void MainWindow::init() } } // load list of services - populateList(); + populateList(ui->khistorycombobox->currentIndex()); } void MainWindow::initSystemTrayIcon() @@ -208,7 +207,7 @@ void MainWindow::quitApp() reply = QMessageBox::question( this, - "RsyncUI", + a.applicationName(), tr("Exiting will stop downloading, and will clear the download queue.\nDo you want to exit ?") + displayText, param, QMessageBox::No); @@ -246,7 +245,7 @@ void MainWindow::closeEvent (QCloseEvent *event) return; if (trayIcon->isVisible() and this->settings.value("CloseCheckbox").toBool() == false) { - msgBox.setWindowTitle("RsyncUI"); + msgBox.setWindowTitle(a.applicationName()); msgBox.setInformativeText(tr("The program will keep running in the " "system tray. To terminate the program, " "choose Quit in the context menu " @@ -297,7 +296,7 @@ void MainWindow::populateTree() } // Populate Listview with list of services -void MainWindow::populateList() +void MainWindow::populateList(int item) { QString server; QString service; @@ -305,7 +304,7 @@ void MainWindow::populateList() int port; int i; - server = ui->khistorycombobox->currentText(); + server = ui->khistorycombobox->itemText(item); port = ui->portEdit->text().toUInt(); if ((server != this->connexion.server) or (port != this->connexion.port)) { @@ -560,7 +559,8 @@ bool MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt addTreeItem(filename, size, fullsize, fileType, date, isDir, parent); if (passwdOk == false and !this->connexion.password.isEmpty()) { - this->settings.setValue("Passwords/" + this->connexion.server + "/" + this->connexion.service + "/" + this->connexion.user, this->connexion.password); + this->settings.setValue("Passwords/" + this->connexion.server + "/" + this->connexion.service + "/", this->connexion.user); + setPassword(this->connexion.user, this->connexion.password); this->settings.sync(); } } @@ -574,7 +574,7 @@ bool MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt { QMessageBox::warning( this, - "RsyncUI", + a.applicationName(), tr("The processus does'nt respond: ") + myProcess->errorString()); } } @@ -660,7 +660,7 @@ bool MainWindow::validateServer(QString server) // server-s address not valid QMessageBox::warning( this, - "RsyncUI", + a.applicationName(), tr("server does not exists" ) ); } @@ -669,16 +669,16 @@ bool MainWindow::validateServer(QString server) } // slot activated when combobox is changed -void MainWindow::on_khistorycombobox_currentIndexChanged(int i) +void MainWindow::on_khistorycombobox_currentIndexChanged(int item) { this->connexion.comboboxChanged = true; - populateList(); + populateList(item); } // slot activated when button connection is clicked void MainWindow::on_connectButton_clicked() { - populateList(); + populateList(ui->khistorycombobox->currentIndex()); } // add parent in treeview @@ -785,7 +785,7 @@ bool MainWindow::getUserPassword(Connexion * object) if (!logins.contains(login)) { password = QInputDialog::getText(this, - tr("RsyncUI Request"), + a.applicationName() + tr(" Request"), tr("Enter password"), QLineEdit::Password, "", &ok, Qt::Popup, Qt::ImhNoPredictiveText); @@ -795,7 +795,7 @@ bool MainWindow::getUserPassword(Connexion * object) } }else { - password = this->settings.value(login).toString(); + password = getPassword(login); } object->user = login; object->password = password; @@ -803,7 +803,7 @@ bool MainWindow::getUserPassword(Connexion * object) }else { object->user = logins.at(0); - object->password = this->settings.value(object->user).toString(); + object->password = getPassword(object->user); returnValue = true; } this->settings.endGroup(); @@ -862,7 +862,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD { reply = QMessageBox::question( this, - "RsyncUI", + a.applicationName(), tr("File is partially downloaded. Do you want to resume download ? if no, the file will be deleted from destination directory"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Cancel); @@ -879,7 +879,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD { reply = QMessageBox::question( this, - "RsyncUI", + a.applicationName(), tr("File is already downloaded. Do you want to reload it ? The old file will be deleted"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); @@ -916,7 +916,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD { QMessageBox::warning( this, - "RsyncUI", + a.applicationName(), tr("File is already downloading" ) ); } @@ -942,7 +942,7 @@ void MainWindow::startDownloading() //QtConcurrent::run(&this->downloadO, &downloadFile::download, this); this->download(); - this->trayIcon->showMessage("RsyncUI", tr("Starting downloading\n") + this->downloading.path, QSystemTrayIcon::Information); + this->trayIcon->showMessage(a.applicationName(), tr("Starting downloading\n") + this->downloading.path, QSystemTrayIcon::Information); } // Slot stopping download @@ -966,7 +966,7 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) { QMessageBox::warning( NULL, - "RsyncUI", + a.applicationName(), tr("Rsync process crashed")); } //test result code of command (if 20 then command stopped by user) @@ -984,7 +984,7 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) // displaying warning with exit code reply = QMessageBox::warning( this, - "RsyncUI", + a.applicationName(), rsyncErrorStrings[exitCode] + tr("\nDo you want to retry?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); @@ -994,7 +994,7 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) } } - this->trayIcon->showMessage("RsyncUI", tr("Download ") + aborted + "\n" + this->downloading.path, QSystemTrayIcon::Information); + this->trayIcon->showMessage(a.applicationName(), tr("Download ") + aborted + "\n" + this->downloading.path, QSystemTrayIcon::Information); // disconnecting signals to slots disconnect(this->downloading.process, 0, 0, 0); @@ -1031,14 +1031,14 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) { // setting savepath from saved settings this->downloading.savePath = this->settings.value(str).toString(); + sleep(2); startDownloading(); }else { // no save path if(!on_DefaultSaveFolder_triggered()) { - cout << "Error no save path so deleting download"; - //downloadFinished(); + cout << "Error no save path so removing download"; return; } } @@ -1060,7 +1060,7 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) // first line clicked on download list reply = QMessageBox::question( this, - "RsyncUI", + a.applicationName(), tr("Do you want to stop downloading and delete this file from download queue ?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); @@ -1074,7 +1074,7 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) // not first line on download list reply = QMessageBox::question( this, - "RsyncUI", + a.applicationName(), tr("Do you want to delete this file from download queue ?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); @@ -1164,7 +1164,7 @@ bool MainWindow::on_DefaultSaveFolder_triggered() { QMessageBox::warning( NULL, - "RsyncUI", + a.applicationName(), tr("Since the save path is linked to service, you need to select a service before you can select a folder")); return false; } @@ -1302,7 +1302,7 @@ void MainWindow::on_actionDownload_triggered() { QMessageBox::warning( this, - "RsyncUI", + a.applicationName(), errorString, QMessageBox::Ok, QMessageBox::Ok); @@ -1320,34 +1320,6 @@ void MainWindow::on_actionExit_triggered() quitApp(); } -void MainWindow::on_loginBox_accepted() -{ - /*Connexion * conn = this->passwordConnexion; - - if (!loginD.loginEdit->currentText().isEmpty()) - { - QString path; - conn->user = loginD.loginEdit->currentText(); - path = "Passwords/" + conn->server + "/" + conn->service + "/" + conn->user; - - if (!loginD.passwordEdit->text().isEmpty()) - { - conn->password = loginD.passwordEdit->text(); - this->settings.setValue("Passwords/" + conn->server + "/" + conn->service + "/" + conn->user, conn->password); - this->settings.sync(); - if (this->rescan == true) - { - this->rescan = false; - populateTree(); - } - }else if (this->settings.contains(path)) - { - conn->password = this->settings.value(path).toString(); - } - } - emit passwordReady();*/ -} - void MainWindow::setDlSpeed(QString speed) { speed.squeeze(); @@ -1358,7 +1330,7 @@ void MainWindow::on_actionHiddenService_triggered() QInputDialog hiddenFolderDialog; bool ok; - QString text = QInputDialog::getText(this, tr("RsyncUI Request"), + QString text = QInputDialog::getText(this, a.applicationName() + tr(" Request"), tr("Hidden service name"), QLineEdit::Normal, "test", &ok); if (ok && !text.isEmpty()) diff --git a/mainwindow.h b/mainwindow.h index 5120221..e30a95d 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -7,6 +7,7 @@ #include "ui_about.h" #include "downloadfile.h" #include "tools.h" +#include "password.h" #include #include #include @@ -89,7 +90,6 @@ class Downloading class About { public: - QString title = "RsyncUI"; QString version = "2.9.2"; QString author = "Daniel TARTAVEL-JEANNOT"; QString licence = "GPL_V3"; @@ -106,6 +106,7 @@ class MainWindow : public QMainWindow Ui::MainWindow *ui; MainWindow(QWidget *parent = nullptr); ~MainWindow(); + // passwdManager; QProgressDialog *progress; Connexion connexion; Connexion downloading; @@ -119,7 +120,6 @@ class MainWindow : public QMainWindow QSystemTrayIcon * trayIcon; QString icon = "/usr/share/icons/RsyncUI.png"; bool rescan = false; - bool passwordReturned; QList UnitText { tr("B"), @@ -149,7 +149,7 @@ class MainWindow : public QMainWindow void displayTree(); void populateTree(); - void populateList(); + void populateList(int); void listServices(); bool validateServer(QString server); bool isIpAddress(QString server); @@ -169,6 +169,8 @@ class MainWindow : public QMainWindow bool getUserPassword(Connexion *); void preparePopulateTree(); bool testServicePresence(QString, bool=false); + void passwordStore (QString account, QString password); + QString passwordGet (QString account); private slots: @@ -214,11 +216,9 @@ class MainWindow : public QMainWindow void setDlSpeed(QString speed); - void on_loginBox_accepted(); - void on_actionHiddenService_triggered(); - signals: +signals: void stopDownloading(QProcess *); void progressSignal(int); void speed(QString); diff --git a/password.cpp b/password.cpp index fd2b295..61564c5 100644 --- a/password.cpp +++ b/password.cpp @@ -2,58 +2,54 @@ #include "password.h" #include #include +#include using namespace std; +extern QApplication a; -/*Password::Password() +QString appName = "RsyncUI"; + +static QSettings sett{appName, appName}; + +void setPassword(QString account, QString pass) { - this->passwdJob->setObjectName(this->appName); - this->passwdJob->setAutoDelete(false); - this->passwdJob->connect(this->passwdJob, SIGNAL(finished(QKeychain::Job*)), this, SLOT(finished(QKeychain::Job*))); - //this->readPass->connect(this->readPass, SIGNAL(finished())) + QKeychain::WritePasswordJob write(appName); + write.setSettings(&sett); + // write.setAutoDelete(false); + write.setKey(account); + write.setTextData(pass); + + QEventLoop loop; + write.connect(&write, &QKeychain::WritePasswordJob::finished, &loop, &QEventLoop::quit); + + write.start(); + loop.exec(); + + if(write.error()) + cout << "Error writing key1. Error: " << write.errorString().toStdString(); } -void Password::store (QString account, QString password) +QString getPassword(const QString& name) { - this->passwdJob->setKey(account); - this->passwdJob->setTextData(password); - this->passwdJob->start(); -} + QKeychain::ReadPasswordJob readPass(appName); + readPass.setSettings(&sett); + // readPass.setAutoDelete(false); + readPass.setKey(name); -QString Password::read(QString account) -{ - this->readPass->setObjectName(""); - this->readPass->setKey(account); - this->readPass->start(); -} + QEventLoop loop; + readPass.connect(&readPass, &QKeychain::ReadPasswordJob::finished, &loop, &QEventLoop::quit); -bool Password::remove(QString) -{ + readPass.start(); + loop.exec(); - -} - -void Password::finished(QKeychain::Job * passwdJob) -{ - if(passwdJob->error()) { - QMessageBox::warning( - NULL, - "RsyncUI", - QString(this->mw->tr("Error: Unable to save password!")) + QString(passwdJob->error())); + if(readPass.error()) + { + qDebug()<<"KeyHandler~Error reading decrypt Pass. Error: " + readPass.errorString(); + return ""; + } + else + { + QString data = readPass.textData(); + return data; } } - -void Password::readReturn() -{ - if(this->readPass->error()) - { - QMessageBox::warning( - NULL, - "RsyncUI", - QString(this->mw->tr("Error: Unable to read password!")) + QString(readPass->error())); - }else - { - this->password = readPass->textData(); - } -} -*/ diff --git a/password.h b/password.h index da3e688..f73bb98 100644 --- a/password.h +++ b/password.h @@ -5,7 +5,12 @@ #include #include -class Password : QObject +extern QApplication a; + +void setPassword(QString account, QString pass); +QString getPassword(const QString& name); + +/*class Password : QObject { public: QString appName; @@ -13,6 +18,7 @@ class Password : QObject QKeychain::ReadPasswordJob * readPass; MainWindow * mw; QString password; + QSettings passwdSettings{a.applicationName(),a.applicationName()}; Password(); ~Password(); @@ -22,8 +28,8 @@ class Password : QObject bool remove(QString); private slots: - void finished(QKeychain::Job*); - void readReturn(); -}; + void storeFinished(); + void readFinished(); +};*/ #endif // PASSWORD_H diff --git a/tools.cpp b/tools.cpp index 648e00d..498b10a 100644 --- a/tools.cpp +++ b/tools.cpp @@ -6,6 +6,7 @@ using namespace std; #define WRITE 1 extern QMap rsyncErrorStrings; +extern QApplication a; //Take a string and explode it in array // s => string to explode @@ -51,7 +52,7 @@ bool testRsyncReturn(MainWindow * w, QProcess * myProcess) { QMessageBox::warning( w, - "RsyncUI", + a.applicationName(), myProcess->errorString(), QMessageBox::Ok, QMessageBox::Ok);