Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34135137
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
22 KB
Subscribers
None
View Options
diff --git a/src/crypto/signencrypttask.cpp b/src/crypto/signencrypttask.cpp
index 358a31100..710248915 100644
--- a/src/crypto/signencrypttask.cpp
+++ b/src/crypto/signencrypttask.cpp
@@ -1,685 +1,691 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/signencrypttask.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "signencrypttask.h"
#include <utils/input.h>
#include <utils/output.h>
#include <utils/path-helper.h>
#include <utils/kleo_assert.h>
#include <Libkleo/AuditLogEntry>
#include <Libkleo/Formatting>
#include <Libkleo/Stl_Util>
#include <Libkleo/KleoException>
#include <QGpgME/Protocol>
#include <QGpgME/SignJob>
#include <QGpgME/SignEncryptJob>
#include <QGpgME/EncryptJob>
#include <gpgme++/signingresult.h>
#include <gpgme++/encryptionresult.h>
#include <gpgme++/key.h>
#include <KLocalizedString>
#include "kleopatra_debug.h"
#include <QPointer>
#include <QTextDocument> // for Qt::escape
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace GpgME;
namespace
{
QString formatInputOutputLabel(const QString &input, const QString &output, bool outputDeleted)
{
return i18nc("Input file --> Output file (rarr is arrow", "%1 → %2",
input.toHtmlEscaped(),
outputDeleted ? QStringLiteral("<s>%1</s>").arg(output.toHtmlEscaped()) : output.toHtmlEscaped());
}
class ErrorResult : public Task::Result
{
public:
ErrorResult(bool sign, bool encrypt, const Error &err, const QString &errStr, const QString &input, const QString &output, const AuditLogEntry &auditLog)
: Task::Result(), m_sign(sign), m_encrypt(encrypt), m_error(err), m_errString(errStr), m_inputLabel(input), m_outputLabel(output), m_auditLog(auditLog) {}
QString overview() const override;
QString details() const override;
GpgME::Error error() const override
{
return m_error;
}
QString errorString() const override
{
return m_errString;
}
VisualCode code() const override
{
return NeutralError;
}
AuditLogEntry auditLog() const override
{
return m_auditLog;
}
private:
const bool m_sign;
const bool m_encrypt;
const Error m_error;
const QString m_errString;
const QString m_inputLabel;
const QString m_outputLabel;
const AuditLogEntry m_auditLog;
};
class SignEncryptFilesResult : public Task::Result
{
public:
SignEncryptFilesResult(const SigningResult &sr, const std::shared_ptr<Input> &input, const std::shared_ptr<Output> &output, bool outputCreated, const AuditLogEntry &auditLog)
: Task::Result(),
m_sresult(sr),
m_inputLabel(input ? input->label() : QString()),
m_inputErrorString(input ? input->errorString() : QString()),
m_outputLabel(output ? output->label() : QString()),
m_outputErrorString(output ? output->errorString() : QString()),
m_outputCreated(outputCreated),
m_auditLog(auditLog)
{
qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString
<< "\noutputError:" << m_outputErrorString;
Q_ASSERT(!m_sresult.isNull());
}
SignEncryptFilesResult(const EncryptionResult &er, const std::shared_ptr<Input> &input, const std::shared_ptr<Output> &output, bool outputCreated, const AuditLogEntry &auditLog)
: Task::Result(),
m_eresult(er),
m_inputLabel(input ? input->label() : QString()),
m_inputErrorString(input ? input->errorString() : QString()),
m_outputLabel(output ? output->label() : QString()),
m_outputErrorString(output ? output->errorString() : QString()),
m_outputCreated(outputCreated),
m_auditLog(auditLog)
{
qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString
<< "\noutputError:" << m_outputErrorString;
Q_ASSERT(!m_eresult.isNull());
}
SignEncryptFilesResult(const SigningResult &sr, const EncryptionResult &er, const std::shared_ptr<Input> &input, const std::shared_ptr<Output> &output, bool outputCreated, const AuditLogEntry &auditLog)
: Task::Result(),
m_sresult(sr),
m_eresult(er),
m_inputLabel(input ? input->label() : QString()),
m_inputErrorString(input ? input->errorString() : QString()),
m_outputLabel(output ? output->label() : QString()),
m_outputErrorString(output ? output->errorString() : QString()),
m_outputCreated(outputCreated),
m_auditLog(auditLog)
{
qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString
<< "\noutputError:" << m_outputErrorString;
Q_ASSERT(!m_sresult.isNull() || !m_eresult.isNull());
}
QString overview() const override;
QString details() const override;
GpgME::Error error() const override;
QString errorString() const override;
VisualCode code() const override;
AuditLogEntry auditLog() const override;
private:
const SigningResult m_sresult;
const EncryptionResult m_eresult;
const QString m_inputLabel;
const QString m_inputErrorString;
const QString m_outputLabel;
const QString m_outputErrorString;
const bool m_outputCreated;
const AuditLogEntry m_auditLog;
};
static QString makeSigningOverview(const Error &err)
{
if (err.isCanceled()) {
return i18n("Signing canceled.");
}
if (err) {
return i18n("Signing failed.");
}
return i18n("Signing succeeded.");
}
static QString makeResultOverview(const SigningResult &result)
{
return makeSigningOverview(result.error());
}
static QString makeEncryptionOverview(const Error &err)
{
if (err.isCanceled()) {
return i18n("Encryption canceled.");
}
if (err) {
return i18n("Encryption failed.");
}
return i18n("Encryption succeeded.");
}
static QString makeResultOverview(const EncryptionResult &result)
{
return makeEncryptionOverview(result.error());
}
static QString makeResultOverview(const SigningResult &sr, const EncryptionResult &er)
{
if (er.isNull() && sr.isNull()) {
return QString();
}
if (er.isNull()) {
return makeResultOverview(sr);
}
if (sr.isNull()) {
return makeResultOverview(er);
}
if (sr.error().isCanceled() || sr.error()) {
return makeResultOverview(sr);
}
if (er.error().isCanceled() || er.error()) {
return makeResultOverview(er);
}
return i18n("Signing and encryption succeeded.");
}
static QString escape(QString s)
{
s = s.toHtmlEscaped();
s.replace(QLatin1Char('\n'), QStringLiteral("<br>"));
return s;
}
static QString makeResultDetails(const SigningResult &result, const QString &inputError, const QString &outputError)
{
const Error err = result.error();
if (err.code() == GPG_ERR_EIO) {
if (!inputError.isEmpty()) {
return i18n("Input error: %1", escape(inputError));
} else if (!outputError.isEmpty()) {
return i18n("Output error: %1", escape(outputError));
}
}
if (err || err.isCanceled()) {
return QString::fromLocal8Bit(err.asString()).toHtmlEscaped();
}
return QString();
}
static QString makeResultDetails(const EncryptionResult &result, const QString &inputError, const QString &outputError)
{
const Error err = result.error();
if (err.code() == GPG_ERR_EIO) {
if (!inputError.isEmpty()) {
return i18n("Input error: %1", escape(inputError));
} else if (!outputError.isEmpty()) {
return i18n("Output error: %1", escape(outputError));
}
}
if (err || err.isCanceled()) {
return QString::fromLocal8Bit(err.asString()).toHtmlEscaped();
}
return i18n(" Encryption succeeded.");
}
}
QString ErrorResult::overview() const
{
Q_ASSERT(m_error || m_error.isCanceled());
Q_ASSERT(m_sign || m_encrypt);
const QString label = formatInputOutputLabel(m_inputLabel, m_outputLabel, true);
const bool canceled = m_error.isCanceled();
if (m_sign && m_encrypt) {
return canceled ? i18n("%1: <b>Sign/encrypt canceled.</b>", label) : i18n(" %1: Sign/encrypt failed.", label);
}
return i18nc("label: result. Example: foo -> foo.gpg: Encryption failed.", "%1: <b>%2</b>", label,
m_sign ? makeSigningOverview(m_error) : makeEncryptionOverview(m_error));
}
QString ErrorResult::details() const
{
return m_errString;
}
class SignEncryptTask::Private
{
friend class ::Kleo::Crypto::SignEncryptTask;
SignEncryptTask *const q;
public:
explicit Private(SignEncryptTask *qq);
private:
std::unique_ptr<QGpgME::SignJob> createSignJob(GpgME::Protocol proto);
std::unique_ptr<QGpgME::SignEncryptJob> createSignEncryptJob(GpgME::Protocol proto);
std::unique_ptr<QGpgME::EncryptJob> createEncryptJob(GpgME::Protocol proto);
std::shared_ptr<const Task::Result> makeErrorResult(const Error &err, const QString &errStr, const AuditLogEntry &auditLog);
private:
void slotResult(const SigningResult &);
void slotResult(const SigningResult &, const EncryptionResult &);
void slotResult(const EncryptionResult &);
private:
std::shared_ptr<Input> input;
std::shared_ptr<Output> output;
QStringList inputFileNames;
QString outputFileName;
std::vector<Key> signers;
std::vector<Key> recipients;
bool sign : 1;
bool encrypt : 1;
bool detached : 1;
bool symmetric: 1;
bool clearsign: 1;
QPointer<QGpgME::Job> job;
std::shared_ptr<OverwritePolicy> m_overwritePolicy;
};
SignEncryptTask::Private::Private(SignEncryptTask *qq)
: q{qq}
, sign{true}
, encrypt{true}
, detached{false}
, clearsign{false}
, m_overwritePolicy{new OverwritePolicy{nullptr}}
{
q->setAsciiArmor(true);
}
std::shared_ptr<const Task::Result> SignEncryptTask::Private::makeErrorResult(const Error &err, const QString &errStr, const AuditLogEntry &auditLog)
{
- return std::shared_ptr<const ErrorResult>(new ErrorResult(sign, encrypt, err, errStr, input->label(), output->label(), auditLog));
+ return std::shared_ptr<const ErrorResult>(new ErrorResult(sign, encrypt, err, errStr, input ? input->label() : QString{}, output ? output->label() : QString{}, auditLog));
}
SignEncryptTask::SignEncryptTask(QObject *p)
: Task(p), d(new Private(this))
{
}
SignEncryptTask::~SignEncryptTask() {}
void SignEncryptTask::setInputFileName(const QString &fileName)
{
kleo_assert(!d->job);
kleo_assert(!fileName.isEmpty());
d->inputFileNames = QStringList(fileName);
}
void SignEncryptTask::setInputFileNames(const QStringList &fileNames)
{
kleo_assert(!d->job);
kleo_assert(!fileNames.empty());
d->inputFileNames = fileNames;
}
void SignEncryptTask::setInput(const std::shared_ptr<Input> &input)
{
kleo_assert(!d->job);
kleo_assert(input);
d->input = input;
}
void SignEncryptTask::setOutput(const std::shared_ptr<Output> &output)
{
kleo_assert(!d->job);
kleo_assert(output);
d->output = output;
}
void SignEncryptTask::setOutputFileName(const QString &fileName)
{
kleo_assert(!d->job);
kleo_assert(!fileName.isEmpty());
d->outputFileName = fileName;
}
void SignEncryptTask::setSigners(const std::vector<Key> &signers)
{
kleo_assert(!d->job);
d->signers = signers;
}
void SignEncryptTask::setRecipients(const std::vector<Key> &recipients)
{
kleo_assert(!d->job);
d->recipients = recipients;
}
void SignEncryptTask::setOverwritePolicy(const std::shared_ptr<OverwritePolicy> &policy)
{
kleo_assert(!d->job);
d->m_overwritePolicy = policy;
}
void SignEncryptTask::setSign(bool sign)
{
kleo_assert(!d->job);
d->sign = sign;
}
void SignEncryptTask::setEncrypt(bool encrypt)
{
kleo_assert(!d->job);
d->encrypt = encrypt;
}
void SignEncryptTask::setDetachedSignature(bool detached)
{
kleo_assert(!d->job);
d->detached = detached;
}
void SignEncryptTask::setEncryptSymmetric(bool symmetric)
{
kleo_assert(!d->job);
d->symmetric = symmetric;
}
void SignEncryptTask::setClearsign(bool clearsign)
{
kleo_assert(!d->job);
d->clearsign = clearsign;
}
Protocol SignEncryptTask::protocol() const
{
if (d->sign && !d->signers.empty()) {
return d->signers.front().protocol();
}
if (d->encrypt || d->symmetric) {
if (!d->recipients.empty()) {
return d->recipients.front().protocol();
} else {
return GpgME::OpenPGP; // symmetric OpenPGP encryption
}
}
throw Kleo::Exception(gpg_error(GPG_ERR_INTERNAL),
i18n("Cannot determine protocol for task"));
}
QString SignEncryptTask::label() const
{
return d->input ? d->input->label() : QString();
}
QString SignEncryptTask::tag() const
{
return Formatting::displayName(protocol());
}
unsigned long long SignEncryptTask::inputSize() const
{
return d->input ? d->input->size() : 0U;
}
void SignEncryptTask::doStart()
{
kleo_assert(!d->job);
if (d->sign) {
kleo_assert(!d->signers.empty());
}
kleo_assert(d->input);
if (!d->output) {
d->output = Output::createFromFile(d->outputFileName, d->m_overwritePolicy);
}
if (d->encrypt || d->symmetric) {
Context::EncryptionFlags flags = Context::AlwaysTrust;
if (d->symmetric) {
flags = static_cast<Context::EncryptionFlags>(flags | Context::Symmetric);
qCDebug(KLEOPATRA_LOG) << "Adding symmetric flag";
}
if (d->sign) {
std::unique_ptr<QGpgME::SignEncryptJob> job = d->createSignEncryptJob(protocol());
kleo_assert(job.get());
#if QGPGME_SUPPORTS_SET_FILENAME
if (d->inputFileNames.size() == 1) {
job->setFileName(d->inputFileNames.front());
}
#endif
job->start(d->signers, d->recipients,
d->input->ioDevice(), d->output->ioDevice(), flags);
d->job = job.release();
} else {
std::unique_ptr<QGpgME::EncryptJob> job = d->createEncryptJob(protocol());
kleo_assert(job.get());
#if QGPGME_SUPPORTS_SET_FILENAME
if (d->inputFileNames.size() == 1) {
job->setFileName(d->inputFileNames.front());
}
#endif
job->start(d->recipients, d->input->ioDevice(), d->output->ioDevice(), flags);
d->job = job.release();
}
} else if (d->sign) {
std::unique_ptr<QGpgME::SignJob> job = d->createSignJob(protocol());
kleo_assert(job.get());
kleo_assert(! (d->detached && d->clearsign));
job->start(d->signers,
d->input->ioDevice(), d->output->ioDevice(),
d->detached ? GpgME::Detached : d->clearsign ?
GpgME::Clearsigned : GpgME::NormalSignatureMode);
d->job = job.release();
} else {
kleo_assert(!"Either 'sign' or 'encrypt' or 'symmetric' must be set!");
}
}
void SignEncryptTask::cancel()
{
if (d->job) {
d->job->slotCancel();
}
}
std::unique_ptr<QGpgME::SignJob> SignEncryptTask::Private::createSignJob(GpgME::Protocol proto)
{
const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
kleo_assert(backend);
std::unique_ptr<QGpgME::SignJob> signJob(backend->signJob(q->asciiArmor(), /*textmode=*/false));
kleo_assert(signJob.get());
connect(signJob.get(), SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)));
connect(signJob.get(), SIGNAL(result(GpgME::SigningResult,QByteArray)),
q, SLOT(slotResult(GpgME::SigningResult)));
return signJob;
}
std::unique_ptr<QGpgME::SignEncryptJob> SignEncryptTask::Private::createSignEncryptJob(GpgME::Protocol proto)
{
const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
kleo_assert(backend);
std::unique_ptr<QGpgME::SignEncryptJob> signEncryptJob(backend->signEncryptJob(q->asciiArmor(), /*textmode=*/false));
kleo_assert(signEncryptJob.get());
connect(signEncryptJob.get(), SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)));
connect(signEncryptJob.get(), SIGNAL(result(GpgME::SigningResult,GpgME::EncryptionResult,QByteArray)),
q, SLOT(slotResult(GpgME::SigningResult,GpgME::EncryptionResult)));
return signEncryptJob;
}
std::unique_ptr<QGpgME::EncryptJob> SignEncryptTask::Private::createEncryptJob(GpgME::Protocol proto)
{
const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
kleo_assert(backend);
std::unique_ptr<QGpgME::EncryptJob> encryptJob(backend->encryptJob(q->asciiArmor(), /*textmode=*/false));
kleo_assert(encryptJob.get());
connect(encryptJob.get(), SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)));
connect(encryptJob.get(), SIGNAL(result(GpgME::EncryptionResult,QByteArray)),
q, SLOT(slotResult(GpgME::EncryptionResult)));
return encryptJob;
}
void SignEncryptTask::Private::slotResult(const SigningResult &result)
{
const auto *const job = qobject_cast<const QGpgME::Job *>(q->sender());
const AuditLogEntry auditLog = AuditLogEntry::fromJob(job);
bool outputCreated = false;
- if (input->failed()) {
+ if (input && input->failed()) {
q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO),
i18n("Input error: %1", escape( input->errorString())),
auditLog));
return;
} else if (result.error().code()) {
output->cancel();
} else {
try {
kleo_assert(!result.isNull());
output->finalize();
outputCreated = true;
- input->finalize();
+ if (input) {
+ input->finalize();
+ }
} catch (const GpgME::Exception &e) {
q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
return;
}
}
q->emitResult(std::shared_ptr<Result>(new SignEncryptFilesResult(result, input, output, outputCreated, auditLog)));
}
void SignEncryptTask::Private::slotResult(const SigningResult &sresult, const EncryptionResult &eresult)
{
const auto *const job = qobject_cast<const QGpgME::Job *>(q->sender());
const AuditLogEntry auditLog = AuditLogEntry::fromJob(job);
bool outputCreated = false;
- if (input->failed()) {
+ if (input && input->failed()) {
output->cancel();
q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO),
i18n("Input error: %1", escape( input->errorString())),
auditLog));
return;
} else if (sresult.error().code() || eresult.error().code()) {
output->cancel();
} else {
try {
kleo_assert(!sresult.isNull() || !eresult.isNull());
output->finalize();
outputCreated = true;
- input->finalize();
+ if (input) {
+ input->finalize();
+ }
} catch (const GpgME::Exception &e) {
q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
return;
}
}
q->emitResult(std::shared_ptr<Result>(new SignEncryptFilesResult(sresult, eresult, input, output, outputCreated, auditLog)));
}
void SignEncryptTask::Private::slotResult(const EncryptionResult &result)
{
const auto *const job = qobject_cast<const QGpgME::Job *>(q->sender());
const AuditLogEntry auditLog = AuditLogEntry::fromJob(job);
bool outputCreated = false;
- if (input->failed()) {
+ if (input && input->failed()) {
output->cancel();
q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO),
i18n("Input error: %1", escape(input->errorString())),
auditLog));
return;
} else if (result.error().code()) {
output->cancel();
} else {
try {
kleo_assert(!result.isNull());
output->finalize();
outputCreated = true;
- input->finalize();
+ if (input) {
+ input->finalize();
+ }
} catch (const GpgME::Exception &e) {
q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
return;
}
}
q->emitResult(std::shared_ptr<Result>(new SignEncryptFilesResult(result, input, output, outputCreated, auditLog)));
}
QString SignEncryptFilesResult::overview() const
{
const QString files = formatInputOutputLabel(m_inputLabel, m_outputLabel, !m_outputCreated);
return files + QLatin1String(": ") + makeOverview(makeResultOverview(m_sresult, m_eresult));
}
QString SignEncryptFilesResult::details() const
{
return errorString();
}
GpgME::Error SignEncryptFilesResult::error() const
{
if (m_sresult.error().code()) {
return m_sresult.error();
}
if (m_eresult.error().code()) {
return m_eresult.error();
}
return {};
}
QString SignEncryptFilesResult::errorString() const
{
const bool sign = !m_sresult.isNull();
const bool encrypt = !m_eresult.isNull();
kleo_assert(sign || encrypt);
if (sign && encrypt) {
return
m_sresult.error().code() ? makeResultDetails(m_sresult, m_inputErrorString, m_outputErrorString) :
m_eresult.error().code() ? makeResultDetails(m_eresult, m_inputErrorString, m_outputErrorString) :
QString();
}
return
sign ? makeResultDetails(m_sresult, m_inputErrorString, m_outputErrorString) :
/*else*/ makeResultDetails(m_eresult, m_inputErrorString, m_outputErrorString);
}
Task::Result::VisualCode SignEncryptFilesResult::code() const
{
if (m_sresult.error().isCanceled() || m_eresult.error().isCanceled()) {
return Warning;
}
return (m_sresult.error().code() || m_eresult.error().code()) ? NeutralError : NeutralSuccess;
}
AuditLogEntry SignEncryptFilesResult::auditLog() const
{
return m_auditLog;
}
#include "moc_signencrypttask.cpp"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 8, 10:57 AM (3 h, 52 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
fc/87/af8a0c91e837fa755c75f7a8fb7f
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment