diff --git a/doc/index.docbook b/doc/index.docbook index 5ee9b99..7dfa11b 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -1,140 +1,146 @@ Symmy"> ]> The &symmy; Handbook ElvisAngelaccio
elvis.angelaccio@kde.org
2017 Elvis Angelaccio 2017-11-23 &symmy; 0.70 &FDLNotice; &symmy; is a frontend for the symmetric encryption functionality of GPG. KDE encryption
Introduction &symmy; is a simple command-line application that can be used to encrypt or decrypt one or more files using the symmetric encryption functionality of GPG. A file encrypted by &symmy; can be decrypted by anyone who has access to the GPG program and the encryption key. &symmy; can also be used from Dolphin or Plasma Folder View thanks to the Encrypt and Decrypt items in the context menu. Usage Encrypt Files You can encrypt one or more files by selecting them in Dolphin or Plasma Folder View and clicking the Encrypt entry in the context menu. Note that you cannot encrypt a folder. If you need to do that, you should compress the folder and then encrypt the resulting archive. It's also not possible to encrypt remote files or files that are already encrypted. Choose an Encryption Key &symmy; will ask you a password (or passphrase) that will be used as encryption key for all the selected files. You should choose a strong encryption key and you should store it in a secure place (such as a password manager). If you need to send the key to another person, you should do so over a secure channel (for example, by meeting in person). + + GPG Requirement + + &symmy; uses GPG to perform the actual encryption, so it assumes that the gpg-agent process is running and properly configured. + + Manage an Encryption Operation The encryption operation will take some time depending on the number of files and on their size. You can track the progress of the operation from the notification applet provided by Plasma. From the notification plasmoid you can also abort the encryption operation if necessary. Decrypt Files You can decrypt one or more encrypted files by selecting them in Dolphin or Plasma Folder View and clicking the Decrypt entry in the context menu. Note that this entry will be visibile only when selecting encrypted files. Type the Decryption Key To decrypt the selected files, &symmy; will ask you the password or passphrase that was used as encryption key. Remember that symmetric encryption means that encryption and decryption keys are the same. &symmy; assumes that all the selected files have been encrypted using the same key. If that's not the case, it will fail to decrypt one or more files and it will tell you at the end of the decryption operation. Manage a Decryption Operation The decryption operation will take some time depending on the number of files and on their size. You can track the progress of the operation from the notification applet provided by Plasma. From the notification plasmoid you can also abort the decryption operation if necessary. Credits and License &symmy; Program copyright © 2017 Elvis Angelaccio elvis.angelaccio@kde.org Documentation copyright © 2017 Elvis Angelaccio elvis.angelaccio@kde.org &underFDL; &underGPL; &documentation.index;
diff --git a/src/compositejob.cpp b/src/compositejob.cpp index bd4e72e..2f42cf6 100644 --- a/src/compositejob.cpp +++ b/src/compositejob.cpp @@ -1,183 +1,186 @@ /* * Copyright (C) 2017 Elvis Angelaccio * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "compositejob.h" #include "decryptjob.h" #include "encryptjob.h" #include "symmydebug.h" #include #include #include #include #include #include namespace Symmy { CompositeJob::CompositeJob(const QStringList &filenames, Task task) : KCompositeJob {} , m_filenames {filenames} , m_task {task} { setCapabilities(Killable); KIO::getJobTracker()->registerJob(this); } CompositeJob::~CompositeJob() { } void CompositeJob::start() { QTimer::singleShot(0, this, &CompositeJob::slotStart); } bool CompositeJob::doKill() { if (!hasSubjobs()) { return false; } return subjobs().at(0)->kill(); } void CompositeJob::slotResult(KJob *job) { - if (job->error() and task() == Task::Decryption) { - qCDebug(SYMMY) << "Job failed with code" << job->error() << "and error" << job->errorText(); - auto decryptJob = qobject_cast(job); + if (job->error() == KJob::UserDefinedError) { + qCDebug(SYMMY) << "Job failed:" << job->errorText(); + if (task() == Task::Encryption) { + setError(KJob::UserDefinedError); + KMessageBox::error(nullptr, xi18nc("@info", "Encryption operation failed. Please check whether the gpg-agent process is running.")); + emitResult(); + return; + } - if (decryptJob and decryptJob->error() != KJob::KilledJobError) { + auto decryptJob = qobject_cast(job); + if (decryptJob) { qCDebug(SYMMY) << "Subjob failed to decrypt" << decryptJob->ciphertextFilename(); m_failedDecryptions << decryptJob->ciphertextFilename(); } } removeSubjob(job); if (hasSubjobs()) { qCDebug(SYMMY) << "Starting next subjob..."; startSubjob(); return; } qCDebug(SYMMY) << "Composite job finished"; if (!m_failedDecryptions.isEmpty()) { - if (m_failedDecryptions.size() == 1) { - KMessageBox::error(nullptr, xi18nc("@info", "Could not decrypt the following ciphertext:%1", m_failedDecryptions.at(0))); - } else { - KMessageBox::errorList(nullptr, i18n("Could not decrypt the following ciphertexts:"), m_failedDecryptions); - } - // Nothing was decrypted, mark the composite job as failed. if (m_failedDecryptions.size() == filenames().size()) { setError(KJob::UserDefinedError); - setErrorText(i18n("Wrong decryption key.")); + KMessageBox::error(nullptr, xi18nc("@info", "Decryption operation failed. Please check whether the decryption key is correct." + "You should also check whether the gpg-agent process is running.")); + } else { + KMessageBox::errorList(nullptr, xi18nc("@info", "Could not decrypt the following ciphertexts.Please check whether the decryption key is correct."), m_failedDecryptions); } } emitResult(); } void CompositeJob::slotAccepted() { for (const auto &filename : filenames()) { Symmy::Job *job = nullptr; if (task() == Task::Encryption) { job = new Symmy::EncryptJob(m_passwordDialog->password(), filename); } else { job = new Symmy::DecryptJob(m_passwordDialog->password(), filename); } addSubjob(job); connect(job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(slotPercent(KJob*, unsigned long))); } qCDebug(SYMMY) << "Got a passphrase, starting first subjob..."; startSubjob(); } void CompositeJob::slotRejected() { qCDebug(SYMMY) << "Passphrase dialog rejected."; setError(KilledJobError); emitResult(); } void CompositeJob::slotStart() { if (filenames().isEmpty()) { emitResult(); return; } qCDebug(SYMMY) << "Starting composite job..."; emit description(this, i18n("Asking Passphrase")); m_passwordDialog = new KPasswordDialog {}; if (task() == Task::Encryption) { m_passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as encryption key.")); } else { m_passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as decryption key.")); } connect(m_passwordDialog, &QDialog::accepted, this, &CompositeJob::slotAccepted); connect(m_passwordDialog, &QDialog::rejected, this, &CompositeJob::slotRejected); connect(m_passwordDialog, &QDialog::finished, m_passwordDialog, &QObject::deleteLater); m_passwordDialog->open(); } void CompositeJob::slotPercent(KJob *, unsigned long percent) { setPercent(percent); } void CompositeJob::startSubjob() { auto job = qobject_cast(subjobs().at(0)); if (task() == Task::Encryption) { emit description(this, i18nc("description of an encryption job", "Encrypting"), qMakePair(i18nc("File used as input of the encryption algorithm", "Plaintext"), job->plaintextFilename()), qMakePair(i18nc("File created by the encryption algorithm", "Ciphertext"), job->ciphertextFilename())); } else { emit description(this, i18nc("description of a decryption job", "Decrypting"), qMakePair(i18nc("File used as input of the decryption algorithm", "Ciphertext"), job->ciphertextFilename()), qMakePair(i18nc("File created by the decryption algorithm", "Plaintext"), job->plaintextFilename())); } job->start(); } QStringList CompositeJob::filenames() const { return m_filenames; } CompositeJob::Task CompositeJob::task() const { return m_task; } } diff --git a/src/encryptjob.cpp b/src/encryptjob.cpp index d5c7ebc..402995d 100644 --- a/src/encryptjob.cpp +++ b/src/encryptjob.cpp @@ -1,103 +1,103 @@ /* * Copyright (C) 2017 Elvis Angelaccio * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "encryptjob.h" #include "symmydebug.h" #include #include #include #include #include using namespace GpgME; using namespace QGpgME; namespace Symmy { EncryptJob::EncryptJob(const QString &passphrase, const QString &plaintextFilename) : Job {passphrase} { m_plaintext = std::make_shared(plaintextFilename); m_ciphertext = std::make_shared(ciphertextFilename()); } EncryptJob::~EncryptJob() { } QString EncryptJob::ciphertextFilename() const { return QStringLiteral("%1.gpg").arg(plaintextFilename()); } QString EncryptJob::plaintextFilename() const { return m_plaintext->fileName(); } void EncryptJob::doWork() { if (not m_plaintext->open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { qCDebug(SYMMY) << "Could not open plaintext file" << m_plaintext->fileName(); emitResult(); return; } if (not m_ciphertext->open()) { qCDebug(SYMMY) << "Could not open ciphertext file" << m_ciphertext->fileName(); emitResult(); return; } auto encryptJob = openpgp()->encryptJob(false, false); auto context = QGpgME::Job::context(encryptJob); context->setPassphraseProvider(this); context->setPinentryMode(GpgME::Context::PinentryLoopback); setJob(encryptJob); connect(encryptJob, &QGpgME::EncryptJob::result, this, &EncryptJob::slotResult); connect(encryptJob, &QGpgME::EncryptJob::progress, this, [this](const QString &, int current, int total) { const auto ratio = static_cast(current) / total; setPercent(static_cast(100 * ratio)); }); encryptJob->start({}, m_plaintext, m_ciphertext, Context::None); } void EncryptJob::slotResult(const EncryptionResult &, const QByteArray &, const QString &, const Error &) { qCDebug(SYMMY) << "Encryption job finished, ciphertext size:" << m_ciphertext->size(); if (m_ciphertext->size() == 0) { - setError(KilledJobError); + setError(UserDefinedError); emitResult(); return; } auto job = KIO::move(QUrl::fromLocalFile(m_ciphertext->fileName()), QUrl::fromLocalFile(ciphertextFilename())); connect(job, &KJob::result, this, &EncryptJob::emitResult); } }