basctl/source/basicide/docsignature.cxx | 2 include/sfx2/digitalsignatures.hxx | 8 + include/sfx2/docfile.hxx | 3 include/sfx2/objsh.hxx | 2 offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 2 sfx2/source/doc/docfile.cxx | 85 ++++++++---- sfx2/source/doc/objserv.cxx | 51 ++++--- xmlsecurity/source/component/documentdigitalsignatures.cxx | 20 ++ 8 files changed, 121 insertions(+), 52 deletions(-)
New commits: commit 38122c330d6b1cb002e6de16dfc3a1dd7fcbb3bc Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Sep 9 09:11:06 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Sep 12 11:29:30 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. (cherry picked from commit caff013bee53216efeb49db4bcda44b55c223b58) Change-Id: If771ced711041364988af45ad9dd0dd1a2a8660d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173118 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@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 a90304313582..58dfe915ba10 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 ca38ff5f9fb9..2b7a1fb82453 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -4332,6 +4332,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() ) @@ -4420,6 +4428,8 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, } else { + auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get()); + assert(xModelSigner); if (xMetaInf.is()) { // ODF. @@ -4428,23 +4438,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; } } @@ -4453,6 +4477,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()) { @@ -4463,17 +4494,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; } } @@ -4482,8 +4517,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; } } } @@ -4492,11 +4529,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 c1768c0e953a..7d4c96e78679 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -217,6 +217,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; }; } @@ -278,11 +282,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( @@ -830,6 +833,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, commit 11af9233ab7b2ff40eaa45922f38fe65b14ff881 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Sep 6 09:47:25 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Sep 12 11:29:20 2024 +0200 cool#9992 lok doc sign: make SfxMedium::SignContents_Impl() async 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 to get rid of this hack is to make SfxMedium::SignContents_Impl() async, now that SfxObjectShell::SignDocumentContent() is async. This requires all callers of SfxMedium::SignContents_Impl() to be async, most notably SfxObjectShell::SignScriptingContent() has to be converted as well. Note that no lifecycle problem is expected here for the callback, since the object shell and its medium is typically around for as long as the document is loaded. (cherry picked from commit de0bc0a2c30a76144b47e9abb17770043813133c) Change-Id: I57f2c747f8448b9adc0398f874ede36211fed817 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173062 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/basctl/source/basicide/docsignature.cxx b/basctl/source/basicide/docsignature.cxx index 08d7a1ab9c13..ee04435274db 100644 --- a/basctl/source/basicide/docsignature.cxx +++ b/basctl/source/basicide/docsignature.cxx @@ -60,7 +60,7 @@ namespace basctl { OSL_PRECOND( supportsSignatures(), "DocumentSignature::signScriptingContent: signatures not supported by this document!" ); if ( m_pShell ) - m_pShell->SignScriptingContent(pDialogParent); + m_pShell->SignScriptingContent(pDialogParent, [](bool /*bSigned*/){}); } SignatureState DocumentSignature::getScriptingSignatureState() const diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx index fb8039f6b8f1..01046aa66789 100644 --- a/include/sfx2/docfile.hxx +++ b/include/sfx2/docfile.hxx @@ -270,9 +270,10 @@ public: const INetURLObject& aDest, const css::uno::Reference< css::ucb::XCommandEnvironment >& xComEnv ); - SAL_DLLPRIVATE bool + SAL_DLLPRIVATE void SignContents_Impl(weld::Window* pDialogParent, bool bSignScriptingContent, bool bHasValidDocumentSignature, + const std::function<void(bool)>& rCallback, const OUString& aSignatureLineId = OUString(), const css::uno::Reference<css::security::XCertificate>& xCert = css::uno::Reference<css::security::XCertificate>(), diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index b3b55286b349..0b9a456b0b0c 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -375,7 +375,7 @@ public: const css::uno::Reference<css::graphic::XGraphic>& xInvalidGraphic, const OUString& aComment); SignatureState GetScriptingSignatureState(); - bool SignScriptingContent(weld::Window* pDialogParent); + void SignScriptingContent(weld::Window* pDialogParent, const std::function<void(bool)>& rCallback); DECL_DLLPRIVATE_LINK(SignDocumentHandler, weld::Button&, void); virtual std::shared_ptr<SfxDocumentInfoDialog> CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet); diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index ba45c8eb9250..ca38ff5f9fb9 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -4298,9 +4298,10 @@ bool SfxMedium::SignDocumentContentUsingCertificate( } // note: this is the only function creating scripting signature -bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent, +void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, bool bSignScriptingContent, bool bHasValidDocumentSignature, + const std::function<void(bool)>& rCallback, const OUString& aSignatureLineId, const Reference<XCertificate>& xCert, const Reference<XGraphic>& xValidGraphic, @@ -4312,7 +4313,8 @@ bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent, if (IsOpen() || GetErrorIgnoreWarning()) { SAL_WARN("sfx.doc", "The medium must be closed by the signer!"); - return bChanges; + rCallback(bChanges); + return; } // The component should know if there was a valid document signature, since @@ -4494,7 +4496,7 @@ bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent, ResetError(); - return bChanges; + rCallback(bChanges); } diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx index eaf8cf71cece..535facf5c81d 100644 --- a/sfx2/source/doc/objserv.cxx +++ b/sfx2/source/doc/objserv.cxx @@ -617,7 +617,11 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) } else { - bHaveWeSigned |= SignScriptingContent(pDialogParent); + // Async, all code before return has to go into the callback. + SignScriptingContent(pDialogParent, [this, pDialogParent] (bool bSigned) { + AfterSignContent(bSigned, pDialogParent); + }); + return; } AfterSignContent(bHaveWeSigned, pDialogParent); @@ -2142,11 +2146,12 @@ void SfxObjectShell::SignDocumentContent(weld::Window* pDialogParent, const std: return; } - bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, false, HasValidSignatures()); - - AfterSigning(bSignSuccess, false); + // Async, all code before the end has to go into the callback. + GetMedium()->SignContents_Impl(pDialogParent, false, HasValidSignatures(), [this, rCallback](bool bSignSuccess) { + AfterSigning(bSignSuccess, false); - rCallback(bSignSuccess); + rCallback(bSignSuccess); + }); } bool SfxObjectShell::ResignDocument(uno::Sequence< security::DocumentSignatureInformation >& rSignaturesInfo) @@ -2257,15 +2262,15 @@ void SfxObjectShell::SignSignatureLine(weld::Window* pDialogParent, if (CheckIsReadonly(false, pDialogParent)) return; - bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, - false, HasValidSignatures(), aSignatureLineId, xCert, xValidGraphic, xInvalidGraphic, aComment); - - AfterSigning(bSignSuccess, false); + GetMedium()->SignContents_Impl(pDialogParent, + false, HasValidSignatures(), [this](bool bSignSuccess) { + AfterSigning(bSignSuccess, false); - // Reload the document to get the updated graphic - // FIXME: Update just the signature line graphic instead of reloading the document - if (SfxViewFrame* pFrame = GetFrame()) - pFrame->GetDispatcher()->Execute(SID_RELOAD); + // Reload the document to get the updated graphic + // FIXME: Update just the signature line graphic instead of reloading the document + if (SfxViewFrame* pFrame = GetFrame()) + pFrame->GetDispatcher()->Execute(SID_RELOAD); + }, aSignatureLineId, xCert, xValidGraphic, xInvalidGraphic, aComment); } SignatureState SfxObjectShell::GetScriptingSignatureState() @@ -2273,19 +2278,25 @@ SignatureState SfxObjectShell::GetScriptingSignatureState() return ImplGetSignatureState( true ); } -bool SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent) +void SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent, const std::function<void(bool)>& rCallback) { if (!PrepareForSigning(pDialogParent)) - return false; + { + rCallback(false); + return; + } if (CheckIsReadonly(true, pDialogParent)) - return false; - - bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, true, HasValidSignatures()); + { + rCallback(false); + return; + } - AfterSigning(bSignSuccess, true); + GetMedium()->SignContents_Impl(pDialogParent, true, HasValidSignatures(), [this, rCallback](bool bSignSuccess) { + AfterSigning(bSignSuccess, true); - return bSignSuccess; + rCallback(bSignSuccess); + }); } const uno::Sequence<sal_Int8>& SfxObjectShell::getUnoTunnelId()