/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * 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/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; namespace { const OUString& PROP_BACNAME() { static const OUString sProp("BusinessAuthorizationCategory:Name"); return sProp; } const OUString& PROP_STARTVALIDITY() { static const OUString sProp("Authorization:StartValidity"); return sProp; } const OUString& PROP_NONE() { static const OUString sProp("None"); return sProp; } const OUString& PROP_IMPACTSCALE() { static const OUString sProp("Impact:Scale"); return sProp; } const OUString& PROP_IMPACTLEVEL() { static const OUString sProp("Impact:Level:Confidentiality"); return sProp; } const OUString& PROP_PREFIX_EXPORTCONTROL() { static const OUString sProp("urn:bails:ExportControl:"); return sProp; } const OUString& PROP_PREFIX_NATIONALSECURITY() { static const OUString sProp("urn:bails:NationalSecurity:"); return sProp; } /// Represents one category of a classification policy. class SfxClassificationCategory { public: /// PROP_BACNAME() is stored separately for easier lookup. OUString m_aName; OUString m_aAbbreviatedName; //< An abbreviation to display instead of m_aName. OUString m_aIdentifier; //< The Identifier of this entry. size_t m_nConfidentiality; //< 0 is the lowest (least-sensitive). std::map m_aLabels; }; /// Parses a policy XML conforming to the TSCP BAF schema. class SfxClassificationParser : public cppu::WeakImplHelper { public: std::vector m_aCategories; std::vector m_aMarkings; std::vector m_aIPParts; std::vector m_aIPPartNumbers; OUString m_aPolicyAuthorityName; bool m_bInPolicyAuthorityName = false; OUString m_aPolicyName; bool m_bInPolicyName = false; OUString m_aProgramID; bool m_bInProgramID = false; OUString m_aScale; bool m_bInScale = false; OUString m_aConfidentalityValue; bool m_bInConfidentalityValue = false; OUString m_aIdentifier; bool m_bInIdentifier = false; OUString m_aValue; bool m_bInValue = false; /// Pointer to a value in m_aCategories, the currently parsed category. SfxClassificationCategory* m_pCategory = nullptr; SfxClassificationParser(); void SAL_CALL startDocument() override; void SAL_CALL endDocument() override; void SAL_CALL startElement(const OUString& rName, const uno::Reference& xAttribs) override; void SAL_CALL endElement(const OUString& rName) override; void SAL_CALL characters(const OUString& rChars) override; void SAL_CALL ignorableWhitespace(const OUString& rWhitespaces) override; void SAL_CALL processingInstruction(const OUString& rTarget, const OUString& rData) override; void SAL_CALL setDocumentLocator(const uno::Reference& xLocator) override; }; SfxClassificationParser::SfxClassificationParser() = default; void SAL_CALL SfxClassificationParser::startDocument() { } void SAL_CALL SfxClassificationParser::endDocument() { } void SAL_CALL SfxClassificationParser::startElement(const OUString& rName, const uno::Reference& xAttribs) { if (rName == "baf:PolicyAuthorityName") { m_aPolicyAuthorityName.clear(); m_bInPolicyAuthorityName = true; } else if (rName == "baf:PolicyName") { m_aPolicyName.clear(); m_bInPolicyName = true; } else if (rName == "baf:ProgramID") { m_aProgramID.clear(); m_bInProgramID = true; } else if (rName == "baf:BusinessAuthorizationCategory") { const OUString aName = xAttribs->getValueByName("Name"); if (!m_pCategory && !aName.isEmpty()) { OUString aIdentifier = xAttribs->getValueByName("Identifier"); // Create a new category and initialize it with the data that's true for all categories. m_aCategories.emplace_back(SfxClassificationCategory()); SfxClassificationCategory& rCategory = m_aCategories.back(); rCategory.m_aName = aName; // Set the abbreviated name, if any, otherwise fallback on the full name. const OUString aAbbreviatedName = xAttribs->getValueByName("loextAbbreviatedName"); rCategory.m_aAbbreviatedName = !aAbbreviatedName.isEmpty() ? aAbbreviatedName : aName; rCategory.m_aIdentifier = aIdentifier; rCategory.m_aLabels["PolicyAuthority:Name"] = m_aPolicyAuthorityName; rCategory.m_aLabels["Policy:Name"] = m_aPolicyName; rCategory.m_aLabels["BusinessAuthorization:Identifier"] = m_aProgramID; rCategory.m_aLabels["BusinessAuthorizationCategory:Identifier"] = aIdentifier; // Also initialize defaults. rCategory.m_aLabels["PolicyAuthority:Identifier"] = PROP_NONE(); rCategory.m_aLabels["PolicyAuthority:Country"] = PROP_NONE(); rCategory.m_aLabels["Policy:Identifier"] = PROP_NONE(); rCategory.m_aLabels["BusinessAuthorization:Name"] = PROP_NONE(); rCategory.m_aLabels["BusinessAuthorization:Locator"] = PROP_NONE(); rCategory.m_aLabels["BusinessAuthorizationCategory:Identifier:OID"] = PROP_NONE(); rCategory.m_aLabels["BusinessAuthorizationCategory:Locator"] = PROP_NONE(); rCategory.m_aLabels["BusinessAuthorization:Locator"] = PROP_NONE(); rCategory.m_aLabels["MarkingPrecedence"] = PROP_NONE(); rCategory.m_aLabels["Marking:general-summary"].clear(); rCategory.m_aLabels["Marking:general-warning-statement"].clear(); rCategory.m_aLabels["Marking:general-warning-statement:ext:2"].clear(); rCategory.m_aLabels["Marking:general-warning-statement:ext:3"].clear(); rCategory.m_aLabels["Marking:general-warning-statement:ext:4"].clear(); rCategory.m_aLabels["Marking:general-distribution-statement"].clear(); rCategory.m_aLabels["Marking:general-distribution-statement:ext:2"].clear(); rCategory.m_aLabels["Marking:general-distribution-statement:ext:3"].clear(); rCategory.m_aLabels["Marking:general-distribution-statement:ext:4"].clear(); rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCHEADER()].clear(); rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCFOOTER()].clear(); rCategory.m_aLabels[SfxClassificationHelper::PROP_DOCWATERMARK()].clear(); rCategory.m_aLabels["Marking:email-first-line-of-text"].clear(); rCategory.m_aLabels["Marking:email-last-line-of-text"].clear(); rCategory.m_aLabels["Marking:email-subject-prefix"].clear(); rCategory.m_aLabels["Marking:email-subject-suffix"].clear(); rCategory.m_aLabels[PROP_STARTVALIDITY()] = PROP_NONE(); rCategory.m_aLabels["Authorization:StopValidity"] = PROP_NONE(); m_pCategory = &rCategory; } } else if (rName == "loext:Marking") { OUString aName = xAttribs->getValueByName("Name"); m_aMarkings.push_back(aName); } else if (rName == "loext:IntellectualPropertyPart") { OUString aName = xAttribs->getValueByName("Name"); m_aIPParts.push_back(aName); } else if (rName == "loext:IntellectualPropertyPartNumber") { OUString aName = xAttribs->getValueByName("Name"); m_aIPPartNumbers.push_back(aName); } else if (rName == "baf:Scale") { m_aScale.clear(); m_bInScale = true; } else if (rName == "baf:ConfidentalityValue") { m_aConfidentalityValue.clear(); m_bInConfidentalityValue = true; } else if (rName == "baf:Identifier") { m_aIdentifier.clear(); m_bInIdentifier = true; } else if (rName == "baf:Value") { m_aValue.clear(); m_bInValue = true; } } void SAL_CALL SfxClassificationParser::endElement(const OUString& rName) { if (rName == "baf:PolicyAuthorityName") m_bInPolicyAuthorityName = false; else if (rName == "baf:PolicyName") m_bInPolicyName = false; else if (rName == "baf:ProgramID") m_bInProgramID = false; else if (rName == "baf:BusinessAuthorizationCategory") m_pCategory = nullptr; else if (rName == "baf:Scale") { m_bInScale = false; if (m_pCategory) m_pCategory->m_aLabels[PROP_IMPACTSCALE()] = m_aScale; } else if (rName == "baf:ConfidentalityValue") { m_bInConfidentalityValue = false; if (m_pCategory) { std::map& rLabels = m_pCategory->m_aLabels; rLabels[PROP_IMPACTLEVEL()] = m_aConfidentalityValue; m_pCategory->m_nConfidentiality = m_aConfidentalityValue.toInt32(); // 0-based class sensitivity; 0 is lowest. // Set the two other type of levels as well, if they're not set // yet: they're optional in BAF, but not in BAILS. rLabels.try_emplace("Impact:Level:Integrity", m_aConfidentalityValue); rLabels.try_emplace("Impact:Level:Availability", m_aConfidentalityValue); } } else if (rName == "baf:Identifier") m_bInIdentifier = false; else if (rName == "baf:Value") { if (m_pCategory) { if (m_aIdentifier == "Document: Header") m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCHEADER()] = m_aValue; else if (m_aIdentifier == "Document: Footer") m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCFOOTER()] = m_aValue; else if (m_aIdentifier == "Document: Watermark") m_pCategory->m_aLabels[SfxClassificationHelper::PROP_DOCWATERMARK()] = m_aValue; } } } void SAL_CALL SfxClassificationParser::characters(const OUString& rChars) { if (m_bInPolicyAuthorityName) m_aPolicyAuthorityName += rChars; else if (m_bInPolicyName) m_aPolicyName += rChars; else if (m_bInProgramID) m_aProgramID += rChars; else if (m_bInScale) m_aScale += rChars; else if (m_bInConfidentalityValue) m_aConfidentalityValue += rChars; else if (m_bInIdentifier) m_aIdentifier += rChars; else if (m_bInValue) m_aValue += rChars; } void SAL_CALL SfxClassificationParser::ignorableWhitespace(const OUString& /*rWhitespace*/) { } void SAL_CALL SfxClassificationParser::processingInstruction(const OUString& /*rTarget*/, const OUString& /*rData*/) { } void SAL_CALL SfxClassificationParser::setDocumentLocator(const uno::Reference& /*xLocator*/) { } } // anonymous namespace /// Implementation details of SfxClassificationHelper. class SfxClassificationHelper::Impl { public: /// Selected categories, one category for each policy type. std::map m_aCategory; /// Possible categories of a policy to choose from. std::vector m_aCategories; std::vector m_aMarkings; std::vector m_aIPParts; std::vector m_aIPPartNumbers; uno::Reference m_xDocumentProperties; bool m_bUseLocalized; explicit Impl(uno::Reference xDocumentProperties, bool bUseLocalized); void parsePolicy(); /// Synchronize m_aLabels back to the document properties. void pushToDocumentProperties(); /// Set the classification start date to the system time. void setStartValidity(SfxClassificationPolicyType eType); }; SfxClassificationHelper::Impl::Impl(uno::Reference xDocumentProperties, bool bUseLocalized) : m_xDocumentProperties(std::move(xDocumentProperties)) , m_bUseLocalized(bUseLocalized) { parsePolicy(); } void SfxClassificationHelper::Impl::parsePolicy() { uno::Reference xComponentContext = comphelper::getProcessComponentContext(); SvtPathOptions aOptions; OUString aPath = aOptions.GetClassificationPath(); // See if there is a localized variant next to the configured XML. OUString aExtension(".xml"); if (aPath.endsWith(aExtension) && m_bUseLocalized) { OUString aBase = aPath.copy(0, aPath.getLength() - aExtension.getLength()); const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag(); // Expected format is "_xx-XX.xml". OUString aLocalized = aBase + "_" + rLanguageTag.getBcp47() + aExtension; if (FStatHelper::IsDocument(aLocalized)) aPath = aLocalized; } std::unique_ptr pStream = utl::UcbStreamHelper::CreateStream(aPath, StreamMode::READ); uno::Reference xInputStream(new utl::OStreamWrapper(std::move(pStream))); xml::sax::InputSource aParserInput; aParserInput.aInputStream = xInputStream; uno::Reference xParser = xml::sax::Parser::create(xComponentContext); rtl::Reference xClassificationParser(new SfxClassificationParser()); xParser->setDocumentHandler(xClassificationParser); try { xParser->parseStream(aParserInput); } catch (const xml::sax::SAXParseException&) { TOOLS_WARN_EXCEPTION("sfx.view", "parsePolicy() failed"); } m_aCategories = xClassificationParser->m_aCategories; m_aMarkings = xClassificationParser->m_aMarkings; m_aIPParts = xClassificationParser->m_aIPParts; m_aIPPartNumbers = xClassificationParser->m_aIPPartNumbers; } static bool lcl_containsProperty(const uno::Sequence& rProperties, std::u16string_view rName) { return std::any_of(rProperties.begin(), rProperties.end(), [&](const beans::Property& rProperty) { return rProperty.Name == rName; }); } void SfxClassificationHelper::Impl::setStartValidity(SfxClassificationPolicyType eType) { auto itCategory = m_aCategory.find(eType); if (itCategory == m_aCategory.end()) return; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(policyTypeToString(eType) + PROP_STARTVALIDITY()); if (it != rCategory.m_aLabels.end()) { if (it->second == PROP_NONE()) { // The policy left the start date unchanged, replace it with the system time. util::DateTime aDateTime = DateTime(DateTime::SYSTEM).GetUNODateTime(); it->second = utl::toISO8601(aDateTime); } } } void SfxClassificationHelper::Impl::pushToDocumentProperties() { uno::Reference xPropertyContainer = m_xDocumentProperties->getUserDefinedProperties(); uno::Reference xPropertySet(xPropertyContainer, uno::UNO_QUERY); uno::Sequence aProperties = xPropertySet->getPropertySetInfo()->getProperties(); for (auto& rPair : m_aCategory) { SfxClassificationPolicyType eType = rPair.first; SfxClassificationCategory& rCategory = rPair.second; std::map aLabels = rCategory.m_aLabels; aLabels[policyTypeToString(eType) + PROP_BACNAME()] = rCategory.m_aName; for (const auto& rLabel : aLabels) { try { if (lcl_containsProperty(aProperties, rLabel.first)) xPropertySet->setPropertyValue(rLabel.first, uno::makeAny(rLabel.second)); else xPropertyContainer->addProperty(rLabel.first, beans::PropertyAttribute::REMOVABLE, uno::makeAny(rLabel.second)); } catch (const uno::Exception&) { TOOLS_WARN_EXCEPTION("sfx.view", "pushDocumentProperties() failed for property " << rLabel.first); } } } } bool SfxClassificationHelper::IsClassified(const uno::Reference& xDocumentProperties) { uno::Reference xPropertyContainer = xDocumentProperties->getUserDefinedProperties(); if (!xPropertyContainer.is()) return false; uno::Reference xPropertySet(xPropertyContainer, uno::UNO_QUERY); const uno::Sequence aProperties = xPropertySet->getPropertySetInfo()->getProperties(); for (const beans::Property& rProperty : aProperties) { if (rProperty.Name.startsWith("urn:bails:")) return true; } return false; } SfxClassificationCheckPasteResult SfxClassificationHelper::CheckPaste(const uno::Reference& xSource, const uno::Reference& xDestination) { if (!SfxClassificationHelper::IsClassified(xSource)) // No classification on the source side. Return early, regardless the // state of the destination side. return SfxClassificationCheckPasteResult::None; if (!SfxClassificationHelper::IsClassified(xDestination)) { // Paste from a classified document to a non-classified one -> deny. return SfxClassificationCheckPasteResult::TargetDocNotClassified; } // Remaining case: paste between two classified documents. SfxClassificationHelper aSource(xSource); SfxClassificationHelper aDestination(xDestination); if (aSource.GetImpactScale() != aDestination.GetImpactScale()) // It's possible to compare them if they have the same scale. return SfxClassificationCheckPasteResult::None; if (aSource.GetImpactLevel() > aDestination.GetImpactLevel()) // Paste from a doc that has higher classification -> deny. return SfxClassificationCheckPasteResult::DocClassificationTooLow; return SfxClassificationCheckPasteResult::None; } bool SfxClassificationHelper::ShowPasteInfo(SfxClassificationCheckPasteResult eResult) { switch (eResult) { case SfxClassificationCheckPasteResult::None: { return true; } break; case SfxClassificationCheckPasteResult::TargetDocNotClassified: { if (!Application::IsHeadlessModeEnabled()) { std::unique_ptr xBox(Application::CreateMessageDialog(nullptr, VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_TARGET_DOC_NOT_CLASSIFIED))); xBox->run(); } return false; } break; case SfxClassificationCheckPasteResult::DocClassificationTooLow: { if (!Application::IsHeadlessModeEnabled()) { std::unique_ptr xBox(Application::CreateMessageDialog(nullptr, VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_DOC_CLASSIFICATION_TOO_LOW))); xBox->run(); } return false; } break; } return true; } SfxClassificationHelper::SfxClassificationHelper(const uno::Reference& xDocumentProperties, bool bUseLocalizedPolicy) : m_pImpl(std::make_unique(xDocumentProperties, bUseLocalizedPolicy)) { if (!xDocumentProperties.is()) return; uno::Reference xPropertyContainer = xDocumentProperties->getUserDefinedProperties(); if (!xPropertyContainer.is()) return; uno::Reference xPropertySet(xPropertyContainer, uno::UNO_QUERY); const uno::Sequence aProperties = xPropertySet->getPropertySetInfo()->getProperties(); for (const beans::Property& rProperty : aProperties) { if (!rProperty.Name.startsWith("urn:bails:")) continue; uno::Any aAny = xPropertySet->getPropertyValue(rProperty.Name); OUString aValue; if (aAny >>= aValue) { SfxClassificationPolicyType eType = stringToPolicyType(rProperty.Name); OUString aPrefix = policyTypeToString(eType); if (!rProperty.Name.startsWith(aPrefix)) // It's a prefix we did not recognize, ignore. continue; //TODO: Support abbreviated names(?) if (rProperty.Name == (aPrefix + PROP_BACNAME())) m_pImpl->m_aCategory[eType].m_aName = aValue; else m_pImpl->m_aCategory[eType].m_aLabels[rProperty.Name] = aValue; } } } SfxClassificationHelper::~SfxClassificationHelper() = default; std::vector const & SfxClassificationHelper::GetMarkings() const { return m_pImpl->m_aMarkings; } std::vector const & SfxClassificationHelper::GetIntellectualPropertyParts() const { return m_pImpl->m_aIPParts; } std::vector const & SfxClassificationHelper::GetIntellectualPropertyPartNumbers() const { return m_pImpl->m_aIPPartNumbers; } const OUString& SfxClassificationHelper::GetBACName(SfxClassificationPolicyType eType) const { return m_pImpl->m_aCategory[eType].m_aName; } const OUString& SfxClassificationHelper::GetAbbreviatedBACName(const OUString& sFullName) { for (const auto& category : m_pImpl->m_aCategories) { if (category.m_aName == sFullName) return category.m_aAbbreviatedName; } return sFullName; } OUString SfxClassificationHelper::GetBACNameForIdentifier(std::u16string_view sIdentifier) { if (sIdentifier.empty()) return ""; for (const auto& category : m_pImpl->m_aCategories) { if (category.m_aIdentifier == sIdentifier) return category.m_aName; } return ""; } OUString SfxClassificationHelper::GetHigherClass(const OUString& first, const OUString& second) { size_t nFirstConfidentiality = 0; size_t nSecondConfidentiality = 0; for (const auto& category : m_pImpl->m_aCategories) { if (category.m_aName == first) nFirstConfidentiality = category.m_nConfidentiality; if (category.m_aName == second) nSecondConfidentiality = category.m_nConfidentiality; } return nFirstConfidentiality >= nSecondConfidentiality ? first : second; } bool SfxClassificationHelper::HasImpactLevel() { auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return false; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE()); if (it == rCategory.m_aLabels.end()) return false; it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL()); return it != rCategory.m_aLabels.end(); } bool SfxClassificationHelper::HasDocumentHeader() { auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return false; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCHEADER()); return it != rCategory.m_aLabels.end() && !it->second.isEmpty(); } bool SfxClassificationHelper::HasDocumentFooter() { auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return false; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCFOOTER()); return it != rCategory.m_aLabels.end() && !it->second.isEmpty(); } InfobarType SfxClassificationHelper::GetImpactLevelType() { InfobarType aRet; aRet = InfobarType::WARNING; auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return aRet; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE()); if (it == rCategory.m_aLabels.end()) return aRet; OUString aScale = it->second; it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL()); if (it == rCategory.m_aLabels.end()) return aRet; OUString aLevel = it->second; // The spec defines two valid scale values: FIPS-199 and UK-Cabinet. if (aScale == "UK-Cabinet") { if (aLevel == "0") aRet = InfobarType::SUCCESS; else if (aLevel == "1") aRet = InfobarType::WARNING; else if (aLevel == "2") aRet = InfobarType::WARNING; else if (aLevel == "3") aRet = InfobarType::DANGER; } else if (aScale == "FIPS-199") { if (aLevel == "Low") aRet = InfobarType::SUCCESS; else if (aLevel == "Moderate") aRet = InfobarType::WARNING; else if (aLevel == "High") aRet = InfobarType::DANGER; } return aRet; } sal_Int32 SfxClassificationHelper::GetImpactLevel() { sal_Int32 nRet = -1; auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return nRet; SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE()); if (it == rCategory.m_aLabels.end()) return nRet; OUString aScale = it->second; it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL()); if (it == rCategory.m_aLabels.end()) return nRet; OUString aLevel = it->second; if (aScale == "UK-Cabinet") { sal_Int32 nValue = aLevel.toInt32(); if (nValue < 0 || nValue > 3) return nRet; nRet = nValue; } else if (aScale == "FIPS-199") { static std::map const aValues { { "Low", 0 }, { "Moderate", 1 }, { "High", 2 } }; auto itValues = aValues.find(aLevel); if (itValues == aValues.end()) return nRet; nRet = itValues->second; } return nRet; } OUString SfxClassificationHelper::GetImpactScale() { auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return OUString(); SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE()); if (it != rCategory.m_aLabels.end()) return it->second; return OUString(); } OUString SfxClassificationHelper::GetDocumentWatermark() { auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty); if (itCategory == m_pImpl->m_aCategory.end()) return OUString(); SfxClassificationCategory& rCategory = itCategory->second; auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCWATERMARK()); if (it != rCategory.m_aLabels.end()) return it->second; return OUString(); } std::vector SfxClassificationHelper::GetBACNames() { if (m_pImpl->m_aCategories.empty()) m_pImpl->parsePolicy(); std::vector aRet; std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory) { return rCategory.m_aName; }); return aRet; } std::vector SfxClassificationHelper::GetBACIdentifiers() { if (m_pImpl->m_aCategories.empty()) m_pImpl->parsePolicy(); std::vector aRet; std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory) { return rCategory.m_aIdentifier; }); return aRet; } std::vector SfxClassificationHelper::GetAbbreviatedBACNames() { if (m_pImpl->m_aCategories.empty()) m_pImpl->parsePolicy(); std::vector aRet; std::transform(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), std::back_inserter(aRet), [](const SfxClassificationCategory& rCategory) { return rCategory.m_aAbbreviatedName; }); return aRet; } void SfxClassificationHelper::SetBACName(const OUString& rName, SfxClassificationPolicyType eType) { if (m_pImpl->m_aCategories.empty()) m_pImpl->parsePolicy(); auto it = std::find_if(m_pImpl->m_aCategories.begin(), m_pImpl->m_aCategories.end(), [&](const SfxClassificationCategory& rCategory) { return rCategory.m_aName == rName; }); if (it == m_pImpl->m_aCategories.end()) { SAL_WARN("sfx.view", "'" << rName << "' is not a recognized category name"); return; } m_pImpl->m_aCategory[eType].m_aName = it->m_aName; m_pImpl->m_aCategory[eType].m_aAbbreviatedName = it->m_aAbbreviatedName; m_pImpl->m_aCategory[eType].m_nConfidentiality = it->m_nConfidentiality; m_pImpl->m_aCategory[eType].m_aLabels.clear(); const OUString& rPrefix = policyTypeToString(eType); for (const auto& rLabel : it->m_aLabels) m_pImpl->m_aCategory[eType].m_aLabels[rPrefix + rLabel.first] = rLabel.second; m_pImpl->setStartValidity(eType); m_pImpl->pushToDocumentProperties(); SfxViewFrame* pViewFrame = SfxViewFrame::Current(); if (!pViewFrame) return; UpdateInfobar(*pViewFrame); } void SfxClassificationHelper::UpdateInfobar(SfxViewFrame& rViewFrame) { OUString aBACName = GetBACName(SfxClassificationPolicyType::IntellectualProperty); bool bImpactLevel = HasImpactLevel(); if (!aBACName.isEmpty() && bImpactLevel) { OUString aMessage = SfxResId(STR_CLASSIFIED_DOCUMENT); aMessage = aMessage.replaceFirst("%1", aBACName); rViewFrame.RemoveInfoBar(u"classification"); rViewFrame.AppendInfoBar("classification", "", aMessage, GetImpactLevelType()); } } SfxClassificationPolicyType SfxClassificationHelper::stringToPolicyType(const OUString& rType) { if (rType.startsWith(PROP_PREFIX_EXPORTCONTROL())) return SfxClassificationPolicyType::ExportControl; else if (rType.startsWith(PROP_PREFIX_NATIONALSECURITY())) return SfxClassificationPolicyType::NationalSecurity; else return SfxClassificationPolicyType::IntellectualProperty; } const OUString& SfxClassificationHelper::policyTypeToString(SfxClassificationPolicyType eType) { switch (eType) { case SfxClassificationPolicyType::ExportControl: return PROP_PREFIX_EXPORTCONTROL(); case SfxClassificationPolicyType::NationalSecurity: return PROP_PREFIX_NATIONALSECURITY(); case SfxClassificationPolicyType::IntellectualProperty: break; } return PROP_PREFIX_INTELLECTUALPROPERTY(); } const OUString& SfxClassificationHelper::PROP_DOCHEADER() { static const OUString sProp("Marking:document-header"); return sProp; } const OUString& SfxClassificationHelper::PROP_DOCFOOTER() { static const OUString sProp("Marking:document-footer"); return sProp; } const OUString& SfxClassificationHelper::PROP_DOCWATERMARK() { static const OUString sProp("Marking:document-watermark"); return sProp; } const OUString& SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY() { static const OUString sProp("urn:bails:IntellectualProperty:"); return sProp; } SfxClassificationPolicyType SfxClassificationHelper::getPolicyType() { sal_Int32 nPolicyTypeNumber = officecfg::Office::Common::Classification::Policy::get(); auto eType = static_cast(nPolicyTypeNumber); return eType; } namespace sfx { namespace { OUString getProperty(uno::Reference const& rxPropertyContainer, OUString const& rName) { try { uno::Reference xPropertySet(rxPropertyContainer, uno::UNO_QUERY); return xPropertySet->getPropertyValue(rName).get(); } catch (const css::uno::Exception&) { } return OUString(); } } // end anonymous namespace sfx::ClassificationCreationOrigin getCreationOriginProperty(uno::Reference const & rxPropertyContainer, sfx::ClassificationKeyCreator const & rKeyCreator) { OUString sValue = getProperty(rxPropertyContainer, rKeyCreator.makeCreationOriginKey()); if (sValue.isEmpty()) return sfx::ClassificationCreationOrigin::NONE; return (sValue == "BAF_POLICY") ? sfx::ClassificationCreationOrigin::BAF_POLICY : sfx::ClassificationCreationOrigin::MANUAL; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */