* @brief Re-encrypts a single encrypted file for a new set of recipients. * @example * bool result = ImitatePass::reencryptSingleFile(fileName, recipients); * std::cout << result << std::endl; // Expected output: true on success, false * on failure * * @param const QString &fileName - Path to the encrypted file to re-encrypt. * @param const QStringList &recipients - List of recipient keys t
| 571 | * verified, and replaced; otherwise false. |
| 572 | */ |
| 573 | auto ImitatePass::reencryptSingleFile(const QString &fileName, |
| 574 | const QStringList &recipients) -> bool { |
| 575 | #ifdef QT_DEBUG |
| 576 | dbg() << "reencrypt " << fileName << " for " << recipients; |
| 577 | #endif |
| 578 | QString local_lastDecrypt; |
| 579 | QStringList args = { |
| 580 | "-d", "--quiet", "--yes", "--no-encrypt-to", |
| 581 | "--batch", "--use-agent", pgpg(fileName)}; |
| 582 | int result = Executor::executeBlocking(QtPassSettings::getGpgExecutable(), |
| 583 | args, &local_lastDecrypt); |
| 584 | |
| 585 | if (result != 0 || local_lastDecrypt.isEmpty()) { |
| 586 | #ifdef QT_DEBUG |
| 587 | dbg() << "Decrypt error on re-encrypt for:" << fileName; |
| 588 | #endif |
| 589 | return false; |
| 590 | } |
| 591 | |
| 592 | if (local_lastDecrypt.right(1) != "\n") { |
| 593 | local_lastDecrypt += "\n"; |
| 594 | } |
| 595 | |
| 596 | // Use passed recipients instead of re-reading from file |
| 597 | if (recipients.isEmpty()) { |
| 598 | emit critical(tr("Can not edit"), |
| 599 | tr("Could not read encryption key to use, .gpg-id " |
| 600 | "file missing or invalid.")); |
| 601 | return false; |
| 602 | } |
| 603 | |
| 604 | // Encrypt to temporary file for atomic replacement |
| 605 | QString tempPath = fileName + ".reencrypt.tmp"; |
| 606 | args = QStringList{"--yes", "--batch", "-eq", "--output", pgpg(tempPath)}; |
| 607 | for (const auto &i : recipients) { |
| 608 | args.append("-r"); |
| 609 | args.append(i); |
| 610 | } |
| 611 | args.append("-"); |
| 612 | result = Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, |
| 613 | local_lastDecrypt); |
| 614 | |
| 615 | if (result != 0) { |
| 616 | #ifdef QT_DEBUG |
| 617 | dbg() << "Encrypt error on re-encrypt for:" << fileName; |
| 618 | #endif |
| 619 | QFile::remove(tempPath); |
| 620 | return false; |
| 621 | } |
| 622 | |
| 623 | // Verify encryption worked by attempting to decrypt the temp file |
| 624 | QString verifyOutput; |
| 625 | args = QStringList{"-d", "--quiet", "--batch", "--use-agent", pgpg(tempPath)}; |
| 626 | result = Executor::executeBlocking(QtPassSettings::getGpgExecutable(), args, |
| 627 | &verifyOutput); |
| 628 | if (result != 0 || verifyOutput.isEmpty()) { |
| 629 | #ifdef QT_DEBUG |
| 630 | dbg() << "Verification failed for:" << tempPath; |