X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/aeb97482e923b5c441dd59e3ca4a7e275ac2b4c2..14d7c1fea979212eb27fe5df19b73415d70a0183:/hotline/transaction_handlers.go diff --git a/hotline/transaction_handlers.go b/hotline/transaction_handlers.go index 137b2a0..d86e928 100644 --- a/hotline/transaction_handlers.go +++ b/hotline/transaction_handlers.go @@ -305,7 +305,7 @@ func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err erro 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 + return res, errors.New("user is not allowed to send private messages") } msg := t.GetField(FieldData) @@ -326,7 +326,10 @@ func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, er reply.Fields = append(reply.Fields, NewField(FieldQuotingMsg, t.GetField(FieldQuotingMsg).Data)) } - id, _ := byteToInt(ID.Data) + id, err := byteToInt(ID.Data) + if err != nil { + return res, errors.New("invalid client ID") + } otherClient, ok := cc.Server.Clients[uint16(id)] if !ok { return res, errors.New("invalid client ID") @@ -334,7 +337,7 @@ func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, er // Check if target user has "Refuse private messages" flag flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(otherClient.Flags))) - if flagBitmap.Bit(userFLagRefusePChat) == 1 { + if flagBitmap.Bit(UserFlagRefusePChat) == 1 { res = append(res, *NewTransaction( TranServerMsg, @@ -382,16 +385,31 @@ func HandleGetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e return res, err } - res = append(res, cc.NewReply(t, - NewField(FieldFileName, []byte(fw.name)), + encodedName, err := txtEncoder.String(fw.name) + if err != nil { + return res, fmt.Errorf("invalid filepath encoding: %w", err) + } + + fields := []Field{ + NewField(FieldFileName, []byte(encodedName)), NewField(FieldFileTypeString, fw.ffo.FlatFileInformationFork.friendlyType()), NewField(FieldFileCreatorString, fw.ffo.FlatFileInformationFork.friendlyCreator()), - NewField(FieldFileComment, fw.ffo.FlatFileInformationFork.Comment), NewField(FieldFileType, fw.ffo.FlatFileInformationFork.TypeSignature), NewField(FieldFileCreateDate, fw.ffo.FlatFileInformationFork.CreateDate), NewField(FieldFileModifyDate, fw.ffo.FlatFileInformationFork.ModifyDate), - NewField(FieldFileSize, fw.totalSize()), - )) + } + + // Include the optional FileComment field if there is a comment. + if len(fw.ffo.FlatFileInformationFork.Comment) != 0 { + fields = append(fields, NewField(FieldFileComment, fw.ffo.FlatFileInformationFork.Comment)) + } + + // Include the FileSize field for files. + if !bytes.Equal(fw.ffo.FlatFileInformationFork.TypeSignature, []byte{0x66, 0x6c, 0x64, 0x72}) { + fields = append(fields, NewField(FieldFileSize, fw.totalSize())) + } + + res = append(res, cc.NewReply(t, fields...)) return res, err } @@ -475,7 +493,11 @@ func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e if err != nil { return nil, err } - hlFile.name = string(fileNewName) + hlFile.name, err = txtDecoder.String(string(fileNewName)) + if err != nil { + return res, fmt.Errorf("invalid filepath encoding: %w", err) + } + err = hlFile.move(fileDir) if os.IsNotExist(err) { res = append(res, cc.NewErrReply(t, "Cannot rename file "+string(fileName)+" because it does not exist or cannot be found.")) @@ -563,9 +585,6 @@ func HandleMoveFile(cc *ClientConn, t *Transaction) (res []Transaction, err erro res = append(res, cc.NewErrReply(t, "Cannot delete file "+fileName+" because it does not exist or cannot be found.")) return res, err } - if err != nil { - return res, err - } switch mode := fi.Mode(); { case mode.IsDir(): if !cc.Authorize(accessMoveFolder) { @@ -611,6 +630,10 @@ func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err err } } newFolderPath := path.Join(cc.Server.Config.FileRoot, subPath, folderName) + newFolderPath, err = txtDecoder.String(newFolderPath) + if err != nil { + return res, fmt.Errorf("invalid filepath encoding: %w", err) + } // TODO: check path and folder name lengths @@ -619,8 +642,6 @@ func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err err return []Transaction{cc.NewErrReply(t, msg)}, nil } - // TODO: check for disallowed characters to maintain compatibility for original client - if err := cc.Server.FS.Mkdir(newFolderPath, 0777); err != nil { msg := fmt.Sprintf("Cannot create folder \"%s\" because an error occurred.", folderName) return []Transaction{cc.NewErrReply(t, msg)}, nil @@ -636,7 +657,7 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error return res, err } - login := DecodeUserString(t.GetField(FieldUserLogin).Data) + login := decodeString(t.GetField(FieldUserLogin).Data) userName := string(t.GetField(FieldUserName).Data) newAccessLvl := t.GetField(FieldUserAccess).Data @@ -671,9 +692,9 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(c.Flags))) if c.Authorize(accessDisconUser) { - flagBitmap.SetBit(flagBitmap, userFlagAdmin, 1) + flagBitmap.SetBit(flagBitmap, UserFlagAdmin, 1) } else { - flagBitmap.SetBit(flagBitmap, userFlagAdmin, 0) + flagBitmap.SetBit(flagBitmap, UserFlagAdmin, 0) } binary.BigEndian.PutUint16(c.Flags, uint16(flagBitmap.Int64())) @@ -707,7 +728,7 @@ func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error res = append(res, cc.NewReply(t, NewField(FieldUserName, []byte(account.Name)), - NewField(FieldUserLogin, negateString(t.GetField(FieldUserLogin).Data)), + NewField(FieldUserLogin, encodeString(t.GetField(FieldUserLogin).Data)), NewField(FieldUserPassword, []byte(account.Password)), NewField(FieldUserAccess, account.Access[:]), )) @@ -752,7 +773,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er } if len(subFields) == 1 { - login := DecodeUserString(getField(FieldData, &subFields).Data) + login := decodeString(getField(FieldData, &subFields).Data) cc.logger.Infow("DeleteUser", "login", login) if !cc.Authorize(accessDeleteUser) { @@ -766,7 +787,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er continue } - login := DecodeUserString(getField(FieldUserLogin, &subFields).Data) + login := decodeString(getField(FieldUserLogin, &subFields).Data) // check if the login dataFile; if so, we know we are updating an existing user if acc, ok := cc.Server.Accounts[login]; ok { @@ -790,8 +811,8 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er } err = cc.Server.UpdateUser( - DecodeUserString(getField(FieldData, &subFields).Data), - DecodeUserString(getField(FieldUserLogin, &subFields).Data), + decodeString(getField(FieldData, &subFields).Data), + decodeString(getField(FieldUserLogin, &subFields).Data), string(getField(FieldUserName, &subFields).Data), acc.Password, acc.Access, @@ -837,7 +858,7 @@ func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error return res, err } - login := DecodeUserString(t.GetField(FieldUserLogin).Data) + login := decodeString(t.GetField(FieldUserLogin).Data) // If the account already dataFile, reply with an error if _, ok := cc.Server.Accounts[login]; ok { @@ -873,7 +894,7 @@ func HandleDeleteUser(cc *ClientConn, t *Transaction) (res []Transaction, err er } // TODO: Handle case where account doesn't exist; e.g. delete race condition - login := DecodeUserString(t.GetField(FieldUserLogin).Data) + login := decodeString(t.GetField(FieldUserLogin).Data) if err := cc.Server.DeleteUser(login); err != nil { return res, err @@ -955,13 +976,13 @@ func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err er // Check refuse private PM option if optBitmap.Bit(refusePM) == 1 { - flagBitmap.SetBit(flagBitmap, userFlagRefusePM, 1) + flagBitmap.SetBit(flagBitmap, UserFlagRefusePM, 1) binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) } // Check refuse private chat option if optBitmap.Bit(refuseChat) == 1 { - flagBitmap.SetBit(flagBitmap, userFLagRefusePChat, 1) + flagBitmap.SetBit(flagBitmap, UserFlagRefusePChat, 1) binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) } @@ -1015,7 +1036,7 @@ func HandleTranOldPostNews(cc *ClientConn, t *Transaction) (res []Transaction, e } newsPost := fmt.Sprintf(newsTemplate+"\r", cc.UserName, time.Now().Format(newsDateTemplate), t.GetField(FieldData).Data) - newsPost = strings.Replace(newsPost, "\n", "\r", -1) + newsPost = strings.ReplaceAll(newsPost, "\n", "\r") // update news in memory cc.Server.FlatNews = append([]byte(newsPost), cc.Server.FlatNews...) @@ -1066,7 +1087,6 @@ func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, er 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)) @@ -1079,7 +1099,11 @@ func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, er )) cc.Server.banList[strings.Split(clientConn.RemoteAddr, ":")[0]] = nil - cc.Server.writeBanList() + } + + err := cc.Server.writeBanList() + if err != nil { + return res, err } } @@ -1644,10 +1668,10 @@ func HandleSetClientUserInfo(cc *ClientConn, t *Transaction) (res []Transaction, optBitmap := big.NewInt(int64(binary.BigEndian.Uint16(options))) flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(cc.Flags))) - flagBitmap.SetBit(flagBitmap, userFlagRefusePM, optBitmap.Bit(refusePM)) + flagBitmap.SetBit(flagBitmap, UserFlagRefusePM, optBitmap.Bit(refusePM)) binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) - flagBitmap.SetBit(flagBitmap, userFLagRefusePChat, optBitmap.Bit(refuseChat)) + flagBitmap.SetBit(flagBitmap, UserFlagRefusePChat, optBitmap.Bit(refuseChat)) binary.BigEndian.PutUint16(cc.Flags, uint16(flagBitmap.Int64())) // Check auto response @@ -1742,7 +1766,7 @@ func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err targetClient := cc.Server.Clients[binary.BigEndian.Uint16(targetID)] flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(targetClient.Flags))) - if flagBitmap.Bit(userFLagRefusePChat) == 1 { + if flagBitmap.Bit(UserFlagRefusePChat) == 1 { res = append(res, *NewTransaction( TranServerMsg,