feat(pusher): add opt-in v2 WeTime ping signing
- 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
This commit is contained in:
@@ -147,11 +147,34 @@ The client tries username/password auth first, then falls back to cookie file au
|
||||
|
||||
---
|
||||
|
||||
## Ed25519 Stats Signing
|
||||
## Ed25519 WeTime Ping Signing
|
||||
|
||||
The pusher signs the statistics payload before sending it to the `welist` server:
|
||||
1. Collects statistics from the database.
|
||||
2. Serializes the stats as JSON.
|
||||
3. Signs the JSON payload with the Ed25519 private key (`privkey.pem`).
|
||||
4. Sends the payload with the base64-encoded signature in the `X-Signature` header.
|
||||
5. The `welist` server can verify the signature using the public key served at `GET /.pub_key.pem`.
|
||||
The pusher signs the report before sending it to the `welist` server. The
|
||||
scheme is selected with `WELIST_PING_SIG_VERSION`:
|
||||
|
||||
### Version 2 (canonical JSON, preferred)
|
||||
|
||||
1. Fetches `info`, `base_fee` and `version` from the local
|
||||
`GET /{chain}/info` endpoint (failure falls back to `null`).
|
||||
2. Builds a compact JSON object with lexicographically sorted keys, every field
|
||||
present, and `null` for absent optional values:
|
||||
`base_fee`, `chain`, `height`, `info`, `last_block_hash`, `median_time`,
|
||||
`sig_version`, `url`, `version`.
|
||||
3. Signs `WELIST-PING-V2\n` followed by that JSON with the Ed25519 private key
|
||||
(`SSL_KEY_PATH`).
|
||||
4. POSTs the same fields plus the base64 signature and `"sig_version": 2` to
|
||||
`{WELIST_SERVER_URL}/ping`.
|
||||
5. The `welist` server discovers the public key from a DNSSEC-validated
|
||||
`_welist-key.<host>` TXT record (`v=we1; alg=ed25519; key=<base64 SPKI DER>`)
|
||||
or from a v3 `.onion` address. No HTTP callback to `/.pub_key.pem` is made.
|
||||
|
||||
The `url` is trimmed of surrounding whitespace and trailing slashes, and the
|
||||
`chain` is lowercase, matching the service-side canonicalization.
|
||||
|
||||
### Version 1 (legacy)
|
||||
|
||||
1. Concatenates `url + chain + height + median_time + last_block_hash`.
|
||||
2. Signs that string with the Ed25519 private key.
|
||||
3. POSTs the fields plus the base64 signature to `{WELIST_SERVER_URL}/ping`.
|
||||
4. The `welist` server verifies the signature with the public key served at
|
||||
`GET /.pub_key.pem`; this scheme only refreshes `last_update`.
|
||||
|
||||
Reference in New Issue
Block a user