include/sfx2/digitalsignatures.hxx                          |    7 +
 offapi/com/sun/star/security/XDocumentDigitalSignatures.idl |    4 
 sfx2/source/doc/docfile.cxx                                 |   15 ++-
 xmlsecurity/inc/documentsignaturemanager.hxx                |    2 
 xmlsecurity/source/component/documentdigitalsignatures.cxx  |   49 +++++++-----
 xmlsecurity/source/helper/documentsignaturemanager.cxx      |   31 +++++++
 6 files changed, 82 insertions(+), 26 deletions(-)

New commits:
commit b46628863a68a5239aeae06298f9675193009644
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Sep 10 10:11:54 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Sep 12 11:29:38 2024 +0200

    cool#9992 lok doc sign: async 
DocumentDigitalSignatures::ImplViewSignatures()
    
    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::ImplViewSignatures()
    async, though that requires all callers of the function to be async, so
    make DocumentDigitalSignatures::signScriptingContent() async as well.
    There is also DocumentDigitalSignatures::signPackage(), but turns out
    that's dead code, so just remove it.
    
    Once this is in place, we had a problem that the callbacks tried to
    interact with libxmlsec, but the dialog was still alive in
    DocumentDigitalSignatures::ImplViewSignatures() by the time the callback
    was running, so there were two DocumentSignatureManager instances at the
    same time, and both assumes it should call the global libxmlsec
    init/uninit, which resulted in failing to verify the just created
    signature.
    
    Fix this similar to how Tomaz fixed the same problem around pdfium in
    commit 067a8a954c8e1d8d6465a4ab5fb61e93f16c26c2 (pdfium: only init
    pdfium library one and destroy on LO exit, 2020-06-03).
    
    (cherry picked from commit 07df95e75a728fbbce03f6d6efdf9dbceab6c581)
    
    Change-Id: I3fb63c06195564732e1576dbd755157e676fb762
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173156
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/include/sfx2/digitalsignatures.hxx 
b/include/sfx2/digitalsignatures.hxx
index bb0abd6e54e3..b364c9518931 100644
--- a/include/sfx2/digitalsignatures.hxx
+++ b/include/sfx2/digitalsignatures.hxx
@@ -38,6 +38,13 @@ public:
                                           const std::function<void(bool)>& 
rCallback)
         = 0;
 
+    /// Async replacement for signScriptingContent().
+    virtual void
+    SignScriptingContentAsync(const css::uno::Reference<css::embed::XStorage>& 
rxStorage,
+                              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 58dfe915ba10..195a940894f4 100644
--- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
+++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
@@ -78,6 +78,8 @@ interface XDocumentDigitalSignatures : 
com::sun::star::uno::XInterface
     /** signs the content of the Scripting including macros and basic dialogs
 
         <p>The rest of document content will not be signed.</p>
+
+       Deprecated, this synchronous version would block the UI till signing is 
in progress.
      */
     boolean signScriptingContent( [in] ::com::sun::star::embed::XStorage 
xStorage,
                                   [in] ::com::sun::star::io::XStream 
xSignStream);
@@ -102,6 +104,8 @@ interface XDocumentDigitalSignatures : 
com::sun::star::uno::XInterface
     string getScriptingContentSignatureDefaultStreamName();
 
     /** signs the full Package, which means everything in the storage except 
the content of META-INF
+
+       Deprecated, this synchronous version would block the UI till signing is 
in progress.
      */
     boolean signPackage( [in] ::com::sun::star::embed::XStorage Storage,
                          [in] ::com::sun::star::io::XStream xSignStream);
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 2b7a1fb82453..79f89d17cb63 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -4382,6 +4382,8 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                 throw uno::RuntimeException();
         }
 
