From c9bbe3b207b2b5da6649d69d0dea43726cd9ba10 Mon Sep 17 00:00:00 2001 From: zv0n Date: Sat, 10 Jul 2021 22:48:31 +0200 Subject: [PATCH] Make jsons slightly safer --- CMakeLists.txt | 3 ++ functions.cpp | 14 +++++++ functions.hpp | 1 + main.cpp | 88 ++++++++++++++++++++++-------------------- rename_object.cpp | 5 ++- themoviedb/moviedb.cpp | 8 ++++ 6 files changed, 76 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ce50a..242f728 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ add_library(thetvdb SHARED thetvdb/tv_rename.cpp thetvdb/functions.cpp rename_object.cpp + functions.cpp filesystem/unix/filesystem.cpp network/unix/network.cpp) @@ -34,12 +35,14 @@ target_link_libraries(thetvdb curl) add_library(simple SHARED simple_rename/simple.cpp rename_object.cpp + functions.cpp filesystem/unix/filesystem.cpp) add_library(moviedb SHARED themoviedb/moviedb.cpp themoviedb/functions.cpp rename_object.cpp + functions.cpp filesystem/unix/filesystem.cpp network/unix/network.cpp) diff --git a/functions.cpp b/functions.cpp index a66e1c4..2278320 100644 --- a/functions.cpp +++ b/functions.cpp @@ -88,3 +88,17 @@ std::vector< std::string > getTargetDirectories( const std::string &target_dir ) std::sort(result.begin(), result.end()); return result; } + +std::string safeJson(std::string input) { + for(size_t i = 0; i < input.size(); i++) { + if(input[i] == '\\') { + input.insert(i, "\\"); + i++; + } + if(input[i] == '"') { + input.insert(i, "\\"); + i++; + } + } + return input; +} diff --git a/functions.hpp b/functions.hpp index 2370562..8cc17ce 100644 --- a/functions.hpp +++ b/functions.hpp @@ -8,5 +8,6 @@ std::vector< RenameLibrary > getLibraries(const std::vector &libraries ); std::vector< std::string > getFilesInSource( const std::string &source_dir ); std::vector< std::string > getTargetDirectories( const std::string &target_dir ); +std::string safeJson(std::string input); #endif diff --git a/main.cpp b/main.cpp index a827b8e..4704d13 100644 --- a/main.cpp +++ b/main.cpp @@ -68,24 +68,27 @@ std::vector> getTypes() { std::string getTypesJson() { auto types = getTypes(); std::ostringstream result; - result << "[\n"; + result << "{\n \"types\": [\n"; if(!types.empty()) { for(const auto &type : types) { - result << " {\n \"id\": " << type.second << "\n"; - result << " \"name\": \"" << type.first << "\"\n },\n"; + result << " {\n \"id\": " << type.second << ",\n"; + result << " \"name\": \"" << safeJson(type.first) << "\"\n },\n"; } result.seekp(-2, std::ios_base::end); result << "\n"; } - result << "]"; - return result.str(); + result << " ]\n}"; + auto res = result.str(); + std::cout << res << std::endl; + return res; } void getTypesRest( const std::shared_ptr< restbed::Session > &session ) { sendResponse(getTypesJson(), restbed::OK, session); } -std::vector< RenameObject > getOptions(const RenameObject &search, size_t type) { +std::vector< RenameObject > getOptions(const RenameObject &search) { + auto type = search.getLibraryId(); if(type >= libraries.size()) { return {}; } @@ -96,10 +99,10 @@ std::vector< RenameObject > getOptions(const RenameObject &search, size_t type) return result; } -std::string getOptionsJson(const RenameObject &search, size_t type) { +std::string getOptionsJson(const RenameObject &search) { std::ostringstream res; - res << "[\n"; - auto options = getOptions(search, type); + res << "{\n \"options\": [\n"; + auto options = getOptions(search); if(!options.empty()) { for(auto &option : options) { res << option.toJson(); @@ -108,8 +111,10 @@ std::string getOptionsJson(const RenameObject &search, size_t type) { res.seekp( -2, std::ios_base::end ); res << "\n"; } - res << "]"; - return res.str(); + res << " ]\n}"; + auto result = res.str(); + std::cout << result << std::endl; + return result; } void getOptionsRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument> &doc ) @@ -121,26 +126,21 @@ void getOptionsRest( const std::shared_ptr< restbed::Session > &session, rapidjs if(!verifyLogin(session, doc)) { return; } - if(doc.FindMember("type") == doc.MemberEnd() || !doc["type"].IsUint64()) { - sendResponse("ERROR: Invalid type!", 401, session); - return; - } - if(doc.FindMember("search") == doc.MemberEnd() || !doc["search"].IsObject()) { + if(doc.FindMember("info") == doc.MemberEnd() || !doc["info"].IsObject()) { sendResponse("ERROR: Invalid search!", 401, session); return; } - size_t type_id = doc["type"].GetUint64(); RenameObject search; rapidjson::StringBuffer sb; rapidjson::Writer writer(sb); - doc["search"].Accept(writer); + doc["info"].Accept(writer); std::string s = sb.GetString(); search.fromJson(s); if(search.getPresentedName().empty()) { sendResponse("Empty search", 401, session); return; } - sendResponse(getOptionsJson(search, type_id), 200, session); + sendResponse(getOptionsJson(search), 200, session); } std::vector< std::string > getCustomKeys(size_t type) { @@ -153,16 +153,16 @@ std::vector< std::string > getCustomKeys(size_t type) { std::string getCustomKeysJson(size_t type) { std::ostringstream res; - res << "[\n"; + res << "{\n \"custom_keys\": [\n"; auto custom_keys = getCustomKeys(type); if(!custom_keys.empty()) { for(auto &key : custom_keys) { - res << "\"" << key << "\",\n"; + res << "\"" << safeJson(key) << "\",\n"; } res.seekp( -2, std::ios_base::end ); res << "\n"; } - res << "]"; + res << " ]\n}"; return res.str(); } @@ -204,9 +204,9 @@ std::string renamePathJson(const std::string &path, const RenameObject &renamer) } else { res << "false"; } - res << "\"\n"; + res << "\n"; if(!rename_result.first) { - res << " \"error\": \"" << rename_result.second << "\"\n"; + res << " \"error\": \"" << safeJson(rename_result.second) << "\"\n"; } res << "}"; return res.str(); @@ -221,15 +221,15 @@ void renamePathRest( const std::shared_ptr< restbed::Session > &session, rapidjs sendResponse("ERROR: Invalid path!", 401, session); return; } - if(doc.FindMember("renamer") == doc.MemberEnd() || !doc["renamer"].IsObject()) { - sendResponse("ERROR: Invalid renamer!", 401, session); + if(doc.FindMember("info") == doc.MemberEnd() || !doc["info"].IsObject()) { + sendResponse("ERROR: Invalid info!", 401, session); return; } std::string path = doc["path"].GetString(); RenameObject renamer; rapidjson::StringBuffer sb; rapidjson::Writer writer(sb); - doc["renamer"].Accept(writer); + doc["info"].Accept(writer); std::string s = sb.GetString(); renamer.fromJson(s); sendResponse(renamePathJson(path, renamer), 200, session); @@ -237,15 +237,15 @@ void renamePathRest( const std::shared_ptr< restbed::Session > &session, rapidjs std::string getFilesJson() { std::ostringstream res; - res << "[\n"; + res << "{\n \"files\": [\n"; auto files = getFilesInSource(cfg.getSourcePath()); if(!files.empty()) { for(const auto &file : files) { - res << "\"" << file << "\",\n"; + res << "\"" << safeJson(file) << "\",\n"; } res.seekp(-2, std::ios_base::end); } - res << "\n]"; + res << "\n ]\n}"; return res.str(); } @@ -268,16 +268,16 @@ std::vector> getTargets() { std::string getTargetsJson() { std::ostringstream res; - res << "[\n"; + res << "{\n \"targets\": [\n"; auto targets = getTargets(); if(!targets.empty()) { for(const auto &target : targets) { res << " {\n" << " \"id\": " << target.first << "\n"; - res << " \"name\": \"" << target.second << "\"\n },\n"; + res << " \"name\": \"" << safeJson(target.second) << "\"\n },\n"; } res.seekp(-2, std::ios_base::end); } - res << "\n]"; + res << "\n ]\n}"; return res.str(); } @@ -294,15 +294,15 @@ std::string getTargetDirectoriesJson(uint64_t id) { return ""; } std::ostringstream res; - res << "[\n"; + res << "{\n \"target_directories\": [\n"; auto dirs = getTargetDirectories(cfg.getTargetPaths()[id].first); if(!dirs.empty()) { for(const auto &dir : dirs) { - res << " \"" << dir << "\",\n"; + res << " \"" << safeJson(dir) << "\",\n"; } res.seekp(-2, std::ios_base::end); } - res << "\n]"; + res << "\n ]\n}"; return res.str(); } @@ -351,9 +351,9 @@ std::string moveJson(const std::string &path, uint64_t target_id, const std::str } else { res << "false"; } - res << "\"\n"; + res << "\n"; if(!move_result.first) { - res << " \"error\": \"" << move_result.second << "\"\n"; + res << " \"error\": \"" << safeJson(move_result.second) << "\"\n"; } res << "}"; return res.str(); @@ -408,9 +408,9 @@ std::string removeJson(const std::string &path) { } else { res << "false"; } - res << "\"\n"; + res << "\n"; if(!remove_result.first) { - res << " \"error\": \"" << remove_result.second << "\"\n"; + res << " \"error\": \"" << safeJson(remove_result.second) << "\"\n"; } res << "}"; return res.str(); @@ -431,6 +431,12 @@ void removeRest( const std::shared_ptr< restbed::Session > &session, rapidjson:: sendResponse(removeJson(path), 200, session); } +std::string loginJson(const std::string &user) { + std::ostringstream res; + res << "{\n \"token\": \"" << createLoginToken(user) << "\"\n}"; + return res.str(); +} + void loginRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument> &doc ) { if(doc.FindMember("user") == doc.MemberEnd() || !doc["user"].IsString()) { sendResponse("ERROR: Invalid user!", 401, session); @@ -450,7 +456,7 @@ void loginRest( const std::shared_ptr< restbed::Session > &session, rapidjson::G } } if(valid) { - sendResponse(createLoginToken(user), 200, session); + sendResponse(loginJson(user), 200, session); } else { sendResponse("Invalid user/password", 401, session); } diff --git a/rename_object.cpp b/rename_object.cpp index 06ce687..db5d9fa 100644 --- a/rename_object.cpp +++ b/rename_object.cpp @@ -1,4 +1,5 @@ #include "rename_object.hpp" +#include "functions.hpp" #include #include #include @@ -35,11 +36,11 @@ void RenameObject::clearCustomFields() { std::string RenameObject::toJson() const { std::ostringstream result; result << "{\n \"library_id\": " << _library_id << ",\n"; - result << " \"name\": \"" << _name << "\",\n"; + result << " \"name\": \"" << safeJson(_name) << "\",\n"; result << " \"custom_fields\": {\n"; if ( _custom_fields.size() > 0 ) { for ( auto &entry : _custom_fields ) { - result << " \"" << entry.first << "\": \"" << entry.second + result << " \"" << safeJson(entry.first) << "\": \"" << safeJson(entry.second) << "\",\n"; } result.seekp( -2, std::ios_base::end ); diff --git a/themoviedb/moviedb.cpp b/themoviedb/moviedb.cpp index f7f5cf7..086a58b 100644 --- a/themoviedb/moviedb.cpp +++ b/themoviedb/moviedb.cpp @@ -56,6 +56,10 @@ bool init(const string &config_path) { return true; } +bool hasKey(const rapidjson::GenericValue> &object, const std::string &key) { + return object.FindMember(key.c_str()) != object.MemberEnd(); +} + std::vector< std::tuple< string, string, string, string > > searchMovie( const string &movie, const string &language, const string &year ) { Request &request = _moviedb_request; @@ -89,6 +93,10 @@ searchMovie( const string &movie, const string &language, const string &year ) { // find all possible movies for ( size_t i = 0; i < results.Size(); i++ ) { + if(!hasKey(results[i], "title") || !hasKey(results[i], "id") || + !hasKey(results[i], "release_date") || !hasKey(results[i], "original_title")) { + continue; + } auto movie = toString( results[i]["title"].GetString() ); auto id = toString( std::to_string( results[i]["id"].GetInt() ) ); string year = toString( results[i]["release_date"].GetString() );