]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/server.go
Implement "Can use any name" permission
[rbdr/mobius] / hotline / server.go
index 1edfd4a9d03a65224bd66a52c2b5dba185621780..e5a7b8eb08a4ed8be7c0fce1555e7839264a8587 100644 (file)
@@ -66,6 +66,9 @@ type Server struct {
 
        flatNewsMux sync.Mutex
        FlatNews    []byte
+
+       banListMU sync.Mutex
+       banList   map[string]*time.Time
 }
 
 type PrivateChat struct {
@@ -184,6 +187,7 @@ func (s *Server) Serve(ctx context.Context, ln net.Listener) error {
                go func() {
                        s.Logger.Infow("Connection established", "RemoteAddr", conn.RemoteAddr())
 
+                       defer conn.Close()
                        if err := s.handleNewConnection(connCtx, conn, conn.RemoteAddr().String()); err != nil {
                                if err == io.EOF {
                                        s.Logger.Infow("Client disconnected", "RemoteAddr", conn.RemoteAddr())
@@ -215,6 +219,7 @@ func NewServer(configDir string, netPort int, logger *zap.SugaredLogger, FS File
                Stats:         &Stats{StartTime: time.Now()},
                ThreadedNews:  &ThreadedNews{},
                FS:            FS,
+               banList:       make(map[string]*time.Time),
        }
 
        var err error
@@ -233,6 +238,9 @@ func NewServer(configDir string, netPort int, logger *zap.SugaredLogger, FS File
                return nil, err
        }
 
+       // try to load the ban list, but ignore errors as this file may not be present or may be empty
+       _ = server.loadBanList(filepath.Join(configDir, "Banlist.yaml"))
+
        if err := server.loadThreadedNews(filepath.Join(configDir, "ThreadedNews.yaml")); err != nil {
                return nil, err
        }
@@ -317,6 +325,22 @@ func (s *Server) keepaliveHandler() {
        }
 }
 
+func (s *Server) writeBanList() error {
+       s.banListMU.Lock()
+       defer s.banListMU.Unlock()
+
+       out, err := yaml.Marshal(s.banList)
+       if err != nil {
+               return err
+       }
+       err = ioutil.WriteFile(
+               filepath.Join(s.ConfigDir, "Banlist.yaml"),
+               out,
+               0666,
+       )
+       return err
+}
+
 func (s *Server) writeThreadedNews() error {
        s.mux.Lock()
        defer s.mux.Unlock()
@@ -448,6 +472,16 @@ func (s *Server) connectedUsers() []Field {
        return connectedUsers
 }
 
+func (s *Server) loadBanList(path string) error {
+       fh, err := os.Open(path)
+       if err != nil {
+               return err
+       }
+       decoder := yaml.NewDecoder(fh)
+
+       return decoder.Decode(s.banList)
+}
+
 // loadThreadedNews loads the threaded news data from disk
 func (s *Server) loadThreadedNews(threadedNewsPath string) error {
        fh, err := os.Open(threadedNewsPath)
@@ -535,6 +569,31 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser
        }
 
        c := s.NewClientConn(rwc, remoteAddr)
+
+       // check if remoteAddr is present in the ban list
+       if banUntil, ok := s.banList[strings.Split(remoteAddr, ":")[0]]; ok {
+               // permaban
+               if banUntil == nil {
+                       s.outbox <- *NewTransaction(
+                               tranServerMsg,
+                               c.ID,
+                               NewField(fieldData, []byte("You are permanently banned on this server")),
+                               NewField(fieldChatOptions, []byte{0, 0}),
+                       )
+                       time.Sleep(1 * time.Second)
+                       return nil
+               } else if time.Now().Before(*banUntil) {
+                       s.outbox <- *NewTransaction(
+                               tranServerMsg,
+                               c.ID,
+                               NewField(fieldData, []byte("You are temporarily banned on this server")),
+                               NewField(fieldChatOptions, []byte{0, 0}),
+                       )
+                       time.Sleep(1 * time.Second)
+                       return nil
+               }
+
+       }
        defer c.Disconnect()
 
        encodedLogin := clientLogin.GetField(fieldUserLogin).Data
@@ -568,7 +627,11 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser
        }
 
        if clientLogin.GetField(fieldUserName).Data != nil {
-               c.UserName = clientLogin.GetField(fieldUserName).Data
+               if c.Authorize(accessAnyName) {
+                       c.UserName = clientLogin.GetField(fieldUserName).Data
+               } else {
+                       c.UserName = []byte(c.Account.Name)
+               }
        }
 
        if clientLogin.GetField(fieldUserIconID).Data != nil {