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

IJHack / QtPass / 23572525144

26 Mar 2026 01:13AM UTC coverage: 17.849% (+0.3%) from 17.516%
23572525144

Pull #769

github

web-flow
Merge e7d2b02d1 into 8c5fc9456
Pull Request #769: CodeFactor: Fix complex method and style recommendations

4 of 141 new or added lines in 2 files covered. (2.84%)

6 existing lines in 1 file now uncovered.

888 of 4975 relevant lines covered (17.85%)

7.22 hits per line

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

6.97
/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;
18✔
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
 */
NEW
200
auto ImitatePass::checkSigningKeys(const QStringList &signingKeys) -> bool {
×
NEW
201
  QString out;
×
202
  QStringList args =
NEW
203
      QStringList{"--status-fd=1", "--list-secret-keys"} + signingKeys;
×
NEW
204
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
×
NEW
205
  for (auto &key : signingKeys) {
×
NEW
206
    if (out.contains("[GNUPG:] KEY_CONSIDERED " + key)) {
×
207
      return true;
208
    }
209
  }
210
  return false;
NEW
211
}
×
212

NEW
213
void ImitatePass::writeGpgIdFile(const QString &gpgIdFile,
×
214
                                 const QList<UserInfo> &users) {
NEW
215
  QFile gpgId(gpgIdFile);
×
NEW
216
  if (!gpgId.open(QIODevice::WriteOnly | QIODevice::Text)) {
×
NEW
217
    emit critical(tr("Cannot update"),
×
NEW
218
                  tr("Failed to open .gpg-id for writing."));
×
219
    return;
220
  }
221
  bool secret_selected = false;
NEW
222
  for (const UserInfo &user : users) {
×
NEW
223
    if (user.enabled) {
×
NEW
224
      gpgId.write((user.key_id + "\n").toUtf8());
×
NEW
225
      secret_selected |= user.have_secret;
×
226
    }
227
  }
NEW
228
  gpgId.close();
×
NEW
229
  if (!secret_selected) {
×
NEW
230
    emit critical(
×
NEW
231
        tr("Check selected users!"),
×
NEW
232
        tr("None of the selected keys have a secret key available.\n"
×
233
           "You will not be able to decrypt any newly added passwords!"));
234
  }
NEW
235
}
×
236

NEW
237
void ImitatePass::signGpgIdFile(const QString &gpgIdFile,
×
238
                                const QStringList &signingKeys) {
NEW
239
  QStringList args;
×
NEW
240
  for (auto &key : signingKeys) {
×
NEW
241
    args.append(QStringList{"--default-key", key});
×
242
  }
NEW
243
  args.append(QStringList{"--yes", "--detach-sign", gpgIdFile});
×
NEW
244
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args);
×
NEW
245
  if (!verifyGpgIdFile(gpgIdFile)) {
×
NEW
246
    emit critical(tr("Check .gpgid file signature!"),
×
NEW
247
                  tr("Signature for %1 is invalid.").arg(gpgIdFile));
×
248
  }
NEW
249
}
×
250

NEW
251
void ImitatePass::gitAddGpgId(const QString &gpgIdFile,
×
252
                              const QString &gpgIdSigFile, bool addFile,
253
                              bool addSigFile) {
NEW
254
  if (addFile) {
×
NEW
255
    executeGit(GIT_ADD, {"add", pgit(gpgIdFile)});
×
256
  }
257
  QString commitPath = gpgIdFile;
NEW
258
  commitPath.replace(Util::endsWithGpg(), "");
×
NEW
259
  GitCommit(gpgIdFile, "Added " + commitPath + " using QtPass.");
×
NEW
260
  if (!addSigFile) {
×
261
    return;
262
  }
NEW
263
  executeGit(GIT_ADD, {"add", pgit(gpgIdSigFile)});
×
NEW
264
  commitPath = gpgIdSigFile;
×
NEW
265
  commitPath.replace(QRegularExpression("\\.gpg$"), "");
×
NEW
266
  GitCommit(gpgIdSigFile, "Added " + commitPath + " using QtPass.");
×
NEW
267
}
×
268

UNCOV
269
void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
×
270
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
271
  QStringList signingKeys =
272
      QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
×
273
#else
274
  QStringList signingKeys =
275
      QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
276
#endif
277
  QString gpgIdSigFile = path + ".gpg-id.sig";
×
278
  bool addSigFile = false;
