From 9dfb87e220c26af257ebe0d941e1bbfe86aab41c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 6 Nov 2018 16:56:05 -0500 Subject: [PATCH] Add string sanitization to property description --- include/openspace/properties/property.h | 5 +- modules/server/src/jsonconverters.cpp | 16 +++++- src/properties/optionproperty.cpp | 7 ++- src/properties/property.cpp | 65 +++++++++++++++++++++---- src/properties/selectionproperty.cpp | 7 ++- 5 files changed, 86 insertions(+), 14 deletions(-) diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 0b9c599146..4105df5596 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -465,7 +465,7 @@ public: * * \return The metadata information text for the property */ - virtual std::string generateMetaDataJsonDescription() const; + std::string generateMetaDataJsonDescription() const; /** * Creates the information that is specific to each subclass of Property%s. If a @@ -530,6 +530,9 @@ private: #endif }; +/// This function sanitizes an incoming string for JSON control characters +std::string sanitizeString(const std::string& str); + } // namespace openspace::properties #endif // __OPENSPACE_CORE___PROPERTY___H__ diff --git a/modules/server/src/jsonconverters.cpp b/modules/server/src/jsonconverters.cpp index 9dce4885cb..ac17df54fe 100644 --- a/modules/server/src/jsonconverters.cpp +++ b/modules/server/src/jsonconverters.cpp @@ -33,10 +33,22 @@ using json = nlohmann::json; namespace openspace::properties { +namespace { + + + +} // namespace + void to_json(json& j, const Property& p) { + std::string description = p.generateBaseJsonDescription(); + json desc = json::parse(description); + + std::string value = p.jsonValue(); + json val = json::parse(value); + j = { - { "Description", json::parse(p.generateBaseJsonDescription()) }, - { "Value", json::parse(p.jsonValue()) } + { "Description", desc }, + { "Value", val } }; j["Description"]["description"] = p.description(); } diff --git a/src/properties/optionproperty.cpp b/src/properties/optionproperty.cpp index 792abf4e45..540493b869 100644 --- a/src/properties/optionproperty.cpp +++ b/src/properties/optionproperty.cpp @@ -132,7 +132,12 @@ std::string OptionProperty::generateAdditionalJsonDescription() const { "{ \"" + OptionsKey + "\": ["; for (size_t i = 0; i < _options.size(); ++i) { const Option& o = _options[i]; - result += "{\"" + std::to_string(o.value) + "\": \"" + o.description + "\"}"; + std::string v = std::to_string(o.value); + std::string vSan = sanitizeString(v); + std::string d = o.description; + std::string dSan = sanitizeString(d); + + result += "{\"" + vSan + "\": \"" + dSan+ "\"}"; if (i != _options.size() - 1) { result += ","; } diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 76abb138bd..3ccc641c35 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -38,6 +38,7 @@ namespace { constexpr const char* MetaDataKeyReadOnly = "isReadOnly"; constexpr const char* _metaDataKeyViewPrefix = "view."; + } // namespace namespace openspace::properties { @@ -56,6 +57,43 @@ const char* Property::JsonValueKey = "Value"; const char* Property::MetaDataKey = "MetaData"; const char* Property::AdditionalDataKey = "AdditionalData"; + + +std::string sanitizeString(const std::string& s) { + std::string result; + + for (const char& c : s) { + switch (c) { + case '"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + default: + result += c; + } + } + + return result; +} + + #ifdef _DEBUG uint64_t Property::Identifier = 0; #endif @@ -275,15 +313,21 @@ void Property::notifyDeleteListeners() { } std::string Property::generateBaseJsonDescription() const { + std::string cName = className(); + std::string cNameSan = sanitizeString(cName); + std::string identifier = fullyQualifiedIdentifier(); + std::string identifierSan = sanitizeString(identifier); + std::string gName = guiName(); + std::string gNameSan = sanitizeString(gName); + std::string metaData = generateMetaDataJsonDescription(); + std::string description = generateAdditionalJsonDescription(); + return - "{ \"" + std::string(TypeKey) + "\": \"" + className() + "\", " + - "\"" + std::string(IdentifierKey) + "\": \"" + - fullyQualifiedIdentifier() + "\", " + - "\"" + std::string(NameKey) + "\": \"" + guiName() + "\", " + - "\"" + std::string(MetaDataKey) + "\": " + - generateMetaDataJsonDescription() + ", " + - "\"" + std::string(AdditionalDataKey) + "\": " + - generateAdditionalJsonDescription() + " }"; + "{ \"" + std::string(TypeKey) + "\": \"" + cNameSan + "\", " + + "\"" + std::string(IdentifierKey) + "\": \"" + identifierSan + "\", " + + "\"" + std::string(NameKey) + "\": \"" + gNameSan + "\", " + + "\"" + std::string(MetaDataKey) + "\": " + metaData + ", " + + "\"" + std::string(AdditionalDataKey) + "\": " + description + " }"; } std::string Property::generateMetaDataJsonDescription() const { @@ -302,9 +346,12 @@ std::string Property::generateMetaDataJsonDescription() const { isReadOnly = _metaData.value(MetaDataKeyReadOnly); } + std::string gIdent = groupIdentifier(); + std::string gIdentSan = sanitizeString(gIdent); + std::string result = "{ "; result += - "\"" + std::string(MetaDataKeyGroup) + "\": \"" + groupIdentifier() + "\", "; + "\"" + std::string(MetaDataKeyGroup) + "\": \"" + gIdentSan + "\", "; result += "\"" + std::string(MetaDataKeyVisibility) + "\": \"" + vis + "\", "; result += diff --git a/src/properties/selectionproperty.cpp b/src/properties/selectionproperty.cpp index d75b584cd5..f4e22449e7 100644 --- a/src/properties/selectionproperty.cpp +++ b/src/properties/selectionproperty.cpp @@ -159,8 +159,13 @@ std::string SelectionProperty::generateAdditionalJsonDescription() const { std::string result = "{ \"" + OptionsKey + "\": ["; for (size_t i = 0; i < _options.size(); ++i) { const Option& o = _options[i]; + std::string v = std::to_string(o.value); + std::string vSan = sanitizeString(v); + std::string d = o.description; + std::string dSan = sanitizeString(d); + result += "{"; - result += "\"" + std::to_string(o.value) + "\": \"" + o.description + "\""; + result += "\"" + vSan + "\": \"" + dSan + "\""; result += "}"; if (i != _options.size() - 1) { result += ",";