From 0decd4fad6d8d161dec1aaaec98febf40d080406 Mon Sep 17 00:00:00 2001 From: Aine Date: Mon, 22 Aug 2022 22:08:32 +0300 Subject: [PATCH] add noowner and federation --- README.md | 3 ++ bot/bot.go | 28 ++++++++++-------- bot/command.go | 8 ++++++ bot/data.go | 14 +++++++++ bot/mailbox.go | 7 +++++ bot/owner.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ cmd/cmd.go | 2 +- config/config.go | 2 ++ config/types.go | 4 +++ 9 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 bot/owner.go diff --git a/README.md b/README.md index 89642bc..8769c19 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,9 @@ env vars ### optional +* **POSTMOOGLE_NOOWNER** - allow change room settings by any room partisipant +* **POSTMOOGLE_FEDERATION** - allow usage of Postmoogle by users from others homeservers +* **POSTMOOGLE_NOENCRYPTION** - disable encryption support * **POSTMOOGLE_SENTRY_DSN** - sentry DSN * **POSTMOOGLE_SENTRY_RATE** - sentry sample rate, from 0 to 100 (default: 20) * **POSTMOOGLE_LOGLEVEL** - log level diff --git a/bot/bot.go b/bot/bot.go index 1337071..bd09d62 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -18,22 +18,26 @@ import ( // Bot represents matrix bot type Bot struct { - prefix string - domain string - rooms map[string]id.RoomID - roomsmu *sync.Mutex - log *logger.Logger - lp *linkpearl.Linkpearl + noowner bool + federation bool + prefix string + domain string + rooms map[string]id.RoomID + roomsmu *sync.Mutex + log *logger.Logger + lp *linkpearl.Linkpearl } // New creates a new matrix bot -func New(lp *linkpearl.Linkpearl, log *logger.Logger, prefix, domain string) *Bot { +func New(lp *linkpearl.Linkpearl, log *logger.Logger, prefix, domain string, noowner, federation bool) *Bot { return &Bot{ - roomsmu: &sync.Mutex{}, - prefix: prefix, - domain: domain, - log: log, - lp: lp, + noowner: noowner, + federation: federation, + roomsmu: &sync.Mutex{}, + prefix: prefix, + domain: domain, + log: log, + lp: lp, } } diff --git a/bot/command.go b/bot/command.go index ed579f1..cc93976 100644 --- a/bot/command.go +++ b/bot/command.go @@ -12,6 +12,7 @@ import ( var commands = map[string]string{ "mailbox": "Get or set mailbox of that room", + "owner": "Get or set owner of that room", "help": "Get help", } @@ -20,9 +21,16 @@ func (b *Bot) handleCommand(ctx context.Context, evt *event.Event, command []str return } + // ignore requests over federation if disabled + if !b.federation && evt.Sender.Homeserver() != b.lp.GetClient().UserID.Homeserver() { + return + } + switch command[0] { case "help": b.sendHelp(ctx, evt.RoomID) + case "owner": + b.handleOwner(ctx, evt, command) case "mailbox": b.handleMailbox(ctx, evt, command) } diff --git a/bot/data.go b/bot/data.go index ed99f20..7f40c1a 100644 --- a/bot/data.go +++ b/bot/data.go @@ -14,6 +14,20 @@ var migrations = []string{} // settings of a room type settings struct { Mailbox string + Owner id.UserID +} + +// Allowed checks if change is allowed +func (s *settings) Allowed(noowner bool, userID id.UserID) bool { + if noowner { + return true + } + + if s.Owner == "" { + return true + } + + return s.Owner == userID } func (b *Bot) migrate() error { diff --git a/bot/mailbox.go b/bot/mailbox.go index 979d76d..7d8bc07 100644 --- a/bot/mailbox.go +++ b/bot/mailbox.go @@ -86,6 +86,13 @@ func (b *Bot) setMailbox(ctx context.Context, evt *event.Event, mailbox string) if cfg == nil { cfg = &settings{} } + + if !cfg.Allowed(b.noowner, evt.Sender) { + b.Error(span.Context(), evt.RoomID, "you don't have permission to do that") + return + } + + cfg.Owner = evt.Sender cfg.Mailbox = mailbox err = b.setSettings(span.Context(), evt.RoomID, cfg) if err != nil { diff --git a/bot/owner.go b/bot/owner.go new file mode 100644 index 0000000..755b718 --- /dev/null +++ b/bot/owner.go @@ -0,0 +1,74 @@ +package bot + +import ( + "context" + + "github.com/getsentry/sentry-go" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/format" + "maunium.net/go/mautrix/id" +) + +func (b *Bot) handleOwner(ctx context.Context, evt *event.Event, command []string) { + if len(command) == 1 { + b.getOwner(ctx, evt) + return + } + b.setOwner(ctx, evt, command[1]) +} + +func (b *Bot) getOwner(ctx context.Context, evt *event.Event) { + span := sentry.StartSpan(ctx, "http.server", sentry.TransactionName("getOwner")) + defer span.Finish() + + cfg, err := b.getSettings(span.Context(), evt.RoomID) + if err != nil || cfg == nil { + b.Error(span.Context(), evt.RoomID, "owner is not set yet") + return + } + + if cfg.Owner == "" { + b.Error(span.Context(), evt.RoomID, "owner is not set yet") + return + } + + content := format.RenderMarkdown("Owner of this room is "+cfg.Owner.String(), true, true) + content.MsgType = event.MsgNotice + _, err = b.lp.Send(evt.RoomID, content) + if err != nil { + b.Error(span.Context(), evt.RoomID, "cannot send message: %v", err) + } +} + +func (b *Bot) setOwner(ctx context.Context, evt *event.Event, owner string) { + span := sentry.StartSpan(ctx, "http.server", sentry.TransactionName("setOwner")) + defer span.Finish() + + ownerID := id.UserID(owner) + cfg, err := b.getSettings(span.Context(), evt.RoomID) + if err != nil { + b.log.Warn("cannot get settings: %v", err) + } + if cfg == nil { + cfg = &settings{} + } + + if !cfg.Allowed(b.noowner, evt.Sender) { + b.Error(span.Context(), evt.RoomID, "you don't have permission to do that") + return + } + + cfg.Owner = ownerID + err = b.setSettings(span.Context(), evt.RoomID, cfg) + if err != nil { + b.Error(span.Context(), evt.RoomID, "cannot update settings: %v", err) + return + } + + content := format.RenderMarkdown("Owner of this room set to "+owner, true, true) + content.MsgType = event.MsgNotice + _, err = b.lp.Send(evt.RoomID, content) + if err != nil { + b.Error(span.Context(), evt.RoomID, "cannot send message: %v", err) + } +} diff --git a/cmd/cmd.go b/cmd/cmd.go index 071a0bc..2782c8b 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -81,7 +81,7 @@ func initBot(cfg *config.Config) { // nolint // Fatal = panic, not os.Exit() log.Fatal("cannot initialize matrix bot: %v", err) } - mxb = bot.New(lp, mxlog, cfg.Prefix, cfg.Domain) + mxb = bot.New(lp, mxlog, cfg.Prefix, cfg.Domain, cfg.NoOwner, cfg.Federation) log.Debug("bot has been created") } diff --git a/config/config.go b/config/config.go index 53e349d..3dc64ff 100644 --- a/config/config.go +++ b/config/config.go @@ -17,6 +17,8 @@ func New() *Config { Domain: env.String("domain", defaultConfig.Domain), Port: env.String("port", defaultConfig.Port), NoEncryption: env.Bool("noencryption"), + NoOwner: env.Bool("noowner"), + Federation: env.Bool("federation"), MaxSize: env.Int("maxsize", defaultConfig.MaxSize), Sentry: Sentry{ DSN: env.String("sentry.dsn", defaultConfig.Sentry.DSN), diff --git a/config/types.go b/config/types.go index 764e56f..246696a 100644 --- a/config/types.go +++ b/config/types.go @@ -16,6 +16,10 @@ type Config struct { LogLevel string // NoEncryption disabled encryption support NoEncryption bool + // NoOwner allows room settings change by any participant + NoOwner bool + // Federation allows usage of Postmoogle by users from other homeservers + Federation bool // Prefix for commands Prefix string // MaxSize of an email (including attachments)