279
  if (!signingKeys.isEmpty()) {
×
NEW
280
    if (!checkSigningKeys(signingKeys)) {
×
UNCOV
281
      emit critical(tr("No signing key!"),
×
282
                    tr("None of the secret signing keys is available.\n"
×
283
                       "You will not be able to change the user list!"));
UNCOV
284
      return;
×
285
    }
286
    QFileInfo checkFile(gpgIdSigFile);
×
287
    if (!checkFile.exists() || !checkFile.isFile()) {
×
288
      addSigFile = true;
289
    }
290
  }
×
291

292
  QString gpgIdFile = path + ".gpg-id";
×
293
  bool addFile = false;
UNCOV
294
  transactionHelper trans(this, PASS_INIT);
×
295
  if (QtPassSettings::isAddGPGId(true)) {
×
296
    QFileInfo checkFile(gpgIdFile);
×
297
    if (!checkFile.exists() || !checkFile.isFile()) {
×
298
      addFile = true;
299
    }
300
  }
×
NEW
301
  writeGpgIdFile(gpgIdFile, users);
×
302

303
  if (!signingKeys.isEmpty()) {
×
NEW
304
    signGpgIdFile(gpgIdFile, signingKeys);
×
305
  }
306

307
  if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit() &&
×
308
      !QtPassSettings::getGitExecutable().isEmpty()) {
×
NEW
309
    gitAddGpgId(gpgIdFile, gpgIdSigFile, addFile, addSigFile);
×
310
  }
311
  reencryptPath(path);
×
312
}
313

314
/**
315
 * @brief ImitatePass::verifyGpgIdFile verify detached gpgid file signature.
316
 * @param file which gpgid file.
317
 * @return was verification succesful?
318
 */
319
auto ImitatePass::verifyGpgIdFile(const QString &file) -> bool {
×
320
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
321
  QStringList signingKeys =
322
      QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
×
323
#else
324
  QStringList signingKeys =
325
      QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
326
#endif
327
  if (signingKeys.isEmpty()) {
×
328
    return true;
329
  }
330
  QString out;
×
331
  QStringList args =
332
      QStringList{"--verify", "--status-fd=1", pgpg(file) + ".sig", pgpg(file)};
×
333
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
×
334
  QRegularExpression re(
335
      R"(^\[GNUPG:\] VALIDSIG ([A-F0-9]{40}) .* ([A-F0-9]{40})\r?$)",
336
      QRegularExpression::MultilineOption);
×
337
  QRegularExpressionMatch m = re.match(out);
×
338
  if (!m.hasMatch()) {
×
339
    return false;
340
  }
341
  QStringList fingerprints = m.capturedTexts();
×
342
  fingerprints.removeFirst();
×
343
  for (auto &key : signingKeys) {
×
344
    if (fingerprints.contains(key)) {
×
345
      return true;
×
346
    }
347
  }
348
  return false;
×
349
}
×
350

351
/**
352
 * @brief ImitatePass::removeDir delete folder recursive.
353
 * @param dirName which folder.
354
 * @return was removal succesful?
355
 */
356
auto ImitatePass::removeDir(const QString &dirName) -> bool {
1✔
357
  bool result = true;
358
  QDir dir(dirName);
1✔
359

360
  if (dir.exists(dirName)) {
1✔
361
    for (const QFileInfo &info :
362
         dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
363
                               QDir::AllDirs | QDir::Files,
364
                           QDir::DirsFirst)) {
1✔
365
      if (info.isDir()) {
×
366
        result = removeDir(info.absoluteFilePath());
×
367
      } else {
368
        result = QFile::remove(info.absoluteFilePath());
×
369
      }
370

371
      if (!result) {
×
372
        return result;
373
      }
374
    }
375
    result = dir.rmdir(dirName);
1✔
376
  }
377
  return result;
378
}
1✔
379

380
/**
381
 * @brief ImitatePass::reencryptPath reencrypt all files under the chosen
382
 * directory
383
 *
384
 * This is stil quite experimental..
385
 * @param dir
386
 */
NEW
387
void ImitatePass::verifyGpgIdForDir(const QString &file,
×
388
                                    QStringList &gpgIdFilesVerified,
389
                                    QStringList &gpgId) {
NEW
390
  QString gpgIdPath = Pass::getGpgIdPath(file);
×
NEW
391
  if (gpgIdFilesVerified.contains(gpgIdPath)) {
×
392
    return;
393
  }
NEW
394
  if (!verifyGpgIdFile(gpgIdPath)) {
×
NEW
395
    emit critical(tr("Check .gpgid file signature!"),
×
NEW
396
                  tr("Signature for %1 is invalid.").arg(gpgIdPath));
×
NEW
397
    emit endReencryptPath();
×
398
    return;
399
  }
400
  gpgIdFilesVerified.append(gpgIdPath);
NEW
401
  gpgId = getRecipientList(file);
×
402
  gpgId.sort();
403
}
404