+        auto xModelSigner = 
dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
+        assert(xModelSigner);
         if ( bSignScriptingContent )
         {
             // If the signature has already the document signature it will be 
removed
@@ -4395,8 +4397,10 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
             // xWriteableZipStor because a writable storage can't have 2
             // instances of sub-storage for the same directory open, but with
             // independent storages it somehow works
-            if 
(xSigner->signScriptingContent(GetScriptingStorageToSign_Impl(), xStream))
-            {
+            xModelSigner->SignScriptingContentAsync(
+                GetScriptingStorageToSign_Impl(), xStream,
+                [this, xSigner, xMetaInf, xWriteableZipStor,
+                 onSignDocumentContentFinished](bool bRet) {
                 // remove the document signature if any
                 OUString aDocSigName = 
xSigner->getDocumentContentSignatureDefaultStreamName();
                 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( 
aDocSigName ) )
@@ -4423,13 +4427,12 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                     || !uno::Reference<util::XModifiable>(pImpl->xStorage, 
uno::UNO_QUERY_THROW)->isModified());
                 // the temporary file has been written, commit it to the 
original file
                 Commit();
-                bChanges = true;
-            }
+                onSignDocumentContentFinished(bRet);
+            });
+            return;
         }
         else
         {
-            auto xModelSigner = 
dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
-            assert(xModelSigner);
             if (xMetaInf.is())
             {
                 // ODF.
diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx 
b/xmlsecurity/inc/documentsignaturemanager.hxx
index ab89e5b96674..9f0c5d61f9e2 100644
--- a/xmlsecurity/inc/documentsignaturemanager.hxx
+++ b/xmlsecurity/inc/documentsignaturemanager.hxx
@@ -54,6 +54,7 @@ class XComponentContext;
 }
 }
 class PDFSignatureHelper;
+class Xmlsec;
 
 /// Manages signatures (addition, removal), used by DigitalSignaturesDialog.
 class XMLSECURITY_DLLPUBLIC DocumentSignatureManager
@@ -75,6 +76,7 @@ private:
     css::uno::Reference<css::xml::crypto::XXMLSecurityContext> 
mxSecurityContext;
     css::uno::Reference<css::xml::crypto::XSEInitializer> mxGpgSEInitializer;
     css::uno::Reference<css::xml::crypto::XXMLSecurityContext> 
mxGpgSecurityContext;
+    std::shared_ptr<Xmlsec> mpXmlsecLibrary;
 
 public:
     DocumentSignatureManager(const 
css::uno::Reference<css::uno::XComponentContext>& xContext,
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 7d4c96e78679..e498bd7c2dcc 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -89,9 +89,10 @@ private:
     bool m_bHasDocumentSignature;
 
     /// @throws css::uno::RuntimeException
-    bool ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& 
rxStorage,
+    void ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& 
rxStorage,
                             const css::uno::Reference<css::io::XStream>& 
xSignStream,
-                            DocumentSignatureMode eMode, bool bReadOnly);
+                            DocumentSignatureMode eMode, bool bReadOnly,
+                            const std::function<void(bool)>& rCallback);
     /// @throws css::uno::RuntimeException
     void ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& 
rxStorage,
                             const css::uno::Reference<css::io::XInputStream>& 
xSignStream,
@@ -221,6 +222,10 @@ public:
     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;
+    /// See sfx2::DigitalSignatures::SignScriptingContentAsync().
+    void SignScriptingContentAsync(const 
css::uno::Reference<css::embed::XStorage>& xStorage,
+                                   const 
css::uno::Reference<css::io::XStream>& xSignStream,
+                                   const std::function<void(bool)>& rCallback) 
override;
 };
 
 }
@@ -359,12 +364,10 @@ OUString 
DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName
 }
 
 sal_Bool DocumentDigitalSignatures::signScriptingContent(
-    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");
-    OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was 
not initialized properly");
-    return ImplViewSignatures( rxStorage, xSignStream, 
DocumentSignatureMode::Macros, false );
+    for (;;) { std::abort(); } // avoid "must return a value" warnings
 }
 
 Sequence< css::security::DocumentSignatureInformation >
@@ -391,11 +394,10 @@ OUString 
DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamNam
 
 
 sal_Bool DocumentDigitalSignatures::signPackage(
-    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::Package, false );
+    for (;;) { std::abort(); } // avoid "must return a value" warnings
 }
 
 Sequence< css::security::DocumentSignatureInformation >
@@ -429,12 +431,12 @@ void DocumentDigitalSignatures::ImplViewSignatures(
     Reference< io::XStream > xStream;
     if ( xSignStream.is() )
         xStream.set( xSignStream, UNO_QUERY );
-    ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly );
+    ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly, [](bool 
/*bSuccess*/){} );
 }
 
