[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.2' - 2 commits - comphelper/source framework/source package/source sfx2/source

Vasily Melenchuk (via logerrit) logerrit at kemper.freedesktop.org
Mon May 18 07:25:49 UTC 2020


 comphelper/source/misc/docpasswordhelper.cxx |   41 ++++++++++++++++++++++++++-
 framework/source/services/autorecovery.cxx   |   32 +++++++++++++++++++++
 package/source/xstor/owriteablestream.cxx    |    8 +++--
 package/source/xstor/owriteablestream.hxx    |    3 +
 package/source/xstor/xstorage.cxx            |    2 -
 sfx2/source/appl/appopen.cxx                 |   16 ++++++++++
 6 files changed, 96 insertions(+), 6 deletions(-)

New commits:
commit b2d08cac8e6b76a96d307c92653181a396ebf42a
Author:     Vasily Melenchuk <vasily.melenchuk at cib.de>
AuthorDate: Mon Feb 17 10:52:11 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Mon May 18 09:25:31 2020 +0200

    tdf#129096: Document Recovery: Use TypeDetection on load
    
    Loading of recovered document happend before via XFilter::filter
    is not updating media descriptor of document. But this is
    important for password protected documents to store entered password
    and used encryption type.
    
    To avoid this problem let's use TypeDetection which during its work
    will ask user for password and store all the info in modified media
    descriptor before actual recovery attempt.
    
    Change-Id: Ide2ebf0955e0937cdc7c9d7165593b71f904649b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88844
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Jenkins
    (cherry picked from commit 8461127750e1fe92a615409505256132e54fb8e8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89789
    Reviewed-by: Vasily Melenchuk <vasily.melenchuk at cib.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94348
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>

diff --git a/framework/source/services/autorecovery.cxx b/framework/source/services/autorecovery.cxx
index da6c33022c23..8dce1f8c994c 100644
--- a/framework/source/services/autorecovery.cxx
+++ b/framework/source/services/autorecovery.cxx
@@ -56,6 +56,7 @@
 #include <com/sun/star/beans/PropertyAttribute.hpp>
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 #include <com/sun/star/document/XDocumentRecovery.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
 #include <com/sun/star/util/XCloseable.hpp>
 #include <com/sun/star/awt/XWindow2.hpp>
 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
@@ -3355,6 +3356,37 @@ void AutoRecovery::implts_openOneDoc(const OUString&               sURL       ,
         }
         else
         {
+            OUString sFilterName;
+            lDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] >>= sFilterName;
+            if (!sFilterName.isEmpty()
+                && (   sFilterName == "Calc MS Excel 2007 XML"
+                    || sFilterName == "Impress MS PowerPoint 2007 XML"
+                    || sFilterName == "MS Word 2007 XML"))
+                // TODO: Propbably need to check other affected formats + templates?
+            {
+                // tdf#129096: in case of recovery of password protected OOXML document it is done not
+                // the same way as ordinal loading. Inside XDocumentRecovery::recoverFromFile
+                // there is a call to XFilter::filter which has constant media descriptor and thus
+                // all encryption data used in document is lost. To avoid this try to walkaround
+                // with explicit call to FormatDetector. It will try to load document, prompt for password
+                // and store this info in media descriptor we will use for recoverFromFile call.
+                Reference< css::document::XExtendedFilterDetection > xDetection(
+                    m_xContext->getServiceManager()->createInstanceWithContext(
+                        "com.sun.star.comp.oox.FormatDetector", m_xContext),
+                    UNO_QUERY_THROW);
+                lDescriptor[utl::MediaDescriptor::PROP_URL()] <<= sURL;
+                Sequence< css::beans::PropertyValue > aDescriptorSeq = lDescriptor.getAsConstPropertyValueList();
+                OUString sType = xDetection->detect(aDescriptorSeq);
+
+                OUString sNewFilterName;
+                lDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] >>= sNewFilterName;
+                if (!sType.isEmpty() && sNewFilterName == sFilterName)
+                {
+                    // Filter detection was okay, update media descriptor with one received from FilterDetect
+                    lDescriptor = aDescriptorSeq;
+                }
+            }
+
             // let it recover itself
             Reference< XDocumentRecovery > xDocRecover( xModel, UNO_QUERY_THROW );
             xDocRecover->recoverFromFile(
commit 65ce7e8a64a7af6ff2fb5b776d60b89bbec32c5e
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Jan 3 22:40:07 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Mon May 18 09:25:16 2020 +0200

    tdf#93389: keep encryption information for autorecovered MS formats
    
    The autorecovery data is stored in ODF, regardless of the original
    document format. When restoring, type detection generates ODF data,
    which is stored in the media descriptor attached to document, even
    after real filter was restored (see AutoRecovery::implts_openDocs).
    If real filter is not ODF, then at the save time, it doesn't find
    necessary information in encryption data, and makes not encrypted
    package.
    
    This patch adds both MS binary data, and OOXML data, to existing
    ODF data for recovered password-protected documents (regardless of
    their real filter).
    
    TODO: only add required information to encryption data: pass real
    filter name to DocPasswordHelper::requestAndVerifyDocPassword from
    AutoRecovery::implts_openDocs.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86201
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit dd198398b6e5c84ab1255a90ef96e6445b66a64f)
    
    Conflicts:
            comphelper/source/misc/docpasswordhelper.cxx
    
    Change-Id: I4717f067ad3c40167312b99eefef5584a467bfed
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88330
    Tested-by: Jenkins
    Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94347
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index 9963e90309d4..76288cab956d 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -431,6 +431,25 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     OUString aPassword;
     DocPasswordVerifierResult eResult = DocPasswordVerifierResult::WrongPassword;
 
+    sal_Int32 nMediaEncDataCount = rMediaEncData.getLength();
+
+    // tdf#93389: if the document is being restored from autorecovery, we need to add encryption
+    // data also for real document type.
+    // TODO: get real filter name here (from CheckPasswd_Impl), to only add necessary data
+    bool bForSalvage = false;
+    if (nMediaEncDataCount)
+    {
+        for (auto& val : rMediaEncData)
+        {
+            if (val.Name == "ForSalvage")
+            {
+                --nMediaEncDataCount; // don't consider this element below
+                val.Value >>= bForSalvage;
+                break;
+            }
+        }
+    }
+
     // first, try provided default passwords
     if( pbIsDefaultPassword )
         *pbIsDefaultPassword = false;
@@ -455,7 +474,7 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     // try media encryption data (skip, if result is OK or ABORT)
     if( eResult == DocPasswordVerifierResult::WrongPassword )
     {
-        if( rMediaEncData.getLength() > 0 )
+        if (nMediaEncDataCount)
         {
             eResult = rVerifier.verifyEncryptionData( rMediaEncData );
             if( eResult == DocPasswordVerifierResult::OK )
@@ -514,6 +533,26 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
             aEncData = comphelper::concatSequences(
                 aEncData, OStorageHelper::CreatePackageEncryptionData(aPassword));
         }
+
+        if (bForSalvage)
+        {
+            // TODO: add individual methods for different target filter, and only call what's needed
+
+            // 1. Prepare binary MS formats encryption data
+            auto aUniqueID = GenerateRandomByteSequence(16);
+            auto aEnc97Key = GenerateStd97Key(aPassword.getStr(), aUniqueID);
+            // 2. Add MS binary and OOXML encryption data to result
+            uno::Sequence< beans::NamedValue > aContainer(3);
+            aContainer[0].Name = "STD97EncryptionKey";
+            aContainer[0].Value <<= aEnc97Key;
+            aContainer[1].Name = "STD97UniqueID";
+            aContainer[1].Value <<= aUniqueID;
+            aContainer[2].Name = "OOXPassword";
+            aContainer[2].Value <<= aPassword;
+
+            aEncData = comphelper::concatSequences(
+                aEncData, aContainer);
+        }
     }
 
     return (eResult == DocPasswordVerifierResult::OK) ? aEncData : uno::Sequence< beans::NamedValue >();
diff --git a/package/source/xstor/owriteablestream.cxx b/package/source/xstor/owriteablestream.cxx
index 89700fe8ec72..5220e8bbb742 100644
--- a/package/source/xstor/owriteablestream.cxx
+++ b/package/source/xstor/owriteablestream.cxx
@@ -81,9 +81,11 @@ struct WSInternalData_Impl
 namespace package
 {
 
-bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
+bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
 {
-    bool bResult = !aHash1.empty() && aHash1.size() == aHash2.size();
+    // tdf#93389: aHash2 may contain more than in aHash1, if it contains also data for other package
+    // formats (as in case of autorecovery)
+    bool bResult = !aHash1.empty() && aHash1.size() <= aHash2.size();
     for ( ::comphelper::SequenceAsHashMap::const_iterator aIter = aHash1.begin();
           bResult && aIter != aHash1.end();
           ++aIter )
@@ -1162,7 +1164,7 @@ uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMod
 
     if ( m_bHasCachedEncryptionData )
     {
-        if ( !::package::PackageEncryptionDatasEqual( m_aEncryptionData, aEncryptionData ) )
+        if ( !::package::PackageEncryptionDataLessOrEqual( m_aEncryptionData, aEncryptionData ) )
             throw packages::WrongPasswordException();
 
         // the correct key must be set already
diff --git a/package/source/xstor/owriteablestream.hxx b/package/source/xstor/owriteablestream.hxx
index 7d7abf6647c3..681d347e8bce 100644
--- a/package/source/xstor/owriteablestream.hxx
+++ b/package/source/xstor/owriteablestream.hxx
@@ -55,7 +55,8 @@ namespace com { namespace sun { namespace star { namespace uno {
 } } } }
 
 namespace package {
-    bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
+    // all data in aHash1 is contained in aHash2
+    bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
 }
 
 struct WSInternalData_Impl;
diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx
index ac0017f9b974..0df5e49da381 100644
--- a/package/source/xstor/xstorage.cxx
+++ b/package/source/xstor/xstorage.cxx
@@ -859,7 +859,7 @@ void OStorage_Impl::CopyStorageElement( SotElement_Impl* pElement,
                 SAL_INFO("package.xstor", "No Encryption: " << rNoEncryptionException);
             }
 
-            if (bHasCommonEncryptionData && ::package::PackageEncryptionDatasEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
+            if (bHasCommonEncryptionData && ::package::PackageEncryptionDataLessOrEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
             {
                 // If the stream can be opened with the common storage password
                 // it must be stored with the common storage password as well
diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx
index 3c52e0f1cb9a..542da9dd6a7e 100644
--- a/sfx2/source/appl/appopen.cxx
+++ b/sfx2/source/appl/appopen.cxx
@@ -42,6 +42,7 @@
 #include <rtl/ustring.hxx>
 
 #include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/synchronousdispatch.hxx>
 
@@ -239,6 +240,21 @@ ErrCode CheckPasswd_Impl
                             if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() )
                                 aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties);
 
+                            // tdf#93389: if recoverying a document, encryption data should contain
+                            // entries for the real filter, not only for recovery ODF, to keep it
+                            // encrypted. Pass this in encryption data.
+                            // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
+                            // to marshal this to requestAndVerifyDocPassword
+                            if (pSet->GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
+                            {
+                                uno::Sequence< beans::NamedValue > aContainer(1);
+                                aContainer[0].Name = "ForSalvage";
+                                aContainer[0].Value <<= true;
+
+                                aEncryptionData = comphelper::concatSequences(
+                                    aEncryptionData, aContainer);
+                            }
+
                             SfxDocPasswordVerifier aVerifier( xStorage );
                             aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
                                 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );


More information about the Libreoffice-commits mailing list