NEW
405
auto ImitatePass::getKeysFromFile(const QString &fileName) -> QStringList {
×
406
  QStringList args = {
407
      "-v",          "--no-secmem-warning", "--no-permission-warning",
NEW
408
      "--list-only", "--keyid-format=long", pgpg(fileName)};
×
NEW
409
  QString keys;
×
NEW
410
  QString err;
×
NEW
411
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, &keys,
×
412
                            &err);
NEW
413
  QStringList actualKeys;
×
414
  keys += err;
415
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
NEW
416
  QStringList key = keys.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
×
417
#else
418
  QStringList key = keys.split(Util::newLinesRegex(), QString::SkipEmptyParts);
419
#endif
420
  QListIterator<QString> itr(key);
NEW
421
  while (itr.hasNext()) {
×
422
    QString current = itr.next();
NEW
423
    QStringList cur = current.split(" ");
×
NEW
424
    if (cur.length() > 4) {
×
NEW
425
      QString actualKey = cur.takeAt(4);
×
NEW
426
      if (actualKey.length() == 16) {
×
427
        actualKeys << actualKey;
428
      }
429
    }
430
  }
431
  actualKeys.sort();
NEW
432
  return actualKeys;
×
NEW
433
}
×
434

NEW
435
void ImitatePass::reencryptSingleFile(const QString &fileName,
×
436
                                      const QStringList &recipients) {
437
#ifdef QT_DEBUG
438
  dbg() << "reencrypt " << fileName << " for " << recipients;
439
#endif
NEW
440
  QString local_lastDecrypt = "Could not decrypt";
×
441
  QStringList args = {
442
      "-d",      "--quiet",     "--yes",       "--no-encrypt-to",
NEW
443
      "--batch", "--use-agent", pgpg(fileName)};
×
NEW
444
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
×
445
                            &local_lastDecrypt);
446

NEW
447
  if (local_lastDecrypt.isEmpty() || local_lastDecrypt == "Could not decrypt") {
×
448
#ifdef QT_DEBUG
449
    dbg() << "Decrypt error on re-encrypt";
450
#endif
NEW
451
    return;
×
452
  }
453

NEW
454
  if (local_lastDecrypt.right(1) != "\n") {
×
NEW
455
    local_lastDecrypt += "\n";
×
456
  }
457

NEW
458
  QStringList recipientsList = Pass::getRecipientList(fileName);
×
NEW
459
  if (recipientsList.isEmpty()) {
×
NEW
460
    emit critical(tr("Can not edit"),
×
NEW
461
                  tr("Could not read encryption key to use, .gpg-id "
×
462
                     "file missing or invalid."));
463
    return;
464
  }
NEW
465
  args = QStringList{"--yes", "--batch", "-eq", "--output", pgpg(fileName)};
×
NEW
466
  for (auto &i : recipientsList) {
×
NEW
467
    args.append("-r");
×
468
    args.append(i);
469
  }
NEW
470
  args.append("-");
×
NEW
471
  Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args,
×
472
                            local_lastDecrypt);
473

NEW
474
  if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit()) {
×
NEW
475
    Executor::executeBlocking(QtPassSettings::getGitExecutable(),
×
476
                              {"add", pgit(fileName)});
477
    QString path =
NEW
478
        QDir(QtPassSettings::getPassStore()).relativeFilePath(fileName);
×
NEW
479
    path.replace(Util::endsWithGpg(), "");
×
NEW
480
    Executor::executeBlocking(QtPassSettings::getGitExecutable(),
×
481
                              {"commit", pgit(fileName), "-m",
NEW
482
                               "Edit for " + path + " using QtPass."});
×
483
  }
NEW
484
}
×
485

486
void ImitatePass::reencryptPath(const QString &dir) {
×
487
  emit statusMsg(tr("Re-encrypting from folder %1").arg(dir), 3000);
×
488
  emit startReencryptPath();
×
489
  if (QtPassSettings::isAutoPull()) {
×
UNCOV
490
    emit statusMsg(tr("Updating password-store"), 2000);
×
491
    GitPull_b();
×
492
  }
493
  QDir currentDir;
×
494
  QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files,
×
495
                        QDirIterator::Subdirectories);
