diff --git a/cmd/soju/main.go b/cmd/soju/main.go index f6bfda5..67dc444 100644 --- a/cmd/soju/main.go +++ b/cmd/soju/main.go @@ -88,6 +88,7 @@ func main() { srv.LogPath = cfg.LogPath srv.HTTPOrigins = cfg.HTTPOrigins srv.AcceptProxyIPs = cfg.AcceptProxyIPs + srv.MaxUserNetworks = cfg.MaxUserNetworks srv.Debug = debug for _, listen := range cfg.Listen { diff --git a/config/config.go b/config/config.go index a9118a8..0c6870a 100644 --- a/config/config.go +++ b/config/config.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "os" + "strconv" "git.sr.ht/~emersion/go-scfg" ) @@ -36,14 +37,18 @@ type TLS struct { } type Server struct { - Listen []string - Hostname string - TLS *TLS - SQLDriver string - SQLSource string - LogPath string + Listen []string + Hostname string + TLS *TLS + + SQLDriver string + SQLSource string + LogPath string + HTTPOrigins []string AcceptProxyIPs IPSet + + MaxUserNetworks int } func Defaults() *Server { @@ -52,9 +57,10 @@ func Defaults() *Server { hostname = "localhost" } return &Server{ - Hostname: hostname, - SQLDriver: "sqlite3", - SQLSource: "soju.db", + Hostname: hostname, + SQLDriver: "sqlite3", + SQLSource: "soju.db", + MaxUserNetworks: -1, } } @@ -113,6 +119,15 @@ func parse(cfg scfg.Block) (*Server, error) { } srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, n) } + case "max-user-networks": + var max string + if err := d.ParseParams(&max); err != nil { + return nil, err + } + var err error + if srv.MaxUserNetworks, err = strconv.Atoi(max); err != nil { + return nil, fmt.Errorf("directive %q: %v", d.Name, err) + } default: return nil, fmt.Errorf("unknown directive %q", d.Name) } diff --git a/doc/soju.1.scd b/doc/soju.1.scd index 103ceca..852f30a 100644 --- a/doc/soju.1.scd +++ b/doc/soju.1.scd @@ -129,6 +129,9 @@ The following directives are supported: By default, all IPs are rejected. +*max-user-networks* + Maximum number of networks per user. By default, there is no limit. + # IRC SERVICE soju exposes an IRC service called *BouncerServ* to manage the bouncer. diff --git a/server.go b/server.go index f516c2d..9e7760c 100644 --- a/server.go +++ b/server.go @@ -46,14 +46,15 @@ func (l *prefixLogger) Printf(format string, v ...interface{}) { } type Server struct { - Hostname string - Logger Logger - HistoryLimit int - LogPath string - Debug bool - HTTPOrigins []string - AcceptProxyIPs config.IPSet - Identd *Identd // can be nil + Hostname string + Logger Logger + HistoryLimit int + LogPath string + Debug bool + HTTPOrigins []string + AcceptProxyIPs config.IPSet + MaxUserNetworks int + Identd *Identd // can be nil db Database stopWG sync.WaitGroup @@ -66,11 +67,12 @@ type Server struct { func NewServer(db Database) *Server { return &Server{ - Logger: log.New(log.Writer(), "", log.LstdFlags), - HistoryLimit: 1000, - db: db, - listeners: make(map[net.Listener]struct{}), - users: make(map[string]*user), + Logger: log.New(log.Writer(), "", log.LstdFlags), + HistoryLimit: 1000, + MaxUserNetworks: -1, + db: db, + listeners: make(map[net.Listener]struct{}), + users: make(map[string]*user), } } diff --git a/user.go b/user.go index 2636ce3..966ba80 100644 --- a/user.go +++ b/user.go @@ -748,6 +748,10 @@ func (u *user) createNetwork(record *Network) (*network, error) { return nil, err } + if u.srv.MaxUserNetworks >= 0 && len(u.networks) >= u.srv.MaxUserNetworks { + return nil, fmt.Errorf("maximum number of networks reached") + } + network := newNetwork(u, record, nil) err := u.srv.db.StoreNetwork(u.ID, &network.Network) if err != nil {