package main import ( "fmt" "go/ast" "go/parser" "go/token" "io" "io/fs" //"io/fs" "os" "path/filepath" "strings" //"strings" ) func responseModToFactoryMap(fn *ast.FuncDecl) (modMap string) { paramCount := len(fn.Type.Params.List) name := fn.Name.Name var x string switch paramCount { case 0: x = fmt.Sprintf(" rsmModMap[\"%s\"] = func(_ ...string) proxychain.ResponseModification {\n return tx.%s()\n }\n", name, name) default: p := []string{} for i := 0; i < paramCount; i++ { p = append(p, fmt.Sprintf("params[%d]", i)) } params := strings.Join(p, ", ") x = fmt.Sprintf(" rsmModMap[\"%s\"] = func(params ...string) proxychain.ResponseModification {\n return tx.%s(%s)\n }\n", name, name, params) } return x } func responseModCodeGen(dir string) (code string, err error) { fset := token.NewFileSet() files, err := os.ReadDir(dir) if err != nil { panic(err) } factoryMaps := []string{} for _, file := range files { if !shouldGenCodeFor(file) { continue } // Parse each Go file node, err := parser.ParseFile(fset, filepath.Join(dir, file.Name()), nil, parser.ParseComments) if err != nil { return "", err } ast.Inspect(node, func(n ast.Node) bool { fn, ok := n.(*ast.FuncDecl) if ok && fn.Recv == nil && fn.Name.IsExported() { factoryMaps = append(factoryMaps, responseModToFactoryMap(fn)) } return true }) } code = fmt.Sprintf(` package ruleset_v2 // DO NOT EDIT THIS FILE. It is automatically generated by ladder/proxychain/codegen/codegen.go // The purpose of this is serialization of rulesets from JSON or YAML into functional options suitable // for use in proxychains. import ( "github.com/everywall/ladder/proxychain" tx "github.com/everywall/ladder/proxychain/responsemodifiers" ) type ResponseModifierFactory func(params ...string) proxychain.ResponseModification var rsmModMap map[string]ResponseModifierFactory func init() { rsmModMap = make(map[string]ResponseModifierFactory) %s }`, strings.Join(factoryMaps, "\n")) // fmt.Println(code) return code, nil } func requestModToFactoryMap(fn *ast.FuncDecl) (modMap string) { paramCount := len(fn.Type.Params.List) name := fn.Name.Name var x string switch paramCount { case 0: x = fmt.Sprintf(" rqmModMap[\"%s\"] = func(_ ...string) proxychain.RequestModification {\n return rx.%s()\n }\n", name, name) default: p := []string{} for i := 0; i < paramCount; i++ { p = append(p, fmt.Sprintf("params[%d]", i)) } params := strings.Join(p, ", ") x = fmt.Sprintf(" rqmModMap[\"%s\"] = func(params ...string) proxychain.RequestModification {\n return rx.%s(%s)\n }\n", name, name, params) } return x } func requestModCodeGen(dir string) (code string, err error) { fset := token.NewFileSet() files, err := os.ReadDir(dir) if err != nil { panic(err) } factoryMaps := []string{} for _, file := range files { if !shouldGenCodeFor(file) { continue } // Parse each Go file node, err := parser.ParseFile(fset, filepath.Join(dir, file.Name()), nil, parser.ParseComments) if err != nil { return "", err } ast.Inspect(node, func(n ast.Node) bool { fn, ok := n.(*ast.FuncDecl) if ok && fn.Recv == nil && fn.Name.IsExported() { factoryMaps = append(factoryMaps, requestModToFactoryMap(fn)) } return true }) } code = fmt.Sprintf(` package ruleset_v2 // DO NOT EDIT THIS FILE. It is automatically generated by ladder/proxychain/codegen/codegen.go // The purpose of this is serialization of rulesets from JSON or YAML into functional options suitable // for use in proxychains. import ( "github.com/everywall/ladder/proxychain" rx "github.com/everywall/ladder/proxychain/requestmodifiers" ) type RequestModifierFactory func(params ...string) proxychain.RequestModification var rqmModMap map[string]RequestModifierFactory func init() { rqmModMap = make(map[string]RequestModifierFactory) %s }`, strings.Join(factoryMaps, "\n")) // fmt.Println(code) return code, nil } func shouldGenCodeFor(file fs.DirEntry) bool { if file.IsDir() { return false } if filepath.Ext(file.Name()) != ".go" { return false } if strings.HasSuffix(file.Name(), "_test.go") { return false } return true } func main() { rqmCode, err := requestModCodeGen("../requestmodifiers/") if err != nil { panic(err) } // fmt.Println(rqmCode) fq, err := os.Create("../ruleset/rule_reqmod_types.gen.go") if err != nil { panic(err) } _, err = io.WriteString(fq, rqmCode) if err != nil { panic(err) } rsmCode, err := responseModCodeGen("../responsemodifiers/") if err != nil { panic(err) } // fmt.Println(rsmCode) fs, err := os.Create("../ruleset/rule_resmod_types.gen.go") if err != nil { panic(err) } _, err = io.WriteString(fs, rsmCode) if err != nil { panic(err) } }