• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 23545294861

25 Mar 2026 02:07PM UTC coverage: 17.516% (+0.003%) from 17.513%
23545294861

push

github

web-flow
Fix Qt 6 compatibility and modernize C++ style (#768)

* Fix Qt 6 compatibility and modernize C++ style

- Fix Q_OS_OSX -> Q_OS_MACOS macro for Qt 6
- Replace Q_FOREACH with range-based for loop
- Replace signals:/slots: with Q_SIGNALS/Q_SLOTS macros
- Replace Q_DECL_OVERRIDE with override
- Remove redundant virtual keywords with override
- Add override to virtual function overrides
- Use nullptr instead of 0/NULL
- Use = default for trivial destructors
- Use 'using' instead of 'typedef'

* Format PR template with prettier

* Fix MD041: use top-level heading in PR template

* Improve DCO wording in PR template

* Add friendly license agreement footer to template

3 of 9 new or added lines in 6 files covered. (33.33%)

866 of 4944 relevant lines covered (17.52%)

7.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.33
/src/imitatepass.cpp
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
ImitatePass::ImitatePass() = default;
8✔
41

42
static auto pgit(const QString &path) -> QString {
×
43
  if (!QtPassSettings::getGitExecutable().startsWith("wsl ")) {
×
44
    return path;
45
  }
46
  QString res = "$(wslpath " + path + ")";
×
47
  return res.replace('\\', '/');
×
48
}
49

50
static auto pgpg(const QString &path) -> QString {
×
51
  if (!QtPassSettings::getGpgExecutable().startsWith("wsl ")) {
×
52
    return path;
53
  }
54
  QString res = "$(wslpath " + path + ")";
×
55
  return res.replace('\\', '/');
×
56
}
57

58
/**
59
 * @brief ImitatePass::GitInit git init wrapper
60
 */
61
void ImitatePass::GitInit() {
×
62
  executeGit(GIT_INIT, {"init", pgit(QtPassSettings::getPassStore())});
×
63
}
×
64

65
/**
66
 * @brief ImitatePass::GitPull git init wrapper
67
 */
68
void ImitatePass::GitPull() { executeGit(GIT_PULL, {"pull"}); }
×
69

70
/**
71
 * @brief ImitatePass::GitPull_b git pull wrapper
72
 */
73
void ImitatePass::GitPull_b() {
×
74
  Executor::executeBlocking(QtPassSettings::getGitExecutable(), {"pull"});
×
75
}
×
76

77
/**
78
 * @brief ImitatePass::GitPush git init wrapper
79
 */
80
void ImitatePass::GitPush() {
×
81
  if (QtPassSettings::isUseGit()) {
×
82
    executeGit(GIT_PUSH, {"push"});
×
83
  }
84
}
×
85

86
/**
87
 * @brief ImitatePass::Show shows content of file
88
 */
89
void ImitatePass::Show(QString file) {
×
90
  file = QtPassSettings::getPassStore() + file + ".gpg";
×
91
  QStringList args = {"-d",      "--quiet",     "--yes",   "--no-encrypt-to",
92
                      "--batch", "--use-agent", pgpg(file)};
×
93
  executeGpg(PASS_SHOW, args);
×
94
}
×
95

96
/**
97
 * @brief ImitatePass::OtpGenerate generates an otp code
98
 */
99
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
}
×
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
void ImitatePass::Insert(QString file, QString newValue, bool overwrite) {
×
116
  file = file + ".gpg";
×
117
  QString gpgIdPath = Pass::getGpgIdPath(file);
×
118
  if (!verifyGpgIdFile(gpgIdPath)) {
×
119
    emit critical(tr("Check .gpgid file signature!"),
×
120
                  tr("Signature for %1 is invalid.").arg(gpgIdPath));
×
121
    return;
×
122
  }
123
  transactionHelper trans(this, PASS_INSERT);
×
124
  QStringList recipients = Pass::getRecipientList(file);
×
125
  if (recipients.isEmpty()) {
×
126
    // TODO(bezet): probably throw here
127
    emit critical(tr("Can not edit"),
×
128
                  tr("Could not read encryption key to use, .gpg-id "
×
129
                     "file missing or invalid."));
130
    return;
131
  }
132
  QStringList args = {"--batch", "-eq", "--output", pgpg(file)};
×
133
  for (auto &r : recipients) {
×
134
    args.append("-r");
×
135
    args.append(r);
136
  }
137
  if (overwrite) {
×
138
    args.append("--yes");
×
139
  }
140
  args.append("-");
×
141
  executeGpg(PASS_INSERT, args, newValue);
×
142
  if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) {
×
143
    // TODO(bezet): why not?
144
    if (!overwrite) {
×
145
      executeGit(GIT_ADD, {"add", pgit(file)});
×
146
    }
147
    QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(file);
×
148
    path.replace(Util::endsWithGpg(), "");
×
149
    QString msg =
150
        QString(overwrite ? "Edit" : "Add") + " for " + path + " using QtPass.";
×
151
    GitCommit(file, msg);
×
152
  }
