platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
105
selective-vpn-api/app/transport_owner_locks_clear.go
Normal file
105
selective-vpn-api/app/transport_owner_locks_clear.go
Normal file
@@ -0,0 +1,105 @@
|
||||
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[:])
|
||||
}
|
||||
Reference in New Issue
Block a user