×
496
  QStringList gpgIdFilesVerified;
×
497
  QStringList gpgId;
×
498
  while (gpgFiles.hasNext()) {
×
499
    QString fileName = gpgFiles.next();
×
500
    if (gpgFiles.fileInfo().path() != currentDir.path()) {
×
NEW
501
      verifyGpgIdForDir(fileName, gpgIdFilesVerified, gpgId);
×
NEW
502
      if (gpgId.isEmpty() && !gpgIdFilesVerified.isEmpty()) {
×
503
        return;
504
      }
505
    }
NEW
506
    QStringList actualKeys = getKeysFromFile(fileName);
×
507
    if (actualKeys != gpgId) {
×
NEW
508
      reencryptSingleFile(fileName, gpgId);
×
509
    }
510
  }
511
  if (QtPassSettings::isAutoPush()) {
×
512
    emit statusMsg(tr("Updating password-store"), 2000);
×
UNCOV
513
    GitPush();
×
514
  }
515
  emit endReencryptPath();
×
516
}
×
517

518
auto ImitatePass::resolveMoveDestination(const QString &src,
4✔
519
                                         const QString &dest, bool force)
520
    -> QString {
521
  QFileInfo srcFileInfo(src);
4✔
522
  QFileInfo destFileInfo(dest);
4✔
523
  QString destFile;
4✔
524
  QString srcFileBaseName = srcFileInfo.fileName();
4✔
525

526
  if (srcFileInfo.isFile()) {
4✔
527
    if (destFileInfo.isFile()) {
2✔
528
      if (!force) {
1✔
529
#ifdef QT_DEBUG
530
        dbg() << "Destination file already exists";
531
#endif
532
        return QString();
533
      }
534
      destFile = dest;
1✔
535
    } else if (destFileInfo.isDir()) {
1✔
536
      destFile = QDir(dest).filePath(srcFileBaseName);
2✔
537
    } else {
538
      destFile = dest;
×
539
    }
540

541
    if (destFile.endsWith(".gpg", Qt::CaseInsensitive)) {
4✔
542
      destFile.chop(4);
2✔
543
    }
544
    destFile.append(".gpg");
2✔
545
  } else if (srcFileInfo.isDir()) {
2✔
546
    if (destFileInfo.isDir()) {
×
547
      destFile = QDir(dest).filePath(srcFileBaseName);
×
548
    } else if (destFileInfo.isFile()) {
×
549
#ifdef QT_DEBUG
550
      dbg() << "Destination is a file";
551
#endif
552
      return QString();
553
    } else {
554
      destFile = dest;
×
555
    }
556
  } else {
557
#ifdef QT_DEBUG
558
    dbg() << "Source file does not exist";
559
#endif
560
    return QString();
561
  }
562
  return destFile;
563
}
4✔
564

NEW
565
void ImitatePass::executeMoveGit(const QString &src, const QString &destFile,
×
566
                                 bool force) {
NEW
567
  QStringList args;
×
NEW
568
  args << "mv";
×
NEW
569
  if (force) {
×
NEW
570
    args << "-f";
×
571
  }
NEW
572
  args << pgit(src);
×
NEW
573
  args << pgit(destFile);
×
NEW
574
  executeGit(GIT_MOVE, args);
×
575

NEW
576
  QString relSrc = QDir(QtPassSettings::getPassStore()).relativeFilePath(src);
×
NEW
577
  relSrc.replace(Util::endsWithGpg(), "");
×
578
  QString relDest =
NEW
579
      QDir(QtPassSettings::getPassStore()).relativeFilePath(destFile);
×
NEW
580
  relDest.replace(Util::endsWithGpg(), "");
×
NEW
581
  QString message = QString("Moved for %1 to %2 using QtPass.");
×
NEW
582
  message = message.arg(relSrc, relDest);
×
NEW
583
  GitCommit("", message);
×
NEW
584
}
×
585

NEW
586
void ImitatePass::Move(const QString src, const QString dest,
×
587
                       const bool force) {
NEW
588
  transactionHelper trans(this, PASS_MOVE);
×
NEW
589
  QString destFile = resolveMoveDestination(src, dest, force);
×
NEW
590
  if (destFile.isEmpty()) {
×
591
    return;
592
  }
593

594
#ifdef QT_DEBUG
595
  dbg() << "Move Source: " << src;
596
  dbg() << "Move Destination: " << destFile;
597
#endif
598

599
  if (QtPassSettings::isUseGit()) {
×
NEW
600
    executeMoveGit(src, destFile, force);
×
601
  } else {
602
    QDir qDir;
×
603
    if (force) {
×
604
      qDir.remove(destFile);
×
605
    }
606
    qDir.rename(src, destFile);
×
607
  }
×
608
}
609