153
}
×
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
void ImitatePass::GitCommit(const QString &file, const QString &msg) {
×
162
  if (file.isEmpty()) {
×
163
    executeGit(GIT_COMMIT, {"commit", "-m", msg});
×
164
  } else {
165
    executeGit(GIT_COMMIT, {"commit", "-m", msg, "--", pgit(file)});
×
166
  }
167
}
×
168

169
/**
170
 * @brief ImitatePass::Remove custom implementation of "pass remove"
171
 */
172
void ImitatePass::Remove(QString file, bool isDir) {
×
173
  file = QtPassSettings::getPassStore() + file;
×
174
  transactionHelper trans(this, PASS_REMOVE);
×
175
  if (!isDir) {
×
176
    file += ".gpg";
×
177
  }
178
  if (QtPassSettings::isUseGit()) {
×
179
    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
    GitCommit(file, "Remove for " + file + " using QtPass.");
×
183
  } else {
184
    if (isDir) {
×
185
      QDir dir(file);
×
186
      dir.removeRecursively();
×
187
    } else {
×
188
      QFile(file).remove();
×
189
    }
190
  }
191
}
×
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
void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
×
201
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
202
  QStringList signingKeys =
203
      QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
×
204
#else
205
  QStringList signingKeys =
206
      QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
207
#endif
208
  QString gpgIdSigFile = path + ".gpg-id.sig";
×
209
  bool addSigFile = false;
210
  if (!signingKeys.isEmpty()) {
×
211
    QString out;
×
212
    QStringList args =
213
        QStringList{"--status-fd=1", "--list-secret-keys"} + signingKeys;
×
214
    Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
×
215
    bool found = false;
216
    for (auto &key : signingKeys) {
×
217
      if (out.contains("[GNUPG:] KEY_CONSIDERED " + key)) {
×
218
        found = true;
219
        break;
220
      }
221
    }
222
    if (!found) {
×
223
      emit critical(tr("No signing key!"),
×
224
                    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
    QFileInfo checkFile(gpgIdSigFile);
×
229
    if (!checkFile.exists() || !checkFile.isFile()) {
×
230
      addSigFile = true;
231
    }
232
  }
×
233

234
  QString gpgIdFile = path + ".gpg-id";
×
235
  QFile gpgId(gpgIdFile);
×
236
  bool addFile = false;
237
  transactionHelper trans(this, PASS_INIT);
×
238
  if (QtPassSettings::isAddGPGId(true)) {
×
239
    QFileInfo checkFile(gpgIdFile);
×
240
    if (!checkFile.exists() || !checkFile.isFile()) {
×
241
      addFile = true;
242
    }
243
  }
×
244
  if (!gpgId.open(QIODevice::WriteOnly | QIODevice::Text)) {
×
245
    emit critical(tr("Cannot update"),
×
246
                  tr("Failed to open .gpg-id for writing."));
×
247
    return;
×
248
  }
249
  bool secret_selected = false;
250
  foreach (const UserInfo &user, users) {
×
251
    if (user.enabled) {
×
252
      gpgId.write((user.key_id + "\n").toUtf8());
×
253
      secret_selected |= user.have_secret;
×
254
    }
255
  }
256
  gpgId.close();
×
257
  if (!secret_selected) {
×
258
    emit critical(
×
259
        tr("Check selected users!"),
×
260
        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
    return;
×
263
  }
264

265
  if (!signingKeys.isEmpty()) {
×
266
    QStringList args;
×
267
    for (auto &key : signingKeys) {
×
268
      args.append(QStringList{"--default-key", key});
×
269
    }
270
    args.append(QStringList{"--yes", "--detach-sign", gpgIdFile});
×
271
    Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args);
×
272
    if (!verifyGpgIdFile(gpgIdFile)) {
×
273
      emit critical(tr("Check .gpgid file signature!"),
×
274
                    tr("Signature for %1 is invalid.").arg(gpgIdFile));
×
275
      return;
276
    }
277
  }
278

279
  if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit() &&
×
280
      !QtPassSettings::getGitExecutable().isEmpty()) {
×
281
    if (addFile) {
×
282
      executeGit(GIT_ADD, {"add", pgit(gpgIdFile)});
×
283
    }
284
    QString commitPath = gpgIdFile;
285
    commitPath.replace(Util::endsWithGpg(), "");
×
286
    GitCommit(gpgIdFile, "Added " + commitPath + " using QtPass.");
×
287
    if (!signingKeys.isEmpty()) {
×
288
      if (addSigFile) {
×
289
        executeGit(GIT_ADD, {"add", pgit(gpgIdSigFile)});
×
290
      }
291
      commitPath = gpgIdSigFile;
×
292
      commitPath.replace(QRegularExpression("\\.gpg$"), "");
×
293
      GitCommit(gpgIdSigFile, "Added " + commitPath + " using QtPass.");
×
294
    }
295
  }
296
  reencryptPath(path);
×
297
}
×
298

