LibreOffice Module sfx2 (master) 1
classificationhelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
11
12#include <map>
13#include <algorithm>
14#include <iterator>
15
16#include <com/sun/star/beans/XPropertyContainer.hpp>
17#include <com/sun/star/beans/Property.hpp>
18#include <com/sun/star/beans/XPropertySet.hpp>
19#include <com/sun/star/document/XDocumentProperties.hpp>
20#include <com/sun/star/xml/sax/Parser.hpp>
21#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22#include <com/sun/star/xml/sax/SAXParseException.hpp>
23#include <com/sun/star/beans/PropertyAttribute.hpp>
24
25#include <sal/log.hxx>
27#include <sfx2/infobar.hxx>
34#include <sfx2/strings.hrc>
35#include <sfx2/sfxresid.hxx>
36#include <sfx2/viewfrm.hxx>
37#include <tools/datetime.hxx>
39#include <unotools/datetime.hxx>
40#include <vcl/svapp.hxx>
41#include <vcl/settings.hxx>
42#include <vcl/weld.hxx>
43#include <svl/fstathelper.hxx>
44
45#include <o3tl/string_view.hxx>
46#include <officecfg/Office/Common.hxx>
47
48using namespace com::sun::star;
49
50namespace
51{
52
53const OUString& PROP_BACNAME()
54{
55 static const OUString sProp("BusinessAuthorizationCategory:Name");
56 return sProp;
57}
58
59const OUString& PROP_STARTVALIDITY()
60{
61 static const OUString sProp("Authorization:StartValidity");
62 return sProp;
63}
64
65const OUString& PROP_NONE()
66{
67 static const OUString sProp("None");
68 return sProp;
69}
70
71const OUString& PROP_IMPACTSCALE()
72{
73 static const OUString sProp("Impact:Scale");
74 return sProp;
75}
76
77const OUString& PROP_IMPACTLEVEL()
78{
79 static const OUString sProp("Impact:Level:Confidentiality");
80 return sProp;
81}
82
83const OUString& PROP_PREFIX_EXPORTCONTROL()
84{
85 static const OUString sProp("urn:bails:ExportControl:");
86 return sProp;
87}
88
89const OUString& PROP_PREFIX_NATIONALSECURITY()
90{
91 static const OUString sProp("urn:bails:NationalSecurity:");
92 return sProp;
93}
94
96class SfxClassificationCategory
97{
98public:
100 OUString m_aName;
101 OUString m_aAbbreviatedName; //< An abbreviation to display instead of m_aName.
102 OUString m_aIdentifier; //< The Identifier of this entry.
103 size_t m_nConfidentiality; //< 0 is the lowest (least-sensitive).
104 std::map<OUString, OUString> m_aLabels;
105};
106
108class SfxClassificationParser : public cppu::WeakImplHelper<xml::sax::XDocumentHandler>
109{
110public:
111 std::vector<SfxClassificationCategory> m_aCategories;
112 std::vector<OUString> m_aMarkings;
113 std::vector<OUString> m_aIPParts;
114 std::vector<OUString> m_aIPPartNumbers;
115
116 OUString m_aPolicyAuthorityName;
117 bool m_bInPolicyAuthorityName = false;
118 OUString m_aPolicyName;
119 bool m_bInPolicyName = false;
120 OUString m_aProgramID;
121 bool m_bInProgramID = false;
122 OUString m_aScale;
123 bool m_bInScale = false;
124 OUString m_aConfidentalityValue;
125 bool m_bInConfidentalityValue = false;
126 OUString m_aIdentifier;
127 bool m_bInIdentifier = false;
128 OUString m_aValue;
129 bool m_bInValue = false;
130
132 SfxClassificationCategory* m_pCategory = nullptr;
133
134 SfxClassificationParser();
135
136 void SAL_CALL startDocument() override;
137
138 void SAL_CALL endDocument() override;
139
140 void SAL_CALL startElement(const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& xAttribs) override;
141
142 void SAL_CALL endElement(const OUString& rName) override;
143
144 void SAL_CALL characters(const OUString& rChars) override;
145
146 void SAL_CALL ignorableWhitespace(const OUString& rWhitespaces) override;
147
148 void SAL_CALL processingInstruction(const OUString& rTarget, const OUString& rData) override;
149
150 void SAL_CALL setDocumentLocator(const uno::Reference<xml::sax::XLocator>& xLocator) override;
151};
152
153SfxClassificationParser::SfxClassificationParser() = default;
154
155void SAL_CALL SfxClassificationParser::startDocument()
156{
157}
158
159void SAL_CALL SfxClassificationParser::endDocument()
160{
161}
162
163void SAL_CALL SfxClassificationParser::startElement(const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& xAttribs)
164{
165 if (rName == "baf:PolicyAuthorityName")
166 {
167 m_aPolicyAuthorityName.clear();
168 m_bInPolicyAuthorityName = true;
169 }
170 else if (rName == "baf:PolicyName")
171 {
172 m_aPolicyName.clear();
173 m_bInPolicyName = true;
174 }
175 else if (rName == "baf:ProgramID")
176 {
177 m_aProgramID.clear();
178 m_bInProgramID = true;
179 }
180 else if (rName == "baf:BusinessAuthorizationCategory")
181 {
182 const OUString aName = xAttribs->getValueByName("Name");
183 if (!m_pCategory && !aName.isEmpty())
184 {
185 OUString aIdentifier = xAttribs->getValueByName("Identifier");
186
187 // Create a new category and initialize it with the data that's true for all categories.
188 m_aCategories.emplace_back();
189 SfxClassificationCategory& rCategory = m_aCategories.back();
190
191 rCategory.m_aName = aName;
192 // Set the abbreviated name, if any, otherwise fallback on the full name.
193 const OUString aAbbreviatedName = xAttribs->getValueByName("loextAbbreviatedName");
194 rCategory.m_aAbbreviatedName = !aAbbreviatedName.isEmpty() ? aAbbreviatedName : aName;
195 rCategory.m_aIdentifier = aIdentifier;
196
197 rCategory.m_aLabels["PolicyAuthority:Name"] = m_aPolicyAuthorityName;
198 rCategory.m_aLabels["Policy:Name"] = m_aPolicyName;
199 rCategory.m_aLabels["BusinessAuthorization:Identifier"] = m_aProgramID;
200 rCategory.m_aLabels["BusinessAuthorizationCategory:Identifier"] = aIdentifier;
201
202 // Also initialize defaults.
203 rCategory.m_aLabels["PolicyAuthority:Identifier"] = PROP_NONE();
204 rCategory.m_aLabels["PolicyAuthority:Country"] = PROP_NONE();
205 rCategory.m_aLabels["Policy:Identifier"] = PROP_NONE();
206 rCategory.m_aLabels["BusinessAuthorization:Name"] = PROP_NONE();
207 rCategory.m_aLabels["BusinessAuthorization:Locator"] = PROP_NONE();
208 rCategory.m_aLabels["BusinessAuthorizationCategory:Identifier:OID"] = PROP_NONE();
209 rCategory.m_aLabels["BusinessAuthorizationCategory:Locator"] = PROP_NONE();
210 rCategory.m_aLabels["BusinessAuthorization:Locator"] = PROP_NONE();
211 rCategory.m_aLabels["MarkingPrecedence"] = PROP_NONE();
212 rCategory.m_aLabels["Marking:general-summary"].clear();
213 rCategory.m_aLabels["Marking:general-warning-statement"].clear();
214 rCategory.m_aLabels["Marking:general-warning-statement:ext:2"].clear();
215 rCategory.m_aLabels["Marking:general-warning-statement:ext:3"].clear();
216 rCategory.m_aLabels["Marking:general-warning-statement:ext:4"].clear();
217 rCategory.m_aLabels["Marking:general-distribution-statement"].clear();
218 rCategory.m_aLabels["Marking:general-distribution-statement:ext:2"].clear();
219 rCategory.m_aLabels["Marking:general-distribution-statement:ext:3"].clear();
220 rCategory.m_aLabels["Marking:general-distribution-statement:ext:4"].clear();
221 rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCHEADER()].clear();
222 rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCFOOTER()].clear();
223 rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCWATERMARK()].clear();
224 rCategory.m_aLabels["Marking:email-first-line-of-text"].clear();
225 rCategory.m_aLabels["Marking:email-last-line-of-text"].clear();
226 rCategory.m_aLabels["Marking:email-subject-prefix"].clear();
227 rCategory.m_aLabels["Marking:email-subject-suffix"].clear();
228 rCategory.m_aLabels[PROP_STARTVALIDITY()] = PROP_NONE();
229 rCategory.m_aLabels["Authorization:StopValidity"] = PROP_NONE();
230 m_pCategory = &rCategory;
231 }
232 }
233 else if (rName == "loext:Marking")
234 {
235 OUString aName = xAttribs->getValueByName("Name");
236 m_aMarkings.push_back(aName);
237 }
238 else if (rName == "loext:IntellectualPropertyPart")
239 {
240 OUString aName = xAttribs->getValueByName("Name");
241 m_aIPParts.push_back(aName);
242 }
243 else if (rName == "loext:IntellectualPropertyPartNumber")
244 {
245 OUString aName = xAttribs->getValueByName("Name");
246 m_aIPPartNumbers.push_back(aName);
247 }
248 else if (rName == "baf:Scale")
249 {
250 m_aScale.clear();
251 m_bInScale = true;
252 }
253 else if (rName == "baf:ConfidentalityValue")
254 {
255 m_aConfidentalityValue.clear();
256 m_bInConfidentalityValue = true;
257 }
258 else if (rName == "baf:Identifier")
259 {
260 m_aIdentifier.clear();
261 m_bInIdentifier = true;
262 }
263 else if (rName == "baf:Value")
264 {
265 m_aValue.clear();
266 m_bInValue = true;
267 }
268}
269
270void SAL_CALL SfxClassificationParser::endElement(const OUString& rName)
271{
272 if (rName == "baf:PolicyAuthorityName")
273 m_bInPolicyAuthorityName = false;
274 else if (rName == "baf:PolicyName")
275 m_bInPolicyName = false;
276 else if (rName == "baf:ProgramID")
277 m_bInProgramID = false;
278 else if (rName == "baf:BusinessAuthorizationCategory")
279 m_pCategory = nullptr;
280 else if (rName == "baf:Scale")
281 {
282 m_bInScale = false;
283 if (m_pCategory)
284 m_pCategory->m_aLabels[PROP_IMPACTSCALE()] = m_aScale;
285 }
286 else if (rName == "baf:ConfidentalityValue")
287 {
288 m_bInConfidentalityValue = false;
289 if (m_pCategory)
290 {
291 std::map<OUString, OUString>& rLabels = m_pCategory->m_aLabels;
292 rLabels[PROP_IMPACTLEVEL()] = m_aConfidentalityValue;
293 m_pCategory->m_nConfidentiality = m_aConfidentalityValue.toInt32(); // 0-based class sensitivity; 0 is lowest.
294 // Set the two other type of levels as well, if they're not set
295 // yet: they're optional in BAF, but not in BAILS.
296 rLabels.try_emplace("Impact:Level:Integrity", m_aConfidentalityValue);
297 rLabels.try_emplace("Impact:Level:Availability", m_aConfidentalityValue);
298 }
299 }
300 else if (rName == "baf:Identifier")
301 m_bInIdentifier = false;
302 else if (rName == "baf:Value")
303 {
304 if (m_pCategory)
305 {
306 if (m_aIdentifier == "Document: Header")
307 m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCHEADER()] = m_aValue;
308 else if (m_aIdentifier == "Document: Footer")
309 m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCFOOTER()] = m_aValue;
310 else if (m_aIdentifier == "Document: Watermark")
311 m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCWATERMARK()] = m_aValue;
312 }
313 }
314}
315
316void SAL_CALL SfxClassificationParser::characters(const OUString& rChars)
317{
318 if (m_bInPolicyAuthorityName)
319 m_aPolicyAuthorityName += rChars;
320 else if (m_bInPolicyName)
321 m_aPolicyName += rChars;
322 else if (m_bInProgramID)
323 m_aProgramID += rChars;
324 else if (m_bInScale)
325 m_aScale += rChars;
326 else if (m_bInConfidentalityValue)
327 m_aConfidentalityValue += rChars;
328 else if (m_bInIdentifier)
329 m_aIdentifier += rChars;
330 else if (m_bInValue)
331 m_aValue += rChars;
332}
333
334void SAL_CALL SfxClassificationParser::ignorableWhitespace(const OUString& /*rWhitespace*/)
335{
336}
337
338void SAL_CALL SfxClassificationParser::processingInstruction(const OUString& /*rTarget*/, const OUString& /*rData*/)
339{
340}
341
342void SAL_CALL SfxClassificationParser::setDocumentLocator(const uno::Reference<xml::sax::XLocator>& /*xLocator*/)
343{
344}
345
346} // anonymous namespace
347
350{
351public:
353 std::map<SfxClassificationPolicyType, SfxClassificationCategory> m_aCategory;
355 std::vector<SfxClassificationCategory> m_aCategories;
356 std::vector<OUString> m_aMarkings;
357 std::vector<OUString> m_aIPParts;
358 std::vector<OUString> m_aIPPartNumbers;
359
360 uno::Reference<document::XDocumentProperties> m_xDocumentProperties;
361
363
364 explicit Impl(uno::Reference<document::XDocumentProperties> xDocumentProperties, bool bUseLocalized);
365 void parsePolicy();
370};
371
372SfxClassificationHelper::Impl::Impl(uno::Reference<document::XDocumentProperties> xDocumentProperties, bool bUseLocalized)
373 : m_xDocumentProperties(std::move(xDocumentProperties))
374 , m_bUseLocalized(bUseLocalized)
375{
376 parsePolicy();
377}
378
380{
381 uno::Reference<uno::XComponentContext> xComponentContext = comphelper::getProcessComponentContext();
382 SvtPathOptions aOptions;
383 OUString aPath = aOptions.GetClassificationPath();
384
385 // See if there is a localized variant next to the configured XML.
386 OUString aExtension(".xml");
387 if (aPath.endsWith(aExtension) && m_bUseLocalized)
388 {
389 std::u16string_view aBase = aPath.subView(0, aPath.getLength() - aExtension.getLength());
390 const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
391 // Expected format is "<original path>_xx-XX.xml".
392 OUString aLocalized = OUString::Concat(aBase) + "_" + rLanguageTag.getBcp47() + aExtension;
394 aPath = aLocalized;
395 }
396
397 std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(aPath, StreamMode::READ);
398 uno::Reference<io::XInputStream> xInputStream(new utl::OStreamWrapper(std::move(pStream)));
399 xml::sax::InputSource aParserInput;
400 aParserInput.aInputStream = xInputStream;
401
402 uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(xComponentContext);
403 rtl::Reference<SfxClassificationParser> xClassificationParser(new SfxClassificationParser());
404 xParser->setDocumentHandler(xClassificationParser);
405 try
406 {
407 xParser->parseStream(aParserInput);
408 }
409 catch (const xml::sax::SAXParseException&)
410 {
411 TOOLS_WARN_EXCEPTION("sfx.view", "parsePolicy() failed");
412 }
413 m_aCategories = xClassificationParser->m_aCategories;
414 m_aMarkings = xClassificationParser->m_aMarkings;
415 m_aIPParts = xClassificationParser->m_aIPParts;
416 m_aIPPartNumbers = xClassificationParser->m_aIPPartNumbers;
417}
418
419static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties, std::u16string_view rName)
420{
421 return std::any_of(rProperties.begin(), rProperties.end(), [&](const beans::Property& rProperty)
422 {
423 return rProperty.Name == rName;
424 });
425}
426
428{
429 auto itCategory = m_aCategory.find(eType);
430 if (itCategory == m_aCategory.end())
431 return;
432
433 SfxClassificationCategory& rCategory = itCategory->second;
434 auto it = rCategory.m_aLabels.find(policyTypeToString(eType) + PROP_STARTVALIDITY());
435 if (it != rCategory.m_aLabels.end())
436 {
437 if (it->second == PROP_NONE())
438 {
439 // The policy left the start date unchanged, replace it with the system time.
440 util::DateTime aDateTime = DateTime(DateTime::SYSTEM).GetUNODateTime();
441 it->second = utl::toISO8601(aDateTime);
442 }
443 }
444}
445
447{
448 uno::Reference<beans::XPropertyContainer> xPropertyContainer = m_xDocumentProperties->getUserDefinedProperties();
449 uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
450 uno::Sequence<beans::Property> aProperties = xPropertySet->getPropertySetInfo()->getProperties();
451 for (auto& rPair : m_aCategory)
452 {
454 SfxClassificationCategory& rCategory = rPair.second;
455 std::map<OUString, OUString> aLabels = rCategory.m_aLabels;
456 aLabels[policyTypeToString(eType) + PROP_BACNAME()] = rCategory.m_aName;
457 for (const auto& rLabel : aLabels)
458 {
459 try
460 {
461 if (lcl_containsProperty(aProperties, rLabel.first))
462 xPropertySet->setPropertyValue(rLabel.first, uno::Any(rLabel.second));
463 else
464 xPropertyContainer->addProperty(rLabel.first, beans::PropertyAttribute::REMOVABLE, uno::Any(rLabel.second));
465 }
466 catch (const uno::Exception&)
467 {
468 TOOLS_WARN_EXCEPTION("sfx.view", "pushDocumentProperties() failed for property " << rLabel.first);
469 }
470 }
471 }
472}
473
474bool SfxClassificationHelper::IsClassified(const uno::Reference<document::XDocumentProperties>& xDocumentProperties)
475{
476 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
477 if (!xPropertyContainer.is())
478 return false;
479
480 uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
481 const uno::Sequence<beans::Property> aProperties = xPropertySet->getPropertySetInfo()->getProperties();
482 for (const beans::Property& rProperty : aProperties)
483 {
484 if (rProperty.Name.startsWith("urn:bails:"))
485 return true;
486 }
487
488 return false;
489}
490
491SfxClassificationCheckPasteResult SfxClassificationHelper::CheckPaste(const uno::Reference<document::XDocumentProperties>& xSource,
492 const uno::Reference<document::XDocumentProperties>& xDestination)
493{
495 // No classification on the source side. Return early, regardless the
496 // state of the destination side.
498
499 if (!SfxClassificationHelper::IsClassified(xDestination))
500 {
501 // Paste from a classified document to a non-classified one -> deny.
503 }
504
505 // Remaining case: paste between two classified documents.
506 SfxClassificationHelper aSource(xSource);
507 SfxClassificationHelper aDestination(xDestination);
508 if (aSource.GetImpactScale() != aDestination.GetImpactScale())
509 // It's possible to compare them if they have the same scale.
511
512 if (aSource.GetImpactLevel() > aDestination.GetImpactLevel())
513 // Paste from a doc that has higher classification -> deny.
515
517}
518
520{
521 switch (eResult)
522 {
524 {
525 return true;
526 }
527 break;
529 {
531 {
532 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
533 VclMessageType::Info, VclButtonsType::Ok,
534 SfxResId(STR_TARGET_DOC_NOT_CLASSIFIED)));
535 xBox->run();
536 }
537 return false;
538 }
539 break;
541 {
543 {
544 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
545 VclMessageType::Info, VclButtonsType::Ok,
546 SfxResId(STR_DOC_CLASSIFICATION_TOO_LOW)));
547 xBox->run();
548 }
549 return false;
550 }
551 break;
552 }
553
554 return true;
555}
556
557SfxClassificationHelper::SfxClassificationHelper(const uno::Reference<document::XDocumentProperties>& xDocumentProperties, bool bUseLocalizedPolicy)
558 : m_pImpl(std::make_unique<Impl>(xDocumentProperties, bUseLocalizedPolicy))
559{
560 if (!xDocumentProperties.is())
561 return;
562
563 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
564 if (!xPropertyContainer.is())
565 return;
566
567 uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
568 const uno::Sequence<beans::Property> aProperties = xPropertySet->getPropertySetInfo()->getProperties();
569 for (const beans::Property& rProperty : aProperties)
570 {
571 if (!rProperty.Name.startsWith("urn:bails:"))
572 continue;
573
574 uno::Any aAny = xPropertySet->getPropertyValue(rProperty.Name);
575 OUString aValue;
576 if (aAny >>= aValue)
577 {
579 OUString aPrefix = policyTypeToString(eType);
580 if (!rProperty.Name.startsWith(aPrefix))
581 // It's a prefix we did not recognize, ignore.
582 continue;
583
584 //TODO: Support abbreviated names(?)
585 if (rProperty.Name == Concat2View(aPrefix + PROP_BACNAME()))
586 m_pImpl->m_aCategory[eType].m_aName = aValue;
587 else
588 m_pImpl->m_aCategory[eType].m_aLabels[rProperty.Name] = aValue;
589 }
590 }
591}
592
594
595std::vector<OUString> const & SfxClassificationHelper::GetMarkings() const
596{
597 return m_pImpl->m_aMarkings;
598}
599
600std::vector<OUString> const & SfxClassificationHelper::GetIntellectualPropertyParts() const
601{
602 return m_pImpl->m_aIPParts;
603}
604
606{
607 return m_pImpl->m_aIPPartNumbers;
608}
609
611{
612 return m_pImpl->m_aCategory[eType].m_aName;
613}
614
615const OUString& SfxClassificationHelper::GetAbbreviatedBACName(const OUString& sFullName)
616{
617 for (const auto& category : m_pImpl->m_aCategories)
618 {
619 if (category.m_aName == sFullName)
620 return category.m_aAbbreviatedName;
621 }
622
623 return sFullName;
624}
625
626OUString SfxClassificationHelper::GetBACNameForIdentifier(std::u16string_view sIdentifier)
627{
628 if (sIdentifier.empty())
629 return "";
630
631 for (const auto& category : m_pImpl->m_aCategories)
632 {
633 if (category.m_aIdentifier == sIdentifier)
634 return category.m_aName;
635 }
636
637 return "";
638}
639
640OUString SfxClassificationHelper::GetHigherClass(const OUString& first, const OUString& second)
641{
642 size_t nFirstConfidentiality = 0;
643 size_t nSecondConfidentiality = 0;
644 for (const auto& category : m_pImpl->m_aCategories)
645 {
646 if (category.m_aName == first)
647 nFirstConfidentiality = category.m_nConfidentiality;
648 if (category.m_aName == second)
649 nSecondConfidentiality = category.m_nConfidentiality;
650 }
651
652 return nFirstConfidentiality >= nSecondConfidentiality ? first : second;
653}
654
656{
657 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
658 if (itCategory == m_pImpl->m_aCategory.end())
659 return false;
660
661 SfxClassificationCategory& rCategory = itCategory->second;
662 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
663 if (it == rCategory.m_aLabels.end())
664 return false;
665
666 it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
667 return it != rCategory.m_aLabels.end();
668}
669
671{
672 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
673 if (itCategory == m_pImpl->m_aCategory.end())
674 return false;
675
676 SfxClassificationCategory& rCategory = itCategory->second;
677 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCHEADER());
678 return it != rCategory.m_aLabels.end() && !it->second.isEmpty();
679}
680
682{
683 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
684 if (itCategory == m_pImpl->m_aCategory.end())
685 return false;
686
687 SfxClassificationCategory& rCategory = itCategory->second;
688 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCFOOTER());
689 return it != rCategory.m_aLabels.end() && !it->second.isEmpty();
690}
691
693{
694 InfobarType aRet;
695
697
698 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
699 if (itCategory == m_pImpl->m_aCategory.end())
700 return aRet;
701
702 SfxClassificationCategory& rCategory = itCategory->second;
703 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
704 if (it == rCategory.m_aLabels.end())
705 return aRet;
706 OUString aScale = it->second;
707
708 it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
709 if (it == rCategory.m_aLabels.end())
710 return aRet;
711 OUString aLevel = it->second;
712
713 // The spec defines two valid scale values: FIPS-199 and UK-Cabinet.
714 if (aScale == "UK-Cabinet")
715 {
716 if (aLevel == "0")
718 else if (aLevel == "1")
720 else if (aLevel == "2")
722 else if (aLevel == "3")
723 aRet = InfobarType::DANGER;
724 }
725 else if (aScale == "FIPS-199")
726 {
727 if (aLevel == "Low")
729 else if (aLevel == "Moderate")
731 else if (aLevel == "High")
732 aRet = InfobarType::DANGER;
733 }
734 return aRet;
735}
736
738{
739 sal_Int32 nRet = -1;
740
741 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
742 if (itCategory == m_pImpl->m_aCategory.end())
743 return nRet;
744
745 SfxClassificationCategory& rCategory = itCategory->second;
746 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
747 if (it == rCategory.m_aLabels.end())
748 return nRet;
749 OUString aScale = it->second;
750
751 it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
752 if (it == rCategory.m_aLabels.end())
753 return nRet;
754 OUString aLevel = it->second;
755
756 if (aScale == "UK-Cabinet")
757 {
758 sal_Int32 nValue = aLevel.toInt32();
759 if (nValue < 0 || nValue > 3)
760 return nRet;
761 nRet = nValue;
762 }
763 else if (aScale == "FIPS-199")
764 {
765 static std::map<OUString, sal_Int32> const aValues
766 {
767 { "Low", 0 },
768 { "Moderate", 1 },
769 { "High", 2 }
770 };
771 auto itValues = aValues.find(aLevel);
772 if (itValues == aValues.end())
773 return nRet;
774 nRet = itValues->second;
775 }
776
777 return nRet;
778}
779
781{
782 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
783 if (itCategory == m_pImpl->m_aCategory.end())
784 return OUString();
785
786 SfxClassificationCategory& rCategory = itCategory->second;
787 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
788 if (it != rCategory.m_aLabels.end())
789 return it->second;
790
791 return OUString();
792}
793
795{
796 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
797 if (itCategory == m_pImpl->m_aCategory.end())
798 return OUString();
799
800 SfxClassificationCategory& rCategory = itCategory->second;
801 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCWATERMARK());
802 if (it != rCategory.m_aLabels.end())
803 return it->second;
804
805 return OUString();
806}
807
809{
810 if (m_pImpl->m_aCategories.empty())
811 m_pImpl->parsePolicy();
812
813 std::vector<OUString> aRet;
814 std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory)
815 {
816 return rCategory.m_aName;
817 });
818 return aRet;
819}
820
822{
823 if (m_pImpl->m_aCategories.empty())
824 m_pImpl->parsePolicy();
825
826 std::vector<OUString> aRet;
827 std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory)
828 {
829 return rCategory.m_aIdentifier;
830 });
831 return aRet;
832}
833
835{
836 if (m_pImpl->m_aCategories.empty())
837 m_pImpl->parsePolicy();
838
839 std::vector<OUString> aRet;
840 std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory)
841 {
842 return rCategory.m_aAbbreviatedName;
843 });
844 return aRet;
845}
846
848{
849 if (m_pImpl->m_aCategories.empty())
850 m_pImpl->parsePolicy();
851
852 auto it = std::find_if(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), [&](const SfxClassificationCategory& rCategory)
853 {
854 return rCategory.m_aName == rName;
855 });
856 if (it == m_pImpl->m_aCategories.end())
857 {
858 SAL_WARN("sfx.view", "'" << rName << "' is not a recognized category name");
859 return;
860 }
861
862 m_pImpl->m_aCategory[eType].m_aName = it->m_aName;
863 m_pImpl->m_aCategory[eType].m_aAbbreviatedName = it->m_aAbbreviatedName;
864 m_pImpl->m_aCategory[eType].m_nConfidentiality = it->m_nConfidentiality;
865 m_pImpl->m_aCategory[eType].m_aLabels.clear();
866 const OUString& rPrefix = policyTypeToString(eType);
867 for (const auto& rLabel : it->m_aLabels)
868 m_pImpl->m_aCategory[eType].m_aLabels[rPrefix + rLabel.first] = rLabel.second;
869
870 m_pImpl->setStartValidity(eType);
871 m_pImpl->pushToDocumentProperties();
872 SfxViewFrame* pViewFrame = SfxViewFrame::Current();
873 if (!pViewFrame)
874 return;
875
876 UpdateInfobar(*pViewFrame);
877}
878
880{
882 bool bImpactLevel = HasImpactLevel();
883 if (!aBACName.isEmpty() && bImpactLevel)
884 {
885 OUString aMessage = SfxResId(STR_CLASSIFIED_DOCUMENT);
886 aMessage = aMessage.replaceFirst("%1", aBACName);
887
888 rViewFrame.RemoveInfoBar(u"classification");
889 rViewFrame.AppendInfoBar("classification", "", aMessage, GetImpactLevelType());
890 }
891}
892
894{
895 if (o3tl::starts_with(rType, PROP_PREFIX_EXPORTCONTROL()))
897 else if (o3tl::starts_with(rType, PROP_PREFIX_NATIONALSECURITY()))
899 else
901}
902
904{
905 switch (eType)
906 {
908 return PROP_PREFIX_EXPORTCONTROL();
910 return PROP_PREFIX_NATIONALSECURITY();
912 break;
913 }
914
916}
917
919{
920 static const OUString sProp("Marking:document-header");
921 return sProp;
922}
923
925{
926 static const OUString sProp("Marking:document-footer");
927 return sProp;
928}
929
931{
932 static const OUString sProp("Marking:document-watermark");
933 return sProp;
934}
935
937{
938 static const OUString sProp("urn:bails:IntellectualProperty:");
939 return sProp;
940}
941
943{
946 sal_Int32 nPolicyTypeNumber = officecfg::Office::Common::Classification::Policy::get();
947 auto eType = static_cast<SfxClassificationPolicyType>(nPolicyTypeNumber);
948 return eType;
949}
950
951namespace sfx
952{
953
954namespace
955{
956
957OUString getProperty(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
958 OUString const& rName)
959{
960 try
961 {
962 uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
963 return xPropertySet->getPropertyValue(rName).get<OUString>();
964 }
965 catch (const css::uno::Exception&)
966 {
967 }
968
969 return OUString();
970}
971
972} // end anonymous namespace
973
974sfx::ClassificationCreationOrigin getCreationOriginProperty(uno::Reference<beans::XPropertyContainer> const & rxPropertyContainer,
975 sfx::ClassificationKeyCreator const & rKeyCreator)
976{
977 OUString sValue = getProperty(rxPropertyContainer, rKeyCreator.makeCreationOriginKey());
978 if (sValue.isEmpty())
980
981 return (sValue == "BAF_POLICY")
984}
985
986}
987
988/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertiesInfo aProperties
const LanguageTag & GetLanguageTag() const
static const AllSettings & GetSettings()
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
static bool IsHeadlessModeEnabled()
css::util::DateTime GetUNODateTime() const
const OUString & getBcp47(bool bResolveSystem=true) const
Implementation details of SfxClassificationHelper.
void setStartValidity(SfxClassificationPolicyType eType)
Set the classification start date to the system time.
std::vector< SfxClassificationCategory > m_aCategories
Possible categories of a policy to choose from.
std::vector< OUString > m_aMarkings
std::vector< OUString > m_aIPPartNumbers
Impl(uno::Reference< document::XDocumentProperties > xDocumentProperties, bool bUseLocalized)
std::map< SfxClassificationPolicyType, SfxClassificationCategory > m_aCategory
Selected categories, one category for each policy type.
uno::Reference< document::XDocumentProperties > m_xDocumentProperties
void pushToDocumentProperties()
Synchronize m_aLabels back to the document properties.
std::vector< OUString > m_aIPParts
Shared code to handle Business Authorization Identification and Labeling Scheme (BAILS) properties.
bool HasDocumentFooter()
The selected category has some content for the document footer.
static const OUString & PROP_DOCFOOTER()
Brief text located at the bottom of each document's pages.
bool HasDocumentHeader()
The selected category has some content for the document header.
static bool IsClassified(const css::uno::Reference< css::document::XDocumentProperties > &xDocumentProperties)
Does the document have any BAILS properties?
std::vector< OUString > const & GetIntellectualPropertyParts() const
OUString GetHigherClass(const OUString &first, const OUString &second)
Returns the class with the higher priority (based on sensitivity).
static SfxClassificationPolicyType getPolicyType()
OUString GetImpactScale()
Comparing the GetImpactLevel() result is only meaningful when the impact scale is the same.
std::vector< OUString > const & GetIntellectualPropertyPartNumbers() const
const OUString & GetBACName(SfxClassificationPolicyType eType) const
Get the currently selected category for eType.
static bool ShowPasteInfo(SfxClassificationCheckPasteResult eResult)
Wrapper around CheckPaste(): informs the user if necessary and finds out if the paste can be continue...
std::vector< OUString > GetBACIdentifiers()
Return all possible valid category identifiers, based on the policy.
sal_Int32 GetImpactLevel()
Larger value means more confidential.
bool HasImpactLevel()
If GetImpactScale() and GetImpactLevel*() will return something meaningful.
const OUString & GetAbbreviatedBACName(const OUString &sFullName)
Get the currently selected category abbreviation for eType. Returns full name if no abbreviation defi...
std::unique_ptr< Impl > m_pImpl
OUString GetBACNameForIdentifier(std::u16string_view sIdentifier)
Get the currently selected category for the identifier.
SfxClassificationHelper(const css::uno::Reference< css::document::XDocumentProperties > &xDocumentProperties, bool bUseLocalizedPolicy=true)
static const OUString & PROP_DOCHEADER()
Brief text located at the top of each document's pages.
std::vector< OUString > const & GetMarkings() const
static SfxClassificationPolicyType stringToPolicyType(std::u16string_view rType)
Does a best-effort conversion of rType to SfxClassificationPolicyType.
std::vector< OUString > GetAbbreviatedBACNames()
Return all possible valid abbreviated category names, based on the policy.
void SetBACName(const OUString &rName, SfxClassificationPolicyType eType)
Setting this sets all the other properties, based on the policy.
static SfxClassificationCheckPasteResult CheckPaste(const css::uno::Reference< css::document::XDocumentProperties > &xSource, const css::uno::Reference< css::document::XDocumentProperties > &xDestination)
Checks if pasting from xSource to xDestination would leak information.
void UpdateInfobar(SfxViewFrame &rViewFrame)
static const OUString & PROP_DOCWATERMARK()
Brief text formatted as a watermark on each document's page.
std::vector< OUString > GetBACNames()
Return all possible valid category names, based on the policy.
static const OUString & policyTypeToString(SfxClassificationPolicyType eType)
Returns the string representation of a SfxClassificationPolicyType element.
static const OUString & PROP_PREFIX_INTELLECTUALPROPERTY()
Get the property prefix for the IntellectualProperty policy type.
static SAL_WARN_UNUSED_RESULT SfxViewFrame * Current()
Definition: viewfrm.cxx:1975
void RemoveInfoBar(std::u16string_view sId)
Definition: viewfrm.cxx:3632
VclPtr< SfxInfoBarWindow > AppendInfoBar(const OUString &sId, const OUString &sPrimaryMessage, const OUString &sSecondaryMessage, InfobarType aInfobarType, bool bShowCloseButton=true)
Append a new InfoBar (see https://wiki.documentfoundation.org/Design/Whiteboards/Infobar).
Definition: viewfrm.cxx:3593
const OUString & GetClassificationPath() const
static bool lcl_containsProperty(const uno::Sequence< beans::Property > &rProperties, std::u16string_view rName)
SfxClassificationPolicyType
Specifies a policy type, to be used with SetBACName(). Getters always use IntellectualProperty for no...
SfxClassificationCheckPasteResult
Return code of SfxClassificationHelper::CheckPaste().
OUString makeCreationOriginKey() const
Classification creation origin key.
static bool IsFuzzing()
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
FilterGroup & rTarget
DocumentType eType
sal_Int16 nValue
const std::pair< sal_uInt16, TranslateId > aLocalized[]
InfobarType
Definition: infobar.hxx:22
OUString aName
#define SAL_WARN(area, stream)
SVL_DLLPUBLIC bool IsDocument(const OUString &rURL)
Reference< XComponentContext > getProcessComponentContext()
constexpr OUStringLiteral first
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
sfx::ClassificationCreationOrigin getCreationOriginProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator)
ClassificationCreationOrigin
Specifies the origin: either defined by the BAF policy or manual via. the advanced classification dia...
SVX_DLLPUBLIC OUString getProperty(css::uno::Reference< css::beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rName)
OUString toISO8601(const css::util::DateTime &rDateTime)
OUString m_aName
OUString SfxResId(TranslateId aId)
Definition: sfxresid.cxx:22