diff options
author | László Németh <nemeth@numbertext.org> | 2021-06-14 20:46:17 +0200 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2021-06-17 10:43:08 +0200 |
commit | 12da70f88517bf3c053afe1c504bb70bd27573f2 (patch) | |
tree | 27097e4bb9cc343ece830f77991b5d5220ea2ff3 | |
parent | 68eb62b9bf8a64d892b3cfa58447e7c890ed3ec4 (diff) |
tdf#90401 xmloff: remove personal info of comments and changes
If Options → LibreOffice → Security → Security Options
and Warnings → Options... → Security Options → Remove personal
information on saving" is enabled.
Use the same time (1970-01-01T00:00:00) for mandatory
time stamps, and replace authors and creator-initials with
"1", "2", "3" etc., also to avoid of joining adjacent
redline ranges.
Note: to see the work of the unit test in Linux command line:
(cd sw && make UITest_writer_tests7 UITEST_TEST_NAME="tdf90401.tdf90401.test_tdf90401_remove_personal_info" SAL_USE_VCLPLUGIN=gen)
Change-Id: I3b4d710dbeeee12177aff378597cd2b683ca6c25
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117319
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r-- | include/unotools/securityoptions.hxx | 12 | ||||
-rw-r--r-- | include/xmloff/xmlexp.hxx | 6 | ||||
-rw-r--r-- | sw/qa/uitest/data/redline-autocorrect.fodt | 24 | ||||
-rw-r--r-- | sw/qa/uitest/writer_tests7/tdf90401.py | 103 | ||||
-rw-r--r-- | unotools/source/config/securityoptions.cxx | 14 | ||||
-rw-r--r-- | xmloff/source/core/xmlexp.cxx | 3 | ||||
-rw-r--r-- | xmloff/source/draw/sdxmlexp.cxx | 16 | ||||
-rw-r--r-- | xmloff/source/text/XMLRedlineExport.cxx | 24 | ||||
-rw-r--r-- | xmloff/source/text/txtflde.cxx | 13 |
9 files changed, 205 insertions, 10 deletions
diff --git a/include/unotools/securityoptions.hxx b/include/unotools/securityoptions.hxx index 7a339a90bcf8..944e6fba5a34 100644 --- a/include/unotools/securityoptions.hxx +++ b/include/unotools/securityoptions.hxx @@ -25,6 +25,7 @@ #include <rtl/ustring.hxx> #include <unotools/options.hxx> #include <memory> +#include <unordered_map> namespace osl { class Mutex; } @@ -184,6 +185,17 @@ class SAL_WARN_UNUSED UNOTOOLS_DLLPUBLIC SvtSecurityOptions final : public utl:: }; // class SvtSecurityOptions +// map personal info strings, e.g. authors to 1, 2, 3... for removing personal info +typedef ::std::unordered_map< OUString, size_t > SvtSecurityMapPersonalInfoType; + +class UNOTOOLS_DLLPUBLIC SvtSecurityMapPersonalInfo final +{ + SvtSecurityMapPersonalInfoType aInfoIDs; + +public: + size_t GetInfoID( const OUString sPersonalInfo ); +}; + #endif // INCLUDED_UNOTOOLS_SECURITYOPTIONS_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/xmloff/xmlexp.hxx b/include/xmloff/xmlexp.hxx index adba9e653077..5b72788313ef 100644 --- a/include/xmloff/xmlexp.hxx +++ b/include/xmloff/xmlexp.hxx @@ -43,6 +43,7 @@ #include <com/sun/star/container/XNamed.hpp> #include <unotools/saveopt.hxx> +#include <unotools/securityoptions.hxx> #include <xmloff/XMLPageExport.hxx> #include <comphelper/servicehelper.hxx> @@ -69,6 +70,7 @@ namespace com::sun::star::xml::sax { class XExtendedDocumentHandler; } namespace com::sun::star::xml::sax { class XLocator; } class SvXMLNamespaceMap; +class SvtSecurityMapPersonalInfo; class SvXMLExport_Impl; class ProgressBarHelper; class XMLEventExport; @@ -135,6 +137,7 @@ class XMLOFF_DLLPUBLIC SvXMLExport : public cppu::WeakImplHelper< OUString msFilterName; OUString msImgFilterName; std::unique_ptr<SvXMLNamespaceMap> mpNamespaceMap; // the namespace map + std::unique_ptr<SvtSecurityMapPersonalInfo> mpAuthorIDs; // map authors to remove personal info SvXMLUnitConverter maUnitConv; // the unit converter std::unique_ptr<SvXMLNumFmtExport> mpNumExport; std::unique_ptr<ProgressBarHelper> mpProgressBarHelper; @@ -390,6 +393,9 @@ public: // Get (const) namespace map. const SvXMLNamespaceMap& GetNamespaceMap() const { return *mpNamespaceMap; } + // Get author id to remove personal info + size_t GetInfoID( const OUString sPersonalInfo ) const { return mpAuthorIDs->GetInfoID(sPersonalInfo); } + // Get unit converter const SvXMLUnitConverter& GetMM100UnitConverter() const { return maUnitConv; } diff --git a/sw/qa/uitest/data/redline-autocorrect.fodt b/sw/qa/uitest/data/redline-autocorrect.fodt new file mode 100644 index 000000000000..ce874d299a8f --- /dev/null +++ b/sw/qa/uitest/data/redline-autocorrect.fodt @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:officeooo="http://openoffice.org/2009/office" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text" xmlns:dc="http://purl.org/dc/elements/1.1/"> + <office:styles> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:default-style style:family="paragraph"> + <style:text-properties fo:language="en" fo:country="US"/> + </style:default-style> + </office:styles> + <office:body> + <office:text> + <text:tracked-changes text:track-changes="false"> + <text:changed-region xml:id="ct94099223789984" text:id="ct94099223789984"> + <text:deletion> + <office:change-info> + <dc:creator>NL</dc:creator> + <dc:date>2020-11-03T19:19:05</dc:date> + </office:change-info> + </text:deletion> + </text:changed-region> + </text:tracked-changes> + <text:p text:style-name="P1"><text:change-start text:change-id="ct94099223789984"/>t<text:change-end text:change-id="ct94099223789984"/>s</text:p> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/uitest/writer_tests7/tdf90401.py b/sw/qa/uitest/writer_tests7/tdf90401.py new file mode 100644 index 000000000000..7260ae914268 --- /dev/null +++ b/sw/qa/uitest/writer_tests7/tdf90401.py @@ -0,0 +1,103 @@ +# -*- 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 type_text +from uitest.uihelper.common import get_state_as_dict +from uitest.uihelper.common import get_url_for_data_file +from uitest.uihelper.common import select_pos +from libreoffice.uno.propertyvalue import mkPropertyValues +from org.libreoffice.unotest import systemPathToFileUrl +from tempfile import TemporaryDirectory +import os.path +#Bug 90401 - remove personal info on redlines and annotations + +class tdf90401(UITestCase): + + def test_tdf90401_remove_personal_info(self): + + # load a test document with a tracked change, and add a comment + + writer_doc = self.ui_test.load_file(get_url_for_data_file('redline-autocorrect.fodt')) + xWriterDoc = self.xUITest.getTopFocusWindow() + xWriterEdit = xWriterDoc.getChild('writer_edit') + + document = self.ui_test.get_component() + selection = self.xUITest.executeCommand('.uno:SelectAll') + self.xUITest.executeCommand('.uno:InsertAnnotation') + + # enable remove personal info security option + + self.ui_test.execute_dialog_through_command('.uno:OptionsTreeDialog') #optionsdialog + xDialog = self.xUITest.getTopFocusWindow() + + xPages = xDialog.getChild('pages') + xGenEntry = xPages.getChild('0') + xSecurityPage = xGenEntry.getChild('6') + xSecurityPage.executeAction('SELECT', tuple()) + # Click Button Options... + xOptions = xDialog.getChild('options') + def handle_options_dlg(dialog): + xRemovePersonal = dialog.getChild('removepersonal') + xRemovePersonal.executeAction('CLICK', tuple()) + #Click on its button Close + xOkBtn = dialog.getChild('ok') + xOkBtn.executeAction('CLICK', tuple()) + + self.ui_test.execute_blocking_action(xOptions.executeAction, args=('CLICK', ()), + dialog_handler=handle_options_dlg) + + xOKBtn = xDialog.getChild('ok') + self.ui_test.close_dialog_through_button(xOKBtn) + + # save and reload the document to remove personal info + + with TemporaryDirectory() as tempdir: + xFilePath = os.path.join(tempdir, 'tdf90401-tmp.fodt') + + # Save Copy as + self.ui_test.execute_dialog_through_command('.uno:SaveAs') + xDialog = self.xUITest.getTopFocusWindow() + + xFileName = xDialog.getChild('file_name') + xFileName.executeAction('TYPE', mkPropertyValues({'KEYCODE':'CTRL+A'})) + xFileName.executeAction('TYPE', mkPropertyValues({'KEYCODE':'BACKSPACE'})) + xFileName.executeAction('TYPE', mkPropertyValues({'TEXT': xFilePath})) + + xOpenBtn = xDialog.getChild('open') + self.ui_test.close_dialog_through_button(xOpenBtn) + + # Close the Writer document + self.ui_test.close_doc() + + self.ui_test.load_file(systemPathToFileUrl(xFilePath)) + document = self.ui_test.get_component() + + # check removed personal info on comments + + textfields = document.getTextFields() + author = "" + year = -1 + for textfield in textfields: + if textfield.supportsService("com.sun.star.text.TextField.Annotation"): + author = textfield.Author + year = textfield.Date.Year + # This was 'Unknown Author' + self.assertEqual(author, 'Author2') + # This was 2021 + self.assertEqual(year, 0) + + # check removed personal info on tracked changes + + self.ui_test.execute_modeless_dialog_through_command('.uno:AcceptTrackedChanges') + xTrackDlg = self.xUITest.getTopFocusWindow() + xTreeList = xTrackDlg.getChild('writerchanges') + state = get_state_as_dict(xTreeList) + # This was 'NL\t11/03/2020 19:19:05\t', containing personal info + self.assertEqual(state['SelectEntryText'], 'Author1\t01/01/1970 00:00:00\t') + + self.ui_test.close_doc() +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/unotools/source/config/securityoptions.cxx b/unotools/source/config/securityoptions.cxx index 7acb0ff2d3c0..ff10bcb584b9 100644 --- a/unotools/source/config/securityoptions.cxx +++ b/unotools/source/config/securityoptions.cxx @@ -933,4 +933,18 @@ Mutex& SvtSecurityOptions::GetInitMutex() return theSecurityOptionsMutex::get(); } +// map personal info strings to 1, 2, ... to remove personal info +size_t SvtSecurityMapPersonalInfo::GetInfoID( const OUString sPersonalInfo ) +{ + SvtSecurityMapPersonalInfoType::iterator aIter = aInfoIDs.find( sPersonalInfo ); + if ( aIter == aInfoIDs.end() ) + { + size_t nNewID = aInfoIDs.size() + 1; + aInfoIDs[sPersonalInfo] = nNewID; + return nNewID; + } + + return aIter->second; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlexp.cxx b/xmloff/source/core/xmlexp.cxx index 05d44229e321..d73783994271 100644 --- a/xmloff/source/core/xmlexp.cxx +++ b/xmloff/source/core/xmlexp.cxx @@ -459,6 +459,7 @@ SvXMLExport::SvXMLExport( m_xContext(xContext), m_implementationName(implementationName), mxAttrList( new SvXMLAttributeList ), mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), meClass( eClass ), mnExportFlags( nExportFlags ), @@ -484,6 +485,7 @@ SvXMLExport::SvXMLExport( mxAttrList( new SvXMLAttributeList ), msOrigFileName( rFileName ), mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), meClass( XML_TOKEN_INVALID ), mnExportFlags( SvXMLExportFlags::NONE ), @@ -517,6 +519,7 @@ SvXMLExport::SvXMLExport( mxAttrList( new SvXMLAttributeList ), msOrigFileName( rFileName ), mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), maUnitConv( xContext, util::MeasureUnit::MM_100TH, SvXMLUnitConverter::GetMeasureUnit(eDefaultFieldUnit), diff --git a/xmloff/source/draw/sdxmlexp.cxx b/xmloff/source/draw/sdxmlexp.cxx index 652bce79610d..db1542fc511f 100644 --- a/xmloff/source/draw/sdxmlexp.cxx +++ b/xmloff/source/draw/sdxmlexp.cxx @@ -2516,6 +2516,10 @@ void SdXMLExport::exportAnnotations( const Reference<XDrawPage>& xDrawPage ) Reference< XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); if( xAnnotationEnumeration.is() && xAnnotationEnumeration->hasMoreElements() ) { + SvtSecurityOptions aSecOpt; + bool bRemovePersonalInfo = aSecOpt.IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + OUStringBuffer sStringBuffer; do { @@ -2551,7 +2555,9 @@ void SdXMLExport::exportAnnotations( const Reference<XDrawPage>& xDrawPage ) if( !aAuthor.isEmpty() ) { SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC, XML_CREATOR, true, false ); - Characters(aAuthor); + Characters( bRemovePersonalInfo + ? "Author" + OUString::number( SvXMLExport::GetInfoID(aAuthor) ) + : aAuthor ); } // initials @@ -2567,7 +2573,9 @@ void SdXMLExport::exportAnnotations( const Reference<XDrawPage>& xDrawPage ) ? XML_CREATOR_INITIALS : XML_SENDER_INITIALS, true, false ); - Characters(aInitials); + Characters( bRemovePersonalInfo + ? OUString::number( SvXMLExport::GetInfoID(aInitials) ) + : aInitials ); } { @@ -2575,7 +2583,9 @@ void SdXMLExport::exportAnnotations( const Reference<XDrawPage>& xDrawPage ) css::util::DateTime aDate( xAnnotation->getDateTime() ); ::sax::Converter::convertDateTime(sStringBuffer, aDate, nullptr, true); SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC, XML_DATE, true, false ); - Characters(sStringBuffer.makeStringAndClear()); + Characters( bRemovePersonalInfo + ? "1970-01-01T00:00::00" + : sStringBuffer.makeStringAndClear() ); } css::uno::Reference < css::text::XText > xText( xAnnotation->getTextRange() ); diff --git a/xmloff/source/text/XMLRedlineExport.cxx b/xmloff/source/text/XMLRedlineExport.cxx index e309b1d86731..fad527a77b59 100644 --- a/xmloff/source/text/XMLRedlineExport.cxx +++ b/xmloff/source/text/XMLRedlineExport.cxx @@ -42,6 +42,7 @@ #include <xmloff/xmlnamespace.hxx> #include <xmloff/xmlexp.hxx> #include <xmloff/xmluconv.hxx> +#include <unotools/securityoptions.hxx> using namespace ::com::sun::star; @@ -433,6 +434,9 @@ OUString XMLRedlineExport::GetRedlineID( void XMLRedlineExport::ExportChangeInfo( const Reference<XPropertySet> & rPropSet) { + SvtSecurityOptions aSecOpt; + bool bRemovePersonalInfo = aSecOpt.IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, XML_CHANGE_INFO, true, true); @@ -445,7 +449,9 @@ void XMLRedlineExport::ExportChangeInfo( SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, XML_CREATOR, true, false ); - rExport.Characters(sTmp); + rExport.Characters(bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp ); } aAny = rPropSet->getPropertyValue("RedlineDateTime"); @@ -457,7 +463,9 @@ void XMLRedlineExport::ExportChangeInfo( SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, XML_DATE, true, false ); - rExport.Characters(sBuf.makeStringAndClear()); + rExport.Characters(bRemovePersonalInfo + ? "1970-01-01T00:00:00" + : sBuf.makeStringAndClear()); } // comment as <text:p> sequence @@ -470,6 +478,9 @@ void XMLRedlineExport::ExportChangeInfo( const Sequence<PropertyValue> & rPropertyValues) { OUString sComment; + SvtSecurityOptions aSecOpt; + bool bRemovePersonalInfo = aSecOpt.IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); for(const PropertyValue& rVal : rPropertyValues) { @@ -479,7 +490,9 @@ void XMLRedlineExport::ExportChangeInfo( rVal.Value >>= sTmp; if (!sTmp.isEmpty()) { - rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_AUTHOR, sTmp); + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_AUTHOR, bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp); } } else if( rVal.Name == "RedlineComment" ) @@ -492,8 +505,9 @@ void XMLRedlineExport::ExportChangeInfo( rVal.Value >>= aDateTime; OUStringBuffer sBuf; ::sax::Converter::convertDateTime(sBuf, aDateTime, nullptr); - rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME, - sBuf.makeStringAndClear()); + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME, bRemovePersonalInfo + ? "1970-01-01T00:00:00" + : sBuf.makeStringAndClear()); } else if( rVal.Name == "RedlineType" ) { diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx index 962e30e995d4..93f43ee6c082 100644 --- a/xmloff/source/text/txtflde.cxx +++ b/xmloff/source/text/txtflde.cxx @@ -1746,6 +1746,10 @@ void XMLTextFieldExport::ExportFieldHelper( DBG_ASSERT(sPresentation.isEmpty(), "Unexpected presentation for annotation field"); + SvtSecurityOptions aSecOpt; + bool bRemovePersonalInfo = aSecOpt.IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + // annotation element + content OUString aName; rPropSet->getPropertyValue(gsPropertyName) >>= aName; @@ -1774,11 +1778,14 @@ void XMLTextFieldExport::ExportFieldHelper( SvXMLElementExport aCreatorElem( GetExport(), XML_NAMESPACE_DC, XML_CREATOR, true, false ); - GetExport().Characters(aAuthor); + GetExport().Characters( bRemovePersonalInfo + ? "Author" + OUString::number( rExport.GetInfoID(aAuthor) ) + : aAuthor ); } // date time util::DateTime aDate( GetDateTimeProperty(gsPropertyDateTimeValue, rPropSet) ); + if ( !bRemovePersonalInfo ) { OUStringBuffer aBuffer; ::sax::Converter::convertDateTime(aBuffer, aDate, nullptr, true); @@ -1804,7 +1811,9 @@ void XMLTextFieldExport::ExportFieldHelper( ? XML_CREATOR_INITIALS : XML_SENDER_INITIALS, true, false ); - GetExport().Characters(aInitials); + GetExport().Characters( bRemovePersonalInfo + ? OUString::number( rExport.GetInfoID(aInitials) ) + : aInitials); } } |