fix(parsers): harden RPC/price/updater parsing against valid-but-unhandled input
Audit of the full-node RPC response parsers and updater release-body parsers (find -> adversarially-verify workflow) surfaced three worth fixing; three others guard formats the project doesn't emit and are backstopped by signature verification, so they're documented rather than churned. - Price (Medium): parseCoinGeckoPriceResponse used .value(key, 0.0), which throws type_error on a PRESENT null. CoinGecko emits null for usd_24h_change/ usd_24h_vol on illiquid tokens (DRGX is one) while still returning a valid spot price; the outer catch turned that into no price update at all. Read null-tolerantly so the valid usd/btc survives. - Daemon updater (Medium): parseDaemonChecksums blanked '|'/backtick but not markdown emphasis, so a bolded **archive.zip** checksum row was dropped and a valid, correctly-signed release would be refused. Also blank '*'/'_' (cannot cause a wrong-asset match; the 64-hex + .zip-suffix tests are unchanged). - Opid poll (Low, severe failure mode): parseOperationStatusPoll read id/status via .value() (throws on a present non-string) and the call site parsed OUTSIDE its try/catch, so a throw left opid_poll_in_progress_ stuck true and wedged all z-operation polling for the session. Type-check the reads and parse inside the guard. (dragonxd can't emit non-string id/status; this is defense-in-depth.) Regression tests: CoinGecko null field; opid non-string id/status; **bold** checksum row. Suite green (1/1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -140,15 +140,16 @@ std::map<std::string, std::string> parseDaemonChecksums(const std::string& body)
|
||||
// | File | SHA-256 |
|
||||
// |------|---------|
|
||||
// | dragonx-1.0.2-linux-amd64.zip | `85f1dd…16` |
|
||||
// Per line: blank out the table/code delimiters ('|' and '`'), then find the 64-hex token (the
|
||||
// hash) and a token ending in ".zip" (the archive name). Header/separator/prose rows lack one
|
||||
// or the other and are skipped, so this is robust to surrounding text and column order.
|
||||
// Per line: blank out the table/code/emphasis delimiters ('|', '`', and markdown '*'/'_' so a
|
||||
// bolded **archive.zip** still tokenizes), then find the 64-hex token (the hash) and a token
|
||||
// ending in ".zip" (the archive name). Header/separator/prose rows lack one or the other and are
|
||||
// skipped, so this is robust to surrounding text and column order.
|
||||
std::map<std::string, std::string> out;
|
||||
std::istringstream in(body);
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
for (char& c : line)
|
||||
if (c == '|' || c == '`') c = ' ';
|
||||
if (c == '|' || c == '`' || c == '*' || c == '_') c = ' ';
|
||||
std::istringstream ls(line);
|
||||
std::string tok, hash, name;
|
||||
while (ls >> tok) {
|
||||
|
||||
Reference in New Issue
Block a user