From 5d14f26495d2e9ada7590ecaaa6b7dd07affd7ae Mon Sep 17 00:00:00 2001 From: J-D-K Date: Mon, 9 Jun 2025 14:58:10 -0400 Subject: [PATCH] TitleOptionState: Add system save protections. --- Makefile | 2 +- include/curl/curl.hpp | 28 ++++++++++---------- include/fs/save_data_functions.hpp | 6 +++++ romfs/Text/ENUS.json | 3 ++- source/JKSV.cpp | 5 ++-- source/appstates/TitleOptionState.cpp | 38 +++++++++++++++++++++++++++ source/curl/curl.cpp | 7 +++-- source/fs/save_data_functions.cpp | 5 ++++ 8 files changed, 72 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 72d5dee..91c63bf 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET := JKSV BUILD := build -SOURCES := source source/appstates source/ui source/data source/system source/fs +SOURCES := source source/appstates source/ui source/data source/system source/fs source/curl DATA := data INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SDL/include EXEFS_SRC := exefs_src diff --git a/include/curl/curl.hpp b/include/curl/curl.hpp index 87a8601..2edc2d6 100644 --- a/include/curl/curl.hpp +++ b/include/curl/curl.hpp @@ -28,6 +28,19 @@ namespace curl /// @brief Exits libcurl void exit(void); + /// @brief Inline templated function to wrap curl_easy_setopt and make using curl::Handle slightly easier. + /// @tparam Option Templated type of the option. This is a headache so let the compiler figure it out. + /// @tparam Value Templated type of the value to set the option too. See above. + /// @param handle curl::Handle the option is being set for. + /// @param option CURLOPT to set. + /// @param value Value to set the CURLOPT to. + /// @return CURLcode returned from curl_easy_setopt. + template + static inline CURLcode set_option(curl::Handle &handle, Option option, Value value) + { + return curl_easy_setopt(handle.get(), option, value); + } + /// @brief Inline function that returns a self cleaning curl handle. /// @return Curl handle. static inline curl::Handle new_handle(void) @@ -67,19 +80,6 @@ namespace curl return true; } - /// @brief Inline templated function to wrap curl_easy_setopt and make using curl::Handle slightly easier. - /// @tparam Option Templated type of the option. This is a headache so let the compiler figure it out. - /// @tparam Value Templated type of the value to set the option too. See above. - /// @param handle curl::Handle the option is being set for. - /// @param option CURLOPT to set. - /// @param value Value to set the CURLOPT to. - /// @return CURLcode returned from curl_easy_setopt. - template - static inline CURLcode set_option(curl::Handle &handle, Option option, Value value) - { - return curl_easy_setopt(handle.get(), option, value); - } - /// @brief Inline wrapper function to make adding to HeaderList simpler. /// @param headerList Header list to append to. /// @param header Header to append. @@ -125,7 +125,7 @@ namespace curl /// @param count Element count. /// @param target File to write the data to. /// @return Number of bytes written to the file. - size_t write_data_to_file(const char *buffer, size_t size, size_t count, fslib::File &target); + size_t write_data_to_file(const char *buffer, size_t size, size_t count, fslib::File *target); /// @brief Gets the value of a header from an array of headers. /// @param array Array of headers to search. diff --git a/include/fs/save_data_functions.hpp b/include/fs/save_data_functions.hpp index ad49618..8d83fbb 100644 --- a/include/fs/save_data_functions.hpp +++ b/include/fs/save_data_functions.hpp @@ -21,4 +21,10 @@ namespace fs /// @param journalSize Size of the journaling space. /// @return True on success. False on failure. bool extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize); + + /// @brief Returns whether or not the saveInfo passed is system type. + /// @param saveInfo FsSaveDataInfo to check. + /// @return True if it is. False if it isn't. + /// @note The config setting overrides this. + bool is_system_save_data(const FsSaveDataInfo *saveInfo); } // namespace fs diff --git a/romfs/Text/ENUS.json b/romfs/Text/ENUS.json index d673ecd..9c5be8f 100644 --- a/romfs/Text/ENUS.json +++ b/romfs/Text/ENUS.json @@ -147,7 +147,8 @@ "Error resetting save data!", "Save data successfully reset!", "SVI file exported successfully!", - "Error exporting SVI file!" + "Error exporting SVI file!", + "This option is unavailable for system saves!" ], "TitleOptionConfirmations": [ "Are you sure you want to add #%s# to your blacklist? Once you do this, it will no longer appear on any title list or selection.", diff --git a/source/JKSV.cpp b/source/JKSV.cpp index d777f98..3dcd6d9 100644 --- a/source/JKSV.cpp +++ b/source/JKSV.cpp @@ -2,6 +2,7 @@ #include "appstates/MainMenuState.hpp" #include "colors.hpp" #include "config.hpp" +#include "curl/curl.hpp" #include "data/data.hpp" #include "fslib.hpp" #include "input.hpp" @@ -22,10 +23,8 @@ namespace { /// @brief Build month. constexpr uint8_t BUILD_MON = 5; - /// @brief Build day. constexpr uint8_t BUILD_DAY = 31; - /// @brief Year. constexpr uint16_t BUILD_YEAR = 2025; } // namespace @@ -70,6 +69,7 @@ JKSV::JKSV(void) ABORT_ON_FAILURE(initialize_service(setInitialize, "Set")); ABORT_ON_FAILURE(initialize_service(setsysInitialize, "SetSys")); ABORT_ON_FAILURE(initialize_service(socketInitializeDefault, "Socket")); + ABORT_ON_FAILURE(curl::initialize()); // Input doesn't have anything to return. input::initialize(); @@ -127,6 +127,7 @@ JKSV::~JKSV() // Try to save config first. config::save(); + curl::exit(); socketExit(); setsysExit(); setExit(); diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index a1589ce..c524fea 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -144,6 +144,15 @@ void TitleOptionState::update(void) case RESET_SAVE_DATA: { + // Need to check this first. For safety. + FsSaveDataInfo *saveInfo = m_targetUser->get_save_info_by_id(m_titleInfo->get_application_id()); + if (!config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM) || fs::is_system_save_data(saveInfo)) + { + ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS, + strings::get_by_name(strings::names::TITLE_OPTION_POPS, 6)); + return; + } + // String std::string confirmString = stringutil::get_formatted_string( strings::get_by_name(strings::names::TITLE_OPTION_CONFIRMATIONS, 2), @@ -166,6 +175,14 @@ void TitleOptionState::update(void) case DELETE_SAVE_FROM_SYSTEM: { + FsSaveDataInfo *saveInfo = m_targetUser->get_save_info_by_id(m_titleInfo->get_application_id()); + if (!config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM) || fs::is_system_save_data(saveInfo)) + { + ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS, + strings::get_by_name(strings::names::TITLE_OPTION_POPS, 6)); + return; + } + // String std::string confirmString = stringutil::get_formatted_string( strings::get_by_name(strings::names::TITLE_OPTION_CONFIRMATIONS, 3), @@ -190,6 +207,14 @@ void TitleOptionState::update(void) case EXTEND_CONTAINER: { + FsSaveDataInfo *saveInfo = m_targetUser->get_save_info_by_id(m_titleInfo->get_application_id()); + if (!config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM) || fs::is_system_save_data(saveInfo)) + { + ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS, + strings::get_by_name(strings::names::TITLE_OPTION_POPS, 6)); + return; + } + // Data std::shared_ptr data = std::make_shared(); data->m_targetUser = m_targetUser; @@ -202,6 +227,12 @@ void TitleOptionState::update(void) case EXPORT_SVI: { + // This type of save data can't have this exported anyway. + FsSaveDataInfo *saveInfo = m_targetUser->get_save_info_by_id(m_titleInfo->get_application_id()); + if (fs::is_system_save_data(saveInfo)) + { + return; + } export_svi_file(m_titleInfo); } break; @@ -459,3 +490,10 @@ static void export_svi_file(data::TitleInfo *titleInfo) ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS, strings::get_by_name(strings::names::TITLE_OPTION_POPS, 4)); } + +static bool is_system_save_data(const FsSaveDataInfo *saveInfo) +{ + // The config setting will override this + return config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM) || + saveInfo->save_data_type == FsSaveDataType_System || saveInfo->save_data_type == FsSaveDataType_SystemBcat; +} diff --git a/source/curl/curl.cpp b/source/curl/curl.cpp index 43e0b29..b116a00 100644 --- a/source/curl/curl.cpp +++ b/source/curl/curl.cpp @@ -1,4 +1,4 @@ -#include "curl.hpp" +#include "curl/curl.hpp" #include "stringutil.hpp" namespace @@ -82,7 +82,7 @@ void curl::prepare_get(curl::Handle &curl) // Setup basic request. curl::set_option(curl, CURLOPT_HTTPGET, 1L); - curl::set_option(curl, CURLOPT_ACCEPT_ENCODING, "") // I think this is how you set the defaults for this? + curl::set_option(curl, CURLOPT_ACCEPT_ENCODING, ""); // I think this is how you set the defaults for this? } void curl::prepare_post(curl::Handle &curl) @@ -99,6 +99,5 @@ void curl::prepare_upload(curl::Handle &curl) curl::set_option(curl, CURLOPT_UPLOAD, 1L); curl::set_option(curl, CURLOPT_UPLOAD_BUFFERSIZE, SIZE_UPLOAD_BUFFER); - curl::set_option(curl, CURLOPT_ACCEPT_ENCODING, "") // Not really sure this will have any affect here... + curl::set_option(curl, CURLOPT_ACCEPT_ENCODING, ""); // Not really sure this will have any affect here... } -` diff --git a/source/fs/save_data_functions.cpp b/source/fs/save_data_functions.cpp index 97b29d6..babab7c 100644 --- a/source/fs/save_data_functions.cpp +++ b/source/fs/save_data_functions.cpp @@ -75,3 +75,8 @@ bool fs::extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t } return true; } + +bool fs::is_system_save_data(const FsSaveDataInfo *saveInfo) +{ + return saveInfo->save_data_type == FsSaveDataType_System || saveInfo->save_data_type == FsSaveDataType_SystemBcat; +}