Files
meshcore-analyzer/cmd/server
efitenandClaude Opus 5.5 abc6ab9b59 fix(analytics): apply nodeBlacklist and hiddenNamePrefixes to Route Patterns (#2184) (#2189)
Fixes #2184.

## Problem

`nodeBlacklist` and `hiddenNamePrefixes` did not apply to Route
Patterns:

- **`subpaths` and `subpaths-bulk`:** `filterBlacklistedFromSubpaths`
asserted `data["subpaths"].([]interface{})`, while the store builds
`[]map[string]interface{}`, so it returned its input unchanged. It then
read `hops` as a list, which is an `int` (the run length). It also ran
only when `nodeBlacklist` was set, so `hiddenNamePrefixes` alone never
filtered anything.
- **`subpath-detail`:** the check compared each raw hop (a prefix) with
full keys, so it matched only a client that sent a full key.
- **Parent paths** in the detail response were not filtered.

## Change

All in `cmd/server/routes.go`; `store.go` is untouched, so this doesn't
overlap #2182.

- **Lists:** an entry is dropped when a name in its resolved `path` is
the name of a blacklisted node (names looked up in the store's node
cache) or has a hidden prefix. A subpath carries names and prefixes, not
keys, and the store picks a node per prefix from context, so
re-resolving a prefix in the handler would not be guaranteed to land on
the same node. Matching the names the reader would see avoids that.
Trade-off: another node with exactly the same name as a blacklisted one
is hidden too.
- **Detail:** 404 when a hop resolved to a blacklisted node (by the
resolved key in `nodes[].pubkey`, so a node without a name is caught and
one that only shares its name is not) or to a hidden-prefix name; parent
paths that show one are dropped (by name, like the lists). The existing
raw-hop check stays.
- The filter runs when either `nodeBlacklist` or `hiddenNamePrefixes` is
set.
- `dropHiddenPaths` replaces `filterBlacklistedFromSubpaths` and returns
a copy: the input can be the store's cached response, which the old
function mutated in place.
- `totalPaths` and `pct` are unchanged, so percentages stay relative to
every stored path, the filtered ones included.

**Perf:** per request, one pass over the node cache (about 2k nodes on
the deployment below) to collect blacklisted names, then at most 8
lookups per entry on at most `limit` entries. It runs outside the store
lock and only when a filter is configured. `map[string]interface{}`
count in `routes.go`: 3 removed, 3 added.

## Tests

- `subpaths_blacklist_2184_test.go`: on the seeded path `["aa","bb"]`
(first hop resolves to TestRepeater), for `subpaths`, `subpaths-bulk`
and `subpath-detail`:
  - unfiltered, the repeater is listed (so the test is not vacuous);
- a blacklisted key, also in capitals, removes it and the detail returns
404;
  - a hidden name prefix removes it;
  - a different key with the same 1-byte prefix leaves it listed;
- clearing the blacklist afterwards shows it again (the cached response
was not changed).
- subpath-detail: a blacklisted node without a name returns 404, a
different node that only shares its name does not hide the detail.
- Red commits first (`0ebee485`, `4acfb70a`, failing on assertions),
then green.
- `cd cmd/server && go test ./...` passes
(`TestSaveGeoFilterPreservesFileMode` skipped, a Windows-only failure on
master too); `go test -race -run 2184` passes; `go vet` clean.

## Validation on a live-fed staging instance

`nodeBlacklist` temporarily set to the key of the node in the top Route
Patterns entry (5848 occurrences), then restored:

| | blacklist set | restored |
|---|---|---|
| `subpaths?limit=200` entries showing the node | 0 (185 entries left) |
15 (200 entries) |
| `subpaths-bulk` groups 2-2 / 3-3 / 5-8 showing it | 0 / 0 / 0 | |
| `subpath-detail` on a path through it | 404 | |
| `subpath-detail` on a path without it | 200 | |

## Not done

- Other analytics responses that carry node names (for example topology)
were not audited for the same gap.
- The UI still shows `pct` relative to all paths; whether a filtered
list should renormalise is left open.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 08:35:16 +02:00
..