feat(mining): enforce xmrig signatures + fix multi-platform checksum/asset bugs
Now that the release publishes a valid .sig per archive (verified against the pinned key for linux/win/macOS), enable enforcement and fix two bugs that the newer multi-platform release (v6.25.3, which added a macOS build) exposed: - kXmrigRequireSignature = true: refuse any install whose release doesn't publish a valid ed25519 signature over the archive. Verified live end-to-end against the signed v6.25.3 (archive SHA-256 + signature -> install). - Drop the redundant inner-binary SHA-256 check. It keyed on the inner filename, but both the linux and macOS archives contain a binary literally named "xmrig", so the two "xmrig (…)" checksum lines collided in the map and the linux install compared against the macOS hash -> spurious "could not verify" failure. The whole archive is already verified (SHA-256 + signature), so every extracted member is authentic by transitivity — the per-member check added nothing but ambiguity. - Fix the macOS platform token: the asset is named "...-macos-x86_64.zip", not "...-macos-x64", so selectXmrigAsset never matched it. currentXmrigPlatformToken() now returns "macos-x86_64" on Intel macs (arm64 has no build -> Unavailable). Added a matcher test for the macOS naming. Both variants build; suite stable (0 failures / multiple runs); live require-mode install verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -321,8 +321,11 @@ void XmrigUpdater::runInstall(std::string targetDir)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Extract the wanted binaries (flatten the versioned subdir), verifying the miner binary's
|
||||
// SHA-256 in memory before writing the executable to disk.
|
||||
// 3. Extract the wanted binaries (flatten the versioned subdir). No per-member hash check is
|
||||
// needed: the whole archive was already verified above (SHA-256, and the ed25519 signature
|
||||
// when a key is pinned), so every member is authentic by transitivity. (A per-member check
|
||||
// keyed on the inner filename is also ambiguous — e.g. both the linux and macOS archives
|
||||
// contain a binary literally named "xmrig".)
|
||||
setProgress(State::Extracting, "Installing miner…");
|
||||
const std::vector<std::string> wanted = xmrigExtractBasenames(token);
|
||||
const std::string minerName = wanted.front(); // "xmrig" / "xmrig.exe"
|
||||
@@ -350,17 +353,6 @@ void XmrigUpdater::runInstall(std::string targetDir)
|
||||
void* mem = mz_zip_reader_extract_to_heap(&zip, i, &outSize, 0);
|
||||
if (!mem) { failed = true; break; }
|
||||
|
||||
// For the miner binary, verify the inner-binary SHA-256 before writing the executable.
|
||||
if (base == minerName) {
|
||||
const std::string actual = sha256Hex(mem, outSize);
|
||||
const auto it = checksums.find(minerName);
|
||||
if (it == checksums.end() || actual != it->second) {
|
||||
mz_free(mem);
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Atomic write: temp file in target dir, then rename over the destination.
|
||||
const std::string finalPath = (fs::path(targetDir) / base).string();
|
||||
const std::string tmpPath = finalPath + ".tmp";
|
||||
|
||||
@@ -54,7 +54,7 @@ struct XmrigRelease {
|
||||
// kXmrigRequireSignature=true to additionally refuse installs that publish no signature.
|
||||
inline constexpr const char* kXmrigSignaturePublicKeyBase64 =
|
||||
"j/9M+0E8NgcudP1q+23ar5uzwAFzQled8TtkFMaou6Q=";
|
||||
inline constexpr bool kXmrigRequireSignature = false; // soft rollout: verify .sig if present
|
||||
inline constexpr bool kXmrigRequireSignature = true; // enforced: refuse installs without a valid .sig
|
||||
|
||||
// ── Pure helpers (no I/O; unit-tested) ───────────────────────────────────────
|
||||
|
||||
|
||||
@@ -77,9 +77,9 @@ std::string currentXmrigPlatformToken()
|
||||
return "win-x64";
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(__aarch64__) || defined(__arm64__)
|
||||
return "macos-arm64";
|
||||
return "macos-arm64"; // no arm64 build published yet -> resolves to Unavailable
|
||||
#else
|
||||
return "macos-x64";
|
||||
return "macos-x86_64"; // matches the release asset naming (note: not "macos-x64")
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(__aarch64__)
|
||||
|
||||
@@ -3998,10 +3998,16 @@ void testXmrigAssetSelection()
|
||||
EXPECT_TRUE(linux != win);
|
||||
EXPECT_TRUE(rel.assets[linux].name.find("linux-x64.zip") != std::string::npos);
|
||||
EXPECT_TRUE(rel.assets[win].name.find("win-x64.zip") != std::string::npos);
|
||||
// No macOS build is published -> graceful "not found".
|
||||
EXPECT_EQ(selectXmrigAsset(rel, "macos-x64"), -1);
|
||||
// No macOS build in this fixture -> graceful "not found".
|
||||
EXPECT_EQ(selectXmrigAsset(rel, "macos-x86_64"), -1);
|
||||
EXPECT_EQ(selectXmrigAsset(rel, "macos-arm64"), -1);
|
||||
EXPECT_EQ(selectXmrigAsset(rel, ""), -1);
|
||||
|
||||
// The matcher handles the macOS asset naming ("macos-x86_64", not "macos-x64").
|
||||
XmrigRelease mac; mac.ok = true; mac.tag = "v6.25.3";
|
||||
mac.assets.push_back({"drg-xmrig-6.25.3-macos-x86_64.zip", "https://x/m", 100});
|
||||
EXPECT_TRUE(selectXmrigAsset(mac, "macos-x86_64") >= 0);
|
||||
EXPECT_EQ(selectXmrigAsset(mac, "macos-x64"), -1); // the wrong token must NOT match
|
||||
}
|
||||
|
||||
void testXmrigChecksumParsing()
|
||||
|
||||
Reference in New Issue
Block a user