Commit Graph

6 Commits

Author SHA1 Message Date
4473e7e00a feat(updater): in-app dragonxd updater + browse-all-releases
Add a full-node daemon updater (util/DaemonUpdater + daemon_download_dialog)
reachable from Settings -> NODE & SECURITY: downloads/verifies (SHA-256 +
enforced ed25519 signature) and atomically installs the latest dragonxd from
the project Gitea, with a "Restart daemon now" step. Add a shared "Browse all
releases..." picker (release_list_view) to both the miner and daemon updaters
so users can pin older/pre-release builds. Pure no-I/O cores
(daemon_updater_core / xmrig_updater_core) are unit-tested; sign-daemon-release.sh
signs release archives offline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 21:27:13 -05:00
b9881278af 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>
2026-06-07 09:29:37 -05:00
85b53baeaf feat(mining): pin xmrig release-signing key + fix raw-signature parsing bug
- Pin the ed25519 public key in xmrig_updater.h, activating signature verification in soft mode
  (kXmrigRequireSignature=false): a release's ".sig" asset is verified when present, but an
  unsigned release still installs on TLS + SHA-256. Verified live against the current release
  (v6.25.2, which ships no .sig yet) — still installs.
- gitignore *.ed25519.key / *.ed25519.pub.b64 so a signing secret key can never be committed.
- Add a unit test that the pinned key decodes to a valid 32-byte ed25519 key (a malformed paste
  fails the build, not silently disabling verification).

Bug fix (found via a flaky test): verifyXmrigSignature trimmed trailing whitespace BEFORE the
raw-64-byte check, so a raw signature whose last byte equals '\n'/'\r'/space/tab (~1.6% of
signatures) was corrupted and rejected. Now base64 is tried first (safe to trim) and the raw
path uses the exact untrimmed bytes. Added a deterministic regression test that forces a
whitespace-terminated raw signature. Suite is stable (0 failures in 10 runs; was ~3/8).

Also de-brittled the live integration test: it no longer pins a release-specific binary hash
(reaching Done already means the worker verified the binary against the release's own checksum).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 00:44:53 -05:00
8765fdf362 feat(mining): opt-in ed25519 signature verification for the xmrig updater (#1)
Closes the supply-chain gap the review flagged: today the archive and its SHA-256 share one
trust root (the release body), so a compromised/edited release can ship an arbitrary binary
that still "verifies". This adds authenticity via a detached ed25519 signature checked against
a public key PINNED IN THE BINARY (not fetched), using libsodium's crypto_sign_verify_detached.

Opt-in / soft rollout:
- kXmrigSignaturePublicKeyBase64 in xmrig_updater.h is EMPTY by default -> signatures are not
  checked and behavior is unchanged (TLS + SHA-256 only). Paste the base64 public key to enable.
- Once a key is pinned, an install verifies a "<archive>.sig" asset (base64/raw 64-byte ed25519
  signature over the archive bytes) when present; kXmrigRequireSignature=true additionally
  refuses installs that publish no signature.
- The check runs after the SHA-256 check, over the same already-read archive bytes; refuses on
  a missing key-but-required, unreachable .sig, or invalid signature.

- verifyXmrigSignature + selectXmrigSignatureAsset are pure (libsodium only) and unit-tested:
  valid base64 + raw-64-byte signatures verify; tampered data, wrong key, and malformed/empty
  inputs all fail closed. Cross-tool interop verified (Python stdlib base64 == sodium base64).
- scripts/sign-xmrig-release.sh: keygen / sign / pubkey helper (PyNaCl = same libsodium ed25519)
  to produce the .sig assets and the public key to pin.

No behavior change until a key is pinned. Both variants build; suite passes; live worker
re-verified (signatures off by default).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:29:49 -05:00
98e0cce8ec fix(mining): harden xmrig updater per adversarial review
Addresses confirmed findings from the multi-lens review of the updater:

- Cancelable + live progress (was: download uncancelable, progress stuck at 0%, closing
  the dialog mid-download blocked the UI thread on the worker join). Wire a libcurl
  CURLOPT_XFERINFOFUNCTION that publishes byte counts and returns abort when cancel() is
  requested; add a Cancel button. The dialog's destructor now aborts the transfer promptly,
  so closing mid-download no longer freezes the UI.
- Graceful "unavailable" instead of a red error on platforms with no published build
  (macOS / ARM): new terminal State::Unavailable rendered neutrally, not as a failure.
- Install-time running guard (TOCTOU): App::isPoolMinerRunning() re-checked in the dialog
  before each install, so a dialog opened before mining started can't replace a live binary.
- Size caps: CURLOPT_MAXFILESIZE on the download and a per-archive-member ceiling before
  decomphressing into memory, to bound an attacker-controlled archive.
- Distinguish a local read failure of the downloaded archive from a checksum mismatch
  (was reported misleadingly as "possible tampering").
- Reword the dialog's verification note to "checked against the release's published SHA-256
  checksum" (integrity, not authenticity — see the signing note below).

Not fixed here (needs your input): WinRing0x64.sys has no per-file hash published, but it is
covered by the verified archive checksum (it is inside the verified zip); and the release is
not cryptographically signed — checksums and binary share one trust root. Adding a pinned-key
ed25519/minisign signature is the real supply-chain hardening and needs an offline signing key
+ a release-process change.

Both variants build; suite passes; live worker re-verified end-to-end on linux-x64.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 18:35:17 -05:00
946958b591 feat(mining): xmrig updater service — fetch/verify/install the latest miner from Gitea
Adds util/XmrigUpdater: a background-thread service (mirrors util/Bootstrap) that pulls
the latest DRG-XMRig release from the project's Gitea, verifies it, and installs the miner
binary into the daemon directory. Service layer only; the mining-tab UI hook comes next.

Flow: GET /api/v1/repos/DragonX/drg-xmrig/releases/latest -> pick the asset matching this
platform (…-linux-x64.zip / …-win-x64.zip; no macOS build -> graceful "unavailable") ->
download (libcurl, TLS verified) -> verify the archive SHA-256 -> extract with miniz,
flattening the versioned subdir the archive nests the binary in -> verify the extracted
binary's SHA-256 in memory before writing it -> atomic install (+chmod +x on POSIX). On
Windows also extracts WinRing0x64.sys; config.json/README.md are skipped.

Security (download-and-execute): TLS is verified, and BOTH the archive and the inner binary
are checked against the SHA-256 checksums published in the release body (parsed as
"<hex>  <name>" lines) — install is refused on a missing or mismatched checksum.

Split into a pure core (xmrig_updater_core.cpp: release parse, asset/platform match, checksum
parse, SHA-256) and the curl/miniz worker (xmrig_updater.cpp). The core is unit-tested against
a real captured release fixture (tests/fixtures/xmrig/release_latest.json); an env-gated
(DRAGONX_TEST_NETWORK=1) integration test exercises the worker live and was verified end-to-end
on linux-x64 (inner binary SHA-256 matches the published value). Both variants build; suite passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 18:07:46 -05:00