[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