You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
3.6 KiB
157 lines
3.6 KiB
package main
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/matrix-org/gomatrix"
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"git.hacknology.de/projekte/leakybot/internal/config"
|
|
"git.hacknology.de/projekte/leakybot/internal/httputil"
|
|
"git.hacknology.de/projekte/leakybot/internal/power"
|
|
"git.hacknology.de/projekte/leakybot/internal/ruler"
|
|
)
|
|
|
|
const (
|
|
idSeparator = "--"
|
|
)
|
|
|
|
var (
|
|
signals = []os.Signal{syscall.SIGINT, syscall.SIGTERM}
|
|
|
|
log = &logrus.Logger{
|
|
Out: os.Stderr,
|
|
Formatter: &logrus.TextFormatter{
|
|
DisableTimestamp: true,
|
|
},
|
|
Hooks: make(logrus.LevelHooks),
|
|
Level: logrus.InfoLevel,
|
|
ExitFunc: os.Exit,
|
|
ReportCaller: false,
|
|
}
|
|
)
|
|
|
|
func formatID(user, room string) string {
|
|
return strings.Join([]string{user, room}, idSeparator)
|
|
}
|
|
|
|
func splitID(id string) (user, room string) {
|
|
tokens := strings.SplitN(id, idSeparator, 2)
|
|
return tokens[0], tokens[1]
|
|
}
|
|
|
|
func main() {
|
|
cfg, err := config.Get(os.Args[0], os.Args[1:], os.Getenv)
|
|
if err != nil {
|
|
log.Fatalf("Error getting config: %s", err)
|
|
}
|
|
|
|
log.SetLevel(cfg.LogLevel)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
wg := &sync.WaitGroup{}
|
|
|
|
log.Infof("Homeserver: %s User: %s", cfg.Account.HomeServer, cfg.Account.Username)
|
|
client, err := gomatrix.NewClient(cfg.Account.HomeServer, cfg.Account.Username, cfg.Account.AccessToken)
|
|
if err != nil {
|
|
log.Fatalf("Error creating client: %s", err)
|
|
}
|
|
|
|
client.Client = &http.Client{
|
|
Timeout: 60 * time.Second,
|
|
Transport: httputil.ContextTransport(ctx, http.DefaultTransport),
|
|
}
|
|
|
|
rooms, err := client.JoinedRooms()
|
|
if err != nil {
|
|
log.Fatalf("Error retrieving rooms: %s", err)
|
|
}
|
|
|
|
for _, r := range rooms.JoinedRooms {
|
|
log.Debugf("Found room: %s", r)
|
|
}
|
|
|
|
rulerFuncs := ruler.Funcs{
|
|
Warn: func(id string) error {
|
|
user, room := splitID(id)
|
|
return power.ModifyLevel(log, client, room, user, -1)
|
|
},
|
|
Unwarn: func(id string) error {
|
|
user, room := splitID(id)
|
|
return power.RemoveLevel(log, client, room, user)
|
|
},
|
|
Ban: func(id string) error {
|
|
user, room := splitID(id)
|
|
_, err := client.BanUser(room, &gomatrix.ReqBanUser{
|
|
Reason: "spam",
|
|
UserID: user,
|
|
})
|
|
return err
|
|
},
|
|
Unban: func(string) error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
r, err := ruler.New(log, cfg.Rules, time.Now, rulerFuncs)
|
|
if err != nil {
|
|
log.Fatalf("Error creating ruler: %s", err)
|
|
}
|
|
|
|
eventCallback := func(evt *gomatrix.Event) {
|
|
id := formatID(evt.Sender, evt.RoomID)
|
|
timeStamp := time.Unix(evt.Timestamp/1000, 0)
|
|
|
|
if err := r.PushEvent(timeStamp, id); err != nil {
|
|
log.Errorf("Error pushing event to ruler: %s", err)
|
|
return
|
|
}
|
|
|
|
// Using MarkRead from the client library results in an error ("content not JSON")
|
|
// TODO revert to using MarkRead once fixed in library
|
|
urlPath := client.BuildURL("rooms", evt.RoomID, "receipt", "m.read", evt.ID)
|
|
if err := client.MakeRequest(http.MethodPost, urlPath, struct{}{}, nil); err != nil {
|
|
log.WithFields(logrus.Fields{
|
|
"event": evt.ID,
|
|
"room": evt.RoomID,
|
|
}).WithError(err).Error("Can not mark event as read.")
|
|
}
|
|
}
|
|
|
|
syncer := client.Syncer.(*gomatrix.DefaultSyncer)
|
|
syncer.OnEventType("m.room.encrypted", eventCallback)
|
|
syncer.OnEventType("m.room.message", eventCallback)
|
|
|
|
sigCh := make(chan os.Signal)
|
|
signal.Notify(sigCh, signals...)
|
|
go func() {
|
|
sig := <-sigCh
|
|
signal.Reset(signals...)
|
|
|
|
log.Debugf("Got signal %q. Terminating...", sig)
|
|
cancel()
|
|
}()
|
|
|
|
r.Start(ctx, wg)
|
|
|
|
log.Debug("Starting synchronization loop...")
|
|
for {
|
|
if ctx.Err() != nil {
|
|
break
|
|
}
|
|
|
|
if err := client.Sync(); err != nil {
|
|
log.Errorf("error during sync: %s", err)
|
|
}
|
|
}
|
|
}
|