Move most code under lib
This commit is contained in:
14
lib/policy/challenge.go
Normal file
14
lib/policy/challenge.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package policy
|
||||
|
||||
type Challenge struct {
|
||||
Mode string `yaml:"mode"`
|
||||
Asset *string `yaml:"asset,omitempty"`
|
||||
Url *string `yaml:"url,omitempty"`
|
||||
|
||||
Parameters map[string]string `json:"parameters,omitempty"`
|
||||
Runtime struct {
|
||||
Mode string `yaml:"mode,omitempty"`
|
||||
Asset string `yaml:"asset,omitempty"`
|
||||
Probability float64 `yaml:"probability,omitempty"`
|
||||
} `yaml:"runtime"`
|
||||
}
|
117
lib/policy/network.go
Normal file
117
lib/policy/network.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/itchyny/gojq"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type Network struct {
|
||||
Url *string `yaml:"url,omitempty"`
|
||||
File *string `yaml:"file,omitempty"`
|
||||
|
||||
JqPath *string `yaml:"jq-path,omitempty"`
|
||||
Regex *string `yaml:"regex,omitempty"`
|
||||
|
||||
Prefixes []string `yaml:"prefixes,omitempty"`
|
||||
}
|
||||
|
||||
func (n Network) FetchPrefixes(c *http.Client) (output []net.IPNet, err error) {
|
||||
if len(n.Prefixes) > 0 {
|
||||
for _, prefix := range n.Prefixes {
|
||||
ipNet, err := parseCIDROrIP(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, ipNet)
|
||||
}
|
||||
}
|
||||
|
||||
var reader io.Reader
|
||||
if n.Url != nil {
|
||||
response, err := c.Get(*n.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode)
|
||||
}
|
||||
reader = response.Body
|
||||
} else if n.File != nil {
|
||||
file, err := os.Open(*n.File)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
reader = file
|
||||
} else {
|
||||
if len(output) > 0 {
|
||||
return output, nil
|
||||
}
|
||||
return nil, errors.New("no url, file or prefixes specified")
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n.JqPath != nil {
|
||||
var jsonData any
|
||||
err = json.Unmarshal(data, &jsonData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query, err := gojq.Parse(*n.JqPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iter := query.Run(jsonData)
|
||||
for {
|
||||
value, more := iter.Next()
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
|
||||
if strValue, ok := value.(string); ok {
|
||||
ipNet, err := parseCIDROrIP(strValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, ipNet)
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid value from jq-query: %v", value)
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
} else if n.Regex != nil {
|
||||
expr, err := regexp.Compile(*n.Regex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefixName := expr.SubexpIndex("prefix")
|
||||
if prefixName == -1 {
|
||||
return nil, fmt.Errorf("invalid regex %q: could not find prefix named match", *n.Regex)
|
||||
}
|
||||
matches := expr.FindAllSubmatch(data, -1)
|
||||
for _, match := range matches {
|
||||
matchName := string(match[prefixName])
|
||||
ipNet, err := parseCIDROrIP(matchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, ipNet)
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("no jq-path or regex specified")
|
||||
}
|
||||
return output, nil
|
||||
}
|
46
lib/policy/policy.go
Normal file
46
lib/policy/policy.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func parseCIDROrIP(value string) (net.IPNet, error) {
|
||||
_, ipNet, err := net.ParseCIDR(value)
|
||||
if err != nil {
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil {
|
||||
return net.IPNet{}, fmt.Errorf("failed to parse CIDR: %s", err)
|
||||
}
|
||||
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return net.IPNet{
|
||||
IP: ip4,
|
||||
// single ip
|
||||
Mask: net.CIDRMask(len(ip4)*8, len(ip4)*8),
|
||||
}, nil
|
||||
}
|
||||
return net.IPNet{
|
||||
IP: ip,
|
||||
// single ip
|
||||
Mask: net.CIDRMask(len(ip)*8, len(ip)*8),
|
||||
}, nil
|
||||
} else if ipNet != nil {
|
||||
return *ipNet, nil
|
||||
} else {
|
||||
return net.IPNet{}, errors.New("invalid CIDR")
|
||||
}
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
|
||||
// Networks map of networks and prefixes to be loaded
|
||||
Networks map[string][]Network `yaml:"networks"`
|
||||
|
||||
Conditions map[string][]string `yaml:"conditions"`
|
||||
|
||||
Challenges map[string]Challenge `yaml:"challenges"`
|
||||
|
||||
Rules []Rule `yaml:"rules"`
|
||||
}
|
20
lib/policy/rule.go
Normal file
20
lib/policy/rule.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package policy
|
||||
|
||||
type RuleAction string
|
||||
|
||||
const (
|
||||
RuleActionPASS RuleAction = "PASS"
|
||||
RuleActionDENY RuleAction = "DENY"
|
||||
RuleActionBLOCK RuleAction = "BLOCK"
|
||||
RuleActionCHALLENGE RuleAction = "CHALLENGE"
|
||||
RuleActionCHECK RuleAction = "CHECK"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Name string `yaml:"name"`
|
||||
Conditions []string `yaml:"conditions"`
|
||||
|
||||
Action string `yaml:"action"`
|
||||
|
||||
Challenges []string `yaml:"challenges"`
|
||||
}
|
Reference in New Issue
Block a user