What's New in v1.2.2
Full Changelog: https://github.com/YDW99/Regalia/releases/tag/v1.2.2/compare/v1.2.1...v1.2.2
Contributors
Bug Fixes
Installation
Download the APK from the assets below and install it on your Android device.
Note: This app requires Stockfish chess engine binaries (libstockfish.so) to be built separately via NDK.
⚠️ Note: If you encounter any issues, please report them here.
Regalia v1.2.2 — Hardened by an 8-Skill Audit
A precision patch release: one real defect fixed, seven false positives cleanly dismissed, and the version bumped from
1.2.1→1.2.2. No new features, no new permissions, no new network access — just a sharper, better-defended build of the same chess experience you already trust.
📦 Download
| Asset | Size | Purpose |
|---|---|---|
Regalia-v1.2.2-release.apk |
~75 MB | Standalone installer for arm64-v8a devices |
Regalia-v1.2.2-manual-en.html |
~1.1 MB | Self-contained English user manual |
Regalia-v1.2.2-manual-zh.html |
~956 KB | Self-contained Chinese user manual |
💡 Bilingual parity — every user-facing string, every changelog entry, and every manual page is synchronized across Chinese (
zh) and English (en). The app auto-detects system language; switch manually anytime via the↔️中 / ↔️ENbutton in the header.
🔐 Integrity Checksums
APK file: Regalia-v1.2.2-release.apk
APK versionCode: 122
APK versionName: 1.2.2
APK signature: v1 ✅ v2 ✅ v3 ✅ (Xiaomi HyperOS 3 compatible)
Stockfish engine SHA-256 (must match all three locations):
Source binary: 8f7116d3f1a7004a6581d4fb0c1ff891ce095bab6d45e52f1578897cf23b61b5
jniLibs copy: 8f7116d3f1a7004a6581d4fb0c1ff891ce095bab6d45e52f1578897cf23b61b5
APK-embedded: 8f7116d3f1a7004a6581d4fb0c1ff891ce095bab6d45e52f1578897cf23b61b5
Verify on your own machine:
# APK signature (v1 + v2 + v3 must all be true)
apksigner verify --verbose Regalia-v1.2.2-release.apk
# Version info
aapt dump badging Regalia-v1.2.2-release.apk | head -2
# Engine SHA-256 (must equal the value above)
unzip -p Regalia-v1.2.2-release.apk lib/arm64-v8a/libstockfish.so | sha256sum🩺 What Happened in This Release
v1.2.2 is the direct result of subjecting v1.2.1 to an 8-skill comprehensive audit. Five sub-reports — totaling 4,199 lines of analysis — were produced using the following skill stack:
| # | Skill | What it does |
|---|---|---|
| 1 | secure-code-review |
OWASP Top 10 (A01–A10) full-spectrum review |
| 2 | code-vuln-audit |
Secret-leak scan + OWASP pattern matching |
| 3 | deep-module-refactor |
God Module friction-point analysis |
| 4 | code-arch-optimizer |
Coupling matrix + refactoring roadmap |
| 5 | git-repo-audit |
Hot-file analysis + contributor metrics |
| 6 | code-to-chart |
Module dependency graph generation |
| 7 | code-safety-audit |
OWASP pattern sweep (45 sites) |
| 8 | web-security-audit |
WebView / XSS / network review |
Every single finding from those reports was then verified line-by-line against the actual source tree — not against the stale snapshot the auditors saw. The result:
7 findings were false positives. 1 finding was real and is now fixed. The architecture recommendations are real but deferred.
This is what a disciplined patch release looks like.
✅ The One Real Fix
YELLOW-1 — FEN Parsing Lacks Length Limit
| Attribute | Value |
|---|---|
| OWASP category | A03 — Injection |
| Severity | 🟡 YELLOW (medium) |
| File | src/main/assets/chess.src/tablebase.js |
| Function | fenToState(fen) |
| Risk if unfixed | Pathologically long FEN strings could cause unnecessary string processing before validation rejected them — a low-impact DoS vector |
| Fix | Added a 200-character length limit at function entry |
Why 200 characters?
A standard FEN is at most ~87 characters. The generous 200 ceiling comfortably accommodates:
- ✅ Chess960 Shredder castling notation (e.g.
HAah) - ✅ En passant target square (e.g.
e3) - ✅ Extended fields (move counters, half-move clock)
- ✅ Reasonable user input noise (trailing whitespace, etc.)
// tablebase.js — fenToState()
function fenToState(fen){
if(!fen || typeof fen !== 'string') return null;
if(fen.length > 200) return null; // ← NEW: DoS guard
const parts = fen.trim().split(/\s+/);
// ...existing validation continues from here
}Why the audit's regex was rejected
The audit suggested a strict character whitelist:
// ❌ Audit's suggestion — REJECTED
if (!/^[1-8PNBRQKpnbrqk\/\s-]+$/.test(fen)) return null;This regex would break legitimate chess functionality:
| Use case | Legal characters | Caught by regex? |
|---|---|---|
Chess960 castling rights (KQkq or AHah) |
A-H, a-h |
❌ Breaks |
En passant target square (e3, g6) |
a-h, 1-8 |
❌ Breaks |
Field separator ( ) |
whitespace | ✅ Passes |
The existing per-character validation already rejects invalid piece characters by returning null — that is the correct whitelist approach, applied at the right granularity. Adding a coarse regex at the top would have created false negatives for valid Chess960 positions.
🚫 The Seven False Positives — and Why
Each of the following audit findings was carefully verified against the current codebase and confirmed to be either (a) based on stale code from previously deleted files, or (b) describing a defense that already exists.
RED-1 — getStatsPayload() returns unescaped PGN data (XSS)
| Audit's claim | StatsActivity.getStatsPayload() returns raw PGN strings that could contain <script> tags, causing XSS in stats.html. |
| Reality | stats.html already escapes every PGN header value (including White / Black player names) via _escFEN() at the rendering layer — see line 1770. |
| Why the audit's fix was rejected | The suggested Java-layer JSON escaping (" → \") would corrupt JSON syntax — getStatsPayload() returns a JSON string, and double-escaping quotes would break JSON.parse() on the JS side. |
| Status | ✅ False positive — existing defense confirmed. |
RED-2 — shouldOverrideUrlLoading doesn't block javascript: protocol
| Audit's claim | ChessWebViewClient.shouldOverrideUrlLoading() doesn't explicitly check for javascript: URLs. |
| Reality | The current implementation uses a fall-through blocker: it allows only file:///android_asset/ and http(s)://, then return true (block) for everything else — including javascript:, data:, intent:, content:, and about:blank. |
| Why the audit's fix was rejected | The audit's suggested early if (url.startsWith("javascript:")) return true; is functionally redundant — the final return true already catches it. Adding it would be harmless but misleading (implying the block list is opt-in rather than default-deny). |
| Status | ✅ False positive — default-deny policy confirmed. |
RED-3 — _buildPGNString i18n text is directly concatenated into PGN output (XSS)
| Audit's claim | i18n strings like T('you') and T('ai_opponent') are concatenated into PGN without HTML/JS escaping. |
| Reality | (1) These i18n strings are static, developer-controlled constants — "你" / "You" / "AI对手" / "AI Opponent". There is no user input path. (2) When user-supplied player names flow into PGN tags, they pass through normalizeTagValue() (PGN escaping: \ → \\, " → \", newlines stripped) and then through _escFEN() at the rendering layer (`&<>"'``). Double-escaped. |
| Why the audit's fix was rejected | The suggested _escapeHtml() wrapper would apply HTML entity encoding to PGN text — corrupting the PGN itself (< in a comment becomes < in the .pgn file). PGN is a plain-text format; HTML escaping belongs at the rendering layer, not the data layer. |
| Status | ✅ False positive — static strings + double escaping confirmed. |
YELLOW-2 — sendToEngine(String) has no UCI command whitelist
| Audit's claim | StockfishNative.sendToEngine() passes JS-supplied strings directly to the engine process without validation. |
| Reality | The very first thing sendToEngine() does is call _jsBridgeGateway.isUciCommandAllowed(command) — if the command isn't on the whitelist, it's rejected with a Log.w() and the method returns immediately. This whitelist has been in place since round-1. |
| Status | ✅ False positive — JsBridgeGateway UCI whitelist confirmed. |
YELLOW-3 — android:allowBackup="true"
| Audit's claim | The manifest allows adb backup to extract app data. |
| Reality | android:allowBackup was set to false back in round-1 (v1.2.1's first refinement pass). The audit was working from a stale snapshot. |
| Status | ✅ False positive — already false since round-1. |
YELLOW-5 — ProGuard rules are too permissive
| Audit's claim | The rule -keep class com.Regalia.MessageBus { *; } retains an entire class including non-public methods. |
| Reality | MessageBus.java was deleted in round-4 (it was a Phase 73 extraction with no external callers). The referenced ProGuard rule does not exist in the current proguard-rules.pro. The current rules are tight: only @JavascriptInterface methods, native JNI methods, and manifest-declared components are kept. |
| Status | ✅ False positive — based on a deleted file. |
P0 #4–5 + P1 #12 — Empty catch blocks & HapticHelper dead code
| Audit's claim | Two empty catch(e){} blocks in chess.html; HapticHelper.java is 128 lines of dead code. |
| Reality | Both were already fixed in prior rounds: empty catches were filled with console.warn() in round-16 (the previous release), and HapticHelper.java was deleted outright in round-10. The audit was working from a stale snapshot. |
| Status | ✅ False positive — both already resolved. |
📐 Architectural Recommendations — Acknowledged, Deferred
The audit's architectural findings are real and well-reasoned, but they require multi-week effort and are inappropriate for a patch release. They are documented here for transparency and future planning.
| # | Friction point | Severity | Recommended fix | ETA |
|---|---|---|---|---|
| F2 | StockfishNative.java is a 4,354-line God Class |
🔴 | Extract EngineController + UCIGateway |
v1.3.x |
| F3 | ui.js (8,522 lines) + ai-bridge.js (4,304 lines) = 66% of JS layer |
🔴 | RendererController componentization |
v1.4.x |
| F4 | 91 @JavascriptInterface methods — no type contract |
🔴 | Facade aggregation (91 → 6 domain facades) | v1.3.x |
| F5 | state-store.js is decorative — core is still imperative globals |
🟠 | Migrate evaluation state (_sfEval etc.) into Store |
v1.4.x |
| F12 | Zero test infrastructure | 🟠 | Introduce Jest (JS) + JUnit (Java) | v1.4.x |
📖 Full details in the audit reports:
regalia_final_arch_refactor.md(1,448 lines) andregalia_final_arch_optimize.md(1,138 lines).
🔢 Version Bump — 11 Locations Updated
Per the project's 版本号位置.md convention, the version string appears in 11 places across the codebase. All were synchronized to 1.2.2:
| # | File | Location | Old | New |
|---|---|---|---|---|
| 1 | version.properties |
VERSION_PATCH / VERSION_BUILD |
1 / 121 |
2 / 122 |
| 2 | build.gradle |
auto-computed from version.properties |
— | — |
| 3 | strings.xml |
app_name |
Regalia v1.2.1 |
Regalia v1.2.2 |
| 4 | ChessWebViewClient.java |
version comment | v1.2.1 |
v1.2.2 |
| 5 | game-logic.js |
loading_title i18n key |
Regalia v1.2.1 |
Regalia v1.2.2 |
| 6 | index.html.tpl |
<title> |
Regalia v1.2.1 |
Regalia v1.2.2 |
| 7 | ui.js |
about-dialog <h2> |
v1.2.1 |
v1.2.2 |
| 8 | ui.js |
header badge <span class="ver"> |
v1.2.1 |
v1.2.2 |
| 9 | ui.js |
about-dialog app_name row | v1.2.1 |
v1.2.2 |
| 10 | HTML manuals | cover, footer, title, AGPL block | v1.2.1 |
v1.2.2 |
| 11 | HTML manuals | filename | Regalia-v1.2.1-manual-{zh,en}.html |
Regalia-v1.2.2-manual-{zh,en}.html |
⚙️ Auto-synced via
BuildConfig.VERSION_NAME—MainActivity.java,StockfishNative.java, andChessApp.javareference the version string through AGP's generatedBuildConfigclass, so they pick up the new version automatically with no manual edits.
📊 Build Verification Checklist
Every box ticked before this release was published:
- All 9 JS modules pass
node --check— zero syntax errors -
state-store.jsTDZ safety verified — no regression from the round-8 white-screen fix -
chess.htmlrebuilt — 21,988 lines, 1,321,170 bytes (viapython3 build-chess.py) - Release APK assembled —
./gradlew assembleRelease -x lint→ 78,141,232 bytes - APK signature verified — v1 ✅ + v2 ✅ + v3 ✅ (HyperOS 3 compatible)
- APK version verified —
versionCode=122,versionName="1.2.2" - FGS subtype property present —
android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE=chess_engine_analysis - Stockfish engine is dotprod variant — SHA-256 three-way match (source = jniLibs = APK-embedded)
- Tarball repackaged — 112 files, 0 forbidden entries (no
.so/jniLibs/build/.gradle/.cxx/.keystore) - All 7
README.licensefiles updated with v1.2.2 entry - All documentation synced —
BUILDING.md,PRIVACY.md,README.md,NOTICE - Both HTML manuals updated — changelog entries in new-to-old order, cover/footer/title/AGPL block bumped
📜 Privacy Impact
Zero privacy impact. No new permissions, no new data collection, no new network access, no changes to data flow or storage.
| Change | Privacy impact |
|---|---|
FEN length limit (tablebase.js) |
✅ None — FEN strings are chess position notation with no PII; the limit just fails faster on invalid input |
| Version bump (v1.2.1 → v1.2.2) | ✅ None — version numbers are public information |
| Audit false positives (no action) | ✅ None — confirmed existing defenses are correct |
The app remains 100% offline: the only network endpoint is the optional Lichess Syzygy tablebase API, which is HTTPS-only with certificate pinning and CSP-restricted to tablebase.lichess.ovh.
🛠️ System Requirements
| Component | Requirement |
|---|---|
| CPU architecture | arm64-v8a (AArch64) |
| Android version | 6.0 (API 23) or later |
| Recommended Android | 12+ (for full Material You theme support) |
| Disk space | ~200 MB for installation |
| RAM | 2 GB minimum; 4 GB recommended for engine analysis |
| Engine | Stockfish 18, arm64-v8a-dotprod build (NNUE with DOTPROD acceleration) |
⚠️ DOTPROD requirement: The bundled engine uses ARMv8.6-A DOTPROD instructions for NNUE acceleration. Devices with Cortex-A76+ / Cortex-X1+ / Snapdragon 855+ CPUs (2019+) fully support this.
📚 Documentation
| Document | Description |
|---|---|
Regalia-v1.2.2-manual-en.html |
Complete English user manual — self-contained HTML, no external dependencies |
Regalia-v1.2.2-manual-zh.html |
Complete Chinese user manual — same content, synchronized |
BUILDING.md |
Build instructions, environment setup, version bump history |
PRIVACY.md |
Privacy policy (zero data collection, full offline disclosure) |
NOTICE |
Third-party components + per-file license classification |
README.md |
Project overview + directory tree + full version history |
🤝 Credits
- Engine: Stockfish 18 — GPL v3
- PGN/UCI logic heritage: DroidFish by Peter Österlund — GPL v3
- Lichess — For the Syzygy tablebase API and ECO opening data
- All contributors who have helped shape Regalia through code reviews, bug reports, and feature suggestions
- App code: Copyright © 2026 Regalia — AGPL v3 (original work) + GPL v3 (DroidFish-derived)
- Audit: 8-skill comprehensive review using
secure-code-review,code-vuln-audit,deep-module-refactor,code-arch-optimizer,git-repo-audit,code-to-chart,code-safety-audit, andweb-security-audit
💬 Feedback
Found a bug? Have a feature request? Want to contribute to the v1.3.x architectural refactor?
- 🐛 Bug reports: Open an issue — please include the FEN/PGN that triggered the bug and your device model
- 💡 Feature requests: Open a discussion — architectural contributions toward F2/F3/F4 (God Module splits) are especially welcome
⏭️ What's Next
v1.2.2 is a stabilization release. The next minor version (v1.3.x) will begin the architectural work documented in the audit:
@JavascriptInterfacefacade aggregation — consolidating 91 scattered methods into 6 typed domain facades- UCI protocol parsing centralization — replacing 15 scattered regex patterns with a single
UCIGateway - Test infrastructure — introducing Jest (JS) and JUnit (Java) unit test frameworks
Until then — enjoy the games. ♔
Release date: 2026-07-14 · Build: 122 · Signed with v1+v2+v3 · 100% offline · AGPL v3 + GPL v3
AI-GEN