299
/**
300
 * @brief ImitatePass::verifyGpgIdFile verify detached gpgid file signature.
301
 * @param file which gpgid file.
302
 * @return was verification succesful?
303
 */
304
auto ImitatePass::verifyGpgIdFile(const QString &file) -> bool {
×
305
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
306
  QStringList signingKeys =
307
      QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
×
308
#else
309
  QStringList signingKeys =
310
      QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
311
#endif
312
  if (signingKeys.isEmpty()) {
×
313
    return true;
314
  }
315
  QString out;
×
316
  QStringList args =
317
      QStringList{"--verify", "--status-fd=1", pgpg(file) + ".sig", pgpg(file)};
×
318
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
×
319
  QRegularExpression re(
320
      R"(^\[GNUPG:\] VALIDSIG ([A-F0-9]{40}) .* ([A-F0-9]{40})\r?$)",
321
      QRegularExpression::MultilineOption);
×
322
  QRegularExpressionMatch m = re.match(out);
×
323
  if (!m.hasMatch()) {
×
324
    return false;
325
  }
326
  QStringList fingerprints = m.capturedTexts();
×
327
  fingerprints.removeFirst();
×
328
  for (auto &key : signingKeys) {
×
329
    if (fingerprints.contains(key)) {
×
330
      return true;
×
331
    }
332
  }
333
  return false;
×
334
}
×
335

336
/**
337
 * @brief ImitatePass::removeDir delete folder recursive.
338
 * @param dirName which folder.
339
 * @return was removal succesful?
340
 */
341
auto ImitatePass::removeDir(const QString &dirName) -> bool {
×
342
  bool result = true;
343
  QDir dir(dirName);
×
344

345
  if (dir.exists(dirName)) {
×
346
    for (const QFileInfo &info :
347
         dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
348
                               QDir::AllDirs | QDir::Files,
NEW
349
                           QDir::DirsFirst)) {
×
350
      if (info.isDir()) {
×
351
        result = removeDir(info.absoluteFilePath());
×
352
      } else {
353
        result = QFile::remove(info.absoluteFilePath());
×
354
      }
355

356
      if (!result) {
×
357
        return result;
358
      }
359
    }
360
    result = dir.rmdir(dirName);
×
361
  }
362
  return result;
363
}
×
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
void ImitatePass::reencryptPath(const QString &dir) {
×
373
  emit statusMsg(tr("Re-encrypting from folder %1").arg(dir), 3000);
×
374
  emit startReencryptPath();
×
375
  if (QtPassSettings::isAutoPull()) {
×
376
    // TODO(bezet): move statuses inside actions?
377
    emit statusMsg(tr("Updating password-store"), 2000);
×
378
    GitPull_b();
×
379
  }
380
  QDir currentDir;
×
381
  QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files,
×
382
                        QDirIterator::Subdirectories);
×
383
  QStringList gpgIdFilesVerified;
×
384
  QStringList gpgId;
