X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/ea5d8c51c2ebfc3d9d26c1ba7123c35b49efcda6..187d6dc500784760654b740a278fef59072ca5a8:/hotline/server.go diff --git a/hotline/server.go b/hotline/server.go index e5a7b8e..3a43c95 100644 --- a/hotline/server.go +++ b/hotline/server.go @@ -308,16 +308,16 @@ func (s *Server) keepaliveHandler() { if c.IdleTime > userIdleSeconds && !c.Idle { c.Idle = true - flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(*c.Flags))) + flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(c.Flags))) flagBitmap.SetBit(flagBitmap, userFlagAway, 1) - binary.BigEndian.PutUint16(*c.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(c.Flags, uint16(flagBitmap.Int64())) c.sendAll( tranNotifyChangeUser, NewField(fieldUserID, *c.ID), - NewField(fieldUserFlags, *c.Flags), + NewField(fieldUserFlags, c.Flags), NewField(fieldUserName, c.UserName), - NewField(fieldUserIconID, *c.Icon), + NewField(fieldUserIconID, c.Icon), ) } } @@ -363,12 +363,12 @@ func (s *Server) NewClientConn(conn io.ReadWriteCloser, remoteAddr string) *Clie clientConn := &ClientConn{ ID: &[]byte{0, 0}, - Icon: &[]byte{0, 0}, - Flags: &[]byte{0, 0}, + Icon: []byte{0, 0}, + Flags: []byte{0, 0}, UserName: []byte{}, Connection: conn, Server: s, - Version: &[]byte{}, + Version: []byte{}, AutoReply: []byte{}, transfers: map[int]map[[4]byte]*FileTransfer{}, Agreed: false, @@ -392,7 +392,7 @@ func (s *Server) NewClientConn(conn io.ReadWriteCloser, remoteAddr string) *Clie } // NewUser creates a new user account entry in the server map and config file -func (s *Server) NewUser(login, name, password string, access []byte) error { +func (s *Server) NewUser(login, name, password string, access accessBitmap) error { s.mux.Lock() defer s.mux.Unlock() @@ -400,7 +400,7 @@ func (s *Server) NewUser(login, name, password string, access []byte) error { Login: login, Name: name, Password: hashAndSalt([]byte(password)), - Access: &access, + Access: access, } out, err := yaml.Marshal(&account) if err != nil { @@ -411,7 +411,7 @@ func (s *Server) NewUser(login, name, password string, access []byte) error { return s.FS.WriteFile(filepath.Join(s.ConfigDir, "Users", login+".yaml"), out, 0666) } -func (s *Server) UpdateUser(login, newLogin, name, password string, access []byte) error { +func (s *Server) UpdateUser(login, newLogin, name, password string, access accessBitmap) error { s.mux.Lock() defer s.mux.Unlock() @@ -426,7 +426,7 @@ func (s *Server) UpdateUser(login, newLogin, name, password string, access []byt } account := s.Accounts[newLogin] - account.Access = &access + account.Access = access account.Name = name account.Password = password @@ -463,8 +463,8 @@ func (s *Server) connectedUsers() []Field { } user := User{ ID: *c.ID, - Icon: *c.Icon, - Flags: *c.Flags, + Icon: c.Icon, + Flags: c.Flags, Name: string(c.UserName), } connectedUsers = append(connectedUsers, NewField(fieldUsernameWithInfo, user.Payload())) @@ -598,7 +598,7 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser encodedLogin := clientLogin.GetField(fieldUserLogin).Data encodedPassword := clientLogin.GetField(fieldUserPassword).Data - *c.Version = clientLogin.GetField(fieldVersion).Data + c.Version = clientLogin.GetField(fieldVersion).Data var login string for _, char := range encodedLogin { @@ -621,11 +621,17 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser return err } - c.logger.Infow("Login failed", "clientVersion", fmt.Sprintf("%x", *c.Version)) + c.logger.Infow("Login failed", "clientVersion", fmt.Sprintf("%x", c.Version)) return nil } + if clientLogin.GetField(fieldUserIconID).Data != nil { + c.Icon = clientLogin.GetField(fieldUserIconID).Data + } + + c.Account = c.Server.Accounts[login] + if clientLogin.GetField(fieldUserName).Data != nil { if c.Authorize(accessAnyName) { c.UserName = clientLogin.GetField(fieldUserName).Data @@ -634,14 +640,8 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser } } - if clientLogin.GetField(fieldUserIconID).Data != nil { - *c.Icon = clientLogin.GetField(fieldUserIconID).Data - } - - c.Account = c.Server.Accounts[login] - if c.Authorize(accessDisconUser) { - *c.Flags = []byte{0, 2} + c.Flags = []byte{0, 2} } s.outbox <- c.NewReply(clientLogin, @@ -651,24 +651,33 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser ) // Send user access privs so client UI knows how to behave - c.Server.outbox <- *NewTransaction(tranUserAccess, c.ID, NewField(fieldUserAccess, *c.Account.Access)) - - // Show agreement to client - c.Server.outbox <- *NewTransaction(tranShowAgreement, c.ID, NewField(fieldData, s.Agreement)) + c.Server.outbox <- *NewTransaction(tranUserAccess, c.ID, NewField(fieldUserAccess, c.Account.Access[:])) + + // Accounts with accessNoAgreement do not receive the server agreement on login. The behavior is different between + // client versions. For 1.2.3 client, we do not send tranShowAgreement. For other client versions, we send + // tranShowAgreement but with the NoServerAgreement field set to 1. + if c.Authorize(accessNoAgreement) { + // If client version is nil, then the client uses the 1.2.3 login behavior + if c.Version != nil { + c.Server.outbox <- *NewTransaction(tranShowAgreement, c.ID, NewField(fieldNoServerAgreement, []byte{1})) + } + } else { + c.Server.outbox <- *NewTransaction(tranShowAgreement, c.ID, NewField(fieldData, s.Agreement)) + } // Used simplified hotline v1.2.3 login flow for clients that do not send login info in tranAgreed - if *c.Version == nil || bytes.Equal(*c.Version, nostalgiaVersion) { + if c.Version == nil || bytes.Equal(c.Version, nostalgiaVersion) { c.Agreed = true c.logger = c.logger.With("name", string(c.UserName)) - c.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%x", *c.Version)) + c.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%x", c.Version)) for _, t := range c.notifyOthers( *NewTransaction( tranNotifyChangeUser, nil, NewField(fieldUserName, c.UserName), NewField(fieldUserID, *c.ID), - NewField(fieldUserIconID, *c.Icon), - NewField(fieldUserFlags, *c.Flags), + NewField(fieldUserIconID, c.Icon), + NewField(fieldUserFlags, c.Flags), ), ) { c.Server.outbox <- t