// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #include "lite_owned_string.h" #include #include namespace dragonx { namespace wallet { namespace { // A backend response is a failure when it is prefixed with "Error:" (the litelib_* convention). bool looksLikeError(const std::string& value) { return value.rfind("Error:", 0) == 0; } // Best-effort scrub of a copied secret-ish payload before the string is released. void wipeString(std::string& value) { std::fill(value.begin(), value.end(), '\0'); value.clear(); } } // namespace LiteBridgeOwnedString::LiteBridgeOwnedString(char* rawValue, FreeStringFn freeString) : rawValue_(rawValue), freeString_(freeString), rawPointerReceived_(rawValue != nullptr) { } LiteBridgeOwnedString::LiteBridgeOwnedString(LiteBridgeOwnedString&& other) noexcept { moveFrom(std::move(other)); } LiteBridgeOwnedString& LiteBridgeOwnedString::operator=(LiteBridgeOwnedString&& other) noexcept { if (this == &other) return *this; copyValueBeforeFree(); releaseRawValue(); wipeString(copiedValue_); moveFrom(std::move(other)); return *this; } LiteBridgeOwnedString::~LiteBridgeOwnedString() { copyValueBeforeFree(); releaseRawValue(); wipeString(copiedValue_); } LiteBridgeStringResult LiteBridgeOwnedString::intoResult() { if (resultTaken_) return {false, {}, "lite bridge string result already consumed"}; resultTaken_ = true; if (!rawPointerReceived_) return {false, {}, "lite bridge returned a null string"}; if (!rawValue_) return {false, {}, "lite bridge string was already released"}; if (!freeString_) { rawValue_ = nullptr; return {false, {}, "lite bridge freeString function is unavailable"}; } copyValueBeforeFree(); releaseRawValue(); const std::string resultValue = copiedValue_; wipeString(copiedValue_); if (looksLikeError(resultValue)) return {false, {}, resultValue}; return {true, resultValue, {}}; } void LiteBridgeOwnedString::copyValueBeforeFree() { if (!rawValue_ || copiedBeforeFree_) return; copiedValue_ = rawValue_; copiedBeforeFree_ = true; } void LiteBridgeOwnedString::releaseRawValue() { if (!rawValue_) return; if (freeString_) { freeString_(rawValue_); freed_ = true; } rawValue_ = nullptr; } void LiteBridgeOwnedString::moveFrom(LiteBridgeOwnedString&& other) noexcept { rawValue_ = other.rawValue_; freeString_ = other.freeString_; rawPointerReceived_ = other.rawPointerReceived_; copiedBeforeFree_ = other.copiedBeforeFree_; freed_ = other.freed_; resultTaken_ = other.resultTaken_; copiedValue_ = std::move(other.copiedValue_); other.rawValue_ = nullptr; other.freeString_ = nullptr; other.rawPointerReceived_ = false; other.copiedBeforeFree_ = false; other.freed_ = false; other.resultTaken_ = true; wipeString(other.copiedValue_); } LiteBridgeStringResult liteBridgeRuntimeTakeOwnedString( char* rawValue, LiteClientBridgeApi::FreeStringFn freeString) { LiteBridgeOwnedString ownedString(rawValue, freeString); return ownedString.intoResult(); } } // namespace wallet } // namespace dragonx