Skip to content

Commit b062416

Browse files
authored
Feat: Add FallbackCommand for HTTP Strategy, refactor packages strategies (#175)
Add FallbackCommand for HTTP Strategy, refactor packages strategies, improve histories implementations.
1 parent 933f029 commit b062416

File tree

10 files changed

+377
-250
lines changed

10 files changed

+377
-250
lines changed

builder/builder.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ package builder
33
import (
44
"errors"
55
"fmt"
6+
"io"
7+
"net/http"
8+
"os"
9+
610
"github.com/mariocandela/beelzebub/v3/parser"
711
"github.com/mariocandela/beelzebub/v3/plugins"
812
"github.com/mariocandela/beelzebub/v3/protocols"
9-
"github.com/mariocandela/beelzebub/v3/protocols/strategies"
13+
"github.com/mariocandela/beelzebub/v3/protocols/strategies/HTTP"
14+
"github.com/mariocandela/beelzebub/v3/protocols/strategies/SSH"
15+
"github.com/mariocandela/beelzebub/v3/protocols/strategies/TCP"
1016
"github.com/mariocandela/beelzebub/v3/tracer"
11-
"io"
12-
"net/http"
13-
"os"
1417

1518
"github.com/prometheus/client_golang/prometheus/promhttp"
1619
amqp "github.com/rabbitmq/amqp091-go"
@@ -106,9 +109,9 @@ Honeypot Framework, happy hacking!`)
106109
}()
107110

108111
// Init Protocol strategies
109-
secureShellStrategy := &strategies.SSHStrategy{}
110-
hypertextTransferProtocolStrategy := &strategies.HTTPStrategy{}
111-
transmissionControlProtocolStrategy := &strategies.TCPStrategy{}
112+
secureShellStrategy := &SSH.SSHStrategy{}
113+
hypertextTransferProtocolStrategy := &HTTP.HTTPStrategy{}
114+
transmissionControlProtocolStrategy := &TCP.TCPStrategy{}
112115

113116
// Init Tracer strategies, and set the trace strategy default HTTP
114117
protocolManager := protocols.InitProtocolManager(b.traceStrategy, hypertextTransferProtocolStrategy)
@@ -122,7 +125,7 @@ Honeypot Framework, happy hacking!`)
122125
return err
123126
} else {
124127
if len(honeypotsConfiguration) == 0 {
125-
return errors.New("No honeypots configuration found")
128+
return errors.New("no honeypots configuration found")
126129
}
127130
b.beelzebubServicesConfiguration = honeypotsConfiguration
128131
}
@@ -132,20 +135,16 @@ Honeypot Framework, happy hacking!`)
132135
switch beelzebubServiceConfiguration.Protocol {
133136
case "http":
134137
protocolManager.SetProtocolStrategy(hypertextTransferProtocolStrategy)
135-
break
136138
case "ssh":
137139
protocolManager.SetProtocolStrategy(secureShellStrategy)
138-
break
139140
case "tcp":
140141
protocolManager.SetProtocolStrategy(transmissionControlProtocolStrategy)
141-
break
142142
default:
143-
log.Fatalf("Protocol %s not managed", beelzebubServiceConfiguration.Protocol)
144-
continue
143+
log.Fatalf("protocol %s not managed", beelzebubServiceConfiguration.Protocol)
145144
}
146145

147146
if err := protocolManager.InitService(beelzebubServiceConfiguration); err != nil {
148-
return errors.New(fmt.Sprintf("Error during init protocol: %s, %s", beelzebubServiceConfiguration.Protocol, err.Error()))
147+
return fmt.Errorf("error during init protocol: %s, %s", beelzebubServiceConfiguration.Protocol, err.Error())
149148
}
150149
}
151150

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/sirupsen/logrus v1.9.3
1414
github.com/stretchr/testify v1.10.0
1515
golang.org/x/crypto v0.33.0
16+
golang.org/x/term v0.29.0
1617
gopkg.in/yaml.v3 v3.0.1
1718
)
1819

@@ -33,6 +34,5 @@ require (
3334
github.com/prometheus/procfs v0.15.1 // indirect
3435
golang.org/x/net v0.33.0 // indirect
3536
golang.org/x/sys v0.30.0 // indirect
36-
golang.org/x/term v0.29.0 // indirect
3737
google.golang.org/protobuf v1.34.2 // indirect
3838
)

historystore/history_store.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package historystore
2+
3+
import (
4+
"sync"
5+
6+
"github.com/mariocandela/beelzebub/v3/plugins"
7+
)
8+
9+
// HistoryStore is a thread-safe structure for storing Messages used to build LLM Context.
10+
type HistoryStore struct {
11+
sync.RWMutex
12+
sessions map[string][]plugins.Message
13+
}
14+
15+
// NewHistoryStore returns a prepared HistoryStore
16+
func NewHistoryStore() *HistoryStore {
17+
return &HistoryStore{
18+
sessions: make(map[string][]plugins.Message),
19+
}
20+
}
21+
22+
// HasKey returns true if the supplied key exists in the map.
23+
func (hs *HistoryStore) HasKey(key string) bool {
24+
hs.RLock()
25+
defer hs.RUnlock()
26+
_, ok := hs.sessions[key]
27+
return ok
28+
}
29+
30+
// Query returns the value stored at the map
31+
func (hs *HistoryStore) Query(key string) []plugins.Message {
32+
hs.RLock()
33+
defer hs.RUnlock()
34+
return hs.sessions[key]
35+
}
36+
37+
// Append will add the slice of Mesages to the entry for the key.
38+
// If the map has not yet been initalised, then a new map is created.
39+
func (hs *HistoryStore) Append(key string, message ...plugins.Message) {
40+
hs.Lock()
41+
defer hs.Unlock()
42+
// In the unexpected case that the map has not yet been initalised, create it.
43+
if hs.sessions == nil {
44+
hs.sessions = make(map[string][]plugins.Message)
45+
}
46+
hs.sessions[key] = append(hs.sessions[key], message...)
47+
}

historystore/history_store_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package historystore
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mariocandela/beelzebub/v3/plugins"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestNewHistoryStore(t *testing.T) {
11+
hs := NewHistoryStore()
12+
assert.NotNil(t, hs)
13+
assert.NotNil(t, hs.sessions)
14+
}
15+
16+
func TestHasKey(t *testing.T) {
17+
hs := NewHistoryStore()
18+
hs.sessions["testKey"] = []plugins.Message{}
19+
assert.True(t, hs.HasKey("testKey"))
20+
assert.False(t, hs.HasKey("nonExistentKey"))
21+
}
22+
23+
func TestQuery(t *testing.T) {
24+
hs := NewHistoryStore()
25+
expectedMessages := []plugins.Message{{Role: "user", Content: "Hello"}}
26+
hs.sessions["testKey"] = expectedMessages
27+
actualMessages := hs.Query("testKey")
28+
assert.Equal(t, expectedMessages, actualMessages)
29+
}
30+
31+
func TestAppend(t *testing.T) {
32+
hs := NewHistoryStore()
33+
message1 := plugins.Message{Role: "user", Content: "Hello"}
34+
message2 := plugins.Message{Role: "assistant", Content: "Hi"}
35+
hs.Append("testKey", message1)
36+
assert.Equal(t, []plugins.Message{message1}, hs.sessions["testKey"])
37+
hs.Append("testKey", message2)
38+
assert.Equal(t, []plugins.Message{message1, message2}, hs.sessions["testKey"])
39+
}
40+
41+
func TestAppendNilSessions(t *testing.T) {
42+
hs := &HistoryStore{}
43+
message1 := plugins.Message{Role: "user", Content: "Hello"}
44+
hs.Append("testKey", message1)
45+
assert.NotNil(t, hs.sessions)
46+
assert.Equal(t, []plugins.Message{message1}, hs.sessions["testKey"])
47+
}

parser/configurations_parser.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type BeelzebubServiceConfiguration struct {
6262
Protocol string `yaml:"protocol"`
6363
Address string `yaml:"address"`
6464
Commands []Command `yaml:"commands"`
65+
FallbackCommand Command `yaml:"fallbackCommand"`
6566
ServerVersion string `yaml:"serverVersion"`
6667
ServerName string `yaml:"serverName"`
6768
DeadlineTimeoutSeconds int `yaml:"deadlineTimeoutSeconds"`

parser/configurations_parser_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ commands:
5656
handler: "login"
5757
headers:
5858
- "Content-Type: text/html"
59+
fallbackCommand:
60+
handler: "404 Not Found!"
61+
statusCode: 404
5962
plugin:
6063
openAISecretKey: "qwerty"
6164
llmModel: "llama3"
@@ -134,6 +137,8 @@ func TestReadConfigurationsServicesValid(t *testing.T) {
134137
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Handler, "login")
135138
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands[0].Headers), 1)
136139
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Headers[0], "Content-Type: text/html")
140+
assert.Equal(t, firstBeelzebubServiceConfiguration.FallbackCommand.Handler, "404 Not Found!")
141+
assert.Equal(t, firstBeelzebubServiceConfiguration.FallbackCommand.StatusCode, 404)
137142
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.OpenAISecretKey, "qwerty")
138143
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.LLMModel, "llama3")
139144
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.LLMProvider, "ollama")
@@ -176,7 +181,8 @@ func TestGelAllFilesNameByDirNameError(t *testing.T) {
176181
files, err := gelAllFilesNameByDirName("nosuchfile")
177182

178183
assert.Nil(t, files)
179-
assert.Equal(t, "open nosuchfile: no such file or directory", err.Error())
184+
// Windows and Linux return slightly different error strings, but share a common prefix, so check for that.
185+
assert.Contains(t, err.Error(), "open nosuchfile: ")
180186
}
181187

182188
func TestReadFileBytesByFilePath(t *testing.T) {

0 commit comments

Comments
 (0)