aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Klöcker <[email protected]>2024-06-18 14:36:40 +0000
committerIngo Klöcker <[email protected]>2024-06-18 14:36:40 +0000
commit7d5df0bf0d86391151911160db24441966b6d938 (patch)
tree8bff5499ec7b3492710e525d0ed33844ad9a4c9e
parentqt,build: Install headers for Qt 5 and Qt 6 in different locations (diff)
downloadgpgme-7d5df0bf0d86391151911160db24441966b6d938.tar.gz
gpgme-7d5df0bf0d86391151911160db24441966b6d938.zip
qt: Allow appending a detached signature to an existing file
* lang/qt/src/qgpgmesignjob.cpp (sign_to_filename): Add argument "appendSignature". Append new detached signature to an existing file if requested. * lang/qt/src/signjob.cpp, lang/qt/src/signjob.h (class SignJob): Add member functions setAppendSignature, appendSignatureEnabled. * lang/qt/src/signjob_p.h (struct SignJobPrivate): Add member m_appendSignature. * lang/qt/tests/run-signjob.cpp (struct CommandLineOptions): Add members signingFlags, appendSignature. Initialize armor. (parseCommandLine): Add command line options --detach-sign and --append. (main): Do not exit if output file exists and append is enabled. Pass new options to the job. -- This change simplifies cross-signing a document by appending additional detached signatures to a file with already existing detached signatures. GnuPG-bug-id: 6867
-rw-r--r--NEWS4
-rw-r--r--lang/qt/src/qgpgmesignjob.cpp42
-rw-r--r--lang/qt/src/signjob.cpp12
-rw-r--r--lang/qt/src/signjob.h14
-rw-r--r--lang/qt/src/signjob_p.h1
-rw-r--r--lang/qt/tests/run-signjob.cpp14
6 files changed, 78 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index 796e3c9e..c317d2f3 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ Noteworthy changes in version 1.24.0 (unrelease)
* qt: Allow specifying import options when importing keys. [T7152]
+ * qt: Allow appending a detached signature to an existing file. [T6867]
+
* Interface changes relative to the 1.23.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_ENCRYPT_FILE NEW.
@@ -67,6 +69,8 @@ Noteworthy changes in version 1.24.0 (unrelease)
qt: SignJob::outputFile NEW.
qt: SignJob::setSigningFlags NEW.
qt: SignJob::signingFlags NEW.
+ qt: SignJob::setAppendSignature NEW.
+ qt: SignJob::appendSignatureEnabled NEW.
qt: VerifyDetachedJob::setSignatureFile NEW.
qt: VerifyDetachedJob::signatureFile NEW.
qt: VerifyDetachedJob::setSignedFile NEW.
diff --git a/lang/qt/src/qgpgmesignjob.cpp b/lang/qt/src/qgpgmesignjob.cpp
index 76e60e72..7ad71767 100644
--- a/lang/qt/src/qgpgmesignjob.cpp
+++ b/lang/qt/src/qgpgmesignjob.cpp
@@ -170,7 +170,8 @@ static QGpgMESignJob::result_type sign_to_filename(Context *ctx,
const std::vector<Key> &signers,
const QString &inputFilePath,
const QString &outputFilePath,
- SignatureMode flags)
+ SignatureMode flags,
+ bool appendSignature)
{
Data indata;
#ifdef Q_OS_WIN
@@ -206,13 +207,42 @@ static QGpgMESignJob::result_type sign_to_filename(Context *ctx,
flags = static_cast<SignatureMode>(flags | SignFile);
const auto signingResult = ctx->sign(indata, outdata, flags);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+
if (!signingResult.error().code()) {
- // the operation succeeded -> save the result under the requested file name
- partFileGuard.commit();
+ // the operation succeeded
+ const bool appendSignatureToExistingFile = appendSignature && (flags & Detached) && QFile::exists(outputFilePath);
+ if (appendSignatureToExistingFile) {
+ // append the result to the existing file
+ QFile newSignatureFile{partFileGuard.tempFileName()};
+ if (!newSignatureFile.open(QIODevice::ReadOnly)) {
+ qCDebug(QGPGME_LOG) << "Failed to open detached signature file" << newSignatureFile.fileName() << "(" << newSignatureFile.errorString() << ")";
+ return std::make_tuple(SigningResult{Error::fromCode(GPG_ERR_GENERAL)}, QByteArray{}, log, ae);
+ }
+ const QByteArray newSigData = newSignatureFile.readAll();
+ if (newSigData.isEmpty()) {
+ qCDebug(QGPGME_LOG) << "Failed to read detached signature from file" << newSignatureFile.fileName() << "(" << newSignatureFile.errorString() << ")";
+ return std::make_tuple(SigningResult{Error::fromCode(GPG_ERR_GENERAL)}, QByteArray{}, log, ae);
+ }
+ newSignatureFile.close();
+
+ QFile existingSignatureFile{outputFilePath};
+ if (!existingSignatureFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
+ qCDebug(QGPGME_LOG) << "Failed to open existing detached signature file for appending" << existingSignatureFile.fileName() << "(" << existingSignatureFile.errorString() << ")";
+ return std::make_tuple(SigningResult{Error::fromCode(GPG_ERR_GENERAL)}, QByteArray{}, log, ae);
+ }
+ const auto bytesWritten = existingSignatureFile.write(newSigData);
+ if (bytesWritten != newSigData.size()) {
+ qCDebug(QGPGME_LOG) << "Failed to write new signature to existing detached signature file" << existingSignatureFile.fileName() << "(" << existingSignatureFile.errorString() << ")";
+ return std::make_tuple(SigningResult{Error::fromCode(GPG_ERR_GENERAL)}, QByteArray{}, log, ae);
+ }
+ } else {
+ // save the result under the requested file name
+ partFileGuard.commit();
+ }
}
- Error ae;
- const QString log = _detail::audit_log_as_html(ctx, ae);
return std::make_tuple(signingResult, QByteArray{}, log, ae);
}
@@ -241,7 +271,7 @@ GpgME::Error QGpgMESignJobPrivate::startIt()
}
q->run([=](Context *ctx) {
- return sign_to_filename(ctx, m_signers, m_inputFilePath, m_outputFilePath, m_signingFlags);
+ return sign_to_filename(ctx, m_signers, m_inputFilePath, m_outputFilePath, m_signingFlags, m_appendSignature);
});
return {};
diff --git a/lang/qt/src/signjob.cpp b/lang/qt/src/signjob.cpp
index 0a9c8651..be15051b 100644
--- a/lang/qt/src/signjob.cpp
+++ b/lang/qt/src/signjob.cpp
@@ -95,4 +95,16 @@ GpgME::SignatureMode SignJob::signingFlags() const
return d->m_signingFlags;
}
+void SignJob::setAppendSignature(bool append)
+{
+ auto d = jobPrivate<SignJobPrivate>(this);
+ d->m_appendSignature = append;
+}
+
+bool SignJob::appendSignatureEnabled() const
+{
+ auto d = jobPrivate<SignJobPrivate>(this);
+ return d->m_appendSignature;
+}
+
#include "signjob.moc"
diff --git a/lang/qt/src/signjob.h b/lang/qt/src/signjob.h
index 273277b5..085f8498 100644
--- a/lang/qt/src/signjob.h
+++ b/lang/qt/src/signjob.h
@@ -113,7 +113,8 @@ public:
*
* \note If a file with this path exists, then the job will fail, i.e. you
* need to delete an existing file that shall be overwritten before you
- * start the job.
+ * start the job. If you create a detached signature then you can tell
+ * the job to append the new detached signature to an existing file.
*/
void setOutputFile(const QString &path);
QString outputFile() const;
@@ -130,6 +131,17 @@ public:
GpgME::SignatureMode signingFlags() const;
/**
+ * If @c true then a new detached signature is appended to an already
+ * existing detached signature.
+ *
+ * Defaults to \c false.
+ *
+ * Used if the job is started with startIt().
+ */
+ void setAppendSignature(bool append);
+ bool appendSignatureEnabled() const;
+
+ /**
Starts the signing operation. \a signers is the list of keys to
sign \a plainText with. Empty (null) keys are ignored.
*/
diff --git a/lang/qt/src/signjob_p.h b/lang/qt/src/signjob_p.h
index 75309782..e1eae6b8 100644
--- a/lang/qt/src/signjob_p.h
+++ b/lang/qt/src/signjob_p.h
@@ -48,6 +48,7 @@ struct SignJobPrivate : public JobPrivate
QString m_inputFilePath;
QString m_outputFilePath;
GpgME::SignatureMode m_signingFlags = GpgME::SignFile;
+ bool m_appendSignature = false;
};
}
diff --git a/lang/qt/tests/run-signjob.cpp b/lang/qt/tests/run-signjob.cpp
index 14b0a406..c1342b66 100644
--- a/lang/qt/tests/run-signjob.cpp
+++ b/lang/qt/tests/run-signjob.cpp
@@ -56,7 +56,9 @@ std::ostream &operator<<(std::ostream &os, const QString &s)
}
struct CommandLineOptions {
- bool armor;
+ GpgME::SignatureMode signingFlags = GpgME::NormalSignatureMode;
+ bool armor = false;
+ bool appendSignature = false;
QString inputFile;
QString outputFile;
std::chrono::seconds cancelTimeout{0};
@@ -72,6 +74,8 @@ CommandLineOptions parseCommandLine(const QStringList &arguments)
parser.addOptions({
{{"o", "output"}, "Write output to FILE.", "FILE"},
{{"a", "armor"}, "Create ASCII armored output."},
+ {{"b", "detach-sign"}, "Create a detached signature."},
+ {"append", "Append new (detached) signature to existing file."},
{"cancel-after", "Cancel the running job after SECONDS seconds.", "SECONDS"},
});
parser.addPositionalArgument("file", "File to sign", "FILE");
@@ -84,6 +88,10 @@ CommandLineOptions parseCommandLine(const QStringList &arguments)
}
options.armor = parser.isSet("armor");
+ if (parser.isSet("detach-sign")) {
+ options.signingFlags = GpgME::Detached;
+ options.appendSignature = parser.isSet("append");
+ }
options.inputFile = args.front();
options.outputFile = parser.value("output");
if (parser.isSet("cancel-after")) {
@@ -114,7 +122,7 @@ int main(int argc, char **argv)
output.reset(new QFile);
output->open(stdout, QIODevice::WriteOnly);
} else {
- if (QFile::exists(options.outputFile)) {
+ if (QFile::exists(options.outputFile) && !options.appendSignature) {
qCritical() << "File" << options.outputFile << "exists. Bailing out.";
return 1;
}
@@ -146,6 +154,8 @@ int main(int argc, char **argv)
} else {
job->setInputFile(options.inputFile);
job->setOutputFile(options.outputFile);
+ job->setSigningFlags(options.signingFlags);
+ job->setAppendSignature(options.appendSignature);
err = job->startIt();
}
if (err) {