×
385
  while (gpgFiles.hasNext()) {
×
386
    QString fileName = gpgFiles.next();
×
387
    if (gpgFiles.fileInfo().path() != currentDir.path()) {
×
388
      QString gpgIdPath = Pass::getGpgIdPath(fileName);
×
389
      if (!gpgIdFilesVerified.contains(gpgIdPath)) {
×
390
        if (!verifyGpgIdFile(gpgIdPath)) {
×
391
          emit critical(tr("Check .gpgid file signature!"),
×
392
                        tr("Signature for %1 is invalid.").arg(gpgIdPath));
×
393
          emit endReencryptPath();
×
394
          return;
395
        }
396
        gpgIdFilesVerified.append(gpgIdPath);
397
      }
398
      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
        "--list-only", "--keyid-format=long", pgpg(fileName)};
×
405
    QString keys;
×
406
    QString err;
×
407
    Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &keys,
×
408
                              &err);
409
    QStringList actualKeys;
×
410
    keys += err;
411
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
412
    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
    while (itr.hasNext()) {
×
419
      QString current = itr.next();
420
      QStringList cur = current.split(" ");
×
421
      if (cur.length() > 4) {
×
422
        QString actualKey = cur.takeAt(4);
×
423
        if (actualKey.length() == 16) {
×
424
          actualKeys << actualKey;
425
        }
426
      }
427
    }
428
    actualKeys.sort();
429
    if (actualKeys != gpgId) {
×
430
      // dbg()<< actualKeys << gpgId << getRecipientList(fileName);
431
#ifdef QT_DEBUG
432
      dbg() << "reencrypt " << fileName << " for " << gpgId;
433
#endif
434
      QString local_lastDecrypt = "Could not decrypt";
×
435
      args = QStringList{
×
436
          "-d",      "--quiet",     "--yes",       "--no-encrypt-to",
437
          "--batch", "--use-agent", pgpg(fileName)};
×
438
      Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
×
439
                                &local_lastDecrypt);
440

441
      if (!local_lastDecrypt.isEmpty() &&
×
442
          local_lastDecrypt != "Could not decrypt") {
443
        if (local_lastDecrypt.right(1) != "\n") {
×
444
          local_lastDecrypt += "\n";
×
445
        }
446

447
        QStringList recipients = Pass::getRecipientList(fileName);
×
448
        if (recipients.isEmpty()) {
×
449
          emit critical(tr("Can not edit"),
×
450
                        tr("Could not read encryption key to use, .gpg-id "
×
451
                           "file missing or invalid."));
452
          return;
453
        }
454
        args =
455
            QStringList{"--yes", "--batch", "-eq", "--output", pgpg(fileName)};
×
456
        for (auto &i : recipients) {
×
457
          args.append("-r");
×
458
          args.append(i);
459
        }
460
        args.append("-");
×
461
        Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
×
462
                                  local_lastDecrypt);
463

