From: Sangwan Kwon Date: Fri, 15 May 2020 07:48:46 +0000 (+0900) Subject: Fix to use vist-json X-Git-Tag: submit/tizen/20200810.073515~16 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=92deb0f851275af8366c1cafc79f27b400fcd533;p=platform%2Fcore%2Fsecurity%2Fvist.git Fix to use vist-json Signed-off-by: Sangwan Kwon --- diff --git a/src/osquery/core/tables.cpp b/src/osquery/core/tables.cpp index 8f3885a..8d1c400 100644 --- a/src/osquery/core/tables.cpp +++ b/src/osquery/core/tables.cpp @@ -6,13 +6,12 @@ * the LICENSE file found in the root directory of this source tree. */ -#include - -#include #include #include #include +#include + namespace osquery { CREATE_LAZY_REGISTRY(TablePlugin, "table"); @@ -40,71 +39,64 @@ void TablePlugin::removeExternal(const std::string& name) { } void TablePlugin::setRequestFromContext(const QueryContext& context, - PluginRequest& request) { - auto doc = JSON::newObject(); - auto constraints = doc.getArray(); - - // The QueryContext contains a constraint map from column to type information - // and the list of operand/expression constraints applied to that column from - // the query given. - for (const auto& constraint : context.constraints) { - auto child = doc.getObject(); - doc.addRef("name", constraint.first, child); - constraint.second.serialize(doc, child); - doc.push(child, constraints); - } - - doc.add("constraints", constraints); - - if (context.colsUsed) { - auto colsUsed = doc.getArray(); - for (const auto& columnName : *context.colsUsed) { - doc.pushCopy(columnName, colsUsed); - } - doc.add("colsUsed", colsUsed); - } - - if (context.colsUsedBitset) { - doc.add("colsUsedBitset", context.colsUsedBitset->to_ullong()); - } - - doc.toString(request["context"]); -} - -QueryContext TablePlugin::getContextFromRequest( - const PluginRequest& request) const { - QueryContext context; - if (request.count("context") == 0) { - return context; - } - - auto doc = JSON::newObject(); - doc.fromString(request.at("context")); - if (doc.doc().HasMember("colsUsed")) { - UsedColumns colsUsed; - for (const auto& columnName : doc.doc()["colsUsed"].GetArray()) { - colsUsed.insert(columnName.GetString()); - } - context.colsUsed = colsUsed; - } - if (doc.doc().HasMember("colsUsedBitset")) { - context.colsUsedBitset = doc.doc()["colsUsedBitset"].GetUint64(); - } else if (context.colsUsed) { - context.colsUsedBitset = usedColumnsToBitset(*context.colsUsed); - } - - if (!doc.doc().HasMember("constraints") || - !doc.doc()["constraints"].IsArray()) { - return context; - } - - // Set the context limit and deserialize each column constraint list. - for (const auto& constraint : doc.doc()["constraints"].GetArray()) { - auto column_name = constraint["name"].GetString(); - context.constraints[column_name].deserialize(constraint); - } - - return context; + PluginRequest& request) { + vist::json::Json document; + vist::json::Array constraints; + + // The QueryContext contains a constraint map from column to type information + // and the list of operand/expression constraints applied to that column from + // the query given. + // + // {"constraints":[{"name":"test_int","list":[{"op":2,"expr":"2"}],"affinity":"TEXT"}]} + for (const auto& constraint : context.constraints) { + auto child = constraint.second.serialize(); + child["name"] = constraint.first; + + constraints.push(child); + } + + document.push("constraints", constraints); + + if (context.colsUsed) { + vist::json::Array colsUsed; + for (const auto& columnName : *context.colsUsed) + colsUsed.push(columnName); + + document.push("colsUsed", colsUsed); + } + + request["context"] = document.serialize(); + DEBUG(OSQUERY) << "request context->" << request["context"]; +} + +QueryContext TablePlugin::getContextFromRequest(const PluginRequest& request) const { + QueryContext context; + if (request.count("context") == 0) + return context; + + using namespace vist::json; + std::string serialized = request.at("context"); + Json document = Json::Parse(serialized); + DEBUG(OSQUERY) << "request context->" << document.serialize(); + + if (document.exist("colsUsed")) { + UsedColumns colsUsed; + Array array = document.get("colsUsed"); + for (auto i = 0; i < array.size(); i++) { + std::string name = array.at(i); + colsUsed.insert(name); + } + context.colsUsed = colsUsed; + } + + Array constraints = document.get("constraints"); + for (auto i = 0; i < constraints.size(); i++) { + auto constraint = Object::Create(constraints.at(i)); + std::string name = constraint["name"]; + context.constraints[name].deserialize(constraint); + } + + return context; } UsedColumnsBitset TablePlugin::usedColumnsToBitset( @@ -451,36 +443,36 @@ template std::set ConstraintList::getAll( template std::set ConstraintList::getAll(ConstraintOperator) const; -void ConstraintList::serialize(JSON& doc, rapidjson::Value& obj) const { - auto expressions = doc.getArray(); - for (const auto& constraint : constraints_) { - auto child = doc.getObject(); - doc.add("op", static_cast(constraint.op), child); - doc.addRef("expr", constraint.expr, child); - doc.push(child, expressions); - } - doc.add("list", expressions, obj); - doc.addCopy("affinity", columnTypeName(affinity), obj); -} - -void ConstraintList::deserialize(const rapidjson::Value& obj) { - // Iterate through the list of operand/expressions, then set the constraint - // type affinity. - if (!obj.IsObject() || !obj.HasMember("list") || !obj["list"].IsArray()) { - return; - } - - for (const auto& list : obj["list"].GetArray()) { - auto op = static_cast(JSON::valueToSize(list["op"])); - Constraint constraint(op); - constraint.expr = list["expr"].GetString(); - constraints_.push_back(constraint); - } - - auto affinity_name = (obj.HasMember("affinity") && obj["affinity"].IsString()) - ? obj["affinity"].GetString() - : "UNKNOWN"; - affinity = columnTypeName(affinity_name); +vist::json::Object ConstraintList::serialize() const { + // format: { "affinity": "TEXT", "list": [ { "expr": "1", "op": 2 } ] } + vist::json::Array list; + for (const auto& constraint : constraints_) { + vist::json::Object element; + element["op"] = static_cast(constraint.op); + element["expr"] = constraint.expr; + list.push(element); + } + + vist::json::Object object; + object.push("list", list); + object["affinity"] = columnTypeName(affinity); + + return object; +} + +void ConstraintList::deserialize(vist::json::Object& obj) { + using namespace vist::json; + Array list = obj.get("list"); + for (auto i = 0; i < list.size(); i++) { + auto element = vist::json::Object::Create(list.at(i)); + int op = element["op"]; + Constraint constraint(static_cast(op)); + constraint.expr = static_cast(element["expr"]); + this->constraints_.emplace_back(std::move(constraint)); + } + + std::string name = obj.exist("affinity") ? static_cast(obj["affinity"]) : "UNKNOWN"; + this->affinity = columnTypeName(name); } bool QueryContext::isColumnUsed(const std::string& colName) const { diff --git a/src/osquery/include/osquery/tables.h b/src/osquery/include/osquery/tables.h index a59cc70..232d8d6 100644 --- a/src/osquery/include/osquery/tables.h +++ b/src/osquery/include/osquery/tables.h @@ -24,7 +24,8 @@ #include #include #include -#include + +#include #include @@ -345,10 +346,10 @@ struct ConstraintList : private boost::noncopyable { * ] * } */ - void serialize(JSON& doc, rapidjson::Value& obj) const; + vist::json::Object serialize() const; + + void deserialize(vist::json::Object& obj); - /// See ConstraintList::unserialize. - void deserialize(const rapidjson::Value& obj); private: /// List of constraint operator/expressions. diff --git a/src/osquery/sql/dynamic_table_row.h b/src/osquery/sql/dynamic_table_row.h index 7da1493..a0d48b5 100644 --- a/src/osquery/sql/dynamic_table_row.h +++ b/src/osquery/sql/dynamic_table_row.h @@ -10,6 +10,7 @@ #include #include +#include namespace osquery { diff --git a/src/osquery/sql/tests/sql_test_utils.h b/src/osquery/sql/tests/sql_test_utils.h index 6660bed..9a93f0a 100644 --- a/src/osquery/sql/tests/sql_test_utils.h +++ b/src/osquery/sql/tests/sql_test_utils.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace osquery { diff --git a/src/vist/json/array.hpp b/src/vist/json/array.hpp index 692e554..1a0de55 100644 --- a/src/vist/json/array.hpp +++ b/src/vist/json/array.hpp @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -30,7 +31,14 @@ struct Array : public Value { void push(const Type& data) { auto value = std::make_shared(); - *value = data; + if constexpr (std::is_same_v || std::is_same_v) { + auto real = std::make_shared(); + *real = data; + value->leaf = real; + } else { + *value = data; + } + this->buffer.emplace_back(std::move(value)); } @@ -74,8 +82,12 @@ struct Array : public Value { if (dumped.empty()) throw std::invalid_argument("Dumped value cannot empty."); - auto stripped = strip(dumped, '[', ']'); - auto tokens = split(trim(stripped), ","); + auto stripped = strip(trim(dumped), '[', ']'); + if (trim(stripped).empty()) + return; + + auto divided = split(stripped, ","); + auto tokens = canonicalize(divided); for (const auto& token : tokens) { auto value = std::make_shared(); value->deserialize(trim(token)); diff --git a/src/vist/json/json.hpp b/src/vist/json/json.hpp index bf445fc..78483ef 100644 --- a/src/vist/json/json.hpp +++ b/src/vist/json/json.hpp @@ -84,19 +84,12 @@ struct Json { template CompositeType& get(const std::string& key) { - if (!this->root.exist(key)) - throw std::runtime_error("Not exist key."); - - if constexpr (std::is_same_v || - std::is_same_v) { - if (auto downcast = std::dynamic_pointer_cast(this->root.pairs[key]->leaf); - downcast == nullptr) - throw std::runtime_error(key + "Mismatched type."); - else - return *downcast; - } else { - static_assert(dependent_false::value, "Only Composite type supported."); - } + return this->root.get(key); + } + + bool exist(const std::string& key) + { + return this->root.exist(key); } std::size_t size() const noexcept diff --git a/src/vist/json/object.hpp b/src/vist/json/object.hpp index df25a51..54d90ef 100644 --- a/src/vist/json/object.hpp +++ b/src/vist/json/object.hpp @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -26,11 +27,23 @@ namespace vist { namespace json { struct Object : public Value { + static Object Create(Value& value) + { + if (auto downcast = std::dynamic_pointer_cast(value.leaf); downcast == nullptr) + throw std::runtime_error("Mismatched type."); + else + return *downcast; + } + template void push(const std::string& key, const Type& data) { + auto real = std::make_shared(); + *real = data; + auto value = std::make_shared(); - *value = data; + value->leaf = real; + this->pairs[key] = std::move(value); } @@ -42,6 +55,24 @@ struct Object : public Value { return *(this->pairs[key]); } + template + CompositeType& get(const std::string& key) + { + if (!this->exist(key)) + throw std::runtime_error("Not exist key."); + + if constexpr (std::is_same_v || + std::is_same_v) { + if (auto downcast = std::dynamic_pointer_cast(this->pairs[key]->leaf); + downcast == nullptr) + throw std::runtime_error(key + "Mismatched type."); + else + return *downcast; + } else { + static_assert(dependent_false::value, "Only Composite type supported."); + } + } + std::string serialize() const override { std::stringstream ss; @@ -67,9 +98,9 @@ struct Object : public Value { if (dumped.empty()) throw std::invalid_argument("Dumped value cannot empty."); - auto stripped = strip(dumped, '{', '}'); - auto divided = split(trim(stripped), ","); - auto tokens = this->canonicalize(divided); + auto stripped = strip(trim(dumped), '{', '}'); + auto divided = split(stripped, ","); + auto tokens = canonicalize(divided); for (const auto& token : tokens) { if (auto pos = token.find(":"); pos != std::string::npos) { auto lhs = token.substr(0, pos); @@ -97,45 +128,6 @@ struct Object : public Value { } std::unordered_map> pairs; - - std::vector canonicalize(std::vector& tokens) - { - std::vector result; - auto rearrange = [&](std::vector::iterator& iter, char first, char last) { - if ((*iter).find(first) == std::string::npos) - return false; - - std::string origin = *iter; - iter++; - - std::size_t lcount = 1, rcount = 0; - while (iter != tokens.end()) { - if ((*iter).find(first) != std::string::npos) - lcount++; - else if ((*iter).find(last) != std::string::npos) - rcount++; - - origin += ", " + *iter; - - if (lcount == rcount) - break; - else - iter++; - } - result.emplace_back(std::move(origin)); - - return true; - }; - - for (auto iter = tokens.begin() ; iter != tokens.end(); iter++) { - if (rearrange(iter, '{', '}') || rearrange(iter, '[', ']')) - continue; - - result.emplace_back(std::move(*iter)); - } - - return result; - } }; } // namespace json diff --git a/src/vist/json/tests/json.cpp b/src/vist/json/tests/json.cpp index 7c461f6..abaf752 100644 --- a/src/vist/json/tests/json.cpp +++ b/src/vist/json/tests/json.cpp @@ -208,6 +208,59 @@ TEST(JsonTests, object) EXPECT_EQ(static_cast(result["string"]), "initial value"); } +TEST(JsonTests, empty_array) +{ + Json json = Json::Parse("{ \"empty\": [ ] }"); + EXPECT_EQ(json.size(), 1); +} + +TEST(JsonTests, osquery_format) +{ + // {"constraints":[{"name":"test_int","list":[{"op":2,"expr":"2"}],"affinity":"TEXT"}]} + Json document; + + { + // "constraints" + Array constraints; + + // "name" + Object child; + child["name"] = "test_int"; + + // "list" + Array list; + Object element; + element["op"] = 2; + element["expr"] = "2"; + list.push(element); + child.push("list", list); + + // "affinity" + child["affinity"] = "TEXT"; + + constraints.push(child); + document.push("constraints", constraints); + + EXPECT_EQ(document.serialize(), "{ \"constraints\": [ { \"affinity\": \"TEXT\", " + "\"name\": \"test_int\", " + "\"list\": [ { \"expr\": \"2\", \"op\": 2 } ] } ] }"); + } + + { + Json restore = Json::Parse(document.serialize()); + EXPECT_TRUE(restore.exist("constraints")); + + Array constraints = restore.get("constraints"); + Object child = Object::Create(constraints.at(0)); + EXPECT_EQ(static_cast(child["name"]), "test_int"); + + Array list = child.get("list"); + Object element = Object::Create(list.at(0)); + EXPECT_EQ(static_cast(element["op"]), 2); + EXPECT_EQ(static_cast(element["expr"]), "2"); + } +} + TEST(JsonTests, serialize) { Json json; diff --git a/src/vist/json/util.hpp b/src/vist/json/util.hpp new file mode 100644 index 0000000..97df9a9 --- /dev/null +++ b/src/vist/json/util.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 language governing permissions and + * limitations under the License + */ + +#pragma once + +#include + +#include +#include + +namespace vist { +namespace json { + +inline std::vector canonicalize(std::vector& tokens) +{ + std::vector result; + auto rearrange = [&](std::vector::iterator& iter, char first, char last) { + if ((*iter).find(first) == std::string::npos) + return false; + + std::string origin = *iter; + iter++; + + std::size_t lcount = 1, rcount = 0; + while (iter != tokens.end()) { + lcount += count(*iter, first); + rcount += count(*iter, last); + + origin += ", " + *iter; + + if (lcount == rcount) + break; + else + iter++; + } + result.emplace_back(std::move(origin)); + + return true; + }; + + for (auto iter = tokens.begin() ; iter != tokens.end(); iter++) { + if (rearrange(iter, '{', '}') || rearrange(iter, '[', ']')) { + if (iter == tokens.end()) + break; + else + continue; + } + + result.emplace_back(std::move(*iter)); + } + + return result; +} + +} // namespace json +} // namespace vist diff --git a/src/vist/json/value.hpp b/src/vist/json/value.hpp index 04bae16..64ff36f 100644 --- a/src/vist/json/value.hpp +++ b/src/vist/json/value.hpp @@ -116,8 +116,6 @@ struct Value { } std::shared_ptr leaf; - -private: }; struct Int : public Value { diff --git a/src/vist/string.hpp b/src/vist/string.hpp index c71a533..bfffd34 100644 --- a/src/vist/string.hpp +++ b/src/vist/string.hpp @@ -62,4 +62,9 @@ inline std::string strip(const std::string& origin, char begin, char end) return copied.substr(1, copied.size() -2); } +inline std::size_t count(const std::string& str, char ch) +{ + return std::count(str.begin(), str.end(), ch); +} + } // namespace vist