X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/0da28a1fe47ffc60e40aeca9dddd7ab37e52a999..1a7d1fb948f08e940aed67070f5313799f19e6d0:/hotline/transaction_handlers.go?ds=sidebyside diff --git a/hotline/transaction_handlers.go b/hotline/transaction_handlers.go index 7f29d73..85879a4 100644 --- a/hotline/transaction_handlers.go +++ b/hotline/transaction_handlers.go @@ -299,6 +299,11 @@ func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err erro // Fields used in the reply: // None func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, err error) { + if !cc.Authorize(accessSendPrivMsg) { + res = append(res, cc.NewErrReply(t, "You are not allowed to send private messages.")) + return res, err + } + msg := t.GetField(fieldData) ID := t.GetField(fieldUserID) @@ -634,7 +639,7 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error if err != nil { return res, err } - if err := os.WriteFile(cc.Server.ConfigDir+"Users/"+login+".yaml", out, 0666); err != nil { + if err := os.WriteFile(filepath.Join(cc.Server.ConfigDir, "Users", login+".yaml"), out, 0666); err != nil { return res, err } @@ -645,22 +650,22 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error newT := NewTransaction(tranUserAccess, c.ID, NewField(fieldUserAccess, newAccessLvl)) res = append(res, *newT) - flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(*c.Flags))) + flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(c.Flags))) if authorize(c.Account.Access, accessDisconUser) { flagBitmap.SetBit(flagBitmap, userFlagAdmin, 1) } else { flagBitmap.SetBit(flagBitmap, userFlagAdmin, 0) } - binary.BigEndian.PutUint16(*c.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(c.Flags, uint16(flagBitmap.Int64())) c.Account.Access = account.Access cc.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), ) } } @@ -698,8 +703,13 @@ func HandleListUsers(cc *ClientConn, t *Transaction) (res []Transaction, err err var userFields []Field for _, acc := range cc.Server.Accounts { - userField := acc.MarshalBinary() - userFields = append(userFields, NewField(fieldData, userField)) + b := make([]byte, 0, 100) + n, err := acc.Read(b) + if err != nil { + return res, err + } + + userFields = append(userFields, NewField(fieldData, b[:n])) } res = append(res, cc.NewReply(t, userFields...)) @@ -903,27 +913,35 @@ func HandleGetUserNameList(cc *ClientConn, t *Transaction) (res []Transaction, e func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err error) { cc.Agreed = true - cc.UserName = t.GetField(fieldUserName).Data - *cc.Icon = t.GetField(fieldUserIconID).Data + + if t.GetField(fieldUserName).Data != nil { + if cc.Authorize(accessAnyName) { + cc.UserName = t.GetField(fieldUserName).Data + } else { + cc.UserName = []byte(cc.Account.Name) + } + } + + cc.Icon = t.GetField(fieldUserIconID).Data cc.logger = cc.logger.With("name", string(cc.UserName)) - cc.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%x", *cc.Version)) + cc.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%x", cc.Version)) options := t.GetField(fieldOptions).Data optBitmap := big.NewInt(int64(binary.BigEndian.Uint16(options))) - flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(*cc.Flags))) + flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(cc.Flags))) // Check refuse private PM option if optBitmap.Bit(refusePM) == 1 { flagBitmap.SetBit(flagBitmap, userFlagRefusePM, 1) - binary.BigEndian.PutUint16(*cc.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) } // Check refuse private chat option if optBitmap.Bit(refuseChat) == 1 { flagBitmap.SetBit(flagBitmap, userFLagRefusePChat, 1) - binary.BigEndian.PutUint16(*cc.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) } // Check auto response @@ -933,20 +951,19 @@ func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err er cc.AutoReply = []byte{} } - for _, t := range cc.notifyOthers( + trans := cc.notifyOthers( *NewTransaction( tranNotifyChangeUser, nil, NewField(fieldUserName, cc.UserName), NewField(fieldUserID, *cc.ID), - NewField(fieldUserIconID, *cc.Icon), - NewField(fieldUserFlags, *cc.Flags), + NewField(fieldUserIconID, cc.Icon), + NewField(fieldUserFlags, cc.Flags), ), - ) { - cc.Server.outbox <- t - } + ) + res = append(res, trans...) if cc.Server.Config.BannerFile != "" { - cc.Server.outbox <- *NewTransaction(tranServerBanner, cc.ID, NewField(fieldBannerType, []byte("JPEG"))) + res = append(res, *NewTransaction(tranServerBanner, cc.ID, NewField(fieldBannerType, []byte("JPEG")))) } res = append(res, cc.NewReply(t)) @@ -1019,12 +1036,48 @@ func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, er return res, err } - if err := clientConn.Connection.Close(); err != nil { - return res, err + // If fieldOptions is set, then the client IP is banned in addition to disconnected. + // 00 01 = temporary ban + // 00 02 = permanent ban + if t.GetField(fieldOptions).Data != nil { + switch t.GetField(fieldOptions).Data[1] { + case 1: + // send message: "You are temporarily banned on this server" + cc.logger.Infow("Disconnect & temporarily ban " + string(clientConn.UserName)) + + res = append(res, *NewTransaction( + tranServerMsg, + clientConn.ID, + NewField(fieldData, []byte("You are temporarily banned on this server")), + NewField(fieldChatOptions, []byte{0, 0}), + )) + + banUntil := time.Now().Add(tempBanDuration) + cc.Server.banList[strings.Split(clientConn.RemoteAddr, ":")[0]] = &banUntil + cc.Server.writeBanList() + case 2: + // send message: "You are permanently banned on this server" + cc.logger.Infow("Disconnect & ban " + string(clientConn.UserName)) + + res = append(res, *NewTransaction( + tranServerMsg, + clientConn.ID, + NewField(fieldData, []byte("You are permanently banned on this server")), + NewField(fieldChatOptions, []byte{0, 0}), + )) + + cc.Server.banList[strings.Split(clientConn.RemoteAddr, ":")[0]] = nil + cc.Server.writeBanList() + } } - res = append(res, cc.NewReply(t)) - return res, err + // TODO: remove this awful hack + go func() { + time.Sleep(1 * time.Second) + clientConn.Disconnect() + }() + + return append(res, cc.NewReply(t)), err } // HandleGetNewsCatNameList returns a list of news categories for a path @@ -1545,27 +1598,26 @@ func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err er } func HandleSetClientUserInfo(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - var icon []byte if len(t.GetField(fieldUserIconID).Data) == 4 { - icon = t.GetField(fieldUserIconID).Data[2:] + cc.Icon = t.GetField(fieldUserIconID).Data[2:] } else { - icon = t.GetField(fieldUserIconID).Data + cc.Icon = t.GetField(fieldUserIconID).Data + } + if cc.Authorize(accessAnyName) { + cc.UserName = t.GetField(fieldUserName).Data } - *cc.Icon = icon - cc.UserName = t.GetField(fieldUserName).Data // the options field is only passed by the client versions > 1.2.3. options := t.GetField(fieldOptions).Data - if options != nil { optBitmap := big.NewInt(int64(binary.BigEndian.Uint16(options))) - flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(*cc.Flags))) + flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(cc.Flags))) flagBitmap.SetBit(flagBitmap, userFlagRefusePM, optBitmap.Bit(refusePM)) - binary.BigEndian.PutUint16(*cc.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) flagBitmap.SetBit(flagBitmap, userFLagRefusePChat, optBitmap.Bit(refuseChat)) - binary.BigEndian.PutUint16(*cc.Flags, uint16(flagBitmap.Int64())) + binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) // Check auto response if optBitmap.Bit(autoResponse) == 1 { @@ -1575,14 +1627,16 @@ func HandleSetClientUserInfo(cc *ClientConn, t *Transaction) (res []Transaction, } } - // Notify all clients of updated user info - cc.sendAll( - tranNotifyChangeUser, - NewField(fieldUserID, *cc.ID), - NewField(fieldUserIconID, *cc.Icon), - NewField(fieldUserFlags, *cc.Flags), - NewField(fieldUserName, cc.UserName), - ) + for _, c := range sortedClients(cc.Server.Clients) { + res = append(res, *NewTransaction( + tranNotifyChangeUser, + c.ID, + NewField(fieldUserID, *cc.ID), + NewField(fieldUserIconID, cc.Icon), + NewField(fieldUserFlags, cc.Flags), + NewField(fieldUserName, cc.UserName), + )) + } return res, err } @@ -1619,7 +1673,7 @@ func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, e return res, err } - fileNames, err := getFileNameList(fullPath) + fileNames, err := getFileNameList(fullPath, cc.Server.Config.IgnoreFiles) if err != nil { return res, err } @@ -1667,8 +1721,8 @@ func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err NewField(fieldChatID, newChatID), NewField(fieldUserName, cc.UserName), NewField(fieldUserID, *cc.ID), - NewField(fieldUserIconID, *cc.Icon), - NewField(fieldUserFlags, *cc.Flags), + NewField(fieldUserIconID, cc.Icon), + NewField(fieldUserFlags, cc.Flags), ), ) @@ -1700,8 +1754,8 @@ func HandleInviteToChat(cc *ClientConn, t *Transaction) (res []Transaction, err NewField(fieldChatID, chatID), NewField(fieldUserName, cc.UserName), NewField(fieldUserID, *cc.ID), - NewField(fieldUserIconID, *cc.Icon), - NewField(fieldUserFlags, *cc.Flags), + NewField(fieldUserIconID, cc.Icon), + NewField(fieldUserFlags, cc.Flags), ), ) @@ -1750,8 +1804,8 @@ func HandleJoinChat(cc *ClientConn, t *Transaction) (res []Transaction, err erro NewField(fieldChatID, chatID), NewField(fieldUserName, cc.UserName), NewField(fieldUserID, *cc.ID), - NewField(fieldUserIconID, *cc.Icon), - NewField(fieldUserFlags, *cc.Flags), + NewField(fieldUserIconID, cc.Icon), + NewField(fieldUserFlags, cc.Flags), ), ) } @@ -1762,8 +1816,8 @@ func HandleJoinChat(cc *ClientConn, t *Transaction) (res []Transaction, err erro for _, c := range sortedClients(privChat.ClientConn) { user := User{ ID: *c.ID, - Icon: *c.Icon, - Flags: *c.Flags, + Icon: c.Icon, + Flags: c.Flags, Name: string(c.UserName), } @@ -1782,7 +1836,10 @@ func HandleLeaveChat(cc *ClientConn, t *Transaction) (res []Transaction, err err chatID := t.GetField(fieldChatID).Data chatInt := binary.BigEndian.Uint32(chatID) - privChat := cc.Server.PrivateChats[chatInt] + privChat, ok := cc.Server.PrivateChats[chatInt] + if !ok { + return res, nil + } delete(privChat.ClientConn, cc.uint16ID())