[Libreoffice-commits] core.git: 3 commits - sw/inc sw/source

Ashod Nakashian ashod.nakashian at collabora.co.uk
Mon Aug 28 01:55:14 UTC 2017


 sw/inc/editsh.hxx                 |    4 
 sw/inc/strings.hrc                |    7 
 sw/source/core/edit/edfcol.cxx    |  267 ++++++++++++++++++++++++++++++--------
 sw/source/core/edit/edws.cxx      |    9 -
 sw/source/core/txtnode/ndtxt.cxx  |    6 
 sw/source/core/txtnode/thints.cxx |   18 ++
 6 files changed, 254 insertions(+), 57 deletions(-)

New commits:
commit af694659763de9a787e018df5ba4debd4976cd03
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Fri Aug 25 20:47:58 2017 -0400

    sw: remove signature metadata on deleting signature field
    
    Change-Id: I1f82b2d59889c1ba84d91880df13d12d3e5b796c
    Reviewed-on: https://gerrit.libreoffice.org/41594
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index b6586595a32e..ae8720ba674e 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -76,6 +76,9 @@
 #include <map>
 #include <memory>
 
+#include <docsh.hxx>
+#include <rdfhelper.hxx>
+
 #ifdef DBG_UTIL
 #define CHECK           Check(true);
 #define CHECK_NOTMERGED Check(false);
@@ -1191,7 +1194,22 @@ void SwTextNode::DestroyAttr( SwTextAttr* pAttr )
 
         case RES_TXTATR_META:
         case RES_TXTATR_METAFIELD:
+        {
+            auto pTextMeta = static_txtattr_cast<SwTextMeta*>(pAttr);
+            SwFormatMeta & rFormatMeta( static_cast<SwFormatMeta &>(pTextMeta->GetAttr()) );
+            if (::sw::Meta* pMeta = rFormatMeta.GetMeta())
+            {
+                if (SwDocShell* pDocSh = pDoc->GetDocShell())
+                {
+                    static const OUString metaNS("urn:bails");
+                    const css::uno::Reference<css::rdf::XResource> xSubject(pMeta->MakeUnoObject(), uno::UNO_QUERY);
+                    uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel();
+                    SwRDFHelper::clearStatements(xModel, metaNS, xSubject);
+                }
+            }
+
             static_txtattr_cast<SwTextMeta*>(pAttr)->ChgTextNode(nullptr);
+        }
             break;
 
         default:
