Covers:
- What antibot_wasm.js is and why it is not in the repo
- How wasm-pack compiles wasm/src/ and what wasm/pkg/ contains
- Step-by-step build (rustup target, wasm-pack install, build, mv to frontend/pkg)
- How heartbeat.js loads and initialises the module via await init()
- MIME type requirements for serving .wasm files
- .gitignore rationale for wasm/pkg/ and frontend/pkg/
- Troubleshooting (missing target, wasm-opt, 404, empty string returns)
GitHub license auto-detection requires a file named LICENSE containing
the full license text. LICENSE-MIT and LICENSE-APACHE remain for
dual-license reference.
Companies integrating security tooling into proprietary stacks are
blocked by GPL copyleft. MIT/Apache-2.0 dual licensing matches the
convention used by the Rust ecosystem (tokio, axum, serde, etc.) and
removes all adoption friction for commercial users.
- Add LICENSE-MIT
- Add LICENSE-APACHE
- Update LICENSE.md to dual-license declaration
- Add [workspace.package] license field to Cargo.toml
Critical:
- crypto.rs (server): use BTreeMap for canonical JSON so key order
matches JS client's JSON.stringify sort — sig verification was always
failing silently
- heartbeat.js: capture sentSalt before rotating to next_salt so both
sides compute next_chain_hash with the same salt — chain was broken
after the first heartbeat
High:
- trust.rs: avg_speed = total_dist / total_time_ms (px/ms), not
distance/event_count — legitimate users were always rejected
- ratelimit.rs: add evict_stale() to drain expired entries and prevent
unbounded HashMap memory growth
- cleanup.rs: call rl.evict_stale() from the periodic cleanup loop
Medium:
- vm.rs: op 0x08 (NOT) is unary — split from binary-op arm so depth
is not decremented incorrectly
- wasm/crypto.rs: replace unwrap() panics in sign_message /
get_public_key with unwrap_or_default(); add JS-side guard
Low:
- shared/Cargo.toml, wasm/Cargo.toml: remove leftover add-this comments
- Dockerfile: rust:1.88-bookworm -> rust:1.87-bookworm (1.88 non-existent)