package firewall import ( "golang.org/x/net/html" "os" "strings" "testing" ) func TestUIOnlyOffersImplementedFirewallOptions(t *testing.T) { data, err := os.ReadFile("../web/static/index.html") if err != nil { t.Fatal(err) } doc, err := html.Parse(strings.NewReader(string(data))) if err != nil { t.Fatal(err) } caps := Capabilities() actions := caps["actions"].(map[string][]string) fields := caps["fields"].(map[string][]string) keyMap := map[string]string{"src": "src_address", "dst": "dst_address", "srclist": "src_address_list", "dstlist": "dst_address_list", "srcgeo": "src_geoip", "dstgeo": "dst_geoip", "proto": "protocol", "sport": "src_port", "dport": "dst_port", "anyport": "any_port", "iniface": "in_interface", "outiface": "out_interface", "inifacelist": "in_interface_list", "outifacelist": "out_interface_list", "pktmark": "packet_mark", "connmark": "connection_mark", "routingmark": "routing_mark", "conntype": "connection_type", "content": "content", "srcmac": "src_mac_address", "inbridgeport": "in_bridge_port", "outbridgeport": "out_bridge_port", "ipsec": "ipsec_policy", "dscp": "dscp", "tcpmss": "tcp_mss", "tos": "tos", "pktsize": "packet_size", "random": "random", "tcpflags": "tcp_flags", "icmpoptions": "icmp_options", "ttl": "ttl", "time": "time", "limit": "limit", "nth": "nth", "connlimit": "connection_limit", "srcaddrtype": "src_address_type", "dstaddrtype": "dst_address_type", "ipfragment": "ip_fragment", "logprefix": "log_prefix"} contains := func(items []string, s string) bool { for _, item := range items { if item == s { return true } } return false } var visit func(*html.Node) visit = func(n *html.Node) { attrs := map[string]string{} for _, a := range n.Attr { attrs[a.Key] = a.Val } id := attrs["id"] for prefix, kind := range map[string]string{"fw": "filter", "nat": "nat", "mangle": "mangle"} { if strings.HasPrefix(id, prefix+"-val-") { key := strings.TrimPrefix(id, prefix+"-val-") field := keyMap[key] if field == "" || !contains(fields[kind], field) { t.Errorf("UI control %s has no supported API/compiler field", id) } } } for _, kind := range []string{"filter", "nat", "mangle"} { if n.Type == html.ElementNode && n.Data == "select" && id == kind+"-modal-action" { for child := n.FirstChild; child != nil; child = child.NextSibling { if child.Type == html.ElementNode && child.Data == "option" { for _, a := range child.Attr { if a.Key == "value" && !contains(actions[kind], a.Val) { t.Errorf("unsupported %s UI action %s", kind, a.Val) } } } } } } for c := n.FirstChild; c != nil; c = c.NextSibling { visit(c) } } visit(doc) }