-bool DocumentDigitalSignatures::ImplViewSignatures(
+void DocumentDigitalSignatures::ImplViewSignatures(
     const Reference< css::embed::XStorage >& rxStorage, const Reference< 
css::io::XStream >& xSignStream,
-    DocumentSignatureMode eMode, bool bReadOnly )
+    DocumentSignatureMode eMode, bool bReadOnly, const 
std::function<void(bool)>& rCallback )
 {
     bool bChanges = false;
     auto xSignaturesDialog = std::make_shared<DigitalSignaturesDialog>(
@@ -452,7 +454,8 @@ bool DocumentDigitalSignatures::ImplViewSignatures(
         {
             xSignaturesDialog->beforeRun();
             weld::DialogController::runAsync(xSignaturesDialog, [] (sal_Int32) 
{});
-            return false;
+            rCallback(false);
+            return;
         }
         else if (xSignaturesDialog->run() == RET_OK)
         {
@@ -466,6 +469,8 @@ bool DocumentDigitalSignatures::ImplViewSignatures(
                     xTrans->commit();
                 }
             }
+            rCallback(bChanges);
+            return;
         }
     }
     else
@@ -476,7 +481,7 @@ bool DocumentDigitalSignatures::ImplViewSignatures(
         xBox->run();
     }
 
-    return bChanges;
+    rCallback(bChanges);
 }
 
 Sequence< css::security::DocumentSignatureInformation >
@@ -838,8 +843,16 @@ void 
DocumentDigitalSignatures::SignDocumentContentAsync(const css::uno::Referen
                               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);
+    ImplViewSignatures( rxStorage, xSignStream, 
DocumentSignatureMode::Content, false, rCallback );
+}
+
+void DocumentDigitalSignatures::SignScriptingContentAsync(
+    const Reference<css::embed::XStorage>& rxStorage,
+    const 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");
+    OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was 
not initialized properly");
+    ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Macros, 
false, rCallback );
 }
 
 sal_Bool DocumentDigitalSignatures::signPackageWithCertificate(
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx 
b/xmlsecurity/source/helper/documentsignaturemanager.cxx
index 80d74c27ba53..0bc34dcd379b 100644
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
@@ -56,6 +56,33 @@ using namespace css;
 using namespace css::graphic;
 using namespace css::uno;
 
+/// RAII class to init / shut down libxmlsec.
+class Xmlsec
+{
+public:
+    Xmlsec();
+    ~Xmlsec();
+};
+
+Xmlsec::Xmlsec() { initXmlSec(); }
+
+Xmlsec::~Xmlsec() { deInitXmlSec(); }
+
+namespace
+{
+/// Shared access to libxmlsec, to avoid double init.
+struct XmlsecLibrary
+{
+    static std::shared_ptr<Xmlsec>& get();
+};
+
+std::shared_ptr<Xmlsec>& XmlsecLibrary::get()
+{
+    static std::shared_ptr<Xmlsec> pInstance = std::make_shared<Xmlsec>();
+    return pInstance;
+}
+}
+
 DocumentSignatureManager::DocumentSignatureManager(
     const uno::Reference<uno::XComponentContext>& xContext, 
DocumentSignatureMode eMode)
     : mxContext(xContext)
@@ -64,7 +91,7 @@ DocumentSignatureManager::DocumentSignatureManager(
 {
 }
 
-DocumentSignatureManager::~DocumentSignatureManager() { deInitXmlSec(); }
+DocumentSignatureManager::~DocumentSignatureManager() { 
mpXmlsecLibrary.reset(); }
 
 bool DocumentSignatureManager::init()
 {
@@ -76,7 +103,7 @@ bool DocumentSignatureManager::init()
                 "DocumentSignatureManager::Init - mxGpgSEInitializer already 
set!");
 
     // xmlsec is needed by both services, so init before those
-    initXmlSec();
+    mpXmlsecLibrary = XmlsecLibrary::get();
 
     mxSEInitializer = xml::crypto::SEInitializer::create(mxContext);
 #if HAVE_FEATURE_GPGME

Reply via email to