bridgev2/config: add option to limit maximum number of logins

This commit is contained in:
Tulir Asokan 2025-10-23 15:46:57 +03:00
commit 1be49d53e4
4 changed files with 21 additions and 5 deletions

View file

@ -24,6 +24,7 @@ type Permissions struct {
DoublePuppet bool `yaml:"double_puppet"`
Admin bool `yaml:"admin"`
ManageRelay bool `yaml:"manage_relay"`
MaxLogins int `yaml:"max_logins"`
}
type PermissionConfig map[string]*Permissions

View file

@ -70,6 +70,15 @@ func fnLogin(ce *Event) {
}
ce.Args = ce.Args[1:]
}
if reauth == nil && ce.User.HasTooManyLogins() {
ce.Reply(
"You have reached the maximum number of logins (%d). "+
"Please logout from an existing login before creating a new one. "+
"If you want to re-authenticate an existing login, use the `$cmdprefix relogin` command.",
ce.User.Permissions.MaxLogins,
)
return
}
flows := ce.Bridge.Network.GetLoginFlows()
var chosenFlowID string
if len(ce.Args) > 0 {

View file

@ -367,17 +367,19 @@ func (prov *ProvisioningAPI) GetCapabilities(w http.ResponseWriter, r *http.Requ
}
var ErrNilStep = errors.New("bridge returned nil step with no error")
var ErrTooManyLogins = bridgev2.RespError{ErrCode: "FI.MAU.BRIDGE.TOO_MANY_LOGINS", Err: "Maximum number of logins exceeded"}
func (prov *ProvisioningAPI) PostLoginStart(w http.ResponseWriter, r *http.Request) {
overrideLogin, failed := prov.GetExplicitLoginForRequest(w, r)
if failed {
return
}
login, err := prov.net.CreateLogin(
r.Context(),
prov.GetUser(r),
r.PathValue("flowID"),
)
user := prov.GetUser(r)
if overrideLogin == nil && user.HasTooManyLogins() {
ErrTooManyLogins.AppendMessage(" (%d)", user.Permissions.MaxLogins).Write(w)
return
}
login, err := prov.net.CreateLogin(r.Context(), user, r.PathValue("flowID"))
if err != nil {
zerolog.Ctx(r.Context()).Err(err).Msg("Failed to create login process")
RespondWithError(w, err, "Internal error creating login process")

View file

@ -176,6 +176,10 @@ func (user *User) GetUserLogins() []*UserLogin {
return maps.Values(user.logins)
}
func (user *User) HasTooManyLogins() bool {
return user.Permissions.MaxLogins > 0 && len(user.GetUserLoginIDs()) >= user.Permissions.MaxLogins
}
func (user *User) GetFormattedUserLogins() string {
user.Bridge.cacheLock.Lock()
logins := make([]string, len(user.logins))