LCOV - code coverage report
Current view: top level - src - imitatepass.cpp (source / functions) Coverage Total Hit
Test: .lcov.total Lines: 0.3 % 307 1
Test Date: 2026-03-23 21:55:57 Functions: 4.5 % 22 1

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : #include "imitatepass.h"
       4              : #include "qtpasssettings.h"
       5              : #include "util.h"
       6              : #include <QDirIterator>
       7              : #include <QRegularExpression>
       8              : #include <utility>
       9              : 
      10              : #ifdef QT_DEBUG
      11              : #include "debughelper.h"
      12              : #endif
      13              : 
      14              : using Enums::CLIPBOARD_ALWAYS;
      15              : using Enums::CLIPBOARD_NEVER;
      16              : using Enums::CLIPBOARD_ON_DEMAND;
      17              : using Enums::GIT_ADD;
      18              : using Enums::GIT_COMMIT;
      19              : using Enums::GIT_COPY;
      20              : using Enums::GIT_INIT;
      21              : using Enums::GIT_MOVE;
      22              : using Enums::GIT_PULL;
      23              : using Enums::GIT_PUSH;
      24              : using Enums::GIT_RM;
      25              : using Enums::GPG_GENKEYS;
      26              : using Enums::INVALID;
      27              : using Enums::PASS_COPY;
      28              : using Enums::PASS_INIT;
      29              : using Enums::PASS_INSERT;
      30              : using Enums::PASS_MOVE;
      31              : using Enums::PASS_OTP_GENERATE;
      32              : using Enums::PASS_REMOVE;
      33              : using Enums::PASS_SHOW;
      34              : using Enums::PROCESS_COUNT;
      35              : 
      36              : /**
      37              :  * @brief ImitatePass::ImitatePass for situaions when pass is not available
      38              :  * we imitate the behavior of pass https://www.passwordstore.org/
      39              :  */
      40           46 : ImitatePass::ImitatePass() = default;
      41              : 
      42            0 : static auto pgit(const QString &path) -> QString {
      43            0 :   if (!QtPassSettings::getGitExecutable().startsWith("wsl ")) {
      44              :     return path;
      45              :   }
      46            0 :   QString res = "$(wslpath " + path + ")";
      47            0 :   return res.replace('\\', '/');
      48              : }
      49              : 
      50            0 : static auto pgpg(const QString &path) -> QString {
      51            0 :   if (!QtPassSettings::getGpgExecutable().startsWith("wsl ")) {
      52              :     return path;
      53              :   }
      54            0 :   QString res = "$(wslpath " + path + ")";
      55            0 :   return res.replace('\\', '/');
      56              : }
      57              : 
      58              : /**
      59              :  * @brief ImitatePass::GitInit git init wrapper
      60              :  */
      61            0 : void ImitatePass::GitInit() {
      62            0 :   executeGit(GIT_INIT, {"init", pgit(QtPassSettings::getPassStore())});
      63            0 : }
      64              : 
      65              : /**
      66              :  * @brief ImitatePass::GitPull git init wrapper
      67              :  */
      68            0 : void ImitatePass::GitPull() { executeGit(GIT_PULL, {"pull"}); }
      69              : 
      70              : /**
      71              :  * @brief ImitatePass::GitPull_b git pull wrapper
      72              :  */
      73            0 : void ImitatePass::GitPull_b() {
      74            0 :   Executor::executeBlocking(QtPassSettings::getGitExecutable(), {"pull"});
      75            0 : }
      76              : 
      77              : /**
      78              :  * @brief ImitatePass::GitPush git init wrapper
      79              :  */
      80            0 : void ImitatePass::GitPush() {
      81            0 :   if (QtPassSettings::isUseGit()) {
      82            0 :     executeGit(GIT_PUSH, {"push"});
      83              :   }
      84            0 : }
      85              : 
      86              : /**
      87              :  * @brief ImitatePass::Show shows content of file
      88              :  */
      89            0 : void ImitatePass::Show(QString file) {
      90            0 :   file = QtPassSettings::getPassStore() + file + ".gpg";
      91              :   QStringList args = {"-d",      "--quiet",     "--yes",   "--no-encrypt-to",
      92            0 :                       "--batch", "--use-agent", pgpg(file)};
      93            0 :   executeGpg(PASS_SHOW, args);
      94            0 : }
      95              : 
      96              : /**
      97              :  * @brief ImitatePass::OtpGenerate generates an otp code
      98              :  */
      99            0 : void ImitatePass::OtpGenerate(QString file) {
     100              : #ifdef QT_DEBUG
     101              :   dbg() << "No OTP generation code for fake pass yet, attempting for file: " +
     102              :                file;
     103              : #else
     104              :   Q_UNUSED(file)
     105              : #endif
     106            0 : }
     107              : 
     108              : /**
     109              :  * @brief ImitatePass::Insert create new file with encrypted content
     110              :  *
     111              :  * @param file      file to be created
     112              :  * @param newValue  value to be stored in file
     113              :  * @param overwrite whether to overwrite existing file
     114              :  */
     115            0 : void ImitatePass::Insert(QString file, QString newValue, bool overwrite) {
     116            0 :   file = file + ".gpg";
     117            0 :   QString gpgIdPath = Pass::getGpgIdPath(file);
     118            0 :   if (!verifyGpgIdFile(gpgIdPath)) {
     119            0 :     emit critical(tr("Check .gpgid file signature!"),
     120            0 :                   tr("Signature for %1 is invalid.").arg(gpgIdPath));
     121            0 :     return;
     122              :   }
     123            0 :   transactionHelper trans(this, PASS_INSERT);
     124            0 :   QStringList recipients = Pass::getRecipientList(file);
     125            0 :   if (recipients.isEmpty()) {
     126              :     // TODO(bezet): probably throw here
     127            0 :     emit critical(tr("Can not edit"),
     128            0 :                   tr("Could not read encryption key to use, .gpg-id "
     129              :                      "file missing or invalid."));
     130              :     return;
     131              :   }
     132            0 :   QStringList args = {"--batch", "-eq", "--output", pgpg(file)};
     133            0 :   for (auto &r : recipients) {
     134            0 :     args.append("-r");
     135              :     args.append(r);
     136              :   }
     137            0 :   if (overwrite) {
     138            0 :     args.append("--yes");
     139              :   }
     140            0 :   args.append("-");
     141            0 :   executeGpg(PASS_INSERT, args, newValue);
     142            0 :   if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) {
     143              :     // TODO(bezet): why not?
     144            0 :     if (!overwrite) {
     145            0 :       executeGit(GIT_ADD, {"add", pgit(file)});
     146              :     }
     147            0 :     QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(file);
     148            0 :     path.replace(Util::endsWithGpg(), "");
     149              :     QString msg =
     150            0 :         QString(overwrite ? "Edit" : "Add") + " for " + path + " using QtPass.";
     151            0 :     GitCommit(file, msg);
     152              :   }
     153            0 : }
     154              : 
     155              : /**
     156              :  * @brief ImitatePass::GitCommit commit a file to git with an appropriate commit
     157              :  * message
     158              :  * @param file
     159              :  * @param msg
     160              :  */
     161            0 : void ImitatePass::GitCommit(const QString &file, const QString &msg) {
     162            0 :   if (file.isEmpty()) {
     163            0 :     executeGit(GIT_COMMIT, {"commit", "-m", msg});
     164              :   } else {
     165            0 :     executeGit(GIT_COMMIT, {"commit", "-m", msg, "--", pgit(file)});
     166              :   }
     167            0 : }
     168              : 
     169              : /**
     170              :  * @brief ImitatePass::Remove custom implementation of "pass remove"
     171              :  */
     172            0 : void ImitatePass::Remove(QString file, bool isDir) {
     173            0 :   file = QtPassSettings::getPassStore() + file;
     174            0 :   transactionHelper trans(this, PASS_REMOVE);
     175            0 :   if (!isDir) {
     176            0 :     file += ".gpg";
     177              :   }
     178            0 :   if (QtPassSettings::isUseGit()) {
     179            0 :     executeGit(GIT_RM, {"rm", (isDir ? "-rf" : "-f"), pgit(file)});
     180              :     // TODO(bezet): commit message used to have pass-like file name inside(ie.
     181              :     //  getFile(file, true)
     182            0 :     GitCommit(file, "Remove for " + file + " using QtPass.");
     183              :   } else {
     184            0 :     if (isDir) {
     185            0 :       QDir dir(file);
     186            0 :       dir.removeRecursively();
     187            0 :     } else {
     188            0 :       QFile(file).remove();
     189              :     }
     190              :   }
     191            0 : }
     192              : 
     193              : /**
     194              :  * @brief ImitatePass::Init initialize pass repository
     195              :  *
     196              :  * @param path      path in which new password-store will be created
     197              :  * @param users     list of users who shall be able to decrypt passwords in
     198              :  * path
     199              :  */
     200            0 : void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
     201              : #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
     202              :   QStringList signingKeys =
     203            0 :       QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
     204              : #else
     205              :   QStringList signingKeys =
     206              :       QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
     207              : #endif
     208            0 :   QString gpgIdSigFile = path + ".gpg-id.sig";
     209              :   bool addSigFile = false;
     210            0 :   if (!signingKeys.isEmpty()) {
     211            0 :     QString out;
     212              :     QStringList args =
     213            0 :         QStringList{"--status-fd=1", "--list-secret-keys"} + signingKeys;
     214            0 :     Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
     215              :     bool found = false;
     216            0 :     for (auto &key : signingKeys) {
     217            0 :       if (out.contains("[GNUPG:] KEY_CONSIDERED " + key)) {
     218              :         found = true;
     219              :         break;
     220              :       }
     221              :     }
     222            0 :     if (!found) {
     223            0 :       emit critical(tr("No signing key!"),
     224            0 :                     tr("None of the secret signing keys is available.\n"
     225              :                        "You will not be able to change the user list!"));
     226              :       return;
     227              :     }
     228            0 :     QFileInfo checkFile(gpgIdSigFile);
     229            0 :     if (!checkFile.exists() || !checkFile.isFile()) {
     230              :       addSigFile = true;
     231              :     }
     232            0 :   }
     233              : 
     234            0 :   QString gpgIdFile = path + ".gpg-id";
     235            0 :   QFile gpgId(gpgIdFile);
     236              :   bool addFile = false;
     237            0 :   transactionHelper trans(this, PASS_INIT);
     238            0 :   if (QtPassSettings::isAddGPGId(true)) {
     239            0 :     QFileInfo checkFile(gpgIdFile);
     240            0 :     if (!checkFile.exists() || !checkFile.isFile()) {
     241              :       addFile = true;
     242              :     }
     243            0 :   }
     244            0 :   if (!gpgId.open(QIODevice::WriteOnly | QIODevice::Text)) {
     245            0 :     emit critical(tr("Cannot update"),
     246            0 :                   tr("Failed to open .gpg-id for writing."));
     247            0 :     return;
     248              :   }
     249              :   bool secret_selected = false;
     250            0 :   foreach (const UserInfo &user, users) {
     251            0 :     if (user.enabled) {
     252            0 :       gpgId.write((user.key_id + "\n").toUtf8());
     253            0 :       secret_selected |= user.have_secret;
     254              :     }
     255              :   }
     256            0 :   gpgId.close();
     257            0 :   if (!secret_selected) {
     258            0 :     emit critical(
     259            0 :         tr("Check selected users!"),
     260            0 :         tr("None of the selected keys have a secret key available.\n"
     261              :            "You will not be able to decrypt any newly added passwords!"));
     262            0 :     return;
     263              :   }
     264              : 
     265            0 :   if (!signingKeys.isEmpty()) {
     266            0 :     QStringList args;
     267            0 :     for (auto &key : signingKeys) {
     268            0 :       args.append(QStringList{"--default-key", key});
     269              :     }
     270            0 :     args.append(QStringList{"--yes", "--detach-sign", gpgIdFile});
     271            0 :     Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args);
     272            0 :     if (!verifyGpgIdFile(gpgIdFile)) {
     273            0 :       emit critical(tr("Check .gpgid file signature!"),
     274            0 :                     tr("Signature for %1 is invalid.").arg(gpgIdFile));
     275              :       return;
     276              :     }
     277              :   }
     278              : 
     279            0 :   if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit() &&
     280            0 :       !QtPassSettings::getGitExecutable().isEmpty()) {
     281            0 :     if (addFile) {
     282            0 :       executeGit(GIT_ADD, {"add", pgit(gpgIdFile)});
     283              :     }
     284              :     QString commitPath = gpgIdFile;
     285            0 :     commitPath.replace(Util::endsWithGpg(), "");
     286            0 :     GitCommit(gpgIdFile, "Added " + commitPath + " using QtPass.");
     287            0 :     if (!signingKeys.isEmpty()) {
     288            0 :       if (addSigFile) {
     289            0 :         executeGit(GIT_ADD, {"add", pgit(gpgIdSigFile)});
     290              :       }
     291            0 :       commitPath = gpgIdSigFile;
     292            0 :       commitPath.replace(QRegularExpression("\\.gpg$"), "");
     293            0 :       GitCommit(gpgIdSigFile, "Added " + commitPath + " using QtPass.");
     294              :     }
     295              :   }
     296            0 :   reencryptPath(path);
     297            0 : }
     298              : 
     299              : /**
     300              :  * @brief ImitatePass::verifyGpgIdFile verify detached gpgid file signature.
     301              :  * @param file which gpgid file.
     302              :  * @return was verification succesful?
     303              :  */
     304            0 : auto ImitatePass::verifyGpgIdFile(const QString &file) -> bool {
     305              : #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
     306              :   QStringList signingKeys =
     307            0 :       QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
     308              : #else
     309              :   QStringList signingKeys =
     310              :       QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
     311              : #endif
     312            0 :   if (signingKeys.isEmpty()) {
     313              :     return true;
     314              :   }
     315            0 :   QString out;
     316              :   QStringList args =
     317            0 :       QStringList{"--verify", "--status-fd=1", pgpg(file) + ".sig", pgpg(file)};
     318            0 :   Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
     319              :   QRegularExpression re(
     320            0 :       R"(^\[GNUPG:\] VALIDSIG ([A-F0-9]{40}) .* ([A-F0-9]{40})\r?$)",
     321            0 :       QRegularExpression::MultilineOption);
     322            0 :   QRegularExpressionMatch m = re.match(out);
     323            0 :   if (!m.hasMatch()) {
     324              :     return false;
     325              :   }
     326            0 :   QStringList fingerprints = m.capturedTexts();
     327            0 :   fingerprints.removeFirst();
     328            0 :   for (auto &key : signingKeys) {
     329            0 :     if (fingerprints.contains(key)) {
     330            0 :       return true;
     331              :     }
     332              :   }
     333            0 :   return false;
     334            0 : }
     335              : 
     336              : /**
     337              :  * @brief ImitatePass::removeDir delete folder recursive.
     338              :  * @param dirName which folder.
     339              :  * @return was removal succesful?
     340              :  */
     341            0 : auto ImitatePass::removeDir(const QString &dirName) -> bool {
     342              :   bool result = true;
     343            0 :   QDir dir(dirName);
     344              : 
     345            0 :   if (dir.exists(dirName)) {
     346            0 :     Q_FOREACH (QFileInfo info,
     347              :                dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System |
     348              :                                      QDir::Hidden | QDir::AllDirs | QDir::Files,
     349              :                                  QDir::DirsFirst)) {
     350            0 :       if (info.isDir()) {
     351            0 :         result = removeDir(info.absoluteFilePath());
     352              :       } else {
     353            0 :         result = QFile::remove(info.absoluteFilePath());
     354              :       }
     355              : 
     356            0 :       if (!result) {
     357              :         return result;
     358              :       }
     359            0 :     }
     360            0 :     result = dir.rmdir(dirName);
     361              :   }
     362              :   return result;
     363            0 : }
     364              : 
     365              : /**
     366              :  * @brief ImitatePass::reencryptPath reencrypt all files under the chosen
     367              :  * directory
     368              :  *
     369              :  * This is stil quite experimental..
     370              :  * @param dir
     371              :  */
     372            0 : void ImitatePass::reencryptPath(const QString &dir) {
     373            0 :   emit statusMsg(tr("Re-encrypting from folder %1").arg(dir), 3000);
     374            0 :   emit startReencryptPath();
     375            0 :   if (QtPassSettings::isAutoPull()) {
     376              :     // TODO(bezet): move statuses inside actions?
     377            0 :     emit statusMsg(tr("Updating password-store"), 2000);
     378            0 :     GitPull_b();
     379              :   }
     380            0 :   QDir currentDir;
     381            0 :   QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files,
     382            0 :                         QDirIterator::Subdirectories);
     383            0 :   QStringList gpgIdFilesVerified;
     384            0 :   QStringList gpgId;
     385            0 :   while (gpgFiles.hasNext()) {
     386            0 :     QString fileName = gpgFiles.next();
     387            0 :     if (gpgFiles.fileInfo().path() != currentDir.path()) {
     388            0 :       QString gpgIdPath = Pass::getGpgIdPath(fileName);
     389            0 :       if (!gpgIdFilesVerified.contains(gpgIdPath)) {
     390            0 :         if (!verifyGpgIdFile(gpgIdPath)) {
     391            0 :           emit critical(tr("Check .gpgid file signature!"),
     392            0 :                         tr("Signature for %1 is invalid.").arg(gpgIdPath));
     393            0 :           emit endReencryptPath();
     394              :           return;
     395              :         }
     396              :         gpgIdFilesVerified.append(gpgIdPath);
     397              :       }
     398            0 :       gpgId = getRecipientList(fileName);
     399              :       gpgId.sort();
     400              :     }
     401              :     // TODO(bezet): enable --with-colons for better future-proofness?
     402              :     QStringList args = {
     403              :         "-v",          "--no-secmem-warning", "--no-permission-warning",
     404            0 :         "--list-only", "--keyid-format=long", pgpg(fileName)};
     405            0 :     QString keys;
     406            0 :     QString err;
     407            0 :     Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &keys,
     408              :                               &err);
     409            0 :     QStringList actualKeys;
     410              :     keys += err;
     411              : #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
     412            0 :     QStringList key = keys.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
     413              : #else
     414              :     QStringList key =
     415              :         keys.split(Util::newLinesRegex(), QString::SkipEmptyParts);
     416              : #endif
     417              :     QListIterator<QString> itr(key);
     418            0 :     while (itr.hasNext()) {
     419              :       QString current = itr.next();
     420            0 :       QStringList cur = current.split(" ");
     421            0 :       if (cur.length() > 4) {
     422            0 :         QString actualKey = cur.takeAt(4);
     423            0 :         if (actualKey.length() == 16) {
     424              :           actualKeys << actualKey;
     425              :         }
     426              :       }
     427              :     }
     428              :     actualKeys.sort();
     429            0 :     if (actualKeys != gpgId) {
     430              :       // dbg()<< actualKeys << gpgId << getRecipientList(fileName);
     431              : #ifdef QT_DEBUG
     432              :       dbg() << "reencrypt " << fileName << " for " << gpgId;
     433              : #endif
     434            0 :       QString local_lastDecrypt = "Could not decrypt";
     435            0 :       args = QStringList{
     436              :           "-d",      "--quiet",     "--yes",       "--no-encrypt-to",
     437            0 :           "--batch", "--use-agent", pgpg(fileName)};
     438            0 :       Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
     439              :                                 &local_lastDecrypt);
     440              : 
     441            0 :       if (!local_lastDecrypt.isEmpty() &&
     442              :           local_lastDecrypt != "Could not decrypt") {
     443            0 :         if (local_lastDecrypt.right(1) != "\n") {
     444            0 :           local_lastDecrypt += "\n";
     445              :         }
     446              : 
     447            0 :         QStringList recipients = Pass::getRecipientList(fileName);
     448            0 :         if (recipients.isEmpty()) {
     449            0 :           emit critical(tr("Can not edit"),
     450            0 :                         tr("Could not read encryption key to use, .gpg-id "
     451              :                            "file missing or invalid."));
     452              :           return;
     453              :         }
     454              :         args =
     455            0 :             QStringList{"--yes", "--batch", "-eq", "--output", pgpg(fileName)};
     456            0 :         for (auto &i : recipients) {
     457            0 :           args.append("-r");
     458              :           args.append(i);
     459              :         }
     460            0 :         args.append("-");
     461            0 :         Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
     462              :                                   local_lastDecrypt);
     463              : 
     464            0 :         if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) {
     465            0 :           Executor::executeBlocking(QtPassSettings::getGitExecutable(),
     466              :                                     {"add", pgit(fileName)});
     467              :           QString path =
     468            0 :               QDir(QtPassSettings::getPassStore()).relativeFilePath(fileName);
     469            0 :           path.replace(Util::endsWithGpg(), "");
     470            0 :           Executor::executeBlocking(QtPassSettings::getGitExecutable(),
     471              :                                     {"commit", pgit(fileName), "-m",
     472            0 :                                      "Edit for " + path + " using QtPass."});
     473              :         }
     474              : 
     475              :       } else {
     476              : #ifdef QT_DEBUG
     477              :         dbg() << "Decrypt error on re-encrypt";
     478              : #endif
     479              :       }
     480              :     }
     481              :   }
     482            0 :   if (QtPassSettings::isAutoPush()) {
     483            0 :     emit statusMsg(tr("Updating password-store"), 2000);
     484              :     // TODO(bezet): this is non-blocking and shall be done outside
     485            0 :     GitPush();
     486              :   }
     487            0 :   emit endReencryptPath();
     488            0 : }
     489              : 
     490            0 : void ImitatePass::Move(const QString src, const QString dest,
     491              :                        const bool force) {
     492            0 :   transactionHelper trans(this, PASS_MOVE);
     493            0 :   QFileInfo srcFileInfo(src);
     494            0 :   QFileInfo destFileInfo(dest);
     495            0 :   QString destFile;
     496            0 :   QString srcFileBaseName = srcFileInfo.fileName();
     497              : 
     498            0 :   if (srcFileInfo.isFile()) {
     499            0 :     if (destFileInfo.isFile()) {
     500            0 :       if (!force) {
     501              : #ifdef QT_DEBUG
     502              :         dbg() << "Destination file already exists";
     503              : #endif
     504              :         return;
     505              :       }
     506            0 :     } else if (destFileInfo.isDir()) {
     507            0 :       destFile = QDir(dest).filePath(srcFileBaseName);
     508              :     } else {
     509            0 :       destFile = dest;
     510              :     }
     511              : 
     512            0 :     if (destFile.endsWith(".gpg", Qt::CaseInsensitive)) {
     513            0 :       destFile.chop(4); //  make sure suffix is lowercase
     514              :     }
     515            0 :     destFile.append(".gpg");
     516            0 :   } else if (srcFileInfo.isDir()) {
     517            0 :     if (destFileInfo.isDir()) {
     518            0 :       destFile = QDir(dest).filePath(srcFileBaseName);
     519            0 :     } else if (destFileInfo.isFile()) {
     520              : #ifdef QT_DEBUG
     521              :       dbg() << "Destination is a file";
     522              : #endif
     523              :       return;
     524              :     } else {
     525            0 :       destFile = dest;
     526              :     }
     527              :   } else {
     528              : #ifdef QT_DEBUG
     529              :     dbg() << "Source file does not exist";
     530              : #endif
     531              :     return;
     532              :   }
     533              : 
     534              : #ifdef QT_DEBUG
     535              :   dbg() << "Move Source: " << src;
     536              :   dbg() << "Move Destination: " << destFile;
     537              : #endif
     538              : 
     539            0 :   if (QtPassSettings::isUseGit()) {
     540            0 :     QStringList args;
     541            0 :     args << "mv";
     542            0 :     if (force) {
     543            0 :       args << "-f";
     544              :     }
     545            0 :     args << pgit(src);
     546            0 :     args << pgit(destFile);
     547            0 :     executeGit(GIT_MOVE, args);
     548              : 
     549            0 :     QString relSrc = QDir(QtPassSettings::getPassStore()).relativeFilePath(src);
     550            0 :     relSrc.replace(Util::endsWithGpg(), "");
     551              :     QString relDest =
     552            0 :         QDir(QtPassSettings::getPassStore()).relativeFilePath(destFile);
     553            0 :     relDest.replace(Util::endsWithGpg(), "");
     554            0 :     QString message = QString("Moved for %1 to %2 using QtPass.");
     555            0 :     message = message.arg(relSrc, relDest);
     556            0 :     GitCommit("", message);
     557              :   } else {
     558            0 :     QDir qDir;
     559            0 :     if (force) {
     560            0 :       qDir.remove(destFile);
     561              :     }
     562            0 :     qDir.rename(src, destFile);
     563            0 :   }
     564            0 : }
     565              : 
     566            0 : void ImitatePass::Copy(const QString src, const QString dest,
     567              :                        const bool force) {
     568            0 :   QFileInfo destFileInfo(dest);
     569            0 :   transactionHelper trans(this, PASS_COPY);
     570            0 :   if (QtPassSettings::isUseGit()) {
     571            0 :     QStringList args;
     572            0 :     args << "cp";
     573            0 :     if (force) {
     574            0 :       args << "-f";
     575              :     }
     576            0 :     args << pgit(src);
     577            0 :     args << pgit(dest);
     578            0 :     executeGit(GIT_COPY, args);
     579              : 
     580            0 :     QString message = QString("copied from %1 to %2 using QTPass.");
     581            0 :     message = message.arg(src, dest);
     582            0 :     GitCommit("", message);
     583              :   } else {
     584            0 :     QDir qDir;
     585            0 :     if (force) {
     586            0 :       qDir.remove(dest);
     587              :     }
     588            0 :     QFile::copy(src, dest);
     589            0 :   }
     590              :   // reecrypt all files under the new folder
     591            0 :   if (destFileInfo.isDir()) {
     592            0 :     reencryptPath(destFileInfo.absoluteFilePath());
     593            0 :   } else if (destFileInfo.isFile()) {
     594            0 :     reencryptPath(destFileInfo.dir().path());
     595              :   }
     596            0 : }
     597              : 
     598              : /**
     599              :  * @brief ImitatePass::executeGpg easy wrapper for running gpg commands
     600              :  * @param args
     601              :  */
     602            0 : void ImitatePass::executeGpg(PROCESS id, const QStringList &args, QString input,
     603              :                              bool readStdout, bool readStderr) {
     604            0 :   executeWrapper(id, QtPassSettings::getGpgExecutable(), args, std::move(input),
     605              :                  readStdout, readStderr);
     606            0 : }
     607              : /**
     608              :  * @brief ImitatePass::executeGit easy wrapper for running git commands
     609              :  * @param args
     610              :  */
     611            0 : void ImitatePass::executeGit(PROCESS id, const QStringList &args, QString input,
     612              :                              bool readStdout, bool readStderr) {
     613            0 :   executeWrapper(id, QtPassSettings::getGitExecutable(), args, std::move(input),
     614              :                  readStdout, readStderr);
     615            0 : }
     616              : 
     617              : /**
     618              :  * @brief ImitatePass::finished this function is overloaded to ensure
     619              :  *                              identical behaviour to RealPass ie. only PASS_*
     620              :  *                              processes are visible inside Pass::finish, so
     621              :  *                              that interface-wise it all looks the same
     622              :  * @param id
     623              :  * @param exitCode
     624              :  * @param out
     625              :  * @param err
     626              :  */
     627            0 : void ImitatePass::finished(int id, int exitCode, const QString &out,
     628              :                            const QString &err) {
     629              : #ifdef QT_DEBUG
     630              :   dbg() << "Imitate Pass";
     631              : #endif
     632            0 :   static QString transactionOutput;
     633            0 :   PROCESS pid = transactionIsOver(static_cast<PROCESS>(id));
     634            0 :   transactionOutput.append(out);
     635              : 
     636            0 :   if (exitCode == 0) {
     637            0 :     if (pid == INVALID) {
     638              :       return;
     639              :     }
     640              :   } else {
     641            0 :     while (pid == INVALID) {
     642            0 :       id = exec.cancelNext();
     643            0 :       if (id == -1) {
     644              :         //  this is probably irrecoverable and shall not happen
     645              : #ifdef QT_DEBUG
     646              :         dbg() << "No such transaction!";
     647              : #endif
     648              :         return;
     649              :       }
     650            0 :       pid = transactionIsOver(static_cast<PROCESS>(id));
     651              :     }
     652              :   }
     653            0 :   Pass::finished(pid, exitCode, transactionOutput, err);
     654            0 :   transactionOutput.clear();
     655              : }
     656              : 
     657              : /**
     658              :  * @brief executeWrapper    overrided so that every execution is a transaction
     659              :  * @param id
     660              :  * @param app
     661              :  * @param args
     662              :  * @param input
     663              :  * @param readStdout
     664              :  * @param readStderr
     665              :  */
     666            0 : void ImitatePass::executeWrapper(PROCESS id, const QString &app,
     667              :                                  const QStringList &args, QString input,
     668              :                                  bool readStdout, bool readStderr) {
     669            0 :   transactionAdd(id);
     670            0 :   Pass::executeWrapper(id, app, args, input, readStdout, readStderr);
     671            0 : }
        

Generated by: LCOV version 2.4-beta