Filter separator-only glob templates in tracker pattern analysis
Unrelated third-party trackers that happened to share a leading separator run (e.g. __support__, __darkreader__wasEnabledForHost, __EXT_APP_REFRESH_BLACK_SUB_DOMAINS__) were being merged under overly broad globs such as __* because templateCandidates emitted every prefix at each '_' or '-' position without requiring any fixed anchor. Add a templateHasFixedAnchor helper and apply it to both templateCandidates loops and the heuristicTemplate result so candidates consisting solely of '_', '-', and '*' are rejected. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -432,7 +432,12 @@ func heuristicTemplate(name string) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix.String() + joinTokens(resultTokens, resultSeps) + suffix, true
|
tmpl := prefix.String() + joinTokens(resultTokens, resultSeps) + suffix
|
||||||
|
if !templateHasFixedAnchor(tmpl) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpl, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func templateCandidates(name string) []string {
|
func templateCandidates(name string) []string {
|
||||||
@@ -440,7 +445,10 @@ func templateCandidates(name string) []string {
|
|||||||
|
|
||||||
for i, ch := range name {
|
for i, ch := range name {
|
||||||
if ch == '_' || ch == '-' {
|
if ch == '_' || ch == '-' {
|
||||||
candidates = append(candidates, name[:i+1]+"*")
|
tmpl := name[:i+1] + "*"
|
||||||
|
if templateHasFixedAnchor(tmpl) {
|
||||||
|
candidates = append(candidates, tmpl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +458,9 @@ func templateCandidates(name string) []string {
|
|||||||
left := joinTokens(tokens[:pos], seps[:pos-1])
|
left := joinTokens(tokens[:pos], seps[:pos-1])
|
||||||
right := joinTokens(tokens[pos+1:], seps[pos+1:])
|
right := joinTokens(tokens[pos+1:], seps[pos+1:])
|
||||||
tmpl := left + string(seps[pos-1]) + "*" + string(seps[pos]) + right
|
tmpl := left + string(seps[pos-1]) + "*" + string(seps[pos]) + right
|
||||||
candidates = append(candidates, tmpl)
|
if templateHasFixedAnchor(tmpl) {
|
||||||
|
candidates = append(candidates, tmpl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,6 +585,22 @@ func joinTokens(tokens []string, seps []byte) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// templateHasFixedAnchor reports whether tmpl contains at least one
|
||||||
|
// character beyond separators and wildcards. Templates like "_*",
|
||||||
|
// "__*", "-*", "--*", "__*__" would merge unrelated third parties
|
||||||
|
// (e.g. __support__, __darkreader__wasEnabledForHost,
|
||||||
|
// __EXT_APP_REFRESH_BLACK_SUB_DOMAINS__) under a single glob, so
|
||||||
|
// candidates without any fixed alphanumeric anchor are rejected.
|
||||||
|
func templateHasFixedAnchor(tmpl string) bool {
|
||||||
|
for _, ch := range tmpl {
|
||||||
|
if ch != '*' && ch != '_' && ch != '-' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func globMatch(pattern, name string) bool {
|
func globMatch(pattern, name string) bool {
|
||||||
parts := strings.Split(pattern, "*")
|
parts := strings.Split(pattern, "*")
|
||||||
if len(parts) == 1 {
|
if len(parts) == 1 {
|
||||||
|
|||||||
@@ -238,6 +238,11 @@ func TestHeuristicTemplate(t *testing.T) {
|
|||||||
input: "__Secure-1PSID",
|
input: "__Secure-1PSID",
|
||||||
changed: false,
|
changed: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "all variable tokens with leading underscores rejected",
|
||||||
|
input: "__a1b2c3d4_e5f6g7h8",
|
||||||
|
changed: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -293,10 +298,9 @@ func TestTemplateCandidates(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "leading underscore",
|
name: "leading underscore drops anchor-free prefix",
|
||||||
input: "_ga_GB2J3DLBHE",
|
input: "_ga_GB2J3DLBHE",
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"_*",
|
|
||||||
"_ga_*",
|
"_ga_*",
|
||||||
"_*_GB2J3DLBHE",
|
"_*_GB2J3DLBHE",
|
||||||
},
|
},
|
||||||
@@ -324,6 +328,38 @@ func TestTemplateCandidates(t *testing.T) {
|
|||||||
"auth0_*_abc123",
|
"auth0_*_abc123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "double leading underscore drops anchor-free prefixes",
|
||||||
|
input: "__support__",
|
||||||
|
expected: []string{
|
||||||
|
"__support_*",
|
||||||
|
"__support__*",
|
||||||
|
"_*_support__",
|
||||||
|
"__support_*_",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double underscore extension key drops anchor-free prefixes",
|
||||||
|
input: "__darkreader__wasEnabledForHost",
|
||||||
|
expected: []string{
|
||||||
|
"__darkreader_*",
|
||||||
|
"__darkreader__*",
|
||||||
|
"_*_darkreader__wasEnabledForHost",
|
||||||
|
"__*__wasEnabledForHost",
|
||||||
|
"__darkreader_*_wasEnabledForHost",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double leading dash drops anchor-free prefixes",
|
||||||
|
input: "--leading-dash-foo",
|
||||||
|
expected: []string{
|
||||||
|
"--leading-*",
|
||||||
|
"--leading-dash-*",
|
||||||
|
"-*-leading-dash-foo",
|
||||||
|
"--*-dash-foo",
|
||||||
|
"--leading-*-foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -915,6 +951,22 @@ func TestFindMergeGroups(t *testing.T) {
|
|||||||
assert.Empty(t, groups)
|
assert.Empty(t, groups)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
t.Run(
|
||||||
|
"unrelated double-underscore keys do not merge under anchor-free glob",
|
||||||
|
func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
patterns := coredata.TrackerPatterns{
|
||||||
|
makePattern("__support__", nil),
|
||||||
|
makePattern("__darkreader__wasEnabledForHost", nil),
|
||||||
|
makePattern("__EXT_APP_REFRESH_BLACK_SUB_DOMAINS__", nil),
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := findMergeGroups(patterns, 3)
|
||||||
|
assert.Empty(t, groups)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDurationBucket(t *testing.T) {
|
func TestDurationBucket(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user