implement proper ruleset json serializer
This commit is contained in:
@@ -4,25 +4,35 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"ladder/proxychain"
|
"ladder/proxychain"
|
||||||
"reflect"
|
// _ "gopkg.in/yaml.v3"
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
_ "gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Domains []string
|
Domains []string
|
||||||
RequestModifications []proxychain.RequestModification
|
RequestModifications []proxychain.RequestModification
|
||||||
|
_rqms []_rqm // internal represenation of RequestModifications
|
||||||
ResponseModifications []proxychain.ResponseModification
|
ResponseModifications []proxychain.ResponseModification
|
||||||
|
_rsms []_rsm // internal represenation of ResponseModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal represenation of ResponseModifications
|
||||||
|
type _rsm struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Params []string `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal represenation of RequestModifications
|
||||||
|
type _rqm struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Params []string `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement type encoding/json/Marshaler
|
// implement type encoding/json/Marshaler
|
||||||
func (rule *Rule) UnmarshalJSON(data []byte) error {
|
func (rule *Rule) UnmarshalJSON(data []byte) error {
|
||||||
type Aux struct {
|
type Aux struct {
|
||||||
Domains []string `json:"domains"`
|
Domains []string `json:"domains"`
|
||||||
RequestModifications []string `json:"request_modifications"`
|
RequestModifications []_rqm `json:"request_modifications"`
|
||||||
ResponseModifications []string `json:"response_modifications"`
|
ResponseModifications []_rsm `json:"response_modifications"`
|
||||||
}
|
}
|
||||||
|
|
||||||
aux := &Aux{}
|
aux := &Aux{}
|
||||||
@@ -30,163 +40,41 @@ func (rule *Rule) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Println(aux.Domains)
|
|
||||||
rule.Domains = aux.Domains
|
rule.Domains = aux.Domains
|
||||||
|
rule._rqms = aux.RequestModifications
|
||||||
|
rule._rsms = aux.ResponseModifications
|
||||||
|
|
||||||
// convert requestModification function call string into actual functional option
|
// convert requestModification function call string into actual functional option
|
||||||
for _, rqmModStr := range aux.RequestModifications {
|
for _, rqm := range aux.RequestModifications {
|
||||||
name, params, err := parseFuncCall(rqmModStr)
|
f, exists := rqmModMap[rqm.Name]
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalJSON invalid function call syntax => '%s'", err)
|
|
||||||
}
|
|
||||||
f, exists := rqmModMap[name]
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return fmt.Errorf("Rule::UnmarshalJSON => requestModifier '%s' does not exist, please check spelling", name)
|
return fmt.Errorf("Rule::UnmarshalJSON => requestModifier '%s' does not exist, please check spelling", rqm.Name)
|
||||||
}
|
}
|
||||||
rule.RequestModifications = append(rule.RequestModifications, f(params...))
|
rule.RequestModifications = append(rule.RequestModifications, f(rqm.Params...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert responseModification function call string into actual functional option
|
// convert responseModification function call string into actual functional option
|
||||||
for _, rsmModStr := range aux.ResponseModifications {
|
for _, rsm := range aux.ResponseModifications {
|
||||||
name, params, err := parseFuncCall(rsmModStr)
|
f, exists := rsmModMap[rsm.Name]
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalJSON invalid function call syntax => '%s'", err)
|
|
||||||
}
|
|
||||||
f, exists := rsmModMap[name]
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return fmt.Errorf("Rule::UnmarshalJSON => responseModifier '%s' does not exist, please check spelling", name)
|
return fmt.Errorf("Rule::UnmarshalJSON => responseModifier '%s' does not exist, please check spelling", rsm.Name)
|
||||||
}
|
}
|
||||||
rule.ResponseModifications = append(rule.ResponseModifications, f(params...))
|
rule.ResponseModifications = append(rule.ResponseModifications, f(rsm.Params...))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// not fully possible to go from rule to JSON rule because
|
|
||||||
// reflection cannot get the parameters of the functional options
|
|
||||||
// of requestmodifiers and responsemodifiers
|
|
||||||
func (r *Rule) MarshalJSON() ([]byte, error) {
|
func (r *Rule) MarshalJSON() ([]byte, error) {
|
||||||
type Aux struct {
|
aux := struct {
|
||||||
Domains []string `json:"domains"`
|
Domains []string `json:"domains"`
|
||||||
RequestModifications []string `json:"request_modifications"`
|
RequestModifications []_rqm `json:"request_modifications"`
|
||||||
ResponseModifications []string `json:"response_modifications"`
|
ResponseModifications []_rsm `json:"response_modifications"`
|
||||||
}
|
}{
|
||||||
aux := &Aux{}
|
Domains: r.Domains,
|
||||||
aux.Domains = r.Domains
|
RequestModifications: r._rqms,
|
||||||
|
ResponseModifications: r._rsms,
|
||||||
for _, rqmMod := range r.RequestModifications {
|
|
||||||
fnName := getFunctionName(rqmMod)
|
|
||||||
aux.RequestModifications = append(aux.RequestModifications, fnName)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsmMod := range r.ResponseModifications {
|
|
||||||
fnName := getFunctionName(rsmMod)
|
|
||||||
aux.ResponseModifications = append(aux.ResponseModifications, fnName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(aux)
|
return json.Marshal(aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFunctionName returns the name of the function
|
|
||||||
func getFunctionName(i interface{}) string {
|
|
||||||
// Get the value of the interface
|
|
||||||
val := reflect.ValueOf(i)
|
|
||||||
|
|
||||||
// Ensure it's a function
|
|
||||||
if val.Kind() != reflect.Func {
|
|
||||||
return "Not a function"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the pointer to the function
|
|
||||||
ptr := val.Pointer()
|
|
||||||
|
|
||||||
// Get the function details from runtime
|
|
||||||
funcForPc := runtime.FuncForPC(ptr)
|
|
||||||
|
|
||||||
if funcForPc == nil {
|
|
||||||
return "Unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the name of the function
|
|
||||||
return extractShortName(funcForPc.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractShortName extracts the short function name from the full name
|
|
||||||
func extractShortName(fullName string) string {
|
|
||||||
parts := strings.Split(fullName, ".")
|
|
||||||
if len(parts) > 0 {
|
|
||||||
// Assuming the function name is always the second last part
|
|
||||||
return parts[len(parts)-2]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// == YAML
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for Rule
|
|
||||||
func (rule *Rule) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
type Aux struct {
|
|
||||||
Domains []string `yaml:"domains"`
|
|
||||||
RequestModifications []string `yaml:"request_modifications"`
|
|
||||||
ResponseModifications []string `yaml:"response_modifications"`
|
|
||||||
}
|
|
||||||
|
|
||||||
aux := &Aux{}
|
|
||||||
if err := unmarshal(aux); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rule.Domains = aux.Domains
|
|
||||||
|
|
||||||
// Process requestModifications
|
|
||||||
for _, rqmModStr := range aux.RequestModifications {
|
|
||||||
name, params, err := parseFuncCall(rqmModStr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalYAML invalid function call syntax => '%s'", err)
|
|
||||||
}
|
|
||||||
f, exists := rqmModMap[name]
|
|
||||||
if !exists {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalYAML => requestModifier '%s' does not exist, please check spelling", name)
|
|
||||||
}
|
|
||||||
rule.RequestModifications = append(rule.RequestModifications, f(params...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process responseModifications
|
|
||||||
for _, rsmModStr := range aux.ResponseModifications {
|
|
||||||
name, params, err := parseFuncCall(rsmModStr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalYAML invalid function call syntax => '%s'", err)
|
|
||||||
}
|
|
||||||
f, exists := rsmModMap[name]
|
|
||||||
if !exists {
|
|
||||||
return fmt.Errorf("Rule::UnmarshalYAML => responseModifier '%s' does not exist, please check spelling", name)
|
|
||||||
}
|
|
||||||
rule.ResponseModifications = append(rule.ResponseModifications, f(params...))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Rule) MarshalYAML() (interface{}, error) {
|
|
||||||
type Aux struct {
|
|
||||||
Domains []string `yaml:"domains"`
|
|
||||||
RequestModifications []string `yaml:"request_modifications"`
|
|
||||||
ResponseModifications []string `yaml:"response_modifications"`
|
|
||||||
}
|
|
||||||
|
|
||||||
aux := &Aux{
|
|
||||||
Domains: r.Domains,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rqmMod := range r.RequestModifications {
|
|
||||||
// Assuming getFunctionName returns a string representation of the function
|
|
||||||
fnName := getFunctionName(rqmMod)
|
|
||||||
aux.RequestModifications = append(aux.RequestModifications, fnName)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsmMod := range r.ResponseModifications {
|
|
||||||
fnName := getFunctionName(rsmMod)
|
|
||||||
aux.ResponseModifications = append(aux.ResponseModifications, fnName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return aux, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package ruleset_v2
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
yaml "gopkg.in/yaml.v3"
|
//yaml "gopkg.in/yaml.v3"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,13 +13,25 @@ func TestRuleUnmarshalJSON(t *testing.T) {
|
|||||||
"example.com",
|
"example.com",
|
||||||
"www.example.com"
|
"www.example.com"
|
||||||
],
|
],
|
||||||
"request_modifications": [
|
|
||||||
"SpoofUserAgent(\"googlebot\")"
|
|
||||||
],
|
|
||||||
"response_modifications": [
|
"response_modifications": [
|
||||||
"APIContent()",
|
{
|
||||||
"SetContentSecurityPolicy(\"foobar\")",
|
"name": "APIContent",
|
||||||
"SetIncomingCookie(\"authorization-bearer\", \"hunter2\")"
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SetContentSecurityPolicy",
|
||||||
|
"params": ["foobar"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SetIncomingCookie",
|
||||||
|
"params": ["authorization-bearer", "hunter2"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"request_modifications": [
|
||||||
|
{
|
||||||
|
"name": "ForwardRequestHeaders",
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}`
|
}`
|
||||||
|
|
||||||
@@ -54,6 +66,7 @@ func TestRuleUnmarshalJSON(t *testing.T) {
|
|||||||
fmt.Println(string(jsonRule))
|
fmt.Println(string(jsonRule))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func TestRuleUnmarshalYAML(t *testing.T) {
|
func TestRuleUnmarshalYAML(t *testing.T) {
|
||||||
ruleYAML := `
|
ruleYAML := `
|
||||||
domains:
|
domains:
|
||||||
@@ -95,3 +108,4 @@ response_modifications:
|
|||||||
}
|
}
|
||||||
fmt.Println(string(yamlRule))
|
fmt.Println(string(yamlRule))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user