- Correct WELIST_ALLOW_LEGACY_PING: legacy pings are accepted by default,
the flag only disables them.
- Describe onion delegation: v2-only inclusion, service-side host
normalization, strict expiry check, deployment order and rollback.
- Warn that disabled delegation rejects onion pings when SSL_KEY_PATH is
the dedicated ping key.
- Document certificate lifetime and revocation limits, offline master
key requirements, helper --days bounds, and a delegation verification
checklist.
- Fix the bal-pusher.sh comment about the service-side defaults.
- Add contrib/make_welist_txt.sh to print the _welist-key TXT
name, value and BIND zone line for a domain and Ed25519 key
- Accept a private/public PEM file or an existing base64 SPKI DER
- Generate private_key.pem and public_key.pem when the key argument
is omitted, reusing an existing private key
- Document the helper in docs/10_dnssec_key_publishing.md
- Load WELIST_PING_DELEGATION_FILE into a typed OnionDelegation
- Send the certificate only with v2 pings for onion hosts
- Validate the onion host, expiry and delegated key against
BAL_SERVER_URL and SSL_KEY_PATH at startup; disable delegation
with a warning on any mismatch
- Stop sending unsigned info/base_fee/version with v1 pings so
v1 remains liveness-only
- Document v1/v2 metadata handling and onion delegation implications
- Add contrib/make_onion_delegation.py to issue certificates offline,
with Ed25519 key validation and clean CLI error handling
- Add WELIST_PING_SIG_VERSION (1 legacy, 2 canonical JSON); default 1
- Sign WELIST-PING-V2\n + compact sorted JSON covering url, chain, height,
median_time, last_block_hash, info, base_fee, version and sig_version
- Fetch info/base_fee/version from the local /{chain}/info endpoint and sign them
- Fall back to null metadata on fetch failure; skip the fetch for onion URLs
- Normalize the advertised URL and bound metadata to match the WeTime service
- Activate v2 in bal-pusher.sh and document the TXT record setup
- Add unit tests for canonical payloads, URL normalization, metadata and onion detection
Includes previously uncommitted local deployment hardening:
- pg-server.sh configurable loopback bind address, volume and recreate handling
- .env loading in bal-server.sh and bal-pusher.sh
- second bal-server/bal-pusher development scripts
bal-server:
- Wire independent actix-governor buckets per endpoint class (pushtxs,
searchtx, info/stats, default) so polling a cheap endpoint can no longer
exhaust the push-txs budget; previously every limit was dead config
- Enforce BAL_SERVER_ACTIX_TIMEOUT_SECS via a request-timeout middleware that
returns 408 Request Timeout, covering slow request bodies
- De-duplicate txids within a single /pushtxs request body
- Replace the byte-slice xpub detection (panic on non-ASCII) with a safe
prefix check
bal-pusher:
- Handle malformed/empty ZMQ frames without indexing panics or UTF-8 expect
- Return an error from sign_message and skip the stats report instead of
panicking when the private key cannot be parsed
validation / db:
- Reject IPv4-mapped IPv6 targets (::ffff:a.b.c.d) in is_valid_welist_url
to close an SSRF bypass, with unit tests
- Use Path::starts_with for the SQLite forbidden-directory check so paths
like /etcfoo are not misclassified
misc:
- Add explicit secret patterns to .gitignore and sync the docs
- Use BAL_SERVER_DB_* / BAL_SERVER_PG_DSN in bal-pusher, Dockerfiles,
scripts and docs instead of the BAL_PUSHER_DB_* duplicates
- Default BAL_SERVER_URL to http://127.0.0.1:9133
- Extract PostgreSQL container startup into a shared pg-server.sh sourced by
bal-server.sh and bal-pusher.sh
- Read the Postgres password from BAL_PG_PASSWORD instead of hardcoding it,
and stop printing the password-bearing DSN
- Redact a real-looking Gitea token from .env.example (revoke it if it was live)
- Correct per-endpoint rate limit tables to reflect actual single global config
- Document RealIpKeyExtractor behavior (X-Real-IP / X-Forwarded-For behind proxy)
- Add BAL_SERVER_TRUSTED_PROXY env var to all relevant docs
- Update security audit and modules detail with proxy-aware rate limiting
- Fix framework references (actix-web, not hyper)
- Update all env var names (BAL_SERVER_*/BAL_PUSHER_* prefix)
- Add validation.rs module documentation
- Fix function signatures in xpub.rs and db.rs
- Update API response formats (InfoResponse, StatsResponse)
- Fix database schema (date_creation/date_update, push_err, tbl_stats)
- Mark fixed vulnerabilities with current status
- Add Docker support and actix tuning documentation
- Remove outdated references (confy, bal-stats.rs.dontcompile)
- Add regression test summary table
The welist host publishes both A and AAAA records. On networks where the
IPv4 route is broken (connection stalls after the TCP handshake) while
IPv6 works, the default connector may pick the broken family and the
report request hangs.
When BAL_PUSHER_PREFER_IPV6 is truthy, the pusher now resolves the welist
host itself and pins the reqwest client to its first IPv6 address; the
original hostname is still used for the Host header and TLS SNI. When the
variable is unset (default) or no AAAA record exists, behavior is
completely unchanged.
Includes unit tests for the URL host/port parsing and documentation in
docs/07_deployment_and_ops.md.
- Add docs/INDEX.md with navigable index and quick reference guides
- Add 9 knowledge base files covering project overview, Bitcoin domain,
architecture, modules, API reference, database schema, deployment/security
- Update AGENTS.md with knowledge base reference and update policy
- Add tests/sql_injection_tests.rs with regression tests for SQL injection
- Fix SQL injection vulnerabilities in bal-pusher.rs:
* Replace string-formatted UPDATE IN with loop + parameterized queries
* Replace string-formatted UPDATE push_err with parameterized query
* Add chain name validation in calculate_stats to prevent env var tampering
- Update .gitignore to exclude bal-pusher.env and bal-pusher.sh