extensions/windows-event-log/wel/MetadataWalker.cpp (159 lines of code) (raw):

/** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <strsafe.h> #include <map> #include <functional> #include <codecvt> #include <regex> #include <string> #include <utility> #include <vector> #include "MetadataWalker.h" #include "XMLString.h" namespace org::apache::nifi::minifi::wel { bool MetadataWalker::for_each(pugi::xml_node &node) { // don't shortcut resolution here so that we can log attributes. const auto idUpdate = [&](const std::string &input) { if (resolve_) { auto resolved = user_id_to_username_fn_(input); replaced_identifiers_[input] = resolved; return resolved; } replaced_identifiers_[input] = input; return input; }; for (pugi::xml_attribute attr : node.attributes()) { if (regex_ && utils::regexMatch(attr.name(), *regex_)) { updateAttributeValue(attr, attr.name(), idUpdate); } } const std::string node_name = node.name(); if (node_name == "Data") { for (pugi::xml_attribute attr : node.attributes()) { if (regex_ && utils::regexMatch(attr.name(), *regex_)) { updateText(node, attr.name(), idUpdate); } if (regex_ && utils::regexMatch(attr.value(), *regex_)) { updateText(node, attr.value(), idUpdate); } } if (resolve_) { std::string nodeText = node.text().get(); std::vector<std::string> ids = getIdentifiers(nodeText); for (const auto &id : ids) { auto resolved = user_id_to_username_fn_(id); std::string replacement = "%{" + id + "}"; replaced_identifiers_[id] = resolved; replaced_identifiers_[replacement] = resolved; nodeText = utils::StringUtils::replaceAll(nodeText, replacement, resolved); } node.text().set(nodeText.c_str()); } } else if (node_name == "TimeCreated") { metadata_["TimeCreated"] = node.attribute("SystemTime").value(); } else if (node_name == "EventRecordID") { metadata_["EventRecordID"] = node.text().get(); } else if (node_name == "Provider") { metadata_["Provider"] = node.attribute("Name").value(); } else if (node_name == "EventID") { metadata_["EventID"] = node.text().get(); } else { static std::map<std::string, EVT_FORMAT_MESSAGE_FLAGS> formatFlagMap = { {"Channel", EvtFormatMessageChannel}, {"Keywords", EvtFormatMessageKeyword}, {"Level", EvtFormatMessageLevel}, {"Opcode", EvtFormatMessageOpcode}, {"Task", EvtFormatMessageTask} }; auto it = formatFlagMap.find(node_name); if (it != formatFlagMap.end()) { std::function<std::string(const std::string &)> updateFunc = [&](const std::string &input) -> std::string { if (resolve_) { auto resolved = windows_event_log_metadata_.getEventData(it->second); if (!resolved.empty()) { return resolved; } } return input; }; updateText(node, node.name(), std::move(updateFunc)); } else { // no conversion is required here, so let the node fall through } } return true; } std::vector<std::string> MetadataWalker::getIdentifiers(const std::string &text) { auto pos = text.find("%{"); std::vector<std::string> found_strings; while (pos != std::string::npos) { auto next_pos = text.find('}', pos); if (next_pos != std::string::npos) { auto potential_identifier = text.substr(pos + 2, next_pos - (pos + 2)); std::smatch match; if (potential_identifier.find("S-") != std::string::npos) { found_strings.push_back(potential_identifier); } } pos = text.find("%{", pos + 2); } return found_strings; } std::string MetadataWalker::getMetadata(METADATA metadata) const { switch (metadata) { case LOG_NAME: return log_name_; case SOURCE: return getString(metadata_, "Provider"); case TIME_CREATED: return windows_event_log_metadata_.getEventTimestamp(); case EVENTID: return getString(metadata_, "EventID"); case EVENT_RECORDID: return getString(metadata_, "EventRecordID"); case OPCODE: return getString(metadata_, "Opcode"); case TASK_CATEGORY: return getString(metadata_, "Task"); case LEVEL: return getString(metadata_, "Level"); case KEYWORDS: return getString(metadata_, "Keywords"); case EVENT_TYPE: return std::to_string(windows_event_log_metadata_.getEventTypeIndex()); case COMPUTER: return WindowsEventLogMetadata::getComputerName(); } return "N/A"; } std::map<std::string, std::string> MetadataWalker::getFieldValues() const { return fields_values_; } std::map<std::string, std::string> MetadataWalker::getIdentifiers() const { return replaced_identifiers_; } std::string MetadataWalker::to_string(const wchar_t* pChar) { return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(pChar); } template<typename Fn> requires std::is_convertible_v<std::invoke_result_t<Fn, std::string>, std::string> void MetadataWalker::updateText(pugi::xml_node &node, const std::string &field_name, Fn &&fn) { std::string previous_value = node.text().get(); auto new_field_value = std::invoke(std::forward<Fn>(fn), previous_value); if (new_field_value != previous_value) { metadata_[field_name] = new_field_value; if (update_xml_) { node.text().set(new_field_value.c_str()); } else { fields_values_[field_name] = new_field_value; } } } template<typename Fn> requires std::is_convertible_v<std::invoke_result_t<Fn, std::string>, std::string> void MetadataWalker::updateAttributeValue(pugi::xml_attribute &attr, const std::string &field_name, Fn &&fn) { std::string previous_value = attr.value(); auto new_field_value = std::invoke(std::forward<Fn>(fn), previous_value); if (new_field_value != previous_value) { metadata_[field_name] = new_field_value; if (update_xml_) { attr.set_value(new_field_value.c_str()); } else { fields_values_[field_name] = new_field_value; } } } } // namespace org::apache::nifi::minifi::wel