security: payment-URI amount validation, export filename sanitize, chat crash-guard, HTTPS-only, conf 0600, pool auto-lock
Six bounded defensive fixes: - Payment-URI amount is now strictly validated (reject NaN/inf/sign/garbage, <=8 decimals, 0..21,000,000) at parse time, so a crafted QR/URI can't inject a bogus amount into the Send form. The z_sendmany call the user confirms is unchanged; this is input validation only. - export-all-keys filename is sanitized (basename-only, no traversal) via a shared util::sanitizeExportFilename (factored out of the CSV export dialog). - Chat append()/upsert() wrap the strict serialize in try/catch so a malformed (invalid-UTF-8, attacker-influenceable) body is skipped, not crashed on — matching appendBatch's existing drop behavior. - http_download (used by the updaters + pool stats) restricts transfers AND redirects to HTTPS and bounds the download path's redirects, so a redirect can't downgrade to http:// or another scheme. - The default DRGX.conf (rpcuser/rpcpassword) is written 0600 from the start via writeFileAtomically, closing the brief world-readable ofstream+chmod window. - Auto-lock is suppressed only for SOLO mining (needs the wallet), not pool mining (pays an external address), which was holding the wallet open forever. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -108,8 +108,18 @@ bool ChatDatabase::append(const ChatMessage& message)
|
||||
|
||||
std::vector<unsigned char> nonce;
|
||||
std::vector<unsigned char> cipher;
|
||||
std::string plain = serialize(message); // full plaintext (decrypted body + metadata)
|
||||
const bool encrypted = encrypt(plain, nonce, cipher);
|
||||
std::string plain;
|
||||
bool encrypted = false;
|
||||
try {
|
||||
// serialize() dumps strictly, so an invalid-UTF-8 (attacker-influenceable) body THROWS here;
|
||||
// skip the row instead of letting it escape the write path and crash (appendBatch already does).
|
||||
plain = serialize(message);
|
||||
encrypted = encrypt(plain, nonce, cipher);
|
||||
} catch (const std::exception& e) {
|
||||
if (!plain.empty()) sodium_memzero(&plain[0], plain.size());
|
||||
DEBUG_LOGF("[chat] append skipped a malformed message: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
if (!plain.empty()) sodium_memzero(&plain[0], plain.size()); // don't leave it on the heap
|
||||
if (!encrypted) return false;
|
||||
|
||||
@@ -187,8 +197,16 @@ bool ChatDatabase::upsert(const ChatMessage& message)
|
||||
|
||||
std::vector<unsigned char> nonce;
|
||||
std::vector<unsigned char> cipher;
|
||||
std::string plain = serialize(message);
|
||||
const bool encrypted = encrypt(plain, nonce, cipher);
|
||||
std::string plain;
|
||||
bool encrypted = false;
|
||||
try {
|
||||
plain = serialize(message); // strict dump → a malformed body throws; skip rather than crash
|
||||
encrypted = encrypt(plain, nonce, cipher);
|
||||
} catch (const std::exception& e) {
|
||||
if (!plain.empty()) sodium_memzero(&plain[0], plain.size());
|
||||
DEBUG_LOGF("[chat] upsert skipped a malformed message: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
if (!plain.empty()) sodium_memzero(&plain[0], plain.size());
|
||||
if (!encrypted) return false;
|
||||
|
||||
@@ -416,7 +434,7 @@ std::string ChatDatabase::serialize(const ChatMessage& message) const
|
||||
json["ts"] = message.timestamp;
|
||||
json["pos"] = static_cast<std::uint64_t>(message.payload_position);
|
||||
json["dl"] = static_cast<int>(message.delivery);
|
||||
return json.dump();
|
||||
return json.dump(); // strict: an invalid-UTF-8 body throws and is DROPPED by the callers (contract)
|
||||
}
|
||||
|
||||
bool ChatDatabase::deserialize(const std::string& json, ChatMessage& out) const
|
||||
|
||||
Reference in New Issue
Block a user