610
void ImitatePass::Copy(const QString src, const QString dest,
×
611
                       const bool force) {
612
  QFileInfo destFileInfo(dest);
×
613
  transactionHelper trans(this, PASS_COPY);
×
614
  if (QtPassSettings::isUseGit()) {
×
615
    QStringList args;
×
616
    args << "cp";
×
617
    if (force) {
×
618
      args << "-f";
×
619
    }
620
    args << pgit(src);
×
621
    args << pgit(dest);
×
622
    executeGit(GIT_COPY, args);
×
623

624
    QString message = QString("copied from %1 to %2 using QTPass.");
×
625
    message = message.arg(src, dest);
×
626
    GitCommit("", message);
×
627
  } else {
628
    QDir qDir;
×
629
    if (force) {
×
630
      qDir.remove(dest);
×
631
    }
632
    QFile::copy(src, dest);
×
633
  }
×
634
  // reecrypt all files under the new folder
635
  if (destFileInfo.isDir()) {
×
636
    reencryptPath(destFileInfo.absoluteFilePath());
×
637
  } else if (destFileInfo.isFile()) {
×
638
    reencryptPath(destFileInfo.dir().path());
×
639
  }
640
}
×
641

642
/**
643
 * @brief ImitatePass::executeGpg easy wrapper for running gpg commands
644
 * @param args
645
 */
646
void ImitatePass::executeGpg(PROCESS id, const QStringList &args, QString input,
×
647
                             bool readStdout, bool readStderr) {
648
  executeWrapper(id, QtPassSettings::getGpgExecutable(), args, std::move(input),
×
649
                 readStdout, readStderr);
650
}
×
651
/**
652
 * @brief ImitatePass::executeGit easy wrapper for running git commands
653
 * @param args
654
 */
655
void ImitatePass::executeGit(PROCESS id, const QStringList &args, QString input,
×
656
                             bool readStdout, bool readStderr) {
657
  executeWrapper(id, QtPassSettings::getGitExecutable(), args, std::move(input),
×
658
                 readStdout, readStderr);
659
}
×
660

661
/**
662
 * @brief ImitatePass::finished this function is overloaded to ensure
663
 *                              identical behaviour to RealPass ie. only PASS_*
664
 *                              processes are visible inside Pass::finish, so
665
 *                              that interface-wise it all looks the same
666
 * @param id
667
 * @param exitCode
668
 * @param out
669
 * @param err
670
 */
671
void ImitatePass::finished(int id, int exitCode, const QString &out,
×
672
                           const QString &err) {
673
#ifdef QT_DEBUG
674
  dbg() << "Imitate Pass";
675
#endif
676
  static QString transactionOutput;
×
677
  PROCESS pid = transactionIsOver(static_cast<PROCESS>(id));
×
678
  transactionOutput.append(out);
×
679

680
  if (exitCode == 0) {
×
681
    if (pid == INVALID) {
×
682
      return;
683
    }
684
  } else {
685
    while (pid == INVALID) {
×
686
      id = exec.cancelNext();
×
687
      if (id == -1) {
×
688
        //  this is probably irrecoverable and shall not happen
689
#ifdef QT_DEBUG
690
        dbg() << "No such transaction!";
691
#endif
692
        return;
693
      }
694
      pid = transactionIsOver(static_cast<PROCESS>(id));
×
695
    }
696
  }
697
  Pass::finished(pid, exitCode, transactionOutput, err);
×
698
  transactionOutput.clear();
×
699
}
700

701
/**
702
 * @brief executeWrapper    overrided so that every execution is a transaction
703
 * @param id
704
 * @param app
705
 * @param args
706
 * @param input
707
 * @param readStdout
708
 * @param readStderr
709
 */
710
void ImitatePass::executeWrapper(PROCESS id, const QString &app,
×
711
                                 const QStringList &args, QString input,
712
                                 bool readStdout, bool readStderr) {
713
  transactionAdd(id);
×
714
  Pass::executeWrapper(id, app, args, input, readStdout, readStderr);
×
715
}
×
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