summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Koreniak <okoreniak@luxoft.com>2016-03-22 13:15:43 +0200
committerOleksandr Koreniak <okoreniak@luxoft.com>2016-04-01 17:56:50 +0300
commit49f0eb57e6ee7e7019dc0c16e73f01ee63672762 (patch)
treee7892e4fbd38e7b8e13aa3d20bde131cbcda3c03
parent98b34b9746e9c32b3453488d757632db2716f465 (diff)
downloadsdl_core-49f0eb57e6ee7e7019dc0c16e73f01ee63672762.tar.gz
Added validator in processing of SystemRequest(QUERY_APPS)
Added class QueryAppsDataValidatorTemplate<SmartObject> to validate request data.
-rw-r--r--src/components/application_manager/src/commands/mobile/system_request.cc473
1 files changed, 396 insertions, 77 deletions
diff --git a/src/components/application_manager/src/commands/mobile/system_request.cc b/src/components/application_manager/src/commands/mobile/system_request.cc
index ec66f325df..1ef89682bf 100644
--- a/src/components/application_manager/src/commands/mobile/system_request.cc
+++ b/src/components/application_manager/src/commands/mobile/system_request.cc
@@ -33,7 +33,8 @@ Copyright (c) 2013, Ford Motor Company
#include <vector>
#include <string>
-#include <stdio.h>
+#include <map>
+#include <set>
#include "application_manager/commands/mobile/system_request.h"
#include "application_manager/application_manager_impl.h"
#include "application_manager/application_impl.h"
@@ -43,9 +44,350 @@ Copyright (c) 2013, Ford Motor Company
#include "utils/file_system.h"
#include "formatters/CFormatterJsonBase.hpp"
#include "json/json.h"
+#include "utils/helpers.h"
namespace application_manager {
+namespace {
+
+CREATE_LOGGERPTR_LOCAL(logger_, "ApplicationManager")
+
+const char* kQueryAppsValidationFailedPrefix =
+ ":QUERY_APPS_VALIDATION_FAILED: ";
+
+const unsigned int kVrSynonymLengthMax = 40U;
+const unsigned int kVrSynonymLengthMin = 1U;
+const unsigned int kTtsNameLengthMax = 500U;
+const unsigned int kVrArraySizeMax = 100U;
+const unsigned int kVrArraySizeMin = 1U;
+const unsigned int kUrlSchemaLengthMax = 255U;
+const unsigned int kPackageNameLengthMax = 255U;
+const unsigned int kAppIdLengthMax = 40U;
+const unsigned int kAppNameLengthMax = 100U;
+const unsigned int kLanguageArraySizeMax = 100U;
+
+class QueryAppsDataValidator {
+ public:
+ typedef std::set<std::string> SynonymsSet;
+ typedef std::map<std::string, SynonymsSet> SynonymsMap;
+
+ QueryAppsDataValidator(const smart_objects::SmartObject& object,
+ const ApplicationManagerImpl& manager)
+ : data_(object), manager_(manager) {}
+
+ bool Validate() const {
+ LOG4CXX_AUTO_TRACE(logger_);
+ if (!data_.isValid()) {
+ LOG4CXX_ERROR(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "QueryApps response is not valid.");
+ return false;
+ }
+ if (!HasResponseKey()) {
+ return false;
+ }
+ return ValidateAppDataAndOsAndLanguagesData();
+ }
+
+ private:
+ bool HasResponseKey() const {
+ if (!data_.keyExists(json::response)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "QueryApps response does not contain '"
+ << json::response << "' parameter.");
+ return false;
+ }
+ return true;
+ }
+
+ bool ValidateAppDataAndOsAndLanguagesData() const {
+ const smart_objects::SmartArray* objects_array =
+ data_[json::response].asArray();
+ if (!objects_array) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "QueryApps response is not array.");
+ return false;
+ }
+ const std::size_t arr_size(objects_array->size());
+ SynonymsMap synonyms_map;
+ for (std::size_t idx = 0; idx < arr_size; ++idx) {
+ const smart_objects::SmartObject& app_data = (*objects_array)[idx];
+
+ if (!app_data.isValid()) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Wrong application data in json file.");
+ return false;
+ }
+ std::set<std::string> app_ids_set;
+ if (!ValidateAppIdAndAppName(app_data, app_ids_set)) {
+ return false;
+ }
+ // Verify os and dependent languages data
+ std::string os_type;
+ if (app_data.keyExists(json::ios)) {
+ os_type = json::ios;
+ if (!app_data[os_type].keyExists(json::urlScheme)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Can't find URL scheme in json file.");
+ return false;
+ }
+ if (app_data[os_type][json::urlScheme].asString().length() >
+ kUrlSchemaLengthMax) {
+ LOG4CXX_WARN(
+ logger_,
+ kQueryAppsValidationFailedPrefix
+ << "An urlscheme length exceeds maximum allowed ["
+ << app_data[os_type][json::urlScheme].asString().length()
+ << "]>[" << kUrlSchemaLengthMax << "]");
+ return false;
+ }
+ }
+ if (os_type.empty()) {
+ if (app_data.keyExists(json::android)) {
+ os_type = json::android;
+ if (!app_data[os_type].keyExists(json::packageName)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Can't find package name in json file.");
+ return false;
+ }
+ if (app_data[json::android][json::packageName].asString().length() >
+ kPackageNameLengthMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Package name length ["
+ << app_data[json::android][json::packageName]
+ .asString()
+ .length() << "] exceeds max length ["
+ << kPackageNameLengthMax << "]in json file.");
+ return false;
+ }
+ }
+ }
+
+ if (os_type.empty()) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Can't find mobile OS type in json file.");
+ return false;
+ }
+
+ // Languages verification
+ if (!app_data[os_type].keyExists(json::languages)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "'languages' doesn't exist");
+ return false;
+ }
+ if (!ValidateLanguages(app_data[os_type][json::languages],
+ synonyms_map)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool ValidateAppIdAndAppName(const smart_objects::SmartObject& app_data,
+ std::set<std::string>& app_ids_set) const {
+ // Verify appid
+ if (!app_data.keyExists(json::appId)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Can't find app ID in json file.");
+ return false;
+ }
+ // Verify appid length
+ const std::string app_id(app_data[json::appId].asString());
+ if (app_id.length() > kAppIdLengthMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "An Object ID length exceeds maximum allowed ["
+ << app_id.length() << "]>[" << kAppIdLengthMax << "]");
+ return false;
+ }
+
+ // Verify that appid is unique
+ if (app_ids_set.find(app_id) != app_ids_set.end()) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "An Object ID is not unigue [" << app_id << "]");
+ return false;
+ }
+ app_ids_set.insert(app_id);
+
+ // Verify that app is not registered yet
+ ApplicationSharedPtr registered_app =
+ manager_.application_by_policy_id(app_id);
+ if (registered_app) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Application with the same id: " << app_id
+ << " is registered already.");
+ return false;
+ }
+ // Verify app name exist
+ if (!app_data.keyExists(json::name)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Can't find app name in json file.");
+ return false;
+ }
+ // And app name length
+ const std::string appName(app_data[json::name].asString());
+ if (appName.length() > kAppNameLengthMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "Name of application exceeds maximum allowed ["
+ << appName.length() << "]>[" << kAppNameLengthMax
+ << "].");
+ return false;
+ }
+ return true;
+ }
+
+ bool ValidateLanguages(const smart_objects::SmartObject& languages,
+ SynonymsMap& synonyms_map) const {
+ bool default_language_found = false;
+ const size_t languages_array_size = languages.length();
+ if (languages_array_size > kLanguageArraySizeMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "'languages' array exceeds max size ["
+ << languages_array_size << "]>[" << kLanguageArraySizeMax
+ << "]");
+ return false;
+ }
+ // Every language has ttsname string and vrsynonyms array
+ for (size_t idx = 0; idx < languages_array_size; ++idx) {
+ const smart_objects::SmartObject& language = languages.getElement(idx);
+ std::set<std::string> keys = language.enumerate();
+ for (std::set<std::string>::const_iterator iter = keys.begin();
+ iter != keys.end();
+ ++iter) {
+ // Verify default language defined
+ if (!(*iter).compare(json::default_)) {
+ default_language_found = true;
+ }
+ // Add set for synonyms' duplicates validation
+ if (synonyms_map.find(*iter) == synonyms_map.end()) {
+ synonyms_map[*iter] = SynonymsSet();
+ }
+ // ttsName verification
+ if (!language[*iter].keyExists(json::ttsName)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "'languages.ttsName' doesn't exist");
+ return false;
+ }
+ const smart_objects::SmartObject& ttsNameObject =
+ language[*iter][json::ttsName];
+ // ttsName is string
+ if (smart_objects::SmartType_String == ttsNameObject.getType()) {
+ const std::string ttsName = language[*iter][json::ttsName].asString();
+ if (ttsName.length() > kTtsNameLengthMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "ttsName string exceeds max length ["
+ << ttsName.length() << "]>[" << kTtsNameLengthMax
+ << "]");
+ return false;
+ }
+ } else {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "ttsName is not the string type.");
+ return false;
+ }
+ if (!language[*iter].keyExists(json::vrSynonyms)) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "'languages.vrSynonyms' doesn't exist");
+ return false;
+ }
+ const smart_objects::SmartArray* synonyms_array =
+ language[*iter][json::vrSynonyms].asArray();
+ if (!synonyms_array) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSynonyms is not array.");
+ return false;
+ }
+ const size_t synonyms_array_size = synonyms_array->size();
+ if (synonyms_array_size < kVrArraySizeMin) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSynomyms array has [" << synonyms_array_size
+ << "] size < allowed min size [" << kVrArraySizeMin
+ << "]");
+ return false;
+ }
+ if (synonyms_array_size > kVrArraySizeMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSynomyms array size [" << synonyms_array_size
+ << "] exceeds maximum allowed size ["
+ << kVrArraySizeMax << "]");
+ return false;
+ }
+ for (std::size_t idx = 0; idx < synonyms_array_size; ++idx) {
+ const smart_objects::SmartObject& synonym = (*synonyms_array)[idx];
+ const std::string vrSynonym = synonym.asString();
+ if (vrSynonym.length() > kVrSynonymLengthMax) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSYnomym item [" << idx
+ << "] exceeds max length [" << vrSynonym.length()
+ << "]>[" << kVrSynonymLengthMax << "]");
+ return false;
+ }
+ if (vrSynonym.length() < kVrSynonymLengthMin) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSYnomym item [" << idx << "] length ["
+ << vrSynonym.length()
+ << "] is less then min length ["
+ << kVrSynonymLengthMin << "] allowed.");
+ return false;
+ }
+ // Verify duplicates
+ SynonymsMap::iterator synonyms_map_iter = synonyms_map.find(*iter);
+ SynonymsSet* synonyms_set = &(synonyms_map_iter->second);
+ if (synonyms_map_iter != synonyms_map.end()) {
+ if ((*synonyms_map_iter).second.find(vrSynonym) ==
+ synonyms_set->end()) {
+ synonyms_set->insert(vrSynonym);
+ } else {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "vrSYnomym item already defined ["
+ << vrSynonym.c_str() << "] for language ["
+ << *iter << "]");
+ return false;
+ }
+ }
+ }
+ }
+ }
+ if (!default_language_found) {
+ LOG4CXX_WARN(logger_,
+ kQueryAppsValidationFailedPrefix
+ << " 'languages'.default' doesn't exist");
+ return false;
+ }
+ return true;
+ }
+
+ const smart_objects::SmartObject& data_;
+ const ApplicationManagerImpl& manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryAppsDataValidator);
+};
+}
+
namespace commands {
uint32_t SystemRequest::index = 0;
@@ -54,11 +396,9 @@ const std::string kSYNC = "SYNC";
const std::string kIVSU = "IVSU";
SystemRequest::SystemRequest(const MessageSharedPtr& message)
- : CommandRequestImpl(message) {
-}
+ : CommandRequestImpl(message) {}
-SystemRequest::~SystemRequest() {
-}
+SystemRequest::~SystemRequest() {}
void SystemRequest::Run() {
LOG4CXX_AUTO_TRACE(logger_);
@@ -77,7 +417,7 @@ void SystemRequest::Run() {
(*message_)[strings::msg_params][strings::request_type].asInt());
if (!policy::PolicyHandler::instance()->IsRequestTypeAllowed(
- application->mobile_app_id(), request_type)) {
+ application->mobile_app_id(), request_type)) {
SendResponse(false, mobile_apis::Result::DISALLOWED);
return;
}
@@ -89,15 +429,14 @@ void SystemRequest::Run() {
file_name = kSYNC;
}
- bool is_system_file =
- std::string::npos != file_name.find(kSYNC) ||
- std::string::npos != file_name.find(kIVSU);
+ bool is_system_file = std::string::npos != file_name.find(kSYNC) ||
+ std::string::npos != file_name.find(kIVSU);
// to avoid override existing file
if (is_system_file) {
const uint8_t max_size = 255;
char buf[max_size] = {'\0'};
- snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%d%s", index++, file_name.c_str());
+ snprintf(buf, max_size - 1, "%d%s", index++, file_name.c_str());
file_name = buf;
}
@@ -118,9 +457,10 @@ void SystemRequest::Run() {
file_dst_path += file_name;
if ((*message_)[strings::params].keyExists(strings::binary_data)) {
- LOG4CXX_DEBUG(logger_, "Binary data is present. Trying to save it to: "
- << binary_data_folder);
- if (mobile_apis::Result::SUCCESS !=
+ LOG4CXX_DEBUG(
+ logger_,
+ "Binary data is present. Trying to save it to: " << binary_data_folder);
+ if (mobile_apis::Result::SUCCESS !=
(ApplicationManagerImpl::instance()->SaveBinary(
binary_data, binary_data_folder, file_name, 0))) {
LOG4CXX_DEBUG(logger_, "Binary data can't be saved.");
@@ -131,16 +471,28 @@ void SystemRequest::Run() {
std::string app_full_file_path = binary_data_folder;
app_full_file_path += file_name;
- LOG4CXX_DEBUG(logger_, "Binary data is not present. Trying to find file "
- << file_name << " within previously saved app file in "
- << binary_data_folder);
+ LOG4CXX_DEBUG(logger_,
+ "Binary data is not present. Trying to find file "
+ << file_name << " within previously saved app file in "
+ << binary_data_folder);
const AppFile* file = application->GetFile(app_full_file_path);
if (!file || !file->is_download_complete ||
!file_system::MoveFile(app_full_file_path, file_dst_path)) {
LOG4CXX_DEBUG(logger_, "Binary data not found.");
- SendResponse(false, mobile_apis::Result::REJECTED);
- return;
+
+ std::string origin_file_name;
+ if ((*message_)[strings::msg_params].keyExists(strings::file_name)) {
+ origin_file_name =
+ (*message_)[strings::msg_params][strings::file_name].asString();
+ }
+ if (!(mobile_apis::RequestType::HTTP == request_type &&
+ 0 == origin_file_name.compare(kIVSU))) {
+ LOG4CXX_DEBUG(logger_, "Binary data required. Reject");
+ SendResponse(false, mobile_apis::Result::REJECTED);
+ return;
+ }
+ LOG4CXX_DEBUG(logger_, "IVSU does not require binary data. Continue");
}
processing_file_ = file_dst_path;
}
@@ -160,9 +512,8 @@ void SystemRequest::Run() {
}
CFormatterJsonBase::jsonValueToObj(root, sm_object);
-
if (!ValidateQueryAppData(sm_object)) {
- SendResponse(false, mobile_apis::Result::INVALID_DATA);
+ SendResponse(false, mobile_apis::Result::GENERIC_ERROR);
return;
}
@@ -172,10 +523,10 @@ void SystemRequest::Run() {
return;
}
- smart_objects::SmartObject msg_params = smart_objects::SmartObject(
- smart_objects::SmartType_Map);
+ smart_objects::SmartObject msg_params =
+ smart_objects::SmartObject(smart_objects::SmartType_Map);
if (std::string::npos != file_name.find(kIVSU)) {
- msg_params[strings::file_name] = file_name.c_str();
+ msg_params[strings::file_name] = file_name;
} else {
msg_params[strings::file_name] = file_dst_path;
}
@@ -186,12 +537,14 @@ void SystemRequest::Run() {
msg_params[strings::request_type] =
(*message_)[strings::msg_params][strings::request_type];
SendHMIRequest(hmi_apis::FunctionID::BasicCommunication_SystemRequest,
- &msg_params, true);
-
+ &msg_params,
+ true);
}
void SystemRequest::on_event(const event_engine::Event& event) {
- LOG4CXX_INFO(logger_, "AddSubMenuRequest::on_event");
+ LOG4CXX_AUTO_TRACE(logger_);
+ using namespace helpers;
+
const smart_objects::SmartObject& message = event.smart_object();
switch (event.id()) {
@@ -199,10 +552,14 @@ void SystemRequest::on_event(const event_engine::Event& event) {
mobile_apis::Result::eType result_code =
GetMobileResultCode(static_cast<hmi_apis::Common_Result::eType>(
message[strings::params][hmi_response::code].asUInt()));
- bool result = mobile_apis::Result::SUCCESS == result_code;
+
+ const bool result = Compare<mobile_api::Result::eType, EQ, ONE>(
+ result_code,
+ mobile_api::Result::SUCCESS,
+ mobile_api::Result::WARNINGS);
ApplicationSharedPtr application =
- ApplicationManagerImpl::instance()->application(connection_key());
+ ApplicationManagerImpl::instance()->application(connection_key());
if (!(application.valid())) {
LOG4CXX_ERROR(logger_, "NULL pointer");
@@ -224,63 +581,25 @@ void SystemRequest::on_event(const event_engine::Event& event) {
}
bool SystemRequest::ValidateQueryAppData(
- const smart_objects::SmartObject& data) const {
+ const smart_objects::SmartObject& data) const {
if (!data.isValid()) {
- LOG4CXX_ERROR(logger_, "QueryApps response is not valid.");
+ LOG4CXX_ERROR(logger_,
+ kQueryAppsValidationFailedPrefix
+ << "QueryApps response is not valid.");
return false;
}
if (!data.keyExists(json::response)) {
LOG4CXX_ERROR(logger_,
- "QueryApps response does not contain '"
- << json::response << "' parameter.");
- return false;
- }
- smart_objects::SmartArray* obj_array = data[json::response].asArray();
- if (NULL == obj_array) {
+ kQueryAppsValidationFailedPrefix
+ << "QueryApps response does not contain '"
+ << json::response << "' parameter.");
return false;
}
+ ApplicationManagerImpl* manager = ApplicationManagerImpl::instance();
+ DCHECK(manager);
- const std::size_t arr_size(obj_array->size());
- for (std::size_t idx = 0; idx < arr_size; ++idx) {
- const smart_objects::SmartObject& app_data = (*obj_array)[idx];
- if (!app_data.isValid()) {
- LOG4CXX_ERROR(logger_, "Wrong application data in json file.");
- continue;
- }
- std::string os_type;
- if (app_data.keyExists(json::ios)) {
- os_type = json::ios;
- if (!app_data[os_type].keyExists(json::urlScheme)) {
- LOG4CXX_ERROR(logger_, "Can't find URL scheme in json file.");
- continue;
- }
- } else if (app_data.keyExists(json::android)) {
- os_type = json::android;
- if (!app_data[os_type].keyExists(json::packageName)) {
- LOG4CXX_ERROR(logger_, "Can't find package name in json file.");
- continue;
- }
- }
-
- if (os_type.empty()) {
- LOG4CXX_ERROR(logger_, "Can't find mobile OS type in json file.");
- continue;
- }
-
- if (!app_data.keyExists(json::appId)) {
- LOG4CXX_ERROR(logger_, "Can't find app ID in json file.");
- continue;
- }
-
- if (!app_data.keyExists(json::name)) {
- LOG4CXX_ERROR(logger_, "Can't find app name in json file.");
- continue;
- }
-
- return true;
- }
-
- return false;
+ QueryAppsDataValidator validator(data, *manager);
+ return validator.Validate();
}
} // namespace commands