commit 2c3dfd9d3bafc6ad84d750c7bec935b5b164e7f7
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Fri Aug 25 20:47:30 2017 -0400

    sw: invalidate paragraph signature on edit
    
    Change-Id: I7267b1492f2eff043058a9322286f742338a2335
    Reviewed-on: https://gerrit.libreoffice.org/41593
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 8391a652df2f..8031dd2fe8b0 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -1211,6 +1211,12 @@ void SwTextNode::Update(
     if (pSortedObjs)
         pSortedObjs->UpdateAll();
 
+    // Update the paragraph signatures.
+    if (SwEditShell* pEditShell = GetDoc()->GetEditShell())
+    {
+        pEditShell->ValidateParagraphSignatures(false);
+    }
+
     // Inform LOK clients about change in position of redlines (if any)
     if (comphelper::LibreOfficeKit::isActive())
     {
commit 3eb31b506a2860eba3a578333a6486ee2a518c1a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Fri Aug 25 20:46:33 2017 -0400

    sw: sign paragraphs and validate
    
    Change-Id: I917ad1460c89183eec38d50de8a0de2d76239ea6
    Reviewed-on: https://gerrit.libreoffice.org/41592
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx
index 411c8eed3921..f8d40ddcd0ba 100644
--- a/sw/inc/editsh.hxx
+++ b/sw/inc/editsh.hxx
@@ -374,6 +374,9 @@ public:
     /// Sign the paragraph at the cursor.
     void SignParagraph(SwPaM* pPaM);
 
+    /// Validate paragraph signatures, if any, at the cursor.
+    void ValidateParagraphSignatures(bool updateDontRemove);
+
     void Insert2(SwField const &, const bool bForceExpandHints);
 
     void UpdateFields( SwField & );   ///< One single field.
@@ -969,6 +972,7 @@ private:
      * the existing nb-space will be removed. Bear this in mind if that problem
      * arises. */
     bool m_bNbspRunNext;    ///< NO-BREAK SPACE state flag passed to and maintained by SvxAutoCorrect::DoAutoCorrect()
+    bool m_bIsValidatingParagraphSignature; ///< Prevent nested calls of ValidateParagraphSignatures.
 };
 
 inline const sfx2::LinkManager& SwEditShell::GetLinkManager() const
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index 9c42670f24e0..9e77c736bdd8 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -1337,6 +1337,13 @@
 #define STR_MENU_UP                             NC_("STR_MENU_UP", "~Upwards")
 #define STR_MENU_DOWN                           NC_("STR_MENU_DOWN", "Do~wnwards")
 
+/*--------------------------------------------------------------------
+    Description: Paragraph Signature
+ --------------------------------------------------------------------*/
+#define STR_VALID                               NC_("STR_VALID", "Valid")
+#define STR_INVALID                             NC_("STR_INVALID", "Invalid")
+#define STR_SIGNED_BY                           NC_("STR_SIGNED_BY", "Signed-by")
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
index 456d06b65b96..5dd18baaedf3 100644
--- a/sw/source/core/edit/edfcol.cxx
+++ b/sw/source/core/edit/edfcol.cxx
@@ -32,12 +32,18 @@
 #include <com/sun/star/text/TextContentAnchorType.hpp>
 #include <com/sun/star/text/VertOrientation.hpp>
 #include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
+#include <com/sun/star/rdf/XMetadatable.hpp>
 
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <comphelper/propertysequence.hxx>
 #include <comphelper/propertyvalue.hxx>
+#include <comphelper/processfactory.hxx>
 #include <comphelper/sequence.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/string.hxx>
 #include <editeng/formatbreakitem.hxx>
 #include <editeng/unoprnms.hxx>
 #include <sfx2/classificationhelper.hxx>
@@ -64,7 +70,11 @@
 #include <sfx2/watermarkitem.hxx>
 #include <DocumentDrawModelManager.hxx>
 
+#include <unoparagraph.hxx>
+#include <unotextrange.hxx>
 #include <cppuhelper/bootstrap.hxx>
+#include <modeltoviewhelper.hxx>
+#include <strings.hrc>
 
 #define WATERMARK_NAME "PowerPlusWaterMarkObject"
 
@@ -169,6 +179,103 @@ uno::Reference<drawing::XShape> lcl_getWatermark(const uno::Reference<text::XTex
     return uno::Reference<drawing::XShape>();
 }
 
+/// Extract the text of the paragraph without any of the fields.
+/// TODO: Consider moving to SwTextNode, or extend ModelToViewHelper.
+OString lcl_getParagraphBodyText(const uno::Reference<text::XTextContent>& xText)
+{
+    OUStringBuffer strBuf;
+    uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xText, uno::UNO_QUERY);
+    if (!xTextPortionEnumerationAccess.is())
+        return OString();
+
+    uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
+    while (xTextPortions->hasMoreElements())
+    {
+        uno::Any elem = xTextPortions->nextElement();
+
+        //TODO: Consider including hidden and conditional texts/portions.
+        OUString aTextPortionType;
+        uno::Reference<beans::XPropertySet> xPropertySet(elem, uno::UNO_QUERY);
+        xPropertySet->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
+        if (aTextPortionType == "Text")
+        {
+            uno::Reference<text::XTextRange> xTextRange(elem, uno::UNO_QUERY);
+            if (xTextRange.is())
+                strBuf.append(xTextRange->getString());
+        }
+    }
+
+    // Cleanup the dummy characters added by fields (which we exclude).
+    comphelper::string::remove(strBuf, CH_TXT_ATR_INPUTFIELDSTART);
+    comphelper::string::remove(strBuf, CH_TXT_ATR_INPUTFIELDEND);
+    comphelper::string::remove(strBuf, CH_TXTATR_BREAKWORD);
+
+    return strBuf.makeStringAndClear().trim().toUtf8();
+}
+
+/// Validate and return validation result and signature field display text.
+std::pair<bool, OUString>
+lcl_MakeParagraphSignatureFieldText(const uno::Reference<frame::XModel>& xModel,
+                                    const uno::Reference<css::text::XTextField>& xField,
+                                    const OString& utf8Text)
+{
+    static const OUString metaNS("urn:bails");
+
+    OUString msg = "Invalid Signature";
+    bool valid = false;
+
+    const css::uno::Reference<css::rdf::XResource> xSubject(xField, uno::UNO_QUERY);
+    std::map<OUString, OUString> aStatements = SwRDFHelper::getStatements(xModel, metaNS, xSubject);
+    const auto it = aStatements.find("loext:signature:signature");
+    if (it != aStatements.end())
+    {
+        const sal_Char* pData = utf8Text.getStr();
+        const std::vector<unsigned char> data(pData, pData + utf8Text.getLength());
+
+        OString encSignature;
+        if (it->second.convertToString(&encSignature, RTL_TEXTENCODING_UTF8, 0))
+        {
+            const std::vector<unsigned char> sig(svl::crypto::DecodeHexString(encSignature));
+            SignatureInformation aInfo(0);
+            valid = svl::crypto::Signing::Verify(data, true, sig, aInfo);
+            valid = valid && aInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+
+            msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.ouSubject + ", " + aInfo.ouDateTime + ": ";
+            if (valid)
+                msg += SwResId(STR_VALID);
+            else
+                msg += SwResId(STR_INVALID);
+        }
+    }
+
+    return std::make_pair(valid, msg);
+}
+
+/// Updates the signature field text if changed and returns true only iff updated.
+bool lcl_UpdateParagraphSignatureField(const uno::Reference<frame::XModel>& xModel,
+                                       const uno::Reference<css::text::XTextField>& xField,
+                                       const OString& utf8Text)
+{
+    const std::pair<bool, OUString> res = lcl_MakeParagraphSignatureFieldText(xModel, xField, utf8Text);
+    uno::Reference<css::text::XTextRange> xText(xField, uno::UNO_QUERY);
+    const OUString curText = xText->getString();
+    if (curText != res.second)
+    {
+        xText->setString(res.second);
+        return true;
+    }
+
+    return false;
+}
+
+void lcl_RemoveParagraphSignatureField(const uno::Reference<css::text::XTextField>& xField)
+{
+    uno::Reference<css::text::XTextContent> xFieldTextContent(xField, uno::UNO_QUERY);
+    uno::Reference<css::text::XTextRange> xParagraph(xFieldTextContent->getAnchor());
+    uno::Reference<css::text::XText> xParagraphText(xParagraph->getText(), uno::UNO_QUERY);
+    xParagraphText->removeTextContent(xFieldTextContent);
+}
+
 } // anonymous namespace
 
 SwTextFormatColl& SwEditShell::GetDfltTextFormatColl() const