464
        if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) {
×
465
          Executor::executeBlocking(QtPassSettings::getGitExecutable(),
×
466
                                    {"add", pgit(fileName)});
467
          QString path =
468
              QDir(QtPassSettings::getPassStore()).relativeFilePath(fileName);
×
469
          path.replace(Util::endsWithGpg(), "");
×
470
          Executor::executeBlocking(QtPassSettings::getGitExecutable(),
×
471
                                    {"commit", pgit(fileName), "-m",
472
                                     "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
  if (QtPassSettings::isAutoPush()) {
×
483
    emit statusMsg(tr("Updating password-store"), 2000);
×
484
    // TODO(bezet): this is non-blocking and shall be done outside
485
    GitPush();
×
486
  }
487
  emit endReencryptPath();
×
488
}
×
489

490
void ImitatePass::Move(const QString src, const QString dest,
×
491
                       const bool force) {
492
  transactionHelper trans(this, PASS_MOVE);
×
493
  QFileInfo srcFileInfo(src);
×
494
  QFileInfo destFileInfo(dest);
×
495
  QString destFile;
×
496
  QString srcFileBaseName = srcFileInfo.fileName();
×
497

498
  if (srcFileInfo.isFile()) {
×
499
    if (destFileInfo.isFile()) {
×
500
      if (!force) {
×
501
#ifdef QT_DEBUG
502
        dbg() << "Destination file already exists";
503
#endif
504
        return;
505
      }
506
    } else if (destFileInfo.isDir()) {
×
507
      destFile = QDir(dest).filePath(srcFileBaseName);
×
508
    } else {
509
      destFile = dest;
×
510
    }
511

512
    if (destFile.endsWith(".gpg", Qt::CaseInsensitive)) {
×
513
      destFile.chop(4); //  make sure suffix is lowercase
×
514
    }
515
    destFile.append(".gpg");
×
516
  } else if (srcFileInfo.isDir()) {
×
517
    if (destFileInfo.isDir()) {
×
518
      destFile = QDir(dest).filePath(srcFileBaseName);
×
519
    } else if (destFileInfo.isFile()) {
×
520
#ifdef QT_DEBUG
521
      dbg() << "Destination is a file";
522
#endif
523
      return;
524
    } else {
525
      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
  if (QtPassSettings::isUseGit()) {
×
540
    QStringList args;
×
541
    args << "mv";
×
542
    if (force) {
×
543
      args << "-f";
×
544
    }
545
    args << pgit(src);
×
546
    args << pgit(destFile);
×
547
    executeGit(GIT_MOVE, args);
×
548

549
    QString relSrc = QDir(QtPassSettings::getPassStore()).relativeFilePath(src);
×
550
    relSrc.replace(Util::endsWithGpg(), "");
×
551
    QString relDest =
552
        QDir(QtPassSettings::getPassStore()).relativeFilePath(destFile);
×
553
    relDest.replace(Util::endsWithGpg(), "");
×
554
    QString message = QString("Moved for %1 to %2 using QtPass.");
×
555
    message = message.arg(relSrc, relDest);
×
556
    GitCommit("", message);
×
557
  } else {
558
    QDir qDir;
×
559
    if (force) {
×
560
      qDir.remove(destFile);
×
561
    }
562
    qDir.rename(src, destFile);
×
563
  }
×
564
}
×
565

566
void ImitatePass::Copy(const QString src, const QString dest,
×
567
                       const bool force) {
568
  QFileInfo destFileInfo(dest);
×
569
  transactionHelper trans(this, PASS_COPY);
×
570
  if (QtPassSettings::isUseGit()) {
×
571
    QStringList args;
×
572
    args << "cp";
×
573
    if (force) {
×
574
      args << "-f";
×
575
    }
576
    args << pgit(src);
×
577
    args << pgit(dest);
×
578
    executeGit(GIT_COPY, args);
×
579

580
    QString message = QString("copied from %1 to %2 using QTPass.");
×
581
    message = message.arg(src, dest);
×
582
    GitCommit("", message);
×
583
  } else {
584
    QDir qDir;
×
585
    if (force) {
×
586
      qDir.remove(dest);
×
587
    }
588
    QFile::copy(src, dest);
×
589
  }
×
590
  // reecrypt all files under the new folder
591
  if (destFileInfo.isDir()) {
×
592
    reencryptPath(destFileInfo.absoluteFilePath());
×
593
  } else if (destFileInfo.isFile()) {
×
594
    reencryptPath(destFileInfo.dir().path());
×
595
  }
596
}
×
597

598
/**
599
 * @brief ImitatePass::executeGpg easy wrapper for running gpg commands
600
 * @param args
601
 */
602
void ImitatePass::executeGpg(PROCESS id, const QStringList &args, QString input,
×
603
                             bool readStdout, bool readStderr) {
604
  executeWrapper(id, QtPassSettings::getGpgExecutable(), args, std::move(input),
×
605
                 readStdout, readStderr);
606
}
×
607
/**
608
 * @brief ImitatePass::executeGit easy wrapper for running git commands
609
 * @param args
610
 */
611
void ImitatePass::executeGit(PROCESS id, const QStringList &args, QString input,
×
612
                             bool readStdout, bool readStderr) {
613
  executeWrapper(id, QtPassSettings::getGitExecutable(), args, std::move(input),
×
614
                 readStdout, readStderr);
615
}
×
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
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
  static QString transactionOutput;
×
633
  PROCESS pid = transactionIsOver(static_cast<PROCESS>(id));
×
634
  transactionOutput.append(out);
×
635

636
  if (exitCode == 0) {
×
637
    if (pid == INVALID) {
×
638
      return;
639
    }
640
  } else {
641
    while (pid == INVALID) {
×
642
      id = exec.cancelNext();
×
643
      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
      pid = transactionIsOver(static_cast<PROCESS>(id));
×
651
    }
652
  }
653
  Pass::finished(pid, exitCode, transactionOutput, err);
×
654
  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
void ImitatePass::executeWrapper(PROCESS id, const QString &app,
×
667
                                 const QStringList &args, QString input,
668
                                 bool readStdout, bool readStderr) {
669
  transactionAdd(id);
×
670
  Pass::executeWrapper(id, app, args, input, readStdout, readStderr);
×
671
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc