Files
beelzebub/protocols/strategies/http.go
Mario Candela 93d7804ba3 Feat: add LMM Honeypot HTTP Server (#110)
* add LMM Honeypot HTTP Server

* improve unit test code coverage

* integrate LLM plugin into http honeypot strategy

* improve code coverage

* fix typos

* improve OpenAI plugin with gpt-4, adpt new API amd map new object
2024-06-23 10:55:06 +02:00

129 lines
3.7 KiB
Go

package strategies
import (
"fmt"
"github.com/mariocandela/beelzebub/v3/parser"
"github.com/mariocandela/beelzebub/v3/plugins"
"github.com/mariocandela/beelzebub/v3/tracer"
"io"
"net/http"
"regexp"
"strings"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
type HTTPStrategy struct {
beelzebubServiceConfiguration parser.BeelzebubServiceConfiguration
}
func (httpStrategy HTTPStrategy) Init(beelzebubServiceConfiguration parser.BeelzebubServiceConfiguration, tr tracer.Tracer) error {
httpStrategy.beelzebubServiceConfiguration = beelzebubServiceConfiguration
serverMux := http.NewServeMux()
serverMux.HandleFunc("/", func(responseWriter http.ResponseWriter, request *http.Request) {
traceRequest(request, tr, beelzebubServiceConfiguration.Description)
for _, command := range httpStrategy.beelzebubServiceConfiguration.Commands {
matched, err := regexp.MatchString(command.Regex, request.RequestURI)
if err != nil {
log.Errorf("Error regex: %s, %s", command.Regex, err.Error())
continue
}
if matched {
responseHTTPBody := command.Handler
if command.Plugin == plugins.ChatGPTPluginName {
openAIGPTVirtualTerminal := plugins.Init(make([]plugins.Message, 0), beelzebubServiceConfiguration.Plugin.OpenAISecretKey, tracer.HTTP)
command := fmt.Sprintf("%s %s", request.Method, request.RequestURI)
if completions, err := openAIGPTVirtualTerminal.GetCompletions(command); err != nil {
log.Errorf("Error GetCompletions: %s, %s", command, err.Error())
responseHTTPBody = "404 Not Found!"
} else {
responseHTTPBody = completions
}
}
setResponseHeaders(responseWriter, command.Headers, command.StatusCode)
fmt.Fprintf(responseWriter, responseHTTPBody)
break
}
}
})
go func() {
err := http.ListenAndServe(httpStrategy.beelzebubServiceConfiguration.Address, serverMux)
if err != nil {
log.Errorf("Error during init HTTP Protocol: %s", err.Error())
return
}
}()
log.WithFields(log.Fields{
"port": beelzebubServiceConfiguration.Address,
"commands": len(beelzebubServiceConfiguration.Commands),
}).Infof("Init service: %s", beelzebubServiceConfiguration.Description)
return nil
}
func traceRequest(request *http.Request, tr tracer.Tracer, HoneypotDescription string) {
bodyBytes, err := io.ReadAll(request.Body)
body := ""
if err == nil {
body = string(bodyBytes)
}
tr.TraceEvent(tracer.Event{
Msg: "HTTP New request",
RequestURI: request.RequestURI,
Protocol: tracer.HTTP.String(),
HTTPMethod: request.Method,
Body: body,
HostHTTPRequest: request.Host,
UserAgent: request.UserAgent(),
Cookies: mapCookiesToString(request.Cookies()),
Headers: mapHeaderToString(request.Header),
Status: tracer.Stateless.String(),
RemoteAddr: request.RemoteAddr,
ID: uuid.New().String(),
Description: HoneypotDescription,
})
}
func mapHeaderToString(headers http.Header) string {
headersString := ""
for key := range headers {
for _, values := range headers[key] {
headersString += fmt.Sprintf("[Key: %s, values: %s],", key, values)
}
}
return headersString
}
func mapCookiesToString(cookies []*http.Cookie) string {
cookiesString := ""
for _, cookie := range cookies {
cookiesString += cookie.String()
}
return cookiesString
}
func setResponseHeaders(responseWriter http.ResponseWriter, headers []string, statusCode int) {
for _, headerStr := range headers {
keyValue := strings.Split(headerStr, ":")
if len(keyValue) > 1 {
responseWriter.Header().Add(keyValue[0], keyValue[1])
}
}
// http.StatusText(statusCode): empty string if the code is unknown.
if len(http.StatusText(statusCode)) > 0 {
responseWriter.WriteHeader(statusCode)
}
}