all: imp code

This commit is contained in:
Stanislav Chzhen 2024-12-16 18:34:06 +03:00
parent 2dd1c94123
commit 7bf8f0a516
4 changed files with 105 additions and 39 deletions

View File

@ -435,25 +435,30 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
break break
} }
ip, _ := netip.ParseAddr(idStr)
c, ok := clients.storage.Find(idStr)
var cj *clientJSON
if !ok {
cj = clients.findRuntime(ip, idStr)
} else {
cj = clientToJSON(c)
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
}
data = append(data, map[string]*clientJSON{ data = append(data, map[string]*clientJSON{
idStr: cj, idStr: clients.findClient(idStr),
}) })
} }
aghhttp.WriteJSONResponseOK(w, r, data) aghhttp.WriteJSONResponseOK(w, r, data)
} }
// findClient returns available information about a client by idStr from the
// client's storage or access settings. cj is guaranteed to be non-nil.
func (clients *clientsContainer) findClient(idStr string) (cj *clientJSON) {
ip, _ := netip.ParseAddr(idStr)
c, ok := clients.storage.Find(idStr)
if !ok {
return clients.findRuntime(ip, idStr)
}
cj = clientToJSON(c)
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
return cj
}
// searchQueryJSON is a request to the POST /control/clients/search HTTP API. // searchQueryJSON is a request to the POST /control/clients/search HTTP API.
// //
// TODO(s.chzhen): Add UIDs. // TODO(s.chzhen): Add UIDs.
@ -480,19 +485,12 @@ func (clients *clientsContainer) handleSearchClient(w http.ResponseWriter, r *ht
data := []map[string]*clientJSON{} data := []map[string]*clientJSON{}
for _, c := range q.Clients { for _, c := range q.Clients {
idStr := c.ID idStr := c.ID
ip, _ := netip.ParseAddr(idStr) if idStr == "" {
c, ok := clients.storage.Find(idStr) break
var cj *clientJSON
if !ok {
cj = clients.findRuntime(ip, idStr)
} else {
cj = clientToJSON(c)
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
} }
data = append(data, map[string]*clientJSON{ data = append(data, map[string]*clientJSON{
idStr: cj, idStr: clients.findClient(idStr),
}) })
} }

View File

@ -16,6 +16,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/client" "github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/schedule" "github.com/AdguardTeam/AdGuardHome/internal/schedule"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/testutil" "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"
@ -410,10 +411,28 @@ func TestClientsContainer_HandleFindClient(t *testing.T) {
} }
func TestClientsContainer_HandleSearchClient(t *testing.T) { func TestClientsContainer_HandleSearchClient(t *testing.T) {
var (
runtimeCli = "runtime_client1"
runtimeCliIP = "3.3.3.3"
blockedCliIP = "4.4.4.4"
nonExistentCliIP = "5.5.5.5"
allowed = false
dissallowed = true
emptyRule = ""
disallowedRule = "disallowed_rule"
)
clients := newClientsContainer(t) clients := newClientsContainer(t)
clients.clientChecker = &testBlockedClientChecker{ clients.clientChecker = &testBlockedClientChecker{
onIsBlockedClient: func(ip netip.Addr, clientID string) (ok bool, rule string) { onIsBlockedClient: func(ip netip.Addr, _ string) (ok bool, rule string) {
return false, "" if ip == netip.MustParseAddr(blockedCliIP) {
return true, disallowedRule
}
return false, emptyRule
}, },
} }
@ -429,11 +448,13 @@ func TestClientsContainer_HandleSearchClient(t *testing.T) {
assertPersistentClients(t, clients, []*client.Persistent{clientOne, clientTwo}) assertPersistentClients(t, clients, []*client.Persistent{clientOne, clientTwo})
clients.UpdateAddress(ctx, netip.MustParseAddr(runtimeCliIP), runtimeCli, nil)
testCases := []struct { testCases := []struct {
name string name string
query *searchQueryJSON query *searchQueryJSON
wantCode int wantPersistent []*client.Persistent
wantClient []*client.Persistent wantRuntime *clientJSON
}{{ }{{
name: "single", name: "single",
query: &searchQueryJSON{ query: &searchQueryJSON{
@ -441,8 +462,7 @@ func TestClientsContainer_HandleSearchClient(t *testing.T) {
ID: testClientIP1, ID: testClientIP1,
}}, }},
}, },
wantCode: http.StatusOK, wantPersistent: []*client.Persistent{clientOne},
wantClient: []*client.Persistent{clientOne},
}, { }, {
name: "multiple", name: "multiple",
query: &searchQueryJSON{ query: &searchQueryJSON{
@ -452,8 +472,47 @@ func TestClientsContainer_HandleSearchClient(t *testing.T) {
ID: testClientIP2, ID: testClientIP2,
}}, }},
}, },
wantCode: http.StatusOK, wantPersistent: []*client.Persistent{clientOne, clientTwo},
wantClient: []*client.Persistent{clientOne, clientTwo}, }, {
name: "runtime",
query: &searchQueryJSON{
Clients: []searchClientJSON{{
ID: runtimeCliIP,
}},
},
wantRuntime: &clientJSON{
Name: runtimeCli,
IDs: []string{runtimeCliIP},
Disallowed: &allowed,
DisallowedRule: &emptyRule,
WHOIS: &whois.Info{},
},
}, {
name: "blocked_access",
query: &searchQueryJSON{
Clients: []searchClientJSON{{
ID: blockedCliIP,
}},
},
wantRuntime: &clientJSON{
IDs: []string{blockedCliIP},
Disallowed: &dissallowed,
DisallowedRule: &disallowedRule,
WHOIS: &whois.Info{},
},
}, {
name: "non_existing_client",
query: &searchQueryJSON{
Clients: []searchClientJSON{{
ID: nonExistentCliIP,
}},
},
wantRuntime: &clientJSON{
IDs: []string{nonExistentCliIP},
Disallowed: &allowed,
DisallowedRule: &emptyRule,
WHOIS: &whois.Info{},
},
}} }}
for _, tc := range testCases { for _, tc := range testCases {
@ -469,7 +528,7 @@ func TestClientsContainer_HandleSearchClient(t *testing.T) {
rw := httptest.NewRecorder() rw := httptest.NewRecorder()
clients.handleSearchClient(rw, r) clients.handleSearchClient(rw, r)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tc.wantCode, rw.Code) require.Equal(t, http.StatusOK, rw.Code)
body, err = io.ReadAll(rw.Body) body, err = io.ReadAll(rw.Body)
require.NoError(t, err) require.NoError(t, err)
@ -478,7 +537,17 @@ func TestClientsContainer_HandleSearchClient(t *testing.T) {
err = json.Unmarshal(body, &clientData) err = json.Unmarshal(body, &clientData)
require.NoError(t, err) require.NoError(t, err)
assertPersistentClientsData(t, clients, clientData, tc.wantClient) if tc.wantPersistent != nil {
assertPersistentClientsData(t, clients, clientData, tc.wantPersistent)
return
}
require.Len(t, clientData, 1)
require.Len(t, clientData[0], 1)
rc := clientData[0][tc.wantRuntime.IDs[0]]
assert.Equal(t, tc.wantRuntime, rc)
}) })
} }
} }

View File

@ -13,9 +13,8 @@
### New client APIs ### New client APIs
* The new `POST /control/clients/search` HTTP API allows config updates. * The new `POST /control/clients/search` HTTP API allows config updates. It
accepts a JSON object with the following format:
These APIs accept and return a JSON object with the following format:
```json ```json
{ {

View File

@ -2779,8 +2779,8 @@
'clients': 'clients':
'type': 'array' 'type': 'array'
'items': 'items':
'$ref': '#/components/schemas/ClientsIDEntry' '$ref': '#/components/schemas/ClientsSearchRequestItem'
'ClientsIDEntry': 'ClientsSearchRequestItem':
'type': 'object' 'type': 'object'
'properties': 'properties':
'id': 'id':