diff options
author | tezeb <tezeb+github@outoftheblue.pl> | 2016-12-04 22:43:17 +0100 |
---|---|---|
committer | tezeb <tezeb+github@outoftheblue.pl> | 2016-12-04 22:43:17 +0100 |
commit | b11e71d331310c27fde3e53a098ba108bc8f0f61 (patch) | |
tree | 41b32b214ec97a11b131aab221bf687c59125e64 | |
parent | aa0eb00e50d732a7fc00fd56b2c10d41a2053a7c (diff) |
Use new executor in Pass
-rw-r--r-- | imitatepass.cpp | 168 | ||||
-rw-r--r-- | imitatepass.h | 13 | ||||
-rw-r--r-- | mainwindow.cpp | 246 | ||||
-rw-r--r-- | mainwindow.h | 12 | ||||
-rw-r--r-- | pass.cpp | 176 | ||||
-rw-r--r-- | pass.h | 55 | ||||
-rw-r--r-- | qtpass.pro | 8 | ||||
-rw-r--r-- | realpass.cpp | 90 | ||||
-rw-r--r-- | realpass.h | 9 |
9 files changed, 393 insertions, 384 deletions
diff --git a/imitatepass.cpp b/imitatepass.cpp index ace52ff7..65f1aceb 100644 --- a/imitatepass.cpp +++ b/imitatepass.cpp @@ -1,47 +1,80 @@ #include "imitatepass.h" +#include "debughelper.h" #include "mainwindow.h" #include "qtpasssettings.h" ImitatePass::ImitatePass() {} +void ImitatePass::executeWrapper(int id, const QString &app, + const QStringList &args, bool readStdout, + bool readStderr) { + executeWrapper(id, app, args, QString(), readStdout, readStderr); +} + +void ImitatePass::executeWrapper(int id, const QString &app, + const QStringList &args, QString input, + bool readStdout, bool readStderr) { + QString d; + for (auto &i : args) + d += " " + i; + dbg() << app << d; + exec.execute(id, QtPassSettings::getPassStore(), app, args, input, readStdout, + readStderr); +} + /** * @brief ImitatePass::GitInit git init wrapper */ void ImitatePass::GitInit() { - executeWrapper(QtPassSettings::getGitExecutable(), - "init \"" + QtPassSettings::getPassStore() + '"'); + executeWrapper(GIT_INIT, QtPassSettings::getGitExecutable(), + {"init", QtPassSettings::getPassStore()}); } /** * @brief ImitatePass::GitPull git init wrapper */ void ImitatePass::GitPull() { - executeWrapper(QtPassSettings::getGitExecutable(), "pull"); + executeWrapper(GIT_PULL, QtPassSettings::getGitExecutable(), {"pull"}); +} + +/** + * @brief ImitatePass::GitPull_b git pull wrapper + */ +void ImitatePass::GitPull_b() { + exec.executeBlocking(QtPassSettings::getGitExecutable(), {"pull"}); } /** * @brief ImitatePass::GitPush git init wrapper */ void ImitatePass::GitPush() { - executeWrapper(QtPassSettings::getGitExecutable(), "push"); + executeWrapper(GIT_PUSH, QtPassSettings::getGitExecutable(), {"push"}); } /** - * @brief ImitatePass::Show git init wrapper + * @brief ImitatePass::Show shows content of file */ -QProcess::ExitStatus ImitatePass::Show(QString file, bool block) { +void ImitatePass::Show(QString file) { // TODO(bezet): apparently not yet needed // file += ".gpg"; - executeWrapper(QtPassSettings::getGpgExecutable(), - "-d --quiet --yes --no-encrypt-to --batch --use-agent \"" + - file + '"'); - if (block) - return waitForProcess(); - return QProcess::NormalExit; + QStringList args = {"-d", "--quiet", "--yes", "--no-encrypt-to", + "--batch", "--use-agent", file}; + executeWrapper(PASS_SHOW, QtPassSettings::getGpgExecutable(), args); } /** - * @brief ImitatePass::Insert git init wrapper + * @brief ImitatePass::Show_b show content of file, blocking version + * + * @returns process exitCode + */ +int ImitatePass::Show_b(QString file) { + QStringList args = {"-d", "--quiet", "--yes", "--no-encrypt-to", + "--batch", "--use-agent", file}; + return exec.executeBlocking(QtPassSettings::getGpgExecutable(), args); +} + +/** + * @brief ImitatePass::Insert create new file with encrypted content * * @param file file to be created * @param value value to be stored in file @@ -50,7 +83,7 @@ QProcess::ExitStatus ImitatePass::Show(QString file, bool block) { void ImitatePass::Insert(QString file, QString newValue, bool overwrite) { file += ".gpg"; // TODO(bezet): getRecipientString is in MainWindow for now - fix this ;) - QString recipients = Pass::getRecipientString(file, " -r "); + QStringList recipients = Pass::getRecipientList(file); if (recipients.isEmpty()) { // TODO(bezet): probably throw here emit critical(tr("Can not edit"), @@ -58,36 +91,43 @@ void ImitatePass::Insert(QString file, QString newValue, bool overwrite) { "file missing or invalid.")); return; } - QString force(overwrite ? " --yes " : " "); - executeWrapper(QtPassSettings::getGpgExecutable(), - force + "--batch -eq --output \"" + file + "\" " + recipients + - " -", + QStringList args = {"--batch", "-eq", "--output", file}; + for (auto &r : recipients) { + args.append("-r"); + args.append(r); + }; + if (overwrite) + args.append("--yes"); + args.append("-"); + executeWrapper(PASS_INSERT, QtPassSettings::getGpgExecutable(), args, newValue); if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) { if (!overwrite) - executeWrapper(QtPassSettings::getGitExecutable(), "add \"" + file + '"'); + executeWrapper(GIT_ADD, QtPassSettings::getGitExecutable(), + {"add", file}); QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(file); path.replace(QRegExp("\\.gpg$"), ""); - executeWrapper(QtPassSettings::getGitExecutable(), - "commit \"" + file + "\" -m \"" + - (overwrite ? "Edit" : "Add") + " for " + path + - " using QtPass.\""); + QString msg = QString(overwrite ? "Edit" : "\"Add") + " for " + path + + " using QtPass."; + GitCommit(file, msg); } } +void ImitatePass::GitCommit(const QString &file, const QString &msg) { + executeWrapper(GIT_COMMIT, QtPassSettings::getGitExecutable(), + {"commit", "-m", msg, "--", file}); +} + /** * @brief ImitatePass::Remove git init wrapper */ void ImitatePass::Remove(QString file, bool isDir) { if (QtPassSettings::isUseGit()) { - executeWrapper(QtPassSettings::getGitExecutable(), - QString("rm ") + (isDir ? "-rf " : "-f ") + '"' + file + - '"'); + executeWrapper(GIT_RM, QtPassSettings::getGitExecutable(), + {"rm", (isDir ? "-rf" : "-f"), file}); // TODO(bezet): commit message used to have pass-like file name inside(ie. // getFile(file, true) - executeWrapper(QtPassSettings::getGitExecutable(), - "commit \"" + file + "\" -m \"Remove for " + file + - " using QtPass.\""); + GitCommit(file, "Remove for " + file + " using QtPass."); } else { if (isDir) { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) @@ -105,7 +145,8 @@ void ImitatePass::Remove(QString file, bool isDir) { * @brief ImitatePass::Init initialize pass repository * * @param path path in which new password-store will be created - * @param users list of users who shall be able to decrypt passwords in path + * @param users list of users who shall be able to decrypt passwords in + * path */ void ImitatePass::Init(QString path, const QList<UserInfo> &users) { QString gpgIdFile = path + ".gpg-id"; @@ -140,13 +181,11 @@ void ImitatePass::Init(QString path, const QList<UserInfo> &users) { if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit() && !QtPassSettings::getGitExecutable().isEmpty()) { if (addFile) - executeWrapper(QtPassSettings::getGitExecutable(), - "add \"" + gpgIdFile + '"'); + executeWrapper(GIT_ADD, QtPassSettings::getGitExecutable(), + {"add", gpgIdFile}); QString path = gpgIdFile; path.replace(QRegExp("\\.gpg$"), ""); - executeWrapper(QtPassSettings::getGitExecutable(), - "commit \"" + gpgIdFile + "\" -m \"Added " + path + - " using QtPass.\""); + GitCommit(gpgIdFile, "Added " + path + " using QtPass."); } reencryptPath(path); } @@ -191,10 +230,8 @@ void ImitatePass::reencryptPath(QString dir) { if (QtPassSettings::isAutoPull()) { // TODO(bezet): move statuses inside actions? emit statusMsg(tr("Updating password-store"), 2000); - GitPull(); + GitPull_b(); } - waitFor(50); - process.waitForFinished(); QDir currentDir; QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files, QDirIterator::Subdirectories); @@ -205,16 +242,14 @@ void ImitatePass::reencryptPath(QString dir) { gpgId = getRecipientList(fileName); gpgId.sort(); } - process.waitForFinished(); - executeWrapper(QtPassSettings::getGpgExecutable(), - "-v --no-secmem-warning " - "--no-permission-warning --list-only " - "--keyid-format long " + - fileName); - process.waitForFinished(3000); + // TODO(bezet): enable --with-colons for better future-proofness? + QStringList args = { + "-v", "--no-secmem-warning", "--no-permission-warning", + "--list-only", "--keyid-format=long", fileName}; + QString keys, err; + exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, &keys, &err); QStringList actualKeys; - QString keys = - process.readAllStandardOutput() + process.readAllStandardError(); + keys += err; QStringList key = keys.split("\n"); QListIterator<QString> itr(key); while (itr.hasNext()) { @@ -230,14 +265,13 @@ void ImitatePass::reencryptPath(QString dir) { actualKeys.sort(); if (actualKeys != gpgId) { // dbg()<< actualKeys << gpgId << getRecipientList(fileName); - dbg()<< "reencrypt " << fileName << " for " << gpgId; + dbg() << "reencrypt " << fileName << " for " << gpgId; QString local_lastDecrypt = "Could not decrypt"; emit lastDecrypt(local_lastDecrypt); - executeWrapper(QtPassSettings::getGpgExecutable(), - "-d --quiet --yes --no-encrypt-to --batch --use-agent \"" + - fileName + '"'); - process.waitForFinished(30000); // long wait (passphrase stuff) - local_lastDecrypt = process.readAllStandardOutput(); + args = QStringList{"-d", "--quiet", "--yes", "--no-encrypt-to", + "--batch", "--use-agent", fileName}; + exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, + &local_lastDecrypt); emit lastDecrypt(local_lastDecrypt); if (!local_lastDecrypt.isEmpty() && @@ -246,33 +280,35 @@ void ImitatePass::reencryptPath(QString dir) { local_lastDecrypt += "\n"; emit lastDecrypt(local_lastDecrypt); - QString recipients = getRecipientString(fileName, " -r "); + QStringList recipients = Pass::getRecipientList(fileName); if (recipients.isEmpty()) { emit critical(tr("Can not edit"), tr("Could not read encryption key to use, .gpg-id " "file missing or invalid.")); return; } - executeWrapper(QtPassSettings::getGpgExecutable(), - "--yes --batch -eq --output \"" + fileName + "\" " + - recipients + " -", - local_lastDecrypt); - process.waitForFinished(3000); + args = QStringList{"--yes", "--batch", "-eq", "--output", fileName}; + for (auto &i : recipients) { + args.append("-r"); + args.append(i); + } + args.append("-"); + exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, + local_lastDecrypt); if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) { - executeWrapper(QtPassSettings::getGitExecutable(), - "add \"" + fileName + '"'); + exec.executeBlocking(QtPassSettings::getGitExecutable(), + {"add", fileName}); QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(fileName); path.replace(QRegExp("\\.gpg$"), ""); - executeWrapper(QtPassSettings::getGitExecutable(), - "commit \"" + fileName + "\" -m \"" + "Edit for " + - path + " using QtPass.\""); - process.waitForFinished(3000); + exec.executeBlocking(QtPassSettings::getGitExecutable(), + {"commit", fileName, "-m", + "Edit for " + path + " using QtPass."}); } } else { - dbg()<< "Decrypt error on re-encrypt"; + dbg() << "Decrypt error on re-encrypt"; } } } diff --git a/imitatepass.h b/imitatepass.h index cc56cb62..8d2fd253 100644 --- a/imitatepass.h +++ b/imitatepass.h @@ -8,13 +8,24 @@ class ImitatePass : public Pass { bool removeDir(const QString &dirName); + void executeWrapper(int id, const QString &app, const QStringList &args, + bool readStdout = true, bool readStderr = true); + + void executeWrapper(int id, const QString &app, const QStringList &args, + QString input, bool readStdout = true, + bool readStderr = true); + + void GitCommit(const QString &file, const QString &msg); + public: ImitatePass(); virtual ~ImitatePass() {} virtual void GitInit() override; virtual void GitPull() override; + virtual void GitPull_b() override; virtual void GitPush() override; - virtual QProcess::ExitStatus Show(QString file, bool block = false) override; + virtual void Show(QString file) override; + virtual int Show_b(QString file) override; virtual void Insert(QString file, QString value, bool overwrite = false) override; virtual void Remove(QString file, bool isDir = false) override; diff --git a/mainwindow.cpp b/mainwindow.cpp index 92deb47c..c63a27f1 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -35,14 +35,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), fusedav(this), keygen(NULL), tray(NULL), pass(nullptr) { - // connect(process.data(), SIGNAL(readyReadStandardOutput()), this, - // SLOT(readyRead())); - // TODO(bezet): this should be reconnected dynamically when pass changes connect(&rpass, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - connect(&rpass, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(processFinished(int, QProcess::ExitStatus))); + connect(&rpass, SIGNAL(finished(int, const QString &, const QString &)), this, + SLOT(processFinished(int, const QString &, const QString &))); connect(&rpass, SIGNAL(startingExecuteWrapper()), this, SLOT(executeWrapperStarted())); connect(&rpass, SIGNAL(statusMsg(QString, int)), this, @@ -52,8 +49,8 @@ MainWindow::MainWindow(QWidget *parent) connect(&ipass, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - connect(&ipass, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(processFinished(int, QProcess::ExitStatus))); + connect(&ipass, SIGNAL(finished(int, const QString &, const QString &)), this, + SLOT(processFinished(int, const QString &, const QString &))); connect(&ipass, SIGNAL(startingExecuteWrapper()), this, SLOT(executeWrapperStarted())); connect(&ipass, SIGNAL(statusMsg(QString, int)), this, @@ -69,7 +66,6 @@ MainWindow::MainWindow(QWidget *parent) ui->setupUi(this); enableUiElements(true); - execQueue = new QQueue<execQueueItem>; ui->statusBar->showMessage(tr("Welcome to QtPass %1").arg(VERSION), 2000); freshStart = true; startupPhase = true; @@ -525,11 +521,12 @@ void MainWindow::config() { /** * @brief MainWindow::on_updateButton_clicked do a git pull */ -// TODO(bezet): add bool block and wait for process to finish -void MainWindow::on_updateButton_clicked() { +void MainWindow::on_updateButton_clicked(bool block) { ui->statusBar->showMessage(tr("Updating password-store"), 2000); - currentAction = GIT; - pass->GitPull(); + if (block) + pass->GitPull_b(); + else + pass->GitPull(); } /** @@ -659,114 +656,139 @@ void MainWindow::executeWrapperStarted() { /** * @brief MainWindow::readyRead we have data */ -void MainWindow::readyRead(bool finished = false) { - if (currentAction == PWGEN) +void MainWindow::readyRead(const QString &p_output, const QString &p_errout) { + QString output = p_output; + QString error = p_errout; + if (currentAction == PWGEN) { return; - QString output = ""; - QString error = ""; - if (currentAction != GPG_INTERNAL) { - error = pass->readAllStandardError(); - QByteArray processOutBytes = pass->readAllStandardOutput(); - QTextCodec *codec = QTextCodec::codecForLocale(); - output = codec->toUnicode(processOutBytes); - if (finished && currentAction == GPG) { - lastDecrypt = output; - QStringList tokens = output.split("\n"); - QString password = tokens.at(0); - - if (QtPassSettings::getClipBoardType() != Enums::CLIPBOARD_NEVER && - !output.isEmpty()) { - clippedText = tokens[0]; - if (QtPassSettings::getClipBoardType() == Enums::CLIPBOARD_ALWAYS) - copyTextToClipboard(tokens[0]); - if (QtPassSettings::isUseAutoclearPanel()) { - clearPanelTimer.start(); - } - if (QtPassSettings::isHidePassword() && - !QtPassSettings::isUseTemplate()) { - tokens[0] = "***" + tr("Password hidden") + "***"; - output = tokens.join("\n"); - } - if (QtPassSettings::isHideContent()) - output = "***" + tr("Content hidden") + "***"; - } - - if (QtPassSettings::isUseTemplate() && !QtPassSettings::isHideContent()) { - while (ui->gridLayout->count() > 0) { - QLayoutItem *item = ui->gridLayout->takeAt(0); - delete item->widget(); - delete item; - } - QStringList remainingTokens; - for (int j = 1; j < tokens.length(); ++j) { - QString token = tokens.at(j); - if (token.contains(':')) { - int colon = token.indexOf(':'); - QString field = token.left(colon); - if (QtPassSettings::isTemplateAllFields() || - QtPassSettings::getPassTemplate().contains(field)) { - QString value = token.right(token.length() - colon - 1); - if (!QtPassSettings::getPassTemplate().contains(field) && - value.startsWith("//")) { - remainingTokens.append(token); - continue; // colon is probably from a url - } - addToGridLayout(j, field, value); - } - } else { - remainingTokens.append(token); - } - } - if (ui->gridLayout->count() == 0) - ui->verticalLayoutPassword->setSpacing(0); - else - ui->verticalLayoutPassword->setSpacing(6); - output = remainingTokens.join("\n"); - } else { - clearTemplateWidgets(); - } - if (!QtPassSettings::isHideContent() && !password.isEmpty()) { - // now set the password. If we set it earlier, the layout will be - // cleared - addToGridLayout(0, tr("Password"), password); - } - if (QtPassSettings::isUseAutoclearPanel()) { - clearPanelTimer.start(); - } - } - output.replace(QRegExp("<"), "<"); - output.replace(QRegExp(">"), ">"); - output.replace(QRegExp(" "), " "); - } else { + } else if (currentAction == GPG) { + passShowHandler(p_output); + } else if (currentAction == GPG_INTERNAL) { // qDebug() << process->readAllStandardOutput(); // qDebug() << process->readAllStandardError(); - if (finished && 0 != keygen) { + if (0 != keygen) { qDebug() << "Keygen Done"; keygen->close(); keygen = 0; // TODO(annejan) some sanity checking ? } + } else { + DisplayInTextBrowser(p_output); } - if (!error.isEmpty()) { - if (currentAction == GIT) { - // https://github.com/IJHack/qtpass/issues/111 - output = "<span style=\"color: darkgray;\">" + error + "</span><br />" + - output; + processErrorExit(p_errout); +} + +void MainWindow::passShowHandler(const QString &p_output) { + QString output = p_output; + lastDecrypt = p_output; + { + QStringList tokens = p_output.split("\n"); + QString password = tokens.at(0); + + if (QtPassSettings::getClipBoardType() != Enums::CLIPBOARD_NEVER && + !p_output.isEmpty()) { + clippedText = tokens[0]; + if (QtPassSettings::getClipBoardType() == Enums::CLIPBOARD_ALWAYS) + copyTextToClipboard(tokens[0]); + if (QtPassSettings::isUseAutoclearPanel()) { + clearPanelTimer.start(); + } + if (QtPassSettings::isHidePassword() && + !QtPassSettings::isUseTemplate()) { + tokens[0] = "***" + tr("Password hidden") + "***"; + output = tokens.join("\n"); + } + if (QtPassSettings::isHideContent()) + output = "***" + tr("Content hidden") + "***"; + } + + if (QtPassSettings::isUseTemplate() && !QtPassSettings::isHideContent()) { + while (ui->gridLayout->count() > 0) { + QLayoutItem *item = ui->gridLayout->takeAt(0); + delete item->widget(); + delete item; + } + QStringList remainingTokens; + for (int j = 1; j < tokens.length(); ++j) { + QString token = tokens.at(j); + if (token.contains(':')) { + int colon = token.indexOf(':'); + QString field = token.left(colon); + if (QtPassSettings::isTemplateAllFields() || + QtPassSettings::getPassTemplate().contains(field)) { + QString value = token.right(token.length() - colon - 1); + if (!QtPassSettings::getPassTemplate().contains(field) && + value.startsWith("//")) { + remainingTokens.append(token); + continue; // colon is probably from a url + } + addToGridLayout(j, field, value); + } + } else { + remainingTokens.append(token); + } + } + if (ui->gridLayout->count() == 0) + ui->verticalLayoutPassword->setSpacing(0); + else + ui->verticalLayoutPassword->setSpacing(6); + output = remainingTokens.join("\n"); } else { - output = - "<span style=\"color: red;\">" + error + "</span><br />" + output; + clearTemplateWidgets(); + } + if (!QtPassSettings::isHideContent() && !password.isEmpty()) { + // now set the password. If we set it earlier, the layout will be + // cleared + addToGridLayout(0, tr("Password"), password); + } + if (QtPassSettings::isUseAutoclearPanel()) { + clearPanelTimer.start(); } } + DisplayInTextBrowser(output); +} + +void MainWindow::DisplayInTextBrowser(QString output, QString prefix, + QString postfix) { + + output.replace(QRegExp("<"), "<"); + output.replace(QRegExp(">"), ">"); + output.replace(QRegExp(" "), " "); + output.replace(QRegExp("((?:https?|ftp|ssh)://\\S+)"), "<a href=\"\\1\">\\1</a>"); output.replace(QRegExp("\n"), "<br />"); + output = prefix + output + postfix; if (!ui->textBrowser->toPlainText().isEmpty()) output = ui->textBrowser->toHtml() + output; ui->textBrowser->setHtml(output); } +void MainWindow::processErrorExit(const QString &p_error) { + if (!p_error.isEmpty()) { + QString output; + QString error = p_error; + error.replace(QRegExp("<"), "<"); + error.replace(QRegExp(">"), ">"); + error.replace(QRegExp(" "), " "); + if (currentAction == GIT) { + // https://github.com/IJHack/qtpass/issues/111 + output = "<span style=\"color: darkgray;\">" + error + "</span><br />"; + } else { + output = "<span style=\"color: red;\">" + error + "</span><br />"; + } + + output.replace(QRegExp("((?:https?|ftp|ssh)://\\S+)"), + "<a href=\"\\1\">\\1</a>"); + output.replace(QRegExp("\n"), "<br />"); + if (!ui->textBrowser->toPlainText().isEmpty()) + output = ui->textBrowser->toHtml() + output; + ui->textBrowser->setHtml(output); + } +} + /** * @brief MainWindow::clearClipboard remove clipboard contents. */ @@ -799,23 +821,23 @@ void MainWindow::clearPanel(bool notify = true) { } /** - * @brief MainWindow::clearPanel because slots needs the same amout of params as - * signals + * @brief MainWindow::clearPanel because slots needs the same amout of params + * as signals */ void MainWindow::clearPanel() { clearPanel(true); } /** - * @brief MainWindow::processFinished process is finished, if there is another - * one queued up to run, start it. + * @brief MainWindow::processFinished background process has finished * @param exitCode * @param exitStatus + * @param output stdout from a process + * @param errout stderr from a process */ -void MainWindow::processFinished(int exitCode, - QProcess::ExitStatus exitStatus) { - bool error = exitStatus != QProcess::NormalExit || exitCode > 0; - readyRead(true); +void MainWindow::processFinished(int exitCode, const QString &output, + const QString &errout) { + readyRead(output, errout); enableUiElements(true); - if (!error && currentAction == EDIT) + if (exitCode == 0 && currentAction == EDIT) on_treeView_clicked(ui->treeView->currentIndex()); } @@ -869,8 +891,8 @@ void MainWindow::processError(QProcess::ProcessError error) { ui->textBrowser->setText(errorString); // TODO(bezet): this probably shall be done in finished handler(I guess it // finishes even on error) - if (pass->state() == QProcess::NotRunning) - enableUiElements(true); + // if (pass->state() == QProcess::NotRunning) + enableUiElements(true); } /** @@ -1421,9 +1443,7 @@ void MainWindow::addFolder() { */ void MainWindow::editPassword() { if (QtPassSettings::isUseGit() && QtPassSettings::isAutoPull()) - on_updateButton_clicked(); - pass->waitFor(30); - pass->waitForProcess(); + on_updateButton_clicked(true); // TODO(annejan) move to editbutton stuff possibly? currentDir = getDir(ui->treeView->currentIndex(), false); lastDecrypt = "Could not decrypt"; @@ -1431,7 +1451,7 @@ void MainWindow::editPassword() { getFile(ui->treeView->currentIndex(), QtPassSettings::isUsePass()); if (!file.isEmpty()) { currentAction = GPG; - if (pass->Show(file, true) == QProcess::NormalExit) + if (pass->Show_b(file) == 0) on_editButton_clicked(); } } diff --git a/mainwindow.h b/mainwindow.h index 64abe785..f09d4e98 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -65,13 +65,13 @@ public slots: void deselect(); private slots: - void on_updateButton_clicked(); + void on_updateButton_clicked(bool block = false); void on_pushButton_clicked(); void on_treeView_clicked(const QModelIndex &index); void on_treeView_doubleClicked(const QModelIndex &index); void on_configButton_clicked(); - void readyRead(bool finished); - void processFinished(int, QProcess::ExitStatus); + void readyRead(const QString &, const QString &); + void processFinished(int, const QString &, const QString &); void processError(QProcess::ProcessError); void clearClipboard(); void clearPanel(bool notify); @@ -97,6 +97,9 @@ private slots: void endReencryptPath(); void critical(QString, QString); void setLastDecrypt(QString); + void passShowHandler(const QString &); + + void processErrorExit(const QString &); private: QAction *actionAddPassword; @@ -114,7 +117,6 @@ private: QTimer clearClipboardTimer; actionType currentAction; QString lastDecrypt; - QQueue<execQueueItem> *execQueue; bool freshStart; QDialog *keygen; QString currentDir; @@ -141,6 +143,8 @@ private: void reencryptPath(QString dir); void addToGridLayout(int position, const QString &field, const QString &value); + void DisplayInTextBrowser(QString toShow, QString prefix = QString(), + QString postfix = QString()); }; #endif // MAINWINDOW_H_ @@ -4,15 +4,14 @@ #include "util.h" #include <QTextCodec> -Pass::Pass() : wrapperRunning(false) { - connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SIGNAL(finished(int, QProcess::ExitStatus))); - connect(&process, SIGNAL(error(QProcess::ProcessError)), this, - SIGNAL(error(QProcess::ProcessError))); - connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(processFinished(int, QProcess::ExitStatus))); +Pass::Pass() : wrapperRunning(false), env(QProcess::systemEnvironment()) { + connect(&exec, SIGNAL(finished(int, const QString &, const QString &)), this, + SIGNAL(finished(int, const QString &, const QString &))); + // TODO(bezet): stop using process + // connect(&process, SIGNAL(error(QProcess::ProcessError)), this, + // SIGNAL(error(QProcess::ProcessError))); - env = QProcess::systemEnvironment(); + connect(&exec, &Executor::starting, this, &Pass::startingExecuteWrapper); #ifdef __APPLE__ // If it exists, add the gpgtools to PATH @@ -30,11 +29,6 @@ Pass::Pass() : wrapperRunning(false) { } } -QProcess::ExitStatus Pass::waitForProcess() { - process.waitForFinished(30000); - return process.exitStatus(); -} - /** * @brief Pass::Generate use either pwgen or internal password * generator @@ -46,22 +40,29 @@ QProcess::ExitStatus Pass::waitForProcess() { QString Pass::Generate(int length, const QString &charset) { QString passwd; if (QtPassSettings::isUsePwgen()) { - waitFor(2); // --secure goes first as it overrides --no-* otherwise - QString args = - QString("-1 ") + (QtPassSettings::isLessRandom() ? "" : "--secure ") + - (QtPassSettings::isAvoidCapitals() ? "--no-capitalize " - : "--capitalize ") + - (QtPassSettings::isAvoidNumbers() ? "--no-numerals " : "--numerals ") + - (QtPassSettings::isUseSymbols() ? "--symbols " : "") + - QString::number(length); - executeWrapper(QtPassSettings::getPwgenExecutable(), args); - process.waitForFinished(1000); - if (process.exitStatus() == QProcess::NormalExit) - passwd = - QString(process.readAllStandardOutput()).remove(QRegExp("[\\n\\r]")); - else - qDebug() << "pwgen fail"; + QStringList args; + args.append("-1"); + if (QtPassSettings::isLessRandom()) + args.append("--secure "); + args.append(QtPassSettings::isAvoidCapitals() ? "--no-capitalize " + : "--capitalize "); + args.append(QtPassSettings::isAvoidNumbers() ? "--no-numerals " + : "--numerals "); + if (QtPassSettings::isUseSymbols()) + args.append("--symbols "); + args.append(QString::number(length)); + QString p_out; + // TODO(bezet): try-catch here(2 statuses to merge o_O) + if (exec.executeBlocking(QtPassSettings::getPwgenExecutable(), args, + &passwd) == 0) + passwd.remove(QRegExp("[\\n\\r]")); + else { + passwd.clear(); + qDebug() << __FILE__ << ":" << __LINE__ << "\t" + << "pwgen fail"; + // TODO(bezet): emit critical ? + } } else { if (charset.length() > 0) { for (int i = 0; i < length; ++i) { @@ -81,12 +82,12 @@ QString Pass::Generate(int length, const QString &charset) { /** * @brief Pass::GenerateGPGKeys internal gpg keypair generator . . - * @param batch + * @param batch GnuPG style configuration string * @param keygenWindow */ void Pass::GenerateGPGKeys(QString batch) { - executeWrapper(QtPassSettings::getGpgExecutable(), - "--gen-key --no-tty --batch", batch); + exec.execute(PASSWD_GENERATE, QtPassSettings::getGpgExecutable(), + {"--gen-key", "--no-tty", "--batch"}, batch); // TODO check status / error messages // https://github.com/IJHack/QtPass/issues/202#issuecomment-251081688 } @@ -98,19 +99,16 @@ void Pass::GenerateGPGKeys(QString batch) { * @return QList<UserInfo> users */ QList<UserInfo> Pass::listKeys(QString keystring, bool secret) { - waitFor(5); QList<UserInfo> users; - QString listopt = secret ? "--list-secret-keys " : "--list-keys "; - executeWrapper(QtPassSettings::getGpgExecutable(), - "--no-tty --with-colons " + listopt + keystring); - process.waitForFinished(2000); - if (process.exitStatus() != QProcess::NormalExit) + QStringList args = {"--no-tty", "--with-colons"}; + args.append(secret ? "--list-secret-keys" : "--list-keys"); + if (!keystring.isEmpty()) + args.append(keystring); + QString p_out; + if (exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, &p_out) != + 0) return users; - QByteArray processOutBytes = process.readAllStandardOutput(); - QTextCodec *codec = QTextCodec::codecForLocale(); - QString processOutString = codec->toUnicode(processOutBytes); - QStringList keys = QString(processOutString) - .split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + QStringList keys = p_out.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); UserInfo current_user; foreach (QString key, keys) { QStringList props = key.split(':'); @@ -135,97 +133,6 @@ QList<UserInfo> Pass::listKeys(QString keystring, bool secret) { } /** - * @brief Pass::waitFor wait until process.atEnd and execQueue.isEmpty - * or timeout after x-seconds - * - * @param seconds - */ -void Pass::waitFor(uint seconds) { - QDateTime current = QDateTime::currentDateTime(); - uint stop = current.toTime_t() + seconds; - while (!process.atEnd() || !execQueue.isEmpty()) { - current = QDateTime::currentDateTime(); - if (stop < current.toTime_t()) { - emit critical(tr("Timed out"), - tr("Can't start process, previous one is still running!")); - } - Util::qSleep(100); - } -} - -/** - * @brief Pass::processFinished process is finished, if there is another - * one queued up to run, start it. - * @param exitCode - * @param exitStatus - */ -void Pass::processFinished(int, QProcess::ExitStatus) { - wrapperRunning = false; - if (!execQueue.isEmpty()) { - execQueueItem item = execQueue.dequeue(); - executeWrapper(item.app, item.args, item.input); - } -} - -/** - * Temporary wrapper to ease refactoring, don't get used to it ;) - */ |