9.9 KiB
Mirror Tool — working journal
Objective
Rewrite the legacy Python TCP mirror manager in Rust, in this repository. Preserve the operator workflow, repair networking/failover bugs, integrate ForcAD accurately, and verify performance rather than promise physically impossible zero overhead.
Binding user decisions
- 2026-10-23: automatic routing means upstream selection inside the TCP proxy; no nftables/iptables or host route changes.
- 2026-10-23 correction: preserve the original UI essentially literally: original CSS, layout, service columns, primary dots, replica row selection, robot switch, open-service icon, login and custom proxy name/port/optional direct-IP workflow. Only small improvements are authorized. The initial redesign was rejected;
web/*now restores the original CSS/layout and interactions. - Preserve manual promotion semantics: the previous primary becomes a replica. Direct-IP entry must not require the operator to create a team first.
- Keep the legacy directories unchanged. Never copy credentials from their config into this repository.
Current state
Rust modules implemented: config, store, engine, scoreboard, control, auth, web and CLI. Initial commit 4b01fb4, branch rewrite/rust; no remote or deployment. The original UI is restored and assets are embedded locally. docs/ui-report.md describes preserved controls and small improvements; source-CSS parity and real browser checks confirm the restoration.
Initial review R1-R5 are addressed: bounded shutdown with early quiesce, probe completion timestamps, Linux/mapped-address loop prevention, removal of rejected journal and restored previous-primary-as-replica. Transient accept recovery and absolute Engine.IO heartbeat are implemented. Final independent review found R6: request cancellation can abandon control transactions. Owned transactions now complete despite caller cancellation; five regressions and the original HTTP reproduction pass, and independent final review is approved.
Fresh root verification after R6: 40 tests on macOS arm64, 41 on Orb Linux amd64; native fmt/Clippy and release binary/examples on both pass. Real Socket.IO-library ForcAD interoperability passes. Browser covers start, route/replica promotion, robot, custom IP, settings, logout, actual390px viewport, watchdog stale/recovery and byte-exact1MiB half-close. Loopback benchmark results are checked in under docs/benchmarks/; isolate saturated its bounded replica queue and explicitly disconnected replicas as designed (3 on macOS,4 on Linux across5 sessions). docs/verification.md is the acceptance record.
Verification policy
No completion/performance claims without fresh output. Use loopback and Orb Linux fixtures; never contact configured legacy game hosts. Test exact byte delivery, half-close, idle connections, live target changes, failure selection, replica overload, ForcAD reconnects, auth and persistence. Record limits explicitly.
Milestone 1
- Async bounded engine, strict/isolate policies, replica response draining, hot target changes, RAII active accounting, acknowledged listener shutdown, bounded whole-engine drain.
- Verified canonical ForcAD init/delta format; persistent Engine.IO 4 implementation with heartbeat and reconnect.
- Typed config validation, same-filesystem fsync+rename state replacement, rollback on persistence failure, fresh-health deterministic selection with cooldown.
- Cookie sessions (HttpOnly/SameSite), CSRF header, same-origin checks, login rate limiting, no secret persistence. HTTP binds locally by default; user supplies environment password.
- Fresh engine evidence: 11 loopback tests passed (see docs/engine-report.md). Full integrated checks still pending.
Final handoff
docs/final-review.md: independent approval; R1-R6 addressed, no remaining Critical/Important findings.docs/verification.md: final gates, browser/ForcAD evidence and measured performance; raw benchmark JSON indocs/benchmarks/.- Generated, git-ignored
dist/contains macOS arm64 and Linux amd64 binaries plus SHA256SUMS. Linux binary is glibc-linked from Orb Ubuntu; not an all-distribution static build. - Legacy tracked files remain unchanged and all12 match Downloads. Local-only rewrite; configure real teams/ports/scoreboard manually before deployment. No service installed.
UI follow-up — 2026-10-23
User asks to repair screenshot bugs, improve small workflows autonomously and explain configuration/ForcAD. No redesign and no load test. Browser reproduced add dialog at x=0,y=0 (1002×1035 viewport); explicit native-dialog margin is missing after Bootstrap reset. Selected-team text lacks flex/nowrap constraints. Current demo is a GUI-session launchd fixture; copy temporary config/state before stopping wrapper. Planned persistent ignored data/demo directory, team add/rename through existing API, inline error/draft retention and configuration help.
UI follow-up completed: centered/scrollable dialogs, stable full-width selected-team row, dark integer inputs/tabular counters, IP error/draft retention and Enter/Escape, add-form draft retention, team add/rename and ForcAD help/status. Direct-IP edits preserve unrelated replicas. Existing routes/backend unchanged. See docs/ui-polish-verification.md for evidence and docs/configuration.md for operator setup. Fresh native40 tests/fmt/Clippy/JS checks, Orb41 tests and both final release artifacts verified; browser/256KiB half-close/stale recovery/persistence checks passed. Live GUI-session demo now uses ignored data/demo/mirror.toml + state.json, original topology preserved, panel16700/proxy18081. Isolated fixture stopped; no load benchmark run. User Zen tab not reloaded; current demo opened separately in Chrome.
Private GitHub publication — 2026-10-23
User requested a private GitHub repository. Created https://github.com/mrvasil/ctf-ad-mirror-tool-rust and verified PRIVATE visibility. The existing mrvasil/ctf-ad-mirror-tool contains unrelated older history and was not modified. Origin points to the new repository; publish local rewrite/rust as remote main, preserving local history. Runtime config/state, dist artifacts and test-results remain ignored. Before publication: native fmt/Clippy and40 tests passed; inspected86 history blobs for common secret signatures (only synthetic localhost credential-URL rejection test matched).
Flag protection in progress
User authorized design explanation followed by implementation. Explained random same-format tokens with XChaCha20-Poly1305 encrypted persistent mapping cache, per-service opt-in, TTL/capacity, key from environment, streaming split handling and explicit ambiguous-tail timeout. Does not distinguish checker from attacker; no TLS/compressed/signed protocol support. Original panel remains foundation. Work tracked in task_plan.md; fixtures synthetic/loopback only.
Flag protection completed — 2026-10-23
User explicitly requires optional substitution, default off. Implemented per-service flag_protection=false, backwards-compatible omitted config/state fields, settings checkbox and indicator without redesign. Mode is captured for each TCP session; disabling affects new sessions. Random same-format tokens use an XChaCha20-Poly1305 encrypted SQLite vault, durable before forwarding, bounded worker queue, TTL/capacity and fail-closed errors. See docs/flag-protection.md and docs/flag-protection-verification.md. Fresh49 native/50 Orb tests, native fmt/Clippy, JS syntax and both release builds passed. Browser toggled on/off and persisted both; TCP tests verify byte integrity/half-close/replica equality and session mode. Live demo16700 upgraded with ignored persistent synthetic vault, original topology unchanged, protection off. No real hosts or flags used.
Portable Linux release in progress
User wants a ready-to-run Linux x64 build on GitHub, exact distribution unknown. Package static musl binary with run.sh, empty first-run config and random persistent private password; do not package runtime data or enable substitution. Workflow verifies native Clippy/fmt and musl tests plus archive login/API/TCP/restart smoke, then tag releases publish privately. Main push artifacts do not replace releases. Actual CI/package verification pending; docs in deploy/QUICKSTART.md.
Portable release completed: v0.1.0 at source f264f8a, private GitHub Release includes static musl Linux x64 tar.gz + SHA256SUMS. CI40011983417 succeeded: fmt/Clippy,50 musl tests, static linkage check, release build and packaged first-run/login/API/restart/256KiB TCP smoke. Downloaded release independently passed SHA256, full package smoke in Orb Ubuntu amd64 and launcher/HTTP/graceful-stop in isolated Alpine3.22 without glibc. Native49 tests/fmt/Clippy also passed. No runtime/compiler/database dependencies beyond normal shell utilities for run.sh. First-run config is empty; real targets still require operator setup. Live demo unchanged. See docs/linux-release-verification.md.
v0.1.1 startup correction — in progress
User explicitly requires panel bind0.0.0.0 and default password in TOML. Native default, example and first-run launcher now bind0.0.0.0:6700; launcher/example explicitly set web.password to a public placeholder. Explicit config password wins; absent field uses legacy environment, and run.sh preserves v0.1.0 password-file fallback. Existing configs are never overwritten. WebConfig password is excluded from serialization and redacted Debug. Native50 tests/fmt/Clippy passed; tag release/package verification pending.
Startup correction complete: published v0.1.1, source3674534, CI40026012470 succeeded with51 musl tests/fmt/Clippy/static package smoke. Native50 tests/fmt/Clippy passed. Downloaded asset SHA256 verified, then full package smoke rerun in Orb: wildcard IPv4 socket confirmed via /proc/net/tcp, TOML default login, changed password after restart, TOML precedence over legacy file and fallback without TOML password, topology persistence and256KiB exact half-close. Existing live demo/configs unchanged. Explicit user requirement supersedes prior loopback/random-password defaults for fresh installs.