sc/inc/unonames.hxx | 1 sc/qa/uitest/calc_tests9/tdf118938.py | 49 ++++++++++++++++++++++++++++++ sc/qa/uitest/data/tdf118938.xlsx |binary sc/source/filter/excel/excdoc.cxx | 11 ++++++ sc/source/filter/oox/workbooksettings.cxx | 11 +----- sc/source/ui/unoobj/confuno.cxx | 13 +++++++ sfx2/source/view/viewfrm.cxx | 7 +++- 7 files changed, 81 insertions(+), 11 deletions(-)
New commits: commit c082158018148be01476d5bc82c1cd71ea6541df Author: Tünde Tóth <toth.tu...@nisz.hu> AuthorDate: Tue Aug 31 12:08:39 2021 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Wed Sep 1 11:29:08 2021 +0200 tdf#118938 XLSX import/export: fix permission for editing The password for editing wasn't asked, also wasn't exported in XLSX documents. Now it's exported in Calc using the following steps, also verified before editing: - In File->Save As, choose Excel 2007–365 (.xlsx) format; - enable checkbox "Save with password" and click Save; - in the dialog "Set password", click on "Options" and enable checkbox "Open file read-only", and enter a password for editing (i.e. skip the password for opening). Note: Excel 2016 doesn't ask password for editing, but Office 365 does. Passwords created in Excel haven't been supported, yet. Also passwords with diacritics aren't interoperable. Note: saving the file under a different path is still allowed both in Calc and Excel without asking the password for editing. Change-Id: Ic00d7c5a785e04d270a182a4087ea922d7d92979 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121371 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx index 56936063f74c..36ab650e918b 100644 --- a/sc/inc/unonames.hxx +++ b/sc/inc/unonames.hxx @@ -666,6 +666,7 @@ // Security options #define SC_UNO_LOADREADONLY "LoadReadonly" #define SC_UNO_MODIFYPASSWORDINFO "ModifyPasswordInfo" +#define SC_UNO_MODIFYPASSWORDHASH "ModifyPasswordHash" // FormulaParser #define SC_UNO_COMPILEENGLISH "CompileEnglish" diff --git a/sc/qa/uitest/calc_tests9/tdf118938.py b/sc/qa/uitest/calc_tests9/tdf118938.py new file mode 100644 index 000000000000..7444f65780ea --- /dev/null +++ b/sc/qa/uitest/calc_tests9/tdf118938.py @@ -0,0 +1,49 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +from uitest.framework import UITestCase +from uitest.uihelper.common import get_url_for_data_file +from libreoffice.uno.propertyvalue import mkPropertyValues + +#Bug 118938 - FILESAVE to Microsoft Excel 2007-2013 XML (.xlsx) files as read-only +# with additional password protection for editing not working (Calc) + +class tdf118938(UITestCase): + def test_tdf118938(self): + with self.ui_test.load_file(get_url_for_data_file("tdf118938.xlsx")): + #The document was created in Calc after this fix. + calcDoc = self.xUITest.getTopFocusWindow() + gridwin = calcDoc.getChild("grid_window") + + incorrectPass = False; + + try: + self.xUITest.executeDialog(".uno:EditDoc") + xDialog = self.xUITest.getTopFocusWindow(); + xPassword = xDialog.getChild("newpassEntry") + xPassword.executeAction("TYPE", mkPropertyValues({"TEXT": "a"})) + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + try: + xWarnDialog = self.xUITest.getTopFocusWindow() + xOK = xWarnDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOK) + + xDialog2 = self.xUITest.getTopFocusWindow(); + xCancelBtn = xDialog2.getChild("cancel") + self.ui_test.close_dialog_through_button(xCancelBtn) + + incorrectPass = True; + except: + pass + except: + assert False, "The password dialog hasn't appeared." + + if incorrectPass: + assert False, "Incorrect password." + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sc/qa/uitest/data/tdf118938.xlsx b/sc/qa/uitest/data/tdf118938.xlsx new file mode 100644 index 000000000000..5e571f9f2475 Binary files /dev/null and b/sc/qa/uitest/data/tdf118938.xlsx differ diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index ebc5a69f937a..1f43caaf73f9 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -806,7 +806,11 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm ) uno::Reference<document::XDocumentPropertiesSupplier> xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties(); - rStrm.exportDocumentProperties(xDocProps, pDocShell->IsSecurityOptOpenReadOnly()); + sal_uInt32 nWriteProtHash = pDocShell->GetModifyPasswordHash(); + OUString sUserName = GetUserName(); + bool bHasPassword = nWriteProtHash && !sUserName.isEmpty(); + rStrm.exportDocumentProperties(xDocProps, + pDocShell->IsSecurityOptOpenReadOnly() && !bHasPassword); rStrm.exportCustomFragments(); sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream(); @@ -821,6 +825,11 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm ) // OOXTODO: XML_rupBuild ); + if (bHasPassword) + rWorkbook->singleElement(XML_fileSharing, + XML_userName, sUserName, + XML_reservationPassword, OString::number(nWriteProtHash, 16).getStr()); + if( !maTableList.IsEmpty() ) { InitializeSave(); diff --git a/sc/source/filter/oox/workbooksettings.cxx b/sc/source/filter/oox/workbooksettings.cxx index 19967601cd30..a7ab887bf967 100644 --- a/sc/source/filter/oox/workbooksettings.cxx +++ b/sc/source/filter/oox/workbooksettings.cxx @@ -210,15 +210,8 @@ void WorkbookSettings::finalizeImport() if (maFileSharing.mbRecommendReadOnly || !maFileSharing.maHashValue.isEmpty()) aSettingsProp.setProperty( PROP_LoadReadonly, true ); - /* TODO: setting ModifyPasswordHash was commented out with commit - * 1a842832cd174d5ccfd832fdb94c93ae42e8eacc of which the filter - * fragment parts meanwhile contain PASSWORDTOMODIFY again, also for - * calc_OOXML.xcu, but setting the property doesn't raise a dialog. If - * it worked, a Sequence<PropertyValue> should be used for - * algorithmName,hashValue,... see also - * SfxObjectShell::SetModifyPasswordInfo() */ -// if( maFileSharing.mnPasswordHash != 0 ) -// aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) ); + if( maFileSharing.mnPasswordHash != 0 ) + aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) ); } catch( Exception& ) { diff --git a/sc/source/ui/unoobj/confuno.cxx b/sc/source/ui/unoobj/confuno.cxx index d7ead11acdd4..f148b9abed8f 100644 --- a/sc/source/ui/unoobj/confuno.cxx +++ b/sc/source/ui/unoobj/confuno.cxx @@ -83,6 +83,7 @@ static const SfxItemPropertyMapEntry* lcl_GetConfigPropertyMap() {u"" SC_UNO_LOADREADONLY, 0, cppu::UnoType<bool>::get(), 0, 0}, {u"" SC_UNO_SHAREDOC, 0, cppu::UnoType<bool>::get(), 0, 0}, {u"" SC_UNO_MODIFYPASSWORDINFO, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0}, + {u"" SC_UNO_MODIFYPASSWORDHASH, 0, cppu::UnoType<sal_Int32>::get(), 0, 0}, {u"" SC_UNO_EMBED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0}, {u"" SC_UNO_EMBED_ONLY_USED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0}, {u"" SC_UNO_EMBED_FONT_SCRIPT_LATIN, 0, cppu::UnoType<bool>::get(), 0, 0}, @@ -337,6 +338,16 @@ void SAL_CALL ScDocumentConfiguration::setPropertyValue( throw beans::PropertyVetoException( "The hash is not allowed to be changed now!" ); } + else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH) + { + sal_Int32 nHash; + if (!(aValue >>= nHash)) + throw lang::IllegalArgumentException("Value of type sal_Int32 expected!", + uno::Reference<uno::XInterface>(), 2); + + if (!pDocShell->SetModifyPasswordHash(nHash)) + throw beans::PropertyVetoException("The hash is not allowed to be changed now!"); + } else if (aPropertyName == SC_UNO_EMBED_FONTS) { bool bVal = aValue.has<bool>() && aValue.get<bool>(); @@ -537,6 +548,8 @@ uno::Any SAL_CALL ScDocumentConfiguration::getPropertyValue( const OUString& aPr } else if ( aPropertyName == SC_UNO_MODIFYPASSWORDINFO ) aRet <<= pDocShell->GetModifyPasswordInfo(); + else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH) + aRet <<= pDocShell->GetModifyPasswordHash(); else if (aPropertyName == SC_UNO_EMBED_FONTS) aRet <<= rDoc.IsEmbedFonts(); else if (aPropertyName == SC_UNO_EMBED_ONLY_USED_FONTS) diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx index ada11bea9930..4ba5bc852834 100644 --- a/sfx2/source/view/viewfrm.cxx +++ b/sfx2/source/view/viewfrm.cxx @@ -352,6 +352,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq ) StreamMode nOpenMode; bool bNeedsReload = false; + bool bPasswordEntered = false; if ( !pSh->IsReadOnly() ) { // Save and reload Readonly @@ -388,6 +389,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq ) } pSh->SetModifyPasswordEntered(); + bPasswordEntered = true; } nOpenMode = pSh->IsOriginallyReadOnlyMedium() ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE; @@ -439,8 +441,11 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq ) aPhysObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); bool bIsWebDAV = aMedObj.isAnyKnownWebDAVScheme(); + // tdf#118938 Reload the document when the user enters the editing password, + // even if the physical name isn't different to the logical name. if ( ( !bNeedsReload && ( ( aMedObj.GetProtocol() == INetProtocol::File && - aMedObj.getFSysPath( FSysStyle::Detect ) != aPhysObj.getFSysPath( FSysStyle::Detect ) && + ( aMedObj.getFSysPath( FSysStyle::Detect ) != aPhysObj.getFSysPath( FSysStyle::Detect ) + || bPasswordEntered ) && !bPhysObjIsYounger ) || ( bIsWebDAV && !bPhysObjIsYounger ) || ( pMed->IsRemote() && !bIsWebDAV ) ) )