1
0
Fork 0
forked from lthn/blockchain

added sanitizing of utf8 in plain wallet, removed unnecessary rpc calls from get recent history

This commit is contained in:
cryptozoidberg 2025-03-14 14:44:27 +04:00
parent 09c3c2c156
commit 3ad96b5028
No known key found for this signature in database
GPG key ID: 2E10CC61CAC8F36D
6 changed files with 161 additions and 34 deletions

View file

@ -840,5 +840,113 @@ std::string get_nix_version_display_string()
return pr.first + " " + pr.second;
}
// Replaces invalid UTF-8 sequences with the UTF-8 replacement character (U+FFFD).
// If the original string is already valid UTF-8, it remains untouched.
// Returns true if the function modified the string, false otherwise.
bool sanitize_utf8(std::string& str_to_sanitize) {
const unsigned char* data = reinterpret_cast<const unsigned char*>(str_to_sanitize.data());
const unsigned char* end = data + str_to_sanitize.size();
std::string output; // remains empty unless invalid data is found
bool foundInvalid = false;
// We'll track where the last "valid segment" started.
const unsigned char* segmentStart = data;
// Helper lambda to append the replacement character U+FFFD (0xEF 0xBF 0xBD).
auto appendReplacementChar = [&](const unsigned char* pos) {
// If this is our first detected invalid sequence, start building 'output'.
// - Copy everything from segmentStart to 'pos' (not inclusive).
if (!foundInvalid) {
foundInvalid = true;
// Reserve approximate space to avoid repeated allocations
output.reserve(str_to_sanitize.size());
output.append(reinterpret_cast<const char*>(segmentStart),
reinterpret_cast<const char*>(pos));
}
// Append the UTF-8 replacement character
output.append("\xEF\xBF\xBD");
};
while (data < end) {
unsigned char c = *data;
int extraBytes = 0;
// 1) Determine how many bytes the current sequence should have,
// based on the leading byte.
if ((c & 0x80) == 0) {
// 1-byte sequence (ASCII)
extraBytes = 0;
}
else if ((c & 0xE0) == 0xC0) {
// 2-byte sequence
extraBytes = 1;
}
else if ((c & 0xF0) == 0xE0) {
// 3-byte sequence
extraBytes = 2;
}
else if ((c & 0xF8) == 0xF0) {
// 4-byte sequence
extraBytes = 3;
}
else {
// Invalid leading byte
appendReplacementChar(data);
data++;
// Next segment of "known good" data starts after this invalid byte
segmentStart = data;
continue;
}
// 2) Check that we have enough bytes left in the string
if (data + extraBytes >= end) {
// We don't have enough continuation bytes for a complete sequence
appendReplacementChar(data);
// Nothing more we can parse, so we're done
data = end;
break;
}
// 3) Validate the continuation bytes, which must match 10xxxxxx
bool invalidContinuation = false;
for (int i = 1; i <= extraBytes; ++i) {
if ((data[i] & 0xC0) != 0x80) {
invalidContinuation = true;
break;
}
}
if (invalidContinuation) {
// One or more continuation bytes are invalid
appendReplacementChar(data);
data++;
segmentStart = data;
continue;
}
// If we reach here, (c + continuation) forms a valid UTF-8 sequence
data += (extraBytes + 1);
}
// If we never encountered invalid data, 'foundInvalid' is false.
// In that case, we do nothing and simply return false.
if (!foundInvalid) {
return false; // No change was made
}
// Otherwise, we need to copy the last valid segment (if any) into 'output'.
// This covers the data from 'segmentStart' to the end.
if (segmentStart < end) {
output.append(reinterpret_cast<const char*>(segmentStart),
reinterpret_cast<const char*>(end));
}
// Now replace the original string with our sanitized version
str_to_sanitize.swap(output);
// Indicate we performed a modification
return true;
}
} // namespace tools

View file

@ -46,6 +46,7 @@ namespace tools
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
uint64_t get_total_system_memory();
std::string pretty_print_big_nums(std::uint64_t num);
bool sanitize_utf8(std::string& input);
std::pair<std::string, std::string> pretty_print_big_nums_to_pair(std::uint64_t num);
inline crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot)

View file

