daemon version check, idle mining control, bootstrap mirror, import key paste, and cleanup
- Add startup binary version checking for dragonxd/xmrig - Display daemon version in UI - Add idle mining thread count adjustment - Add bootstrap mirror option (bootstrap2.dragonx.is) in setup wizard - Add paste button to import private key dialog with address validation - Add z-address generation UI feedback (loading indicator) - Add option to delete blockchain data while preserving wallet.dat - Add font scale slider hotkey tooltip (Ctrl+Plus/Ctrl+Minus) - Fix Windows RPC auth: trim \r from config values, add .cookie fallback - Fix connection status message during block index loading - Improve application shutdown to prevent lingering background process
This commit is contained in:
@@ -118,13 +118,16 @@ ConnectionConfig Connection::parseConfFile(const std::string& path)
|
||||
std::string key = line.substr(0, eq_pos);
|
||||
std::string value = line.substr(eq_pos + 1);
|
||||
|
||||
// Trim whitespace
|
||||
while (!key.empty() && (key.back() == ' ' || key.back() == '\t')) {
|
||||
// Trim whitespace (including \r from Windows line endings)
|
||||
while (!key.empty() && (key.back() == ' ' || key.back() == '\t' || key.back() == '\r')) {
|
||||
key.pop_back();
|
||||
}
|
||||
while (!value.empty() && (value[0] == ' ' || value[0] == '\t')) {
|
||||
value.erase(0, 1);
|
||||
}
|
||||
while (!value.empty() && (value.back() == ' ' || value.back() == '\t' || value.back() == '\r')) {
|
||||
value.pop_back();
|
||||
}
|
||||
|
||||
// Map to config
|
||||
if (key == "rpcuser") {
|
||||
@@ -172,6 +175,16 @@ ConnectionConfig Connection::autoDetectConfig()
|
||||
}
|
||||
}
|
||||
|
||||
// If rpcpassword is empty, the daemon may be using .cookie auth
|
||||
if (config.rpcpassword.empty()) {
|
||||
std::string cookieUser, cookiePass;
|
||||
if (readAuthCookie(data_dir, cookieUser, cookiePass)) {
|
||||
config.rpcuser = cookieUser;
|
||||
config.rpcpassword = cookiePass;
|
||||
DEBUG_LOGF("Using .cookie authentication (no rpcpassword in config)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Set defaults for missing values
|
||||
if (config.host.empty()) {
|
||||
config.host = DRAGONX_DEFAULT_RPC_HOST;
|
||||
@@ -319,5 +332,40 @@ bool Connection::ensureEncryptionEnabled(const std::string& confPath)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::readAuthCookie(const std::string& dataDir, std::string& user, std::string& password)
|
||||
{
|
||||
if (dataDir.empty()) return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string cookiePath = dataDir + "\\.cookie";
|
||||
#else
|
||||
std::string cookiePath = dataDir + "/.cookie";
|
||||
#endif
|
||||
|
||||
std::ifstream file(cookiePath);
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
std::string cookie;
|
||||
std::getline(file, cookie);
|
||||
file.close();
|
||||
|
||||
// Cookie format: __cookie__:base64encodedpassword
|
||||
size_t colonPos = cookie.find(':');
|
||||
if (colonPos == std::string::npos || colonPos == 0) return false;
|
||||
|
||||
user = cookie.substr(0, colonPos);
|
||||
password = cookie.substr(colonPos + 1);
|
||||
|
||||
// Trim \r if present (Windows line endings)
|
||||
while (!password.empty() && (password.back() == '\r' || password.back() == '\n')) {
|
||||
password.pop_back();
|
||||
}
|
||||
|
||||
if (user.empty() || password.empty()) return false;
|
||||
|
||||
DEBUG_LOGF("Read auth cookie from: %s (user=%s)\n", cookiePath.c_str(), user.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace dragonx
|
||||
|
||||
@@ -87,6 +87,15 @@ public:
|
||||
*/
|
||||
static bool ensureEncryptionEnabled(const std::string& confPath);
|
||||
|
||||
/**
|
||||
* @brief Try to read .cookie auth file from the data directory
|
||||
* @param dataDir Path to the daemon data directory
|
||||
* @param user Output: cookie username (__cookie__)
|
||||
* @param password Output: cookie password
|
||||
* @return true if cookie file was read successfully
|
||||
*/
|
||||
static bool readAuthCookie(const std::string& dataDir, std::string& user, std::string& password);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -100,7 +100,20 @@ bool RPCClient::connect(const std::string& host, const std::string& port,
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
last_connect_error_ = e.what();
|
||||
DEBUG_LOGF("Connection failed: %s\n", e.what());
|
||||
// Daemon warmup messages (Loading block index, Verifying blocks, etc.)
|
||||
// are normal startup progress — don't label them "Connection failed".
|
||||
std::string msg = e.what();
|
||||
bool isWarmup = (msg.find("Loading") != std::string::npos ||
|
||||
msg.find("Verifying") != std::string::npos ||
|
||||
msg.find("Activating") != std::string::npos ||
|
||||
msg.find("Rewinding") != std::string::npos ||
|
||||
msg.find("Rescanning") != std::string::npos ||
|
||||
msg.find("Pruning") != std::string::npos);
|
||||
if (isWarmup) {
|
||||
DEBUG_LOGF("Daemon starting: %s\n", msg.c_str());
|
||||
} else {
|
||||
DEBUG_LOGF("Connection failed: %s\n", msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
connected_ = false;
|
||||
|
||||
Reference in New Issue
Block a user