Related tdf#97694 Preserve macro signatures in Base

Change-Id: I139ac003d1c95144e6cb1beec774f3cf142625b7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91466
Tested-by: Jenkins
Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx
index ff4e68e..fd93feb 100644
--- a/dbaccess/source/core/dataaccess/databasedocument.cxx
+++ b/dbaccess/source/core/dataaccess/databasedocument.cxx
@@ -40,6 +40,8 @@
#include <com/sun/star/lang/NoSupportException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
#include <com/sun/star/sdb/DatabaseContext.hpp>
#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
@@ -60,6 +62,7 @@
#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/numberedcollection.hxx>
#include <comphelper/storagehelper.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertysetinfo.hxx>
#include <comphelper/types.hxx>

@@ -69,7 +72,9 @@
#include <cppuhelper/supportsservice.hxx>
#include <framework/titlehelper.hxx>
#include <unotools/saveopt.hxx>
#include <unotools/tempfile.hxx>
#include <tools/diagnose_ex.h>
#include <osl/file.hxx>
#include <osl/diagnose.h>

#include <vcl/GraphicObject.hxx>
@@ -1021,6 +1026,22 @@
        _rGuard.reset();
    }

    bool bTryToPreserveScriptSignature = false;
    utl::TempFile aTempFile;
    aTempFile.EnableKillingFile();
    OUString aTmpFileURL = aTempFile.GetURL();
    if (m_pImpl->getScriptingSignatureState() == SignatureState::OK
        || m_pImpl->getScriptingSignatureState() == SignatureState::NOTVALIDATED
        || m_pImpl->getScriptingSignatureState() == SignatureState::INVALID)
    {
        bTryToPreserveScriptSignature = true;
        // We need to first save the file (which removes the macro signature), then add the macro signature again.
        // For that, we need a temporary copy of the original file.
        osl::File::RC rc = osl::File::copy(m_pImpl->getDocFileLocation(), aTmpFileURL);
        if (rc != osl::FileBase::E_None)
            throw uno::RuntimeException("Could not create temp file");
    }

    Reference< XStorage > xNewRootStorage;
        // will be non-NULL if our storage changed

@@ -1066,6 +1087,75 @@
        Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) );
        impl_storeToStorage_throw( xCurrentStorage, aMediaDescriptor, _rGuard );

        // Preserve script signature if the script has not changed
        if (bTryToPreserveScriptSignature)
        {
            uno::Reference<security::XDocumentDigitalSignatures> xDDSigns;
            try
            {
                OUString aODFVersion(
                    comphelper::OStorageHelper::GetODFVersionFromStorage(xCurrentStorage));
                xDDSigns = security::DocumentDigitalSignatures::createWithVersion(
                    comphelper::getProcessComponentContext(), aODFVersion);

                const OUString aScriptSignName
                    = xDDSigns->getScriptingContentSignatureDefaultStreamName();

                if (!aScriptSignName.isEmpty())
                {
                    Reference<XStorage> xReadOrig
                        = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
                            ZIP_STORAGE_FORMAT_STRING, aTmpFileURL, ElementModes::READ);
                    if (!xReadOrig.is())
                        throw uno::RuntimeException("Could not read " + aTmpFileURL);
                    uno::Reference<embed::XStorage> xMetaInf
                        = xReadOrig->openStorageElement("META-INF", embed::ElementModes::READ);

                    Reference<XStorage> xTarget
                        = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
                            ZIP_STORAGE_FORMAT_STRING, _rURL, ElementModes::READWRITE);
                    if (!xTarget.is())
                        throw uno::RuntimeException("Could not read " + _rURL);
                    uno::Reference<embed::XStorage> xTargetMetaInf
                        = xTarget->openStorageElement("META-INF", embed::ElementModes::READWRITE);

                    if (xMetaInf.is() && xTargetMetaInf.is())
                    {
                        xMetaInf->copyElementTo(aScriptSignName, xTargetMetaInf, aScriptSignName);

                        uno::Reference<embed::XTransactedObject> xTransact(xTargetMetaInf,
                                                                           uno::UNO_QUERY);
                        if (xTransact.is())
                            xTransact->commit();

                        xTargetMetaInf->dispose();

                        // now check the copied signature
                        uno::Sequence<security::DocumentSignatureInformation> aInfos
                            = xDDSigns->verifyScriptingContentSignatures(
                                xTarget, uno::Reference<io::XInputStream>());
                        SignatureState nState = DocumentSignatures::getSignatureState(aInfos);
                        if (nState == SignatureState::OK || nState == SignatureState::NOTVALIDATED
                            || nState == SignatureState::PARTIAL_OK)
                        {
                            // commit the ZipStorage from target medium
                            xTransact.set(xTarget, uno::UNO_QUERY);
                            if (xTransact.is())
                                xTransact->commit();
                        }
                        else
                        {
                            SAL_WARN("dbaccess", "An invalid signature was copied!");
                        }
                    }
                }
            }
            catch (uno::Exception&)
            {
                SAL_WARN("dbaccess", "Preserving macro signature failed!");
            }
        }

        // success - tell our impl
        m_pImpl->setDocFileLocation( _rURL );
        m_pImpl->setResource( _rURL, aMediaDescriptor );