mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-02-16 09:59:49 +03:00
Pull request 1841: AG-21462-safebrowsing-parental-http-tests
Merge in DNS/adguard-home from AG-21462-safebrowsing-parental-http-tests to master Squashed commit of the following: commit 22a83ebad08a27939a443530137a7c195f512ee4 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed May 3 17:39:46 2023 +0300 filtering: fix test commit c3ca8b4987245cdd552f6f09759804e716bcae80 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed May 3 16:43:35 2023 +0300 filtering: imp tests even more commit 7643bfae350373b5b6dfb61b64e57da66c6ab952 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed May 3 16:17:42 2023 +0300 filtering: imp tests more commit 399c05ee4d479a727b61378b7a07158a568d0181 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed May 3 14:45:41 2023 +0300 filtering: imp tests commit f361df39e784ec9c5191666736a6c64b332928e8 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Tue May 2 12:49:26 2023 +0300 filtering: add tests
This commit is contained in:
parent
381f2f651d
commit
db52f7a3ac
4 changed files with 310 additions and 137 deletions
|
@ -1035,3 +1035,69 @@ func (d *DNSFilter) Start() {
|
||||||
// So for now we just start this periodic task from here.
|
// So for now we just start this periodic task from here.
|
||||||
go d.periodicallyRefreshFilters()
|
go d.periodicallyRefreshFilters()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safe browsing and parental control methods.
|
||||||
|
|
||||||
|
// TODO(a.garipov): Unify with checkParental.
|
||||||
|
func (d *DNSFilter) checkSafeBrowsing(
|
||||||
|
host string,
|
||||||
|
_ uint16,
|
||||||
|
setts *Settings,
|
||||||
|
) (res Result, err error) {
|
||||||
|
if !setts.ProtectionEnabled || !setts.SafeBrowsingEnabled {
|
||||||
|
return Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.GetLevel() >= log.DEBUG {
|
||||||
|
timer := log.StartTimer()
|
||||||
|
defer timer.LogElapsed("safebrowsing lookup for %q", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
res = Result{
|
||||||
|
Rules: []*ResultRule{{
|
||||||
|
Text: "adguard-malware-shavar",
|
||||||
|
FilterListID: SafeBrowsingListID,
|
||||||
|
}},
|
||||||
|
Reason: FilteredSafeBrowsing,
|
||||||
|
IsFiltered: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := d.safeBrowsingChecker.Check(host)
|
||||||
|
if !block || err != nil {
|
||||||
|
return Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(a.garipov): Unify with checkSafeBrowsing.
|
||||||
|
func (d *DNSFilter) checkParental(
|
||||||
|
host string,
|
||||||
|
_ uint16,
|
||||||
|
setts *Settings,
|
||||||
|
) (res Result, err error) {
|
||||||
|
if !setts.ProtectionEnabled || !setts.ParentalEnabled {
|
||||||
|
return Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.GetLevel() >= log.DEBUG {
|
||||||
|
timer := log.StartTimer()
|
||||||
|
defer timer.LogElapsed("parental lookup for %q", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
res = Result{
|
||||||
|
Rules: []*ResultRule{{
|
||||||
|
Text: "parental CATEGORY_BLACKLISTED",
|
||||||
|
FilterListID: ParentalListID,
|
||||||
|
}},
|
||||||
|
Reason: FilteredParental,
|
||||||
|
IsFiltered: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := d.parentalControlChecker.Check(host)
|
||||||
|
if !block || err != nil {
|
||||||
|
return Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
|
@ -458,6 +459,80 @@ func (d *DNSFilter) handleCheckHost(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setProtectedBool sets the value of a boolean pointer under a lock. l must
|
||||||
|
// protect the value under ptr.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Make it generic?
|
||||||
|
func setProtectedBool(mu *sync.RWMutex, ptr *bool, val bool) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
*ptr = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// protectedBool gets the value of a boolean pointer under a read lock. l must
|
||||||
|
// protect the value under ptr.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Make it generic?
|
||||||
|
func protectedBool(mu *sync.RWMutex, ptr *bool) (val bool) {
|
||||||
|
mu.RLock()
|
||||||
|
defer mu.RUnlock()
|
||||||
|
|
||||||
|
return *ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSafeBrowsingEnable is the handler for the POST
|
||||||
|
// /control/safebrowsing/enable HTTP API.
|
||||||
|
func (d *DNSFilter) handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) {
|
||||||
|
setProtectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled, true)
|
||||||
|
d.Config.ConfigModified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSafeBrowsingDisable is the handler for the POST
|
||||||
|
// /control/safebrowsing/disable HTTP API.
|
||||||
|
func (d *DNSFilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) {
|
||||||
|
setProtectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled, false)
|
||||||
|
d.Config.ConfigModified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSafeBrowsingStatus is the handler for the GET
|
||||||
|
// /control/safebrowsing/status HTTP API.
|
||||||
|
func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
resp := &struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}{
|
||||||
|
Enabled: protectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled),
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleParentalEnable is the handler for the POST /control/parental/enable
|
||||||
|
// HTTP API.
|
||||||
|
func (d *DNSFilter) handleParentalEnable(w http.ResponseWriter, r *http.Request) {
|
||||||
|
setProtectedBool(&d.confLock, &d.Config.ParentalEnabled, true)
|
||||||
|
d.Config.ConfigModified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleParentalDisable is the handler for the POST /control/parental/disable
|
||||||
|
// HTTP API.
|
||||||
|
func (d *DNSFilter) handleParentalDisable(w http.ResponseWriter, r *http.Request) {
|
||||||
|
setProtectedBool(&d.confLock, &d.Config.ParentalEnabled, false)
|
||||||
|
d.Config.ConfigModified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleParentalStatus is the handler for the GET /control/parental/status
|
||||||
|
// HTTP API.
|
||||||
|
func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
resp := &struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}{
|
||||||
|
Enabled: protectedBool(&d.confLock, &d.Config.ParentalEnabled),
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterFilteringHandlers - register handlers
|
// RegisterFilteringHandlers - register handlers
|
||||||
func (d *DNSFilter) RegisterFilteringHandlers() {
|
func (d *DNSFilter) RegisterFilteringHandlers() {
|
||||||
registerHTTP := d.HTTPRegister
|
registerHTTP := d.HTTPRegister
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -136,3 +137,171 @@ func TestDNSFilter_handleFilteringSetURL(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNSFilter_handleSafeBrowsingStatus(t *testing.T) {
|
||||||
|
const (
|
||||||
|
testTimeout = time.Second
|
||||||
|
statusURL = "/control/safebrowsing/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
confModCh := make(chan struct{})
|
||||||
|
filtersDir := t.TempDir()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
url string
|
||||||
|
enabled bool
|
||||||
|
wantStatus assert.BoolAssertionFunc
|
||||||
|
}{{
|
||||||
|
name: "enable_off",
|
||||||
|
url: "/control/safebrowsing/enable",
|
||||||
|
enabled: false,
|
||||||
|
wantStatus: assert.True,
|
||||||
|
}, {
|
||||||
|
name: "enable_on",
|
||||||
|
url: "/control/safebrowsing/enable",
|
||||||
|
enabled: true,
|
||||||
|
wantStatus: assert.True,
|
||||||
|
}, {
|
||||||
|
name: "disable_on",
|
||||||
|
url: "/control/safebrowsing/disable",
|
||||||
|
enabled: true,
|
||||||
|
wantStatus: assert.False,
|
||||||
|
}, {
|
||||||
|
name: "disable_off",
|
||||||
|
url: "/control/safebrowsing/disable",
|
||||||
|
enabled: false,
|
||||||
|
wantStatus: assert.False,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
handlers := make(map[string]http.Handler)
|
||||||
|
|
||||||
|
d, err := New(&Config{
|
||||||
|
ConfigModified: func() {
|
||||||
|
testutil.RequireSend(testutil.PanicT{}, confModCh, struct{}{}, testTimeout)
|
||||||
|
},
|
||||||
|
DataDir: filtersDir,
|
||||||
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
||||||
|
handlers[url] = handler
|
||||||
|
},
|
||||||
|
SafeBrowsingEnabled: tc.enabled,
|
||||||
|
}, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(d.Close)
|
||||||
|
|
||||||
|
d.RegisterFilteringHandlers()
|
||||||
|
require.NotEmpty(t, handlers)
|
||||||
|
require.Contains(t, handlers, statusURL)
|
||||||
|
|
||||||
|
r := httptest.NewRequest(http.MethodPost, tc.url, nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
go handlers[tc.url].ServeHTTP(w, r)
|
||||||
|
|
||||||
|
testutil.RequireReceive(t, confModCh, testTimeout)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(http.MethodGet, statusURL, nil)
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
|
||||||
|
handlers[statusURL].ServeHTTP(w, r)
|
||||||
|
require.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
|
status := struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}{
|
||||||
|
Enabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewDecoder(w.Body).Decode(&status)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tc.wantStatus(t, status.Enabled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDNSFilter_handleParentalStatus(t *testing.T) {
|
||||||
|
const (
|
||||||
|
testTimeout = time.Second
|
||||||
|
statusURL = "/control/parental/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
confModCh := make(chan struct{})
|
||||||
|
filtersDir := t.TempDir()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
url string
|
||||||
|
enabled bool
|
||||||
|
wantStatus assert.BoolAssertionFunc
|
||||||
|
}{{
|
||||||
|
name: "enable_off",
|
||||||
|
url: "/control/parental/enable",
|
||||||
|
enabled: false,
|
||||||
|
wantStatus: assert.True,
|
||||||
|
}, {
|
||||||
|
name: "enable_on",
|
||||||
|
url: "/control/parental/enable",
|
||||||
|
enabled: true,
|
||||||
|
wantStatus: assert.True,
|
||||||
|
}, {
|
||||||
|
name: "disable_on",
|
||||||
|
url: "/control/parental/disable",
|
||||||
|
enabled: true,
|
||||||
|
wantStatus: assert.False,
|
||||||
|
}, {
|
||||||
|
name: "disable_off",
|
||||||
|
url: "/control/parental/disable",
|
||||||
|
enabled: false,
|
||||||
|
wantStatus: assert.False,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
handlers := make(map[string]http.Handler)
|
||||||
|
|
||||||
|
d, err := New(&Config{
|
||||||
|
ConfigModified: func() {
|
||||||
|
testutil.RequireSend(testutil.PanicT{}, confModCh, struct{}{}, testTimeout)
|
||||||
|
},
|
||||||
|
DataDir: filtersDir,
|
||||||
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
||||||
|
handlers[url] = handler
|
||||||
|
},
|
||||||
|
ParentalEnabled: tc.enabled,
|
||||||
|
}, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(d.Close)
|
||||||
|
|
||||||
|
d.RegisterFilteringHandlers()
|
||||||
|
require.NotEmpty(t, handlers)
|
||||||
|
require.Contains(t, handlers, statusURL)
|
||||||
|
|
||||||
|
r := httptest.NewRequest(http.MethodPost, tc.url, nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
go handlers[tc.url].ServeHTTP(w, r)
|
||||||
|
|
||||||
|
testutil.RequireReceive(t, confModCh, testTimeout)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(http.MethodGet, statusURL, nil)
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
|
||||||
|
handlers[statusURL].ServeHTTP(w, r)
|
||||||
|
require.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
|
status := struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}{
|
||||||
|
Enabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewDecoder(w.Body).Decode(&status)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tc.wantStatus(t, status.Enabled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
package filtering
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
|
||||||
"github.com/AdguardTeam/golibs/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Safe browsing and parental control methods.
|
|
||||||
|
|
||||||
// TODO(a.garipov): Unify with checkParental.
|
|
||||||
func (d *DNSFilter) checkSafeBrowsing(
|
|
||||||
host string,
|
|
||||||
_ uint16,
|
|
||||||
setts *Settings,
|
|
||||||
) (res Result, err error) {
|
|
||||||
if !setts.ProtectionEnabled || !setts.SafeBrowsingEnabled {
|
|
||||||
return Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if log.GetLevel() >= log.DEBUG {
|
|
||||||
timer := log.StartTimer()
|
|
||||||
defer timer.LogElapsed("safebrowsing lookup for %q", host)
|
|
||||||
}
|
|
||||||
|
|
||||||
res = Result{
|
|
||||||
Rules: []*ResultRule{{
|
|
||||||
Text: "adguard-malware-shavar",
|
|
||||||
FilterListID: SafeBrowsingListID,
|
|
||||||
}},
|
|
||||||
Reason: FilteredSafeBrowsing,
|
|
||||||
IsFiltered: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
block, err := d.safeBrowsingChecker.Check(host)
|
|
||||||
if !block || err != nil {
|
|
||||||
return Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(a.garipov): Unify with checkSafeBrowsing.
|
|
||||||
func (d *DNSFilter) checkParental(
|
|
||||||
host string,
|
|
||||||
_ uint16,
|
|
||||||
setts *Settings,
|
|
||||||
) (res Result, err error) {
|
|
||||||
if !setts.ProtectionEnabled || !setts.ParentalEnabled {
|
|
||||||
return Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if log.GetLevel() >= log.DEBUG {
|
|
||||||
timer := log.StartTimer()
|
|
||||||
defer timer.LogElapsed("parental lookup for %q", host)
|
|
||||||
}
|
|
||||||
|
|
||||||
res = Result{
|
|
||||||
Rules: []*ResultRule{{
|
|
||||||
Text: "parental CATEGORY_BLACKLISTED",
|
|
||||||
FilterListID: ParentalListID,
|
|
||||||
}},
|
|
||||||
Reason: FilteredParental,
|
|
||||||
IsFiltered: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
block, err := d.parentalControlChecker.Check(host)
|
|
||||||
if !block || err != nil {
|
|
||||||
return Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setProtectedBool sets the value of a boolean pointer under a lock. l must
|
|
||||||
// protect the value under ptr.
|
|
||||||
//
|
|
||||||
// TODO(e.burkov): Make it generic?
|
|
||||||
func setProtectedBool(mu *sync.RWMutex, ptr *bool, val bool) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
*ptr = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// protectedBool gets the value of a boolean pointer under a read lock. l must
|
|
||||||
// protect the value under ptr.
|
|
||||||
//
|
|
||||||
// TODO(e.burkov): Make it generic?
|
|
||||||
func protectedBool(mu *sync.RWMutex, ptr *bool) (val bool) {
|
|
||||||
mu.RLock()
|
|
||||||
defer mu.RUnlock()
|
|
||||||
|
|
||||||
return *ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setProtectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled, true)
|
|
||||||
d.Config.ConfigModified()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setProtectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled, false)
|
|
||||||
d.Config.ConfigModified()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) {
|
|
||||||
resp := &struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
}{
|
|
||||||
Enabled: protectedBool(&d.confLock, &d.Config.SafeBrowsingEnabled),
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleParentalEnable(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setProtectedBool(&d.confLock, &d.Config.ParentalEnabled, true)
|
|
||||||
d.Config.ConfigModified()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleParentalDisable(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setProtectedBool(&d.confLock, &d.Config.ParentalEnabled, false)
|
|
||||||
d.Config.ConfigModified()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) {
|
|
||||||
resp := &struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
}{
|
|
||||||
Enabled: protectedBool(&d.confLock, &d.Config.ParentalEnabled),
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue