sd/qa/uitest/impress_tests/save_readonly_with_password.py |   47 +++++++++
 sd/source/filter/eppt/epptooxml.hxx                       |    2 
 sd/source/filter/eppt/pptx-epptooxml.cxx                  |   71 ++++++++++++++
 3 files changed, 120 insertions(+)

New commits:
commit 04e279007272de286be31152d01e9cb45c9bd3e3
Author:     Tünde Tóth <toth.tu...@nisz.hu>
AuthorDate: Wed Nov 3 12:59:47 2021 +0100
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Wed Nov 24 09:19:18 2021 +0100

    tdf#145511 PPTX: export the password for editing
    
    The password for editing wasn't exported in PPTX
    documents.
    
    Test: Edit->Edit Mode doesn't change to edit mode
    any more without asking the password for editing.
    
    Follow-up to commit 5697e09b3e726a38b58ce31ac0c3a97e7871c74a
    "tdf#144943 PPTX import: fix permission for editing".
    
    Change-Id: I1a9de511cf8b79224d8ac0a9aa0bf860b87bf184
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124651
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sd/qa/uitest/impress_tests/save_readonly_with_password.py 
b/sd/qa/uitest/impress_tests/save_readonly_with_password.py
index 3f789035d0a8..cd4fe98339c0 100644
--- a/sd/qa/uitest/impress_tests/save_readonly_with_password.py
+++ b/sd/qa/uitest/impress_tests/save_readonly_with_password.py
@@ -13,6 +13,53 @@ import os.path
 
 class save_readonly_with_password(UITestCase):
 
+    #Bug 145511 - FILESAVE to PPTX as read-only with additional password 
protection for editing not working
+   def test_save_to_pptx(self):
+
+        with TemporaryDirectory() as tempdir:
+            xFilePath = os.path.join(tempdir, "tdf144374-tmp.pptx")
+
+            with self.ui_test.create_doc_in_start_center("impress"):
+                xTemplateDlg = self.xUITest.getTopFocusWindow()
+                xCancelBtn = xTemplateDlg.getChild("close")
+                self.ui_test.close_dialog_through_button(xCancelBtn)
+
+                # Save the document
+                with self.ui_test.execute_dialog_through_command(".uno:Save", 
close_button="") as xSaveDialog:
+                    xFileName = xSaveDialog.getChild("file_name")
+                    xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"CTRL+A"}))
+                    xFileName.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"BACKSPACE"}))
+                    xFileName.executeAction("TYPE", mkPropertyValues({"TEXT": 
xFilePath}))
+                    xFileTypeCombo = xSaveDialog.getChild("file_type")
+                    select_by_text(xFileTypeCombo, "Office Open XML 
Presentation (.pptx)")
+                    xPasswordCheckButton = xSaveDialog.getChild("password")
+                    xPasswordCheckButton.executeAction("CLICK", tuple())
+                    xOpen = xSaveDialog.getChild("open")
+
+                    with self.ui_test.execute_dialog_through_action(xOpen, 
"CLICK") as xPasswordDialog:
+                        xReadonly = xPasswordDialog.getChild("readonly")
+                        xReadonly.executeAction("CLICK", tuple())
+                        xNewPassword = 
xPasswordDialog.getChild("newpassroEntry")
+                        xNewPassword.executeAction("TYPE", 
mkPropertyValues({"TEXT": "password"}))
+                        xConfirmPassword = 
xPasswordDialog.getChild("confirmropassEntry")
+                        xConfirmPassword.executeAction("TYPE", 
mkPropertyValues({"TEXT": "password"}))
+
+                # PPTX confirmation dialog is displayed
+                xWarnDialog = self.xUITest.getTopFocusWindow()
+                xSave = xWarnDialog.getChild("save")
+                self.ui_test.close_dialog_through_button(xSave)
+
+            with self.ui_test.load_file(systemPathToFileUrl(xFilePath)) as 
document:
+
+                self.assertTrue(document.isReadonly())
+
+                # Without the fix in place, this dialog wouldn't have been 
displayed
+                with 
self.ui_test.execute_dialog_through_command(".uno:EditDoc") as xDialog:
+                    xPassword = xDialog.getChild("newpassEntry")
+                    xPassword.executeAction("TYPE", mkPropertyValues({"TEXT": 
"password"}))
+
+                self.assertFalse(document.isReadonly())
+
    def test_save_to_odp(self):
 
         with TemporaryDirectory() as tempdir:
diff --git a/sd/source/filter/eppt/epptooxml.hxx 
b/sd/source/filter/eppt/epptooxml.hxx
index 82bb6a3ab937..0c7e098f5771 100644
--- a/sd/source/filter/eppt/epptooxml.hxx
+++ b/sd/source/filter/eppt/epptooxml.hxx
@@ -168,6 +168,8 @@ private:
 
     /// If this is PPTM, output the VBA stream.
     void WriteVBA();
+
+    void WriteModifyVerifier();
 };
 
 }
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx 
b/sd/source/filter/eppt/pptx-epptooxml.cxx
index 59f2e879b06f..d5787d6f4cb7 100644
--- a/sd/source/filter/eppt/pptx-epptooxml.cxx
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -495,6 +495,8 @@ bool PowerPointExport::exportDocument()
 
     WriteVBA();
 
+    WriteModifyVerifier();
+
     mPresentationFS->endElementNS(XML_p, XML_presentation);
     mPresentationFS.reset();
     // Free all FSHelperPtr, to flush data before committing storage
@@ -1258,6 +1260,75 @@ void PowerPointExport::WriteVBA()
     addRelation(mPresentationFS->getOutputStream(), 
oox::getRelationship(Relationship::VBAPROJECT), u"vbaProject.bin");
 }
 
+void PowerPointExport::WriteModifyVerifier()
+{
+    Sequence<PropertyValue> aInfo;
+
+    try
+    {
+        Reference<lang::XMultiServiceFactory> xFactory(mXModel, UNO_QUERY);
+        Reference<XPropertySet> xDocSettings(
+            xFactory->createInstance("com.sun.star.document.Settings"), 
UNO_QUERY);
+        xDocSettings->getPropertyValue("ModifyPasswordInfo") >>= aInfo;
+    }
+    catch (const Exception&)
+    {
+    }
+
+    if (aInfo.hasElements())
+    {
+        OUString sAlgorithm, sSalt, sHash;
+        sal_Int32 nCount = 0;
+        for (auto& prop : aInfo)
+        {
+            if (prop.Name == "algorithm-name")
+                prop.Value >>= sAlgorithm;
+            else if (prop.Name == "salt")
+                prop.Value >>= sSalt;
+            else if (prop.Name == "iteration-count")
+                prop.Value >>= nCount;
+            else if (prop.Name == "hash")
+                prop.Value >>= sHash;
+        }
+        if (!sAlgorithm.isEmpty() && !sSalt.isEmpty() && !sHash.isEmpty())
+        {
+            sal_Int32 nAlgorithmSid = 0;
+            if (sAlgorithm == "MD2")
+                nAlgorithmSid = 1;
+            else if (sAlgorithm == "MD4")
+                nAlgorithmSid = 2;
+            else if (sAlgorithm == "MD5")
+                nAlgorithmSid = 3;
+            else if (sAlgorithm == "SHA-1")
+                nAlgorithmSid = 4;
+            else if (sAlgorithm == "MAC")
+                nAlgorithmSid = 5;
+            else if (sAlgorithm == "RIPEMD")
+                nAlgorithmSid = 6;
+            else if (sAlgorithm == "RIPEMD-160")
+                nAlgorithmSid = 7;
+            else if (sAlgorithm == "HMAC")
+                nAlgorithmSid = 9;
+            else if (sAlgorithm == "SHA-256")
+                nAlgorithmSid = 12;
+            else if (sAlgorithm == "SHA-384")
+                nAlgorithmSid = 13;
+            else if (sAlgorithm == "SHA-512")
+                nAlgorithmSid = 14;
+
+            if (nAlgorithmSid != 0)
+                mPresentationFS->singleElementNS(XML_p, XML_modifyVerifier,
+                    XML_cryptProviderType, "rsaAES",
+                    XML_cryptAlgorithmClass, "hash",
+                    XML_cryptAlgorithmType, "typeAny",
+                    XML_cryptAlgorithmSid, 
OString::number(nAlgorithmSid).getStr(),
+                    XML_spinCount, OString::number(nCount).getStr(),
+                    XML_saltData, sSalt.toUtf8().getStr(),
+                    XML_hashData, sHash.toUtf8().getStr());
+        }
+    }
+}
+
 void PowerPointExport::ImplWriteSlide(sal_uInt32 nPageNum, sal_uInt32 
nMasterNum, sal_uInt16 /* nMode */,
                                       bool bHasBackground, Reference< 
XPropertySet > const& aXBackgroundPropSet)
 {

Reply via email to