106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package app
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/netip"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type transportOwnerLockClearFilter struct {
|
|
ClientID string
|
|
DestinationIPs []string
|
|
}
|
|
|
|
func normalizeTransportOwnerLockClearRequest(in TransportOwnerLocksClearRequest) (transportOwnerLockClearFilter, error) {
|
|
filter := transportOwnerLockClearFilter{
|
|
ClientID: sanitizeID(in.ClientID),
|
|
}
|
|
seen := map[string]struct{}{}
|
|
appendIP := func(raw string) error {
|
|
v := strings.TrimSpace(raw)
|
|
if v == "" {
|
|
return nil
|
|
}
|
|
addr, err := netip.ParseAddr(v)
|
|
if err != nil || !addr.Is4() {
|
|
return fmt.Errorf("invalid destination ip: %q", raw)
|
|
}
|
|
key := addr.String()
|
|
if _, ok := seen[key]; ok {
|
|
return nil
|
|
}
|
|
seen[key] = struct{}{}
|
|
filter.DestinationIPs = append(filter.DestinationIPs, key)
|
|
return nil
|
|
}
|
|
if err := appendIP(in.DestinationIP); err != nil {
|
|
return transportOwnerLockClearFilter{}, err
|
|
}
|
|
for _, raw := range in.DestinationIPs {
|
|
if err := appendIP(raw); err != nil {
|
|
return transportOwnerLockClearFilter{}, err
|
|
}
|
|
}
|
|
sort.Strings(filter.DestinationIPs)
|
|
if filter.ClientID == "" && len(filter.DestinationIPs) == 0 {
|
|
return transportOwnerLockClearFilter{}, fmt.Errorf("at least one selector is required: client_id or destination_ip(s)")
|
|
}
|
|
return filter, nil
|
|
}
|
|
|
|
func splitTransportOwnerLocksByFilter(items []TransportOwnerLockRecord, filter transportOwnerLockClearFilter) (matched, remaining []TransportOwnerLockRecord) {
|
|
matchIPs := map[string]struct{}{}
|
|
for _, ip := range filter.DestinationIPs {
|
|
matchIPs[ip] = struct{}{}
|
|
}
|
|
matched = make([]TransportOwnerLockRecord, 0, len(items))
|
|
remaining = make([]TransportOwnerLockRecord, 0, len(items))
|
|
for _, it := range items {
|
|
match := true
|
|
if filter.ClientID != "" && sanitizeID(it.ClientID) != filter.ClientID {
|
|
match = false
|
|
}
|
|
if len(matchIPs) > 0 {
|
|
dst := strings.TrimSpace(it.DestinationIP)
|
|
if addr, err := netip.ParseAddr(dst); err == nil && addr.Is4() {
|
|
dst = addr.String()
|
|
}
|
|
if _, ok := matchIPs[dst]; !ok {
|
|
match = false
|
|
}
|
|
}
|
|
if match {
|
|
matched = append(matched, it)
|
|
} else {
|
|
remaining = append(remaining, it)
|
|
}
|
|
}
|
|
return matched, remaining
|
|
}
|
|
|
|
func digestTransportOwnerLocksClear(baseRevision int64, filter transportOwnerLockClearFilter, matched []TransportOwnerLockRecord) string {
|
|
keys := make([]string, 0, len(matched))
|
|
for _, it := range matched {
|
|
keys = append(keys, strings.TrimSpace(it.ClientID)+"|"+strings.TrimSpace(it.DestinationIP))
|
|
}
|
|
sort.Strings(keys)
|
|
payload := struct {
|
|
BaseRevision int64 `json:"base_revision"`
|
|
ClientID string `json:"client_id,omitempty"`
|
|
DestinationIPs []string `json:"destination_ips,omitempty"`
|
|
Matches []string `json:"matches,omitempty"`
|
|
}{
|
|
BaseRevision: baseRevision,
|
|
ClientID: filter.ClientID,
|
|
DestinationIPs: append([]string(nil), filter.DestinationIPs...),
|
|
Matches: keys,
|
|
}
|
|
b, _ := json.Marshal(payload)
|
|
h := sha256.Sum256(b)
|
|
return hex.EncodeToString(h[:])
|
|
}
|