Skip to content

feat: metrics, votes, ALTCHA and rate limits - #5

Merged
Mimic890 merged 4 commits into
mainfrom
feat/metrics
Nov 4, 2026
Merged

Mimic890 merged 4 commits into
mainfrom
feat/metrics

Conversation

@Mimic890

@Mimic890 Mimic890 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Stage 5: metrics, votes, ALTCHA, rate limits, /metrics.

Changes

  • Store (internal/store): SQLite at DATA_DIR/hyperhack.db (mode 0600, WAL) via modernc.org/sqlite v1.61.0. Per-post counters, daily views for "Popular", votes keyed by the hashed vid cookie, and search stats. An hourly prune drops old search and daily rows.
  • Rate limiter (internal/ratelimit): per-client token bucket (IPv4 /32, IPv6 /64), LRU of 10k clients. 429 + Retry-After on /api/altcha, /api/vote, /api/beacon, /search and /reindex. The WARN log carries the endpoint, never the IP.
  • Votes: GET /api/altcha + POST /api/vote. Like / dislike / none, one vote per vid cookie (HttpOnly, SameSite=Lax, Secure on https). Each vote needs a solved ALTCHA challenge. Signatures cannot be replayed. Origin / Sec-Fetch-Site are checked on every API call.
  • ALTCHA: altcha-lib-go/v2 v2.4.1 on the server, with our own small solver (static/altcha.js, Web Crypto) on the page. A test runs the embedded JS solver in node and checks its payload against altcha.VerifySolution (fast and re-derive paths) and altcha.SolveChallenge.
  • Beacon: POST /api/beacon sends a delta on every hide. Each delta carries a random per-page-view id. The server sums time per view and clamps the sum at 4 h before it reaches the aggregate. Views, depth, source, device, lang and theme are counted once per visitor and post per day, using an in-memory HMAC visitor key with a daily key. Outbound clicks are counted only for hosts linked from the post. Code copies are counted too. Fuzz test included.
  • Pages: view count on the post, vote buttons, "Popular" list on the home page, 429 error page. The new strings are in en and ru.
  • /metrics: Prometheus text format, CIDR-restricted by METRICS_ALLOW. Exposes per-post counters, likes/dislikes gauges, sync stats, search counters and latency, top queries and top zero-result queries, and HTTP requests and latency per route.
  • SPEC / SPEC.ru: endpoint table, the beacon and visitor-hash details, the chosen libraries, and a Decision log entry.

Checks

  • go vet, staticcheck v0.8.2, govulncheck v1.9.0, and go test -race ./... all pass. govulncheck reports one x/crypto advisory (GO-2026-5932) that our code does not reach.
  • FuzzBeacon ran 45 s with no failures.
  • Browser smoke in headless Chrome:
    • vote like, then switch to dislike; the counts persist after reload;
    • views are deduped across reloads;
    • time is summed per view;
    • depth markers, source, device, lang and theme are recorded;
    • /metrics output looks right;
    • the DB files are 0600 and owned by the non-root user.

Not checked

  • Votes on a plain-http origin other than localhost: browsers hide crypto.subtle there, so the vote buttons stay disabled. Production is https.
  • Real Prometheus scrape and Grafana (stage 6).
  • Behaviour under real traffic: memory caps (100k views, 200k visitor bits, 100k used ALTCHA signatures) are covered by tests only.

@Mimic890
Mimic890 merged commit 7a07816 into main Nov 4, 2026
4 checks passed
@Mimic890
Mimic890 deleted the feat/metrics branch November 4, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant