include/sfx2/digitalsignatures.hxx | 8 + offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 2 sfx2/source/doc/docfile.cxx | 79 ++++++++---- xmlsecurity/source/component/documentdigitalsignatures.cxx | 20 ++- 4 files changed, 82 insertions(+), 27 deletions(-)
New commits: commit caff013bee53216efeb49db4bcda44b55c223b58 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Sep 9 09:11:06 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Sep 9 17:30:28 2024 +0200 cool#9992 lok doc sign: async DocumentDigitalSignatures::signDocumentContent() Currently SfxObjectShell::CheckIsReadonly() has a hack for the LOK case to show the signatures dialog read-only, as only that is async. The next step is to make DocumentDigitalSignatures::signDocumentContent() async, but passing an std::function via the UNO API is tricky. Notice how DocumentDigitalSignatures in xmlsecurity/ also implements sfx2::DigitalSignatures, add a new SignDocumentContentAsync() there and adapt all uses of signDocumentContent() to go with that instead. This requires introducing some lambdas for code after signDocumentContent() in general and for ODF/OOXML specific code in particular, to avoid code duplication. Change-Id: If771ced711041364988af45ad9dd0dd1a2a8660d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173060 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/sfx2/digitalsignatures.hxx b/include/sfx2/digitalsignatures.hxx index b46cdd52e9d9..bb0abd6e54e3 100644 --- a/include/sfx2/digitalsignatures.hxx +++ b/include/sfx2/digitalsignatures.hxx @@ -9,6 +9,8 @@ #pragma once +#include <functional> + #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/io/XStream.hpp> @@ -30,6 +32,12 @@ public: const css::uno::Reference<css::io::XStream>& xStream) = 0; + /// Async replacement for signDocumentContent(). + virtual void SignDocumentContentAsync(const css::uno::Reference<css::embed::XStorage>& xStorage, + const css::uno::Reference<css::io::XStream>& xSignStream, + const std::function<void(bool)>& rCallback) + = 0; + protected: ~DigitalSignatures() noexcept = default; }; diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl index d85be941c8d1..cd201d080f82 100644 --- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl +++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl @@ -32,6 +32,8 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface /** signs the content of the document including text and pictures. <p>Macros will not be signed.</p> + + Deprecated, this synchronous version would block the UI till signing is in progress. */ boolean signDocumentContent( [in] ::com::sun::star::embed::XStorage xStorage, [in] ::com::sun::star::io::XStream xSignStream); diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index ee9308f51bfe..2d8290a6476a 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -4338,6 +4338,14 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, CreateTempFile( false ); GetMedium_Impl(); + auto onSignDocumentContentFinished = [this, rCallback](bool bRet) { + CloseAndRelease(); + + ResetError(); + + rCallback(bRet); + }; + try { if ( !pImpl->xStream.is() ) @@ -4426,6 +4434,8 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, } else { + auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get()); + assert(xModelSigner); if (xMetaInf.is()) { // ODF. @@ -4434,23 +4444,37 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW); bool bSuccess = false; + auto onODFSignDocumentContentFinished = [this, xMetaInf, xWriteableZipStor]() { + uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW ); + xTransact->commit(); + xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + + // the temporary file has been written, commit it to the original file + Commit(); + }; if (xCert.is()) bSuccess = xSigner->signSignatureLine( GetZipStorageToSign_Impl(), xStream, aSignatureLineId, xCert, xValidGraphic, xInvalidGraphic, aComment); else - bSuccess = xSigner->signDocumentContent(GetZipStorageToSign_Impl(), - xStream); + { + // Async, all code before return has to go into the callback. + xModelSigner->SignDocumentContentAsync(GetZipStorageToSign_Impl(), + xStream, [onODFSignDocumentContentFinished, onSignDocumentContentFinished](bool bRet) { + if (bRet) + { + onODFSignDocumentContentFinished(); + } + + onSignDocumentContentFinished(bRet); + }); + return; + } if (bSuccess) { - uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW ); - xTransact->commit(); - xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW ); - xTransact->commit(); - - // the temporary file has been written, commit it to the original file - Commit(); + onODFSignDocumentContentFinished(); bChanges = true; } } @@ -4459,6 +4483,13 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, // OOXML. uno::Reference<io::XStream> xStream; + auto onOOXMLSignDocumentContentFinished = [this, xWriteableZipStor]() { + uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW); + xTransact->commit(); + + // the temporary file has been written, commit it to the original file + Commit(); + }; bool bSuccess = false; if (xCert.is()) { @@ -4469,17 +4500,21 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, else { // We need read-write to be able to add the signature relation. - bSuccess =xSigner->signDocumentContent( - GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream); + xModelSigner->SignDocumentContentAsync( + GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream, [onOOXMLSignDocumentContentFinished, onSignDocumentContentFinished](bool bRet) { + if (bRet) + { + onOOXMLSignDocumentContentFinished(); + } + + onSignDocumentContentFinished(bRet); + }); + return; } if (bSuccess) { - uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW); - xTransact->commit(); - - // the temporary file has been written, commit it to the original file - Commit(); + onOOXMLSignDocumentContentFinished(); bChanges = true; } } @@ -4488,8 +4523,10 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, // Something not ZIP based: e.g. PDF. std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE)); uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream)); - if (xSigner->signDocumentContent(uno::Reference<embed::XStorage>(), xStream)) - bChanges = true; + xModelSigner->SignDocumentContentAsync(uno::Reference<embed::XStorage>(), xStream, [onSignDocumentContentFinished](bool bRet) { + onSignDocumentContentFinished(bRet); + }); + return; } } } @@ -4498,11 +4535,7 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, TOOLS_WARN_EXCEPTION("sfx.doc", "Couldn't use signing functionality!"); } - CloseAndRelease(); - - ResetError(); - - rCallback(bChanges); + onSignDocumentContentFinished(bChanges); } diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index c49b7427f67d..31b965a63765 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -212,6 +212,10 @@ public: const css::uno::Reference<css::security::XCertificate>& xCertificate, const css::uno::Reference<css::embed::XStorage>& xStorage, const css::uno::Reference<css::io::XStream>& xStream) override; + /// See sfx2::DigitalSignatures::SignDocumentContentAsync(). + void SignDocumentContentAsync(const css::uno::Reference<css::embed::XStorage>& xStorage, + const css::uno::Reference<css::io::XStream>& xSignStream, + const std::function<void(bool)>& rCallback) override; }; } @@ -273,11 +277,10 @@ DocumentDigitalSignatures::getSupportedServiceNames() } sal_Bool DocumentDigitalSignatures::signDocumentContent( - const Reference< css::embed::XStorage >& rxStorage, - const Reference< css::io::XStream >& xSignStream) + const Reference< css::embed::XStorage >& /*rxStorage*/, + const Reference< css::io::XStream >& /*xSignStream*/) { - OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); - return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Content, false ); + for (;;) { std::abort(); } // avoid "must return a value" warnings } sal_Bool DocumentDigitalSignatures::signSignatureLine( @@ -827,6 +830,15 @@ bool DocumentDigitalSignatures::SignModelWithCertificate( DocumentSignatureMode::Content); } +void DocumentDigitalSignatures::SignDocumentContentAsync(const css::uno::Reference<css::embed::XStorage>& rxStorage, + const css::uno::Reference<css::io::XStream>& xSignStream, + const std::function<void(bool)>& rCallback) +{ + OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); + bool bRet = ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Content, false ); + rCallback(bRet); +} + sal_Bool DocumentDigitalSignatures::signPackageWithCertificate( css::uno::Reference<css::security::XCertificate> const& xCertificate, css::uno::Reference<css::embed::XStorage> const& xStorage,