@ -15,6 +15,11 @@ namespace tools
core_fast_rpc_proxy(currency::core_rpc_server& rpc_srv) :m_rpc(rpc_srv)
{}
//------------------------------------------------------------------------------------------------------------------------------
virtual bool is_daemon_inbox()
{
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
virtual bool set_connection_addr(const std::string& url) override
{
return true;

View file

@ -67,6 +67,8 @@ namespace tools
std::shared_ptr<proxy_diagnostic_info> get_editable_proxy_diagnostic_info() { return m_pdiganostic_info; }
virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id){ return false; }
virtual void set_connectivity(unsigned int connection_timeout, size_t repeats_count) {}
// This method determines if the daemons share the same address space as the caller (which may help decide if some RPC calls can be skipped).
virtual bool is_daemon_inbox() { return false; }
protected:
std::shared_ptr<proxy_diagnostic_info> m_pdiganostic_info;
};

View file

@ -42,7 +42,7 @@
LOG_ERROR("Core already deinitialised or not initialized yet."); \
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response); \
ok_response.result.return_code = API_RETURN_CODE_UNINITIALIZED; \
return epee::serialization::store_t_to_json(ok_response); \
return sanitized_store_to_json(ok_response); \
}
namespace plain_wallet
{
@ -80,6 +80,13 @@ namespace plain_wallet
typedef epee::json_rpc::response<epee::json_rpc::dummy_result, error> error_response;
template<class t_struct>
std::string sanitized_store_to_json(const t_struct& t_obj)
{
std::string r = epee::serialization::store_t_to_json(t_obj);
tools::sanitize_utf8(r);
return r;
}
std::string get_set_working_dir(bool need_to_set = false, const std::string val = "")
{
@ -182,7 +189,7 @@ namespace plain_wallet
inst_ptr->gwm.quick_clear_wallets_no_save();
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
@ -197,7 +204,7 @@ namespace plain_wallet
LOG_ERROR("Double-initialization in plain_wallet detected.");
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_ALREADY_EXISTS;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
epee::static_helpers::set_or_call_on_destruct(true, static_destroy_handler);
@ -254,7 +261,7 @@ namespace plain_wallet
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = API_RETURN_CODE_INTERNAL_ERROR;
err_result.error.message = LOCATION_STR + " \nmessage:" + ec.message();
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
std::string app_config_folder = get_app_config_folder();
@ -264,14 +271,14 @@ namespace plain_wallet
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = API_RETURN_CODE_INTERNAL_ERROR;
err_result.error.message = LOCATION_STR + " \nmessage:" + ec.message();
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
#endif
std::atomic_store(&ginstance_ptr, ptr);
#ifndef CAKEWALLET
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
#else
return API_RETURN_CODE_OK;
#endif
@ -299,7 +306,7 @@ namespace plain_wallet
{
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = ret_code;
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
return res_str;
}
@ -311,13 +318,13 @@ namespace plain_wallet
{
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = ret_code;
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
else
{
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
}
bool is_wallet_exist(const std::string& path)
@ -344,7 +351,7 @@ namespace plain_wallet
epee::log_space::log_singletone::truncate_log_files();
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
std::string get_connectivity_status()
@ -374,7 +381,7 @@ namespace plain_wallet
std::string wallet_files_path = get_wallets_folder();
strings_list sl = AUTO_VAL_INIT(sl);
epee::file_io_utils::get_folder_content(wallet_files_path, sl.items, true);
return epee::serialization::store_t_to_json(sl);
return sanitized_store_to_json(sl);
}
std::string get_export_private_info(const std::string& target_dir)
@ -388,18 +395,18 @@ namespace plain_wallet
LOG_ERROR("Failed to create target directory(" << full_target_path << "):" << ec.message());
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_FAIL;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
if(!tools::copy_dir(src_folder_path, full_target_path))
{
LOG_ERROR("Failed to copy target directory");
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_FAIL;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
std::string delete_wallet(const std::string& file_name)
@ -410,7 +417,7 @@ namespace plain_wallet
boost::filesystem::remove(wallet_files_path + file_name, er);
epee::json_rpc::response<view::api_responce_return_code, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
ok_response.result.return_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
std::string get_address_info(const std::string& addr)
@ -463,11 +470,11 @@ namespace plain_wallet
inst_ptr->gwm.run_wallet(ok_response.result.wallet_id);
}
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = rsp;
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
std::string restore(const std::string& seed, const std::string& path, const std::string& password, const std::string& seed_password)
@ -487,11 +494,11 @@ namespace plain_wallet
{
inst_ptr->gwm.run_wallet(ok_response.result.wallet_id);
}
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = rsp;
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
std::string generate(const std::string& path, const std::string& password)
@ -511,11 +518,11 @@ namespace plain_wallet
{
inst_ptr->gwm.run_wallet(ok_response.result.wallet_id);
}
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
error_response err_result = AUTO_VAL_INIT(err_result);
err_result.error.code = rsp;
return epee::serialization::store_t_to_json(err_result);
return sanitized_store_to_json(err_result);
}
std::string get_opened_wallets()
@ -523,7 +530,7 @@ namespace plain_wallet
GET_INSTANCE_PTR(inst_ptr);
epee::json_rpc::response<std::list<view::open_wallet_response>, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
inst_ptr->gwm.get_opened_wallets(ok_response.result);
return epee::serialization::store_t_to_json(ok_response);
return sanitized_store_to_json(ok_response);
}
std::string close_wallet(hwallet h)
@ -588,7 +595,7 @@ namespace plain_wallet
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(ar);
return sanitized_store_to_json(ar);
}
std::string handle_run_wallet(uint64_t instance_id)
@ -609,7 +616,7 @@ namespace plain_wallet
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = inst_ptr->gwm.run_wallet(instance_id);
return epee::serialization::store_t_to_json(ar);
return sanitized_store_to_json(ar);
}
std::string handle_configure(const std::string& settings_json)
@ -621,11 +628,11 @@ namespace plain_wallet
if (!res)
{
conf_resp.status = API_RETURN_CODE_BAD_ARG;
return epee::serialization::store_t_to_json(conf_resp);
return sanitized_store_to_json(conf_resp);
}
inst_ptr->postponed_run_wallet = conf.postponed_run_wallet;
conf_resp.status = API_RETURN_CODE_OK;
return epee::serialization::store_t_to_json(conf_resp);
return sanitized_store_to_json(conf_resp);
}
std::string sync_call(const std::string& method_name, uint64_t instance_id, const std::string& params)
@ -636,7 +643,7 @@ namespace plain_wallet
close_wallet(instance_id);
view::api_responce_return_code rc = AUTO_VAL_INIT(rc);
rc.return_code = API_RETURN_CODE_OK;
res = epee::serialization::store_t_to_json(rc);
res = sanitized_store_to_json(rc);
}
else if (method_name == "open")
{
@ -645,7 +652,7 @@ namespace plain_wallet
{
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = "Wrong parameter";
res = epee::serialization::store_t_to_json(ar);
res = sanitized_store_to_json(ar);
}else
{
res = open(owr.path, owr.pass);
@ -658,7 +665,7 @@ namespace plain_wallet
{
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = "Wrong parameter";
res = epee::serialization::store_t_to_json(ar);
res = sanitized_store_to_json(ar);
}
else
{
@ -672,13 +679,13 @@ namespace plain_wallet
{
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = "Wrong parameter";
res = epee::serialization::store_t_to_json(ar);
res = sanitized_store_to_json(ar);
}
else
{
view::api_response_t<view::seed_phrase_info> rsp = AUTO_VAL_INIT(rsp);
rsp.error_code = tools::get_seed_phrase_info(sip.seed_phrase, sip.seed_password, rsp.response_data);
res = epee::serialization::store_t_to_json(rsp);
res = sanitized_store_to_json(rsp);
}
}
else if (method_name == "invoke")
@ -705,7 +712,7 @@ namespace plain_wallet
{
view::api_response ar = AUTO_VAL_INIT(ar);
ar.error_code = "UNKNOWN METHOD";
res = epee::serialization::store_t_to_json(ar);
res = sanitized_store_to_json(ar);
}
return res;
}
@ -748,7 +755,7 @@ namespace plain_wallet
wallet_extended_info wei = AUTO_VAL_INIT(wei);
inst_ptr->gwm.get_wallet_info(h, wei.wi);
inst_ptr->gwm.get_wallet_info_extra(h, wei.wi_extended);
return epee::serialization::store_t_to_json(wei);
return sanitized_store_to_json(wei);
}
std::string reset_wallet_password(hwallet h, const std::string& password)
{

View file

@ -4588,7 +4588,11 @@ void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_tra
if (wti.remote_addresses.size() == 1)
{
wti.remote_aliases = get_aliases_for_address(wti.remote_addresses[0]);
//this code is significantly slowing down when daemon are not "in-the-same-box"
if (m_core_proxy->is_daemon_inbox())
{
wti.remote_aliases = get_aliases_for_address(wti.remote_addresses[0]);
}
}
if (trs.size() >= count)