diff --git a/README.md b/README.md index f46bd9c..d1be7aa 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ env vars * **POSTMOOGLE_LOGLEVEL** - log level * **POSTMOOGLE_DB_DSN** - database connection string * **POSTMOOGLE_DB_DIALECT** - database dialect (postgres, sqlite3) +* **POSTMOOGLE_MAILBOXES_RESERVED** - space separated list of reserved mailboxes (e.g.: `postmaster admin root`), nobody can create them * **POSTMOOGLE_MAXSIZE** - max email size (including attachments) in megabytes * **POSTMOOGLE_ADMINS** - a space-separated list of admin users. See `POSTMOOGLE_USERS` for syntax examples diff --git a/bot/access.go b/bot/access.go index cbd011b..aaca84e 100644 --- a/bot/access.go +++ b/bot/access.go @@ -73,6 +73,15 @@ func (b *Bot) allowSend(actorID id.UserID, targetRoomID id.RoomID) bool { return !cfg.NoSend() } +func (b *Bot) isReserved(mailbox string) bool { + for _, reserved := range b.reservedMailboxes { + if mailbox == reserved { + return true + } + } + return false +} + // IsGreylisted checks if host is in greylist func (b *Bot) IsGreylisted(addr net.Addr) bool { if b.getBotSettings().Greylist() == 0 { diff --git a/bot/bot.go b/bot/bot.go index cfadf7f..c9eee4e 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -20,6 +20,7 @@ type Bot struct { domains []string allowedUsers []*regexp.Regexp allowedAdmins []*regexp.Regexp + reservedMailboxes []string commands commandList banlist bglist rooms sync.Map @@ -36,15 +37,17 @@ func New( log *logger.Logger, prefix string, domains []string, + reserved []string, admins []string, ) (*Bot, error) { b := &Bot{ - prefix: prefix, - domains: domains, - rooms: sync.Map{}, - log: log, - lp: lp, - mu: map[string]*sync.Mutex{}, + reservedMailboxes: reserved, + domains: domains, + prefix: prefix, + rooms: sync.Map{}, + log: log, + lp: lp, + mu: map[string]*sync.Mutex{}, } users, err := b.initBotUsers() if err != nil { diff --git a/bot/command_owner.go b/bot/command_owner.go index c454514..a0e4970 100644 --- a/bot/command_owner.go +++ b/bot/command_owner.go @@ -86,7 +86,7 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { evt := eventFromContext(ctx) if name == roomOptionMailbox { existingID, ok := b.getMapping(value) - if ok && existingID != "" && existingID != evt.RoomID { + if (ok && existingID != "" && existingID != evt.RoomID) || b.isReserved(value) { b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Mailbox `%s` (%s) already taken, kupo", value, utils.EmailsList(value, ""))) return } diff --git a/cmd/cmd.go b/cmd/cmd.go index 7cdf3cf..60a682b 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -98,7 +98,7 @@ func initBot(cfg *config.Config) { log.Fatal("cannot initialize matrix bot: %v", err) } - mxb, err = bot.New(lp, mxlog, cfg.Prefix, cfg.Domains, cfg.Admins) + mxb, err = bot.New(lp, mxlog, cfg.Prefix, cfg.Domains, cfg.Mailboxes.Reserved, cfg.Admins) if err != nil { // nolint // Fatal = panic, not os.Exit() log.Fatal("cannot start matrix bot: %v", err) diff --git a/config/config.go b/config/config.go index e0eeffd..63f1b04 100644 --- a/config/config.go +++ b/config/config.go @@ -22,6 +22,9 @@ func New() *Config { MaxSize: env.Int("maxsize", defaultConfig.MaxSize), StatusMsg: env.String("statusmsg", defaultConfig.StatusMsg), Admins: env.Slice("admins"), + Mailboxes: Mailboxes{ + Reserved: env.Slice("mailboxes.reserved"), + }, TLS: TLS{ Certs: env.Slice("tls.cert"), Keys: env.Slice("tls.key"), diff --git a/config/types.go b/config/types.go index e34c988..764212b 100644 --- a/config/types.go +++ b/config/types.go @@ -24,6 +24,8 @@ type Config struct { MaxSize int // StatusMsg of the bot StatusMsg string + // Mailboxes config + Mailboxes Mailboxes // Admins holds list of admin users (wildcards supported), e.g.: @*:example.com, @bot.*:example.com, @admin:*. Empty = no admins Admins []string @@ -57,3 +59,8 @@ type TLS struct { type Sentry struct { DSN string } + +// Mailboxes config +type Mailboxes struct { + Reserved []string +}