import (
"bufio"
- "bytes"
"context"
"encoding/binary"
"errors"
name string
}
-var nostalgiaVersion = []byte{0, 0, 2, 0x2c} // version ID used by the Nostalgia client
-var frogblastVersion = []byte{0, 0, 0, 0xb9} // version ID used by the Frogblast 1.2.4 client
-
-var heildrun = []byte{0, 0x97}
-
-var obsessionVersion = []byte{0xbe, 0x00} // version ID used by the Obsession client
-
type Server struct {
Port int
Accounts map[string]*Account
Version: []byte{},
AutoReply: []byte{},
transfers: map[int]map[[4]byte]*FileTransfer{},
- Agreed: false,
RemoteAddr: remoteAddr,
}
clientConn.transfers = map[int]map[[4]byte]*FileTransfer{
var connectedUsers []Field
for _, c := range sortedClients(s.Clients) {
- if !c.Agreed {
- continue
- }
user := User{
ID: *c.ID,
Icon: c.Icon,
return err
}
- 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(
+ t := NewTransaction(
tranServerMsg,
- c.ID,
+ &[]byte{0, 0},
NewField(fieldData, []byte("You are permanently banned on this server")),
NewField(fieldChatOptions, []byte{0, 0}),
)
+
+ b, err := t.MarshalBinary()
+ if err != nil {
+ return err
+ }
+
+ _, err = rwc.Write(b)
+ if err != nil {
+ return err
+ }
+
time.Sleep(1 * time.Second)
return nil
- } else if time.Now().Before(*banUntil) {
- s.outbox <- *NewTransaction(
+ }
+
+ // temporary ban
+ if time.Now().Before(*banUntil) {
+ t := NewTransaction(
tranServerMsg,
- c.ID,
+ &[]byte{0, 0},
NewField(fieldData, []byte("You are temporarily banned on this server")),
NewField(fieldChatOptions, []byte{0, 0}),
)
+ b, err := t.MarshalBinary()
+ if err != nil {
+ return err
+ }
+
+ _, err = rwc.Write(b)
+ if err != nil {
+ return err
+ }
+
time.Sleep(1 * time.Second)
return nil
}
-
}
+
+ c := s.NewClientConn(rwc, remoteAddr)
defer c.Disconnect()
encodedLogin := clientLogin.GetField(fieldUserLogin).Data
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
- // TODO: figure out a generalized solution that doesn't require playing whack-a-mole for specific client versions
- if c.Version == nil || bytes.Equal(c.Version, nostalgiaVersion) || bytes.Equal(c.Version, frogblastVersion) || bytes.Equal(c.Version, obsessionVersion) || bytes.Equal(c.Version, heildrun) {
- c.Agreed = true
+ // If the client has provided a username as part of the login, we can infer that it is using the 1.2.3 login
+ // flow and not the 1.5+ flow.
+ if len(c.UserName) != 0 {
+ // Add the client username to the logger. For 1.5+ clients, we don't have this information yet as it comes as
+ // part of tranAgreed
c.logger = c.logger.With("name", string(c.UserName))
- c.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%v", func() int { i, _ := byteToInt(c.Version); return i }()))
+ c.logger.Infow("Login successful", "clientVersion", "Not sent (probably 1.2.3)")
+
+ // Notify other clients on the server that the new user has logged in. For 1.5+ clients we don't have this
+ // information yet, so we do it in tranAgreed instead
for _, t := range c.notifyOthers(
*NewTransaction(
tranNotifyChangeUser, nil,