@@ -216,7 +323,7 @@ void SwEditShell::SetClassification(const OUString& rName, SfxClassificationPoli
     for (const OUString& rPageStyleName : aUsedPageStyles)
     {
         uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
-        OUString aServiceName = "com.sun.star.text.TextField.DocInfo.Custom";
+        const OUString aServiceName = "com.sun.star.text.TextField.DocInfo.Custom";
         uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
 
         if (bHeaderIsNeeded || bWatermarkIsNeeded || bHadWatermark)
@@ -572,67 +679,119 @@ void SwEditShell::SignParagraph(SwPaM* pPaM)
 {
     if (!pPaM)
         return;
-
     SwDocShell* pDocShell = GetDoc()->GetDocShell();
     if (!pDocShell)
         return;
-    SwWrtShell* pCurShell = pDocShell->GetWrtShell();
-    if (!pCurShell)
+    const SwPosition* pPosStart = pPaM->Start();
+    if (!pPosStart)
+        return;
+    SwTextNode* pNode = pPosStart->nNode.GetNode().GetTextNode();
+    if (!pNode)
         return;
 
+    // 1. Get the text (without fields).
+    const uno::Reference<text::XTextContent> xParent = SwXParagraph::CreateXParagraph(*pNode->GetDoc(), pNode);
+    const OString utf8Text = lcl_getParagraphBodyText(xParent);
+    if (utf8Text.isEmpty())
+        return;
+
+    // 2. Get certificate and SignatureInformation (needed to show signer name).
+    //FIXME: Temporary until the Paragraph Signing Dialog is available.
+    uno::Reference<uno::XComponentContext> xComponentContext = cppu::defaultBootstrap_InitialComponentContext();
+    uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xComponentContext);
+    uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
+    uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
+    uno::Sequence<uno::Reference<security::XCertificate>> aCertificates = xSecurityEnvironment->getPersonalCertificates();
+    if (!aCertificates.hasElements())
+        return;
+
+    uno::Reference<security::XCertificate> xCert = aCertificates[0];
+    if (!xCert.is())
+        return;
+
+    // 3. Sign it.
+    svl::crypto::Signing signing(xCert);
+    signing.AddDataRange(utf8Text.getStr(), utf8Text.getLength());
+    OStringBuffer sigBuf;
+    if (!signing.Sign(sigBuf))
+        return;
+
+    const OString signature = sigBuf.makeStringAndClear();
+
+    // 4. Add metadata
+    static const OUString metaNS("urn:bails");
+    static const OUString metaFile("bails.rdf");
+
+    uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
+    uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
+    uno::Reference<css::text::XTextField> xField(xMultiServiceFactory->createInstance("com.sun.star.text.textfield.MetadataField"), uno::UNO_QUERY);
+
+    uno::Reference<text::XTextContent> xContent(xField, uno::UNO_QUERY);
+    xContent->attach(xParent->getAnchor()->getEnd());
+
+    uno::Reference<rdf::XResource> xRes(xField, uno::UNO_QUERY);
+    const OUString name = "loext:signature:signature";
+    SwRDFHelper::addStatement(xModel, metaNS, metaFile, xRes, name, OStringToOUString(signature, RTL_TEXTENCODING_UTF8, 0));
+
+    const std::pair<bool, OUString> res = lcl_MakeParagraphSignatureFieldText(xModel, xField, utf8Text);
+    uno::Reference<css::text::XTextRange> xText(xField, uno::UNO_QUERY);
+    xText->setString(res.second);
+}
+
+void SwEditShell::ValidateParagraphSignatures(bool updateDontRemove)
+{
+    SwDocShell* pDocShell = GetDoc()->GetDocShell();
+    if (!pDocShell || m_bIsValidatingParagraphSignature)
+        return;
+
+    SwPaM* pPaM = GetCursor();
     const SwPosition* pPosStart = pPaM->Start();
     SwTextNode* pNode = pPosStart->nNode.GetNode().GetTextNode();
-    if (pNode)
+    if (!pNode)
+        return;
+
+    const uno::Reference<text::XTextContent> xParent = SwXParagraph::CreateXParagraph(*pNode->GetDoc(), pNode);
+
+    // 1. Get the text (without fields).
+    const OString utf8Text = lcl_getParagraphBodyText(xParent);
+    if (utf8Text.isEmpty())
+        return;
+
+    // 2. For each signature field, update it.
+    uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParent, uno::UNO_QUERY);
+    if (!xTextPortionEnumerationAccess.is())
+        return;
+
+    uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
+    uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
+    m_bIsValidatingParagraphSignature = true;
+    comphelper::ScopeGuard const g([this] () {
+            m_bIsValidatingParagraphSignature = false;
+        });
+
+    while (xTextPortions->hasMoreElements())
     {
-        // 1. Get the text (without fields).
-        const OUString text = pNode->GetText();
-        if (text.isEmpty())
-            return;
-
-        // 2. Get certificate and SignatureInformation (needed to show signer name).
-        //FIXME: Temporary until the Paragraph Signing Dialog is available.
-        uno::Reference<uno::XComponentContext> xComponentContext = cppu::defaultBootstrap_InitialComponentContext();
-        uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xComponentContext);
-        uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
-        uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
-        uno::Sequence<uno::Reference<security::XCertificate>> aCertificates = xSecurityEnvironment->getPersonalCertificates();
-        if (!aCertificates.hasElements())
-            return;
-
-        SignatureInformation aInfo(0);
-        uno::Reference<security::XCertificate> xCert = aCertificates[0];
-        if (!xCert.is())
-            return;
-
-        // 3. Sign it.
-        svl::crypto::Signing signing(xCert);
-        signing.AddDataRange(text.getStr(), text.getLength());
-        OStringBuffer sigBuf;
-        if (!signing.Sign(sigBuf))
-            return;
-
-        const OString signature = sigBuf.makeStringAndClear();
-        const auto pData = reinterpret_cast<const unsigned char*>(text.getStr());
-        const std::vector<unsigned char> data(pData, pData + text.getLength());
-        const std::vector<unsigned char> sig(svl::crypto::DecodeHexString(signature));
-        if (!svl::crypto::Signing::Verify(data, true, sig, aInfo))
-            return;
-
-        // 4. Add metadata
-        static const OUString metaNS("urn:bails");
-        static const OUString metaFile("bails.rdf");
-
-        std::map<OUString, OUString> aStatements = SwRDFHelper::getTextNodeStatements(metaNS, *pNode);
-        OUString name = "loext:signature:index";
-        const OUString indexOld = aStatements[name];
-
-        // Update the index
-        const OUString index = OUString::number(indexOld.isEmpty() ? 1 : (indexOld.toInt32() + 1));
-        SwRDFHelper::updateTextNodeStatement(metaNS, metaFile, *pNode, name, indexOld, index);
-
-        // Add the signature
-        name = "loext:signature:signature" + index;
-        SwRDFHelper::addTextNodeStatement(metaNS, metaFile, *pNode, name, OStringToOUString(signature, RTL_TEXTENCODING_UTF8, 0));
+        uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
+        OUString aTextPortionType;
+        xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
+        if (aTextPortionType != UNO_NAME_TEXT_FIELD)
+            continue;
+
+        uno::Reference<lang::XServiceInfo> xTextField;
+        xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
+        if (!xTextField->supportsService("com.sun.star.text.textfield.MetadataField"))
+            continue;
+
+        uno::Reference<text::XTextField> xContent(xTextField, uno::UNO_QUERY);
+
+        const bool isUndoEnabled = GetDoc()->GetIDocumentUndoRedo().DoesUndo();
+        GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
+        if (updateDontRemove)
+            lcl_UpdateParagraphSignatureField(xModel, xContent, utf8Text);
+        else if (!lcl_MakeParagraphSignatureFieldText(xModel, xContent, utf8Text).first)
+            lcl_RemoveParagraphSignatureField(xContent);
+
+        GetDoc()->GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
     }
 }
 
