From 74c39cc8e9ceede41524be8c0fc5220579829e55 Mon Sep 17 00:00:00 2001 From: David Fifield Date: Fri, 15 Aug 2025 19:09:50 +0000 Subject: [PATCH] Bin country stats counts before sorting, not after. This avoids an information leak where, if two countries have the same count but are not in alphabetical order, you know the first one had a larger count than the second one before binning. Example: AA=25,BB=27 Without binning, these should sort descending by count: BB=27,AA=25 But with binning, the counts are the same, so it should sort ascending by country code: AA=32,BB=32 Before this change, BB would sort before AA even after binning, which lets you infer that the count of BB was greater than the count of AA *before* binning: BB=32,AA=32 --- broker/metrics.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/broker/metrics.go b/broker/metrics.go index b735dfa..748f42c 100644 --- a/broker/metrics.go +++ b/broker/metrics.go @@ -191,10 +191,14 @@ func (r records) Less(i, j int) bool { // // formatAndClearCountryStats has the side effect of deleting all entries in m. func formatAndClearCountryStats(m *sync.Map, binned bool) string { - // Extract entries from the map into a slice of records. + // Extract entries from the map into a slice of records, binning counts + // if asked to.. rs := records{} m.Range(func(cc, countPtr any) bool { count := *countPtr.(*uint64) + if binned { + count = binCount(count) + } rs = append(rs, record{cc: cc.(string), count: count}) m.Delete(cc) return true @@ -204,14 +208,10 @@ func formatAndClearCountryStats(m *sync.Map, binned bool) string { // Format and concatenate. var output strings.Builder for i, r := range rs { - count := r.count - if binned { - count = binCount(count) - } if i != 0 { output.WriteString(",") } - fmt.Fprintf(&output, "%s=%d", r.cc, count) + fmt.Fprintf(&output, "%s=%d", r.cc, r.count) } return output.String() }