From 2c92f0b4654f45548463c393e79aeab5b191d240 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 22 May 2022 18:20:49 +0300 Subject: [PATCH] Move bridge permission config from mautrix-whatsapp --- bridge/bridge.go | 10 +---- bridge/bridgeconfig/config.go | 9 ++-- bridge/bridgeconfig/permissions.go | 71 ++++++++++++++++++++++++++++++ bridge/commands/handler.go | 6 +-- bridge/crypto.go | 3 +- bridge/matrix.go | 9 ++-- id/userid.go | 10 +++++ 7 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 bridge/bridgeconfig/permissions.go diff --git a/bridge/bridge.go b/bridge/bridge.go index 28a46baa..f0d504a3 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -58,16 +58,8 @@ type DisappearingPortal interface { ScheduleDisappearing() } -type PermissionLevel int - -const ( - PermissionRelay PermissionLevel = 5 - PermissionUser PermissionLevel = 10 - PermissionAdmin PermissionLevel = 100 -) - type User interface { - GetPermissionLevel() PermissionLevel + GetPermissionLevel() bridgeconfig.PermissionLevel IsLoggedIn() bool GetManagementRoomID() id.RoomID SetManagementRoom(id.RoomID) diff --git a/bridge/bridgeconfig/config.go b/bridge/bridgeconfig/config.go index 9226685a..12302a3c 100644 --- a/bridge/bridgeconfig/config.go +++ b/bridge/bridgeconfig/config.go @@ -171,11 +171,7 @@ type BaseConfig struct { Logging appservice.LogConfig `yaml:"logging"` } -type configUpgrader struct{} - -var Upgrader = configUpgrader{} - -func (upg configUpgrader) DoUpgrade(helper *up.Helper) { +func doUpgrade(helper *up.Helper) { helper.Copy(up.Str, "homeserver", "address") helper.Copy(up.Str, "homeserver", "domain") helper.Copy(up.Bool, "homeserver", "asmux") @@ -207,3 +203,6 @@ func (upg configUpgrader) DoUpgrade(helper *up.Helper) { helper.Copy(up.Str|up.Timestamp, "logging", "timestamp_format") helper.Copy(up.Str, "logging", "print_level") } + +// Upgrader is a config upgrader that copies the default fields in the homeserver, appservice and logging blocks. +var Upgrader = up.SimpleUpgrader(doUpgrade) diff --git a/bridge/bridgeconfig/permissions.go b/bridge/bridgeconfig/permissions.go new file mode 100644 index 00000000..2b61cc67 --- /dev/null +++ b/bridge/bridgeconfig/permissions.go @@ -0,0 +1,71 @@ +// Copyright (c) 2022 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package bridgeconfig + +import ( + "strconv" + "strings" + + "maunium.net/go/mautrix/id" +) + +type PermissionConfig map[string]PermissionLevel + +type PermissionLevel int + +const ( + PermissionLevelBlock PermissionLevel = 0 + PermissionLevelRelay PermissionLevel = 5 + PermissionLevelUser PermissionLevel = 10 + PermissionLevelAdmin PermissionLevel = 100 +) + +var namesToLevels = map[string]PermissionLevel{ + "block": PermissionLevelBlock, + "relay": PermissionLevelRelay, + "user": PermissionLevelUser, + "admin": PermissionLevelAdmin, +} + +func RegisterPermissionLevel(name string, level PermissionLevel) { + namesToLevels[name] = level +} + +func (pc *PermissionConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + rawPC := make(map[string]string) + err := unmarshal(&rawPC) + if err != nil { + return err + } + + if *pc == nil { + *pc = make(map[string]PermissionLevel) + } + for key, value := range rawPC { + level, ok := namesToLevels[strings.ToLower(value)] + if ok { + (*pc)[key] = level + } else if val, err := strconv.Atoi(value); err == nil { + (*pc)[key] = PermissionLevel(val) + } else { + (*pc)[key] = PermissionLevelBlock + } + } + return nil +} + +func (pc PermissionConfig) Get(userID id.UserID) PermissionLevel { + if level, ok := pc[string(userID)]; ok { + return level + } else if level, ok = pc[userID.Homeserver()]; len(userID.Homeserver()) > 0 && ok { + return level + } else if level, ok = pc["*"]; ok { + return level + } else { + return PermissionLevelBlock + } +} diff --git a/bridge/commands/handler.go b/bridge/commands/handler.go index 69bb47b7..efd2e362 100644 --- a/bridge/commands/handler.go +++ b/bridge/commands/handler.go @@ -7,7 +7,7 @@ package commands import ( - "maunium.net/go/mautrix/bridge" + "maunium.net/go/mautrix/bridge/bridgeconfig" ) type Handler interface { @@ -51,13 +51,13 @@ func (fh *FullHandler) GetAliases() []string { } func (fh *FullHandler) HasPermission(ce *Event) bool { - return (!fh.RequiresAdmin || ce.User.GetPermissionLevel() >= bridge.PermissionAdmin) && + return (!fh.RequiresAdmin || ce.User.GetPermissionLevel() >= bridgeconfig.PermissionLevelAdmin) && (!fh.RequiresPortal || ce.Portal != nil) && (!fh.RequiresLogin || ce.User.IsLoggedIn()) } func (fh *FullHandler) Run(ce *Event) { - if fh.RequiresAdmin && ce.User.GetPermissionLevel() < bridge.PermissionAdmin { + if fh.RequiresAdmin && ce.User.GetPermissionLevel() < bridgeconfig.PermissionLevelAdmin { ce.Reply("That command is limited to bridge administrators.") } else if fh.RequiresPortal && ce.Portal == nil { ce.Reply("That command can only be ran in portal rooms.") diff --git a/bridge/crypto.go b/bridge/crypto.go index 8538c163..fb60780c 100644 --- a/bridge/crypto.go +++ b/bridge/crypto.go @@ -14,6 +14,7 @@ import ( "maunium.net/go/maulogger/v2" "maunium.net/go/mautrix" + "maunium.net/go/mautrix/bridge/bridgeconfig" "maunium.net/go/mautrix/crypto" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -91,7 +92,7 @@ func (helper *CryptoHelper) allowKeyShare(device *crypto.DeviceIdentity, info ev } user := helper.bridge.Child.GetIUser(device.UserID, true) // FIXME reimplement IsInPortal - if user.GetPermissionLevel() < PermissionAdmin /*&& !user.IsInPortal(portal.Key)*/ { + if user.GetPermissionLevel() < bridgeconfig.PermissionLevelAdmin /*&& !user.IsInPortal(portal.Key)*/ { helper.log.Debugfln("Rejecting key request for %s from %s/%s: user is not in portal", info.SessionID, device.UserID, device.DeviceID) return &crypto.KeyShareRejection{Code: event.RoomKeyWithheldUnauthorized, Reason: "You're not in that portal"} } diff --git a/bridge/matrix.go b/bridge/matrix.go index b2959080..db4b3855 100644 --- a/bridge/matrix.go +++ b/bridge/matrix.go @@ -16,6 +16,7 @@ import ( "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" + "maunium.net/go/mautrix/bridge/bridgeconfig" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" @@ -155,7 +156,7 @@ func (mx *MatrixHandler) HandleBotInvite(evt *event.Event) { func (mx *MatrixHandler) HandleGhostInvite(evt *event.Event, inviter User, ghost Ghost) { intent := ghost.DefaultIntent() - if inviter.GetPermissionLevel() < PermissionUser { + if inviter.GetPermissionLevel() < bridgeconfig.PermissionLevelUser { mx.log.Debugfln("Rejecting invite for %s from %s to %s: user is not whitelisted", ghost.GetMXID(), evt.Sender, evt.RoomID) _, err := intent.LeaveRoom(evt.RoomID, &mautrix.ReqLeave{ Reason: "You're not whitelisted to use this bridge", @@ -245,7 +246,7 @@ func (mx *MatrixHandler) HandleMembership(evt *event.Event) { mx.HandleGhostInvite(evt, user, ghost) } return - } else if user.GetPermissionLevel() < PermissionUser || !user.IsLoggedIn() { + } else if user.GetPermissionLevel() < bridgeconfig.PermissionLevelUser || !user.IsLoggedIn() { return } @@ -402,7 +403,7 @@ func (mx *MatrixHandler) HandleMessage(evt *event.Event) { content := evt.Content.AsMessage() content.RemoveReplyFallback() - if user.GetPermissionLevel() >= PermissionUser && content.MsgType == event.MsgText { + if user.GetPermissionLevel() >= bridgeconfig.PermissionLevelUser && content.MsgType == event.MsgText { commandPrefix := mx.bridge.Config.Bridge.GetCommandPrefix() hasCommandPrefix := strings.HasPrefix(content.Body, commandPrefix) if hasCommandPrefix { @@ -427,7 +428,7 @@ func (mx *MatrixHandler) HandleReaction(evt *event.Event) { } user := mx.bridge.Child.GetIUser(evt.Sender, true) - if user == nil || user.GetPermissionLevel() < PermissionUser || !user.IsLoggedIn() { + if user == nil || user.GetPermissionLevel() < bridgeconfig.PermissionLevelUser || !user.IsLoggedIn() { return } diff --git a/id/userid.go b/id/userid.go index 3b9e3a1e..b0e83638 100644 --- a/id/userid.go +++ b/id/userid.go @@ -52,6 +52,16 @@ func (userID UserID) Parse() (localpart, homeserver string, err error) { return } +func (userID UserID) Localpart() string { + localpart, _, _ := userID.Parse() + return localpart +} + +func (userID UserID) Homeserver() string { + _, homeserver, _ := userID.Parse() + return homeserver +} + // URI returns the user ID as a MatrixURI struct, which can then be stringified into a matrix: URI or a matrix.to URL. // // This does not parse or validate the user ID. Use the ParseAndValidate method if you want to ensure the user ID is valid first.