Skip to content

feat(backend,frontend): show the estimated number of Tor users per country - #606

Merged
JuliusHenke merged 3 commits into
masterfrom
feat/country-usage
Oct 12, 2026
Merged

JuliusHenke merged 3 commits into
masterfrom
feat/country-usage

Conversation

@JuliusHenke

Copy link
Copy Markdown
Member

Fifth step of the TorFlow feature comparison. Adds Tor Metrics' estimated number of relay users per country as an optional map layer. This is the one new data source of the plan.

Data source

userstats-relay-country.csv from Tor Metrics (CC0): date,country,users,lower,upper,frac, daily from 2011-03-06, about 2 days behind. I checked the live file: ~1.3 M rows, ~38 MB, 247 country codes (including the empty global total, ?? and legacy codes). The method is documented at https://metrics.torproject.org/reproducible-metrics.html#relay-users: users are estimated from the directory requests relays report, so this counts users that connect to Tor directly, not the traffic they cause. frac is the share of the network that contributed (11 % in 2011, 50 to 75 % recently), so early values are less reliable. The UI shows this.

Backend

  • country_usage(day, country_code, users, lower, upper, frac) (Flyway V5).
  • CountryUsageService: the first run downloads the complete history, later runs only ?start=<latest day - 14> (Tor Metrics revises recent days). Scheduled every 12 h like the other imports, upserts in chunks.
  • Only countries are stored: the global total, ?? and legacy codes like a1/a2 are skipped.
  • GET /relay/country-usage/day/{day} returns [{country, users, lower, upper, frac}], day is a strictly parsed LocalDate (400 otherwise), [] for days without estimates. Cached per day in a bounded cache (400 entries), cleared after each import.
  • Configurable under usage-statistics.* in application.yml.

Frontend

  • New settings section Tor users per country with a switch (default off), a color scale legend and a note on how reliable the day's estimate is.
  • Countries are colored on a logarithmic scale in a map pane below the relay markers. The tooltip is a text node with the estimate and its range.
  • Nothing is requested while the switch is off. Failures (older backend, lost connection, non-list response) leave the map unchanged and show one warning.

Security (THREAT_MODEL.md updated)

New outbound call, checked against the review checklist:

  • One configured URL, http(s) only, redirects are not followed, connect and request timeouts, at most 128 MB read per response.
  • The response is untrusted content: strict per-line validation (date, [a-z]{2} country, bounded numbers, no future dates), malformed lines are skipped and counted, bound parameters only.
  • The new endpoint is covered by /relay/**; SecurityRulesTest includes it. No change to SecurityConfig.
  • No dependency changes.

Deployment notes

  • Operators must allow outbound HTTPS from the backend to metrics.torproject.org.
  • The first run after the upgrade downloads ~40 MB once. Until then the layer shows "currently not available".
  • Setting usage-statistics.baseUrl to another mirror is possible but not needed.

Testing

  • Backend (Testcontainers): full suite passes, 115 tests. New: CSV parser (valid, ignored and malformed lines), repository (upsert, ordering, nulls), service against a local HTTP server (first import, incremental start, cache clearing, 500, size limit, redirect not followed, future dates) and controller (data, empty, 400 for invalid days).
  • Frontend: full suite passes, 296 tests; tsc, ESLint and yarn build clean. New tests for the color scale, layer and tooltip text, the loading component and the settings section.
  • Not done: Snyk (not authenticated here), and I have not looked at the layer in a browser with real data.

🤖 Generated with Claude Code

JuliusHenke and others added 2 commits October 12, 2026 19:04
Adds the country_usage table (V5), a scheduled import of Tor Metrics'
userstats-relay-country.csv and GET /relay/country-usage/day/{day}.
The import uses one configured URL without redirects, timeouts, a size limit
and strict per-line validation.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds a Tor users per country section to the settings. When enabled, countries
are colored by Tor Metrics' estimate for the selected day on a logarithmic
scale, with a plain text tooltip. The estimate's reliability (share of relays
that contributed) is shown, and the layer degrades to a message if the backend
does not provide the data.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@JuliusHenke JuliusHenke added enhancement New feature or request frontend backend deployment Operators must take action when deploying labels Oct 12, 2026
storedRows += rows.size
}
}
if (malformedLines > 0) {
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit fb75a1f):

https://tormap-36f44--pr606-feat-country-usage-z790ot1w.web.app

(expires Wed, 11 Nov 2026 21:51:38 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 0c1f71965de18e60b0e686b0d0356977fec090dc

@JuliusHenke
JuliusHenke marked this pull request as ready for review October 12, 2026 21:44
Resolve conflicts with the accessibility fixes and adapt the country
usage layer to the lazily loaded country borders (#607): the borders
only carry the country code now, so the tooltip takes the name from
getFullCountryName, and the layer loads the borders with
loadWorldFeatures instead of importing them into the main bundle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JuliusHenke
JuliusHenke merged commit a0a51e0 into master Oct 12, 2026
16 of 17 checks passed
@JuliusHenke
JuliusHenke deleted the feat/country-usage branch October 12, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend deployment Operators must take action when deploying enhancement New feature or request frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants