ui_contract_test.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. package firewall
  2. import (
  3. "golang.org/x/net/html"
  4. "os"
  5. "strings"
  6. "testing"
  7. )
  8. func TestUIOnlyOffersImplementedFirewallOptions(t *testing.T) {
  9. data, err := os.ReadFile("../web/static/index.html")
  10. if err != nil {
  11. t.Fatal(err)
  12. }
  13. doc, err := html.Parse(strings.NewReader(string(data)))
  14. if err != nil {
  15. t.Fatal(err)
  16. }
  17. caps := Capabilities()
  18. actions := caps["actions"].(map[string][]string)
  19. fields := caps["fields"].(map[string][]string)
  20. 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"}
  21. contains := func(items []string, s string) bool {
  22. for _, item := range items {
  23. if item == s {
  24. return true
  25. }
  26. }
  27. return false
  28. }
  29. var visit func(*html.Node)
  30. visit = func(n *html.Node) {
  31. attrs := map[string]string{}
  32. for _, a := range n.Attr {
  33. attrs[a.Key] = a.Val
  34. }
  35. id := attrs["id"]
  36. for prefix, kind := range map[string]string{"fw": "filter", "nat": "nat", "mangle": "mangle"} {
  37. if strings.HasPrefix(id, prefix+"-val-") {
  38. key := strings.TrimPrefix(id, prefix+"-val-")
  39. field := keyMap[key]
  40. if field == "" || !contains(fields[kind], field) {
  41. t.Errorf("UI control %s has no supported API/compiler field", id)
  42. }
  43. }
  44. }
  45. for _, kind := range []string{"filter", "nat", "mangle"} {
  46. if n.Type == html.ElementNode && n.Data == "select" && id == kind+"-modal-action" {
  47. for child := n.FirstChild; child != nil; child = child.NextSibling {
  48. if child.Type == html.ElementNode && child.Data == "option" {
  49. for _, a := range child.Attr {
  50. if a.Key == "value" && !contains(actions[kind], a.Val) {
  51. t.Errorf("unsupported %s UI action %s", kind, a.Val)
  52. }
  53. }
  54. }
  55. }
  56. }
  57. }
  58. for c := n.FirstChild; c != nil; c = c.NextSibling {
  59. visit(c)
  60. }
  61. }
  62. visit(doc)
  63. }