diff --git a/sw/source/core/edit/edws.cxx b/sw/source/core/edit/edws.cxx
index 3a719b11736f..4eb1ece5d0aa 100644
--- a/sw/source/core/edit/edws.cxx
+++ b/sw/source/core/edit/edws.cxx
@@ -35,13 +35,16 @@
 
 // masqueraded copy constructor
 SwEditShell::SwEditShell( SwEditShell& rEdSH, vcl::Window *pWindow )
-    : SwCursorShell( rEdSH, pWindow ),
-    m_bNbspRunNext(false)   // TODO: would copying that make sense? only if editing continues
+    : SwCursorShell( rEdSH, pWindow )
+    , m_bNbspRunNext(false)   // TODO: would copying that make sense? only if editing continues
+    , m_bIsValidatingParagraphSignature(false)
 {
 }
 
 SwEditShell::SwEditShell( SwDoc& rDoc, vcl::Window *pWindow, const SwViewOption *pOptions )
-    : SwCursorShell( rDoc, pWindow, pOptions ), m_bNbspRunNext(false)
+    : SwCursorShell( rDoc, pWindow, pOptions )
+    , m_bNbspRunNext(false)
+    , m_bIsValidatingParagraphSignature(false)
 {
     if (0 < officecfg::Office::Common::Undo::Steps::get())
     {


More information about the Libreoffice-commits mailing list