Skip to content
Snippets Groups Projects
match.go 1.43 KiB
Newer Older
package metrics

import "strings"

// treeNode is used for domain whitelisting.
type treeNode struct {
	Leaf      bool
	Value     string
	FullValue string
	SubNodes  []*treeNode
}

func (t *treeNode) findOrCreateSubNode(v string) *treeNode {
	if t.SubNodes == nil {
		t.SubNodes = []*treeNode{}
	}

	for _, n := range t.SubNodes {
		if !n.Leaf && n.Value == v {
			return n
		}
	}
	node := &treeNode{Value: v}
	t.SubNodes = append(t.SubNodes, node)
	return node
}

func (t *treeNode) getMatch(s []string) string {
	if t.Leaf || len(t.SubNodes) == 0 || len(s) == 0 {
		return ""
	}

	for _, node := range t.SubNodes {
		if node.Value == "*" || node.Value == s[0] {
			if node.Leaf {
				return node.FullValue
			}
			if match := node.getMatch(s[1:]); match != "" {
				return match
			}
		}
	}

	return ""
}

func parseWhitelistSlice(hostnameWhitelist []string) *treeNode {
	// NOTE: using arrays because the provided order is important (maps would be a check if part in in map,
	// then check for *, which works but doesn't maintain order)
	tree := &treeNode{SubNodes: []*treeNode{}}
	for _, d := range hostnameWhitelist {
		split := strings.Split(d, ".")

		currentNode := tree
		for i, s := range split {
			currentNode = currentNode.findOrCreateSubNode(s)

			if i+1 == len(split) {
				currentNode.Leaf = true
				currentNode.FullValue = d
				continue
			}
			if currentNode.SubNodes == nil {
				currentNode.SubNodes = []*treeNode{}
			}
		}
	}
	return tree
}