Add Disconnect.me tracking-protection blocklist source
Downloads and caches the Disconnect.me services.json feed (24h TTL), matching domains against the Advertising, Analytics, Social, Content, and Disconnect categories. Severity is warn (privacy classification, not malware). Reuses the shared feedCache infrastructure.
This commit is contained in:
parent
9916ab0732
commit
c2cc88e1df
3 changed files with 290 additions and 0 deletions
127
checker/disconnect_test.go
Normal file
127
checker/disconnect_test.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package checker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
const disconnectFakeFeed = `{
|
||||
"categories": {
|
||||
"Advertising": [
|
||||
{
|
||||
"Evil Corp": {
|
||||
"https://evilcorp.com": ["tracker.com", "sub.example.org"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"Analytics": [
|
||||
{
|
||||
"Metrics Inc": {
|
||||
"https://metrics.io": ["analytics.net"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
func newDisconnectTestSource(srv *httptest.Server) *disconnectSource {
|
||||
return &disconnectSource{
|
||||
cache: newFeedCache(time.Hour, disconnectFetch(srv.URL)),
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectSource_Listed(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(disconnectFakeFeed))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
s := newDisconnectTestSource(srv)
|
||||
r := s.Query(context.Background(), "tracker.com", "tracker.com", sdk.CheckerOptions{"enable_disconnect": true})[0]
|
||||
|
||||
if !r.Enabled || r.Error != "" {
|
||||
t.Fatalf("expected enabled with no error, got %+v", r)
|
||||
}
|
||||
if len(r.Evidence) == 0 {
|
||||
t.Fatalf("expected evidence, got none")
|
||||
}
|
||||
found := false
|
||||
for _, e := range r.Evidence {
|
||||
if e.Value == "Advertising" {
|
||||
found = true
|
||||
if e.Extra["company"] != "Evil Corp" {
|
||||
t.Errorf("expected company 'Evil Corp', got %q", e.Extra["company"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("expected Advertising evidence, got %+v", r.Evidence)
|
||||
}
|
||||
if listed, sev := s.Evaluate(r); !listed || sev != SeverityWarn {
|
||||
t.Errorf("expected (true, warn), got (%v, %q)", listed, sev)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectSource_SubdomainInFeed(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(disconnectFakeFeed))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
// Feed has "sub.example.org"; querying registered domain "example.org" should match.
|
||||
s := newDisconnectTestSource(srv)
|
||||
r := s.Query(context.Background(), "example.org", "example.org", sdk.CheckerOptions{"enable_disconnect": true})[0]
|
||||
|
||||
if !r.Enabled || r.Error != "" {
|
||||
t.Fatalf("expected enabled with no error, got %+v", r)
|
||||
}
|
||||
if len(r.Evidence) == 0 {
|
||||
t.Errorf("expected subdomain match evidence, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectSource_NotListed(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(disconnectFakeFeed))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
s := newDisconnectTestSource(srv)
|
||||
r := s.Query(context.Background(), "clean.example.com", "clean.example.com", sdk.CheckerOptions{"enable_disconnect": true})[0]
|
||||
|
||||
if !r.Enabled || r.Error != "" {
|
||||
t.Fatalf("expected enabled with no error, got %+v", r)
|
||||
}
|
||||
if len(r.Evidence) != 0 {
|
||||
t.Errorf("expected no evidence for clean domain, got %+v", r.Evidence)
|
||||
}
|
||||
if listed, _ := s.Evaluate(r); listed {
|
||||
t.Errorf("expected not listed for clean domain")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectSource_Disabled(t *testing.T) {
|
||||
s := &disconnectSource{cache: newFeedCache(time.Hour, disconnectFetch("http://nope"))}
|
||||
r := s.Query(context.Background(), "tracker.com", "tracker.com", sdk.CheckerOptions{"enable_disconnect": false})[0]
|
||||
if r.Enabled {
|
||||
t.Errorf("expected disabled result, got %+v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectSource_HTTPError(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
s := newDisconnectTestSource(srv)
|
||||
r := s.Query(context.Background(), "tracker.com", "tracker.com", sdk.CheckerOptions{"enable_disconnect": true})[0]
|
||||
if r.Error == "" {
|
||||
t.Errorf("expected error on HTTP 500, got empty error")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue