Sfoglia il codice sorgente

Send ChatNavError SNAC for common chatroom errors

This causes the AIM client to show a chat join error instead of closing the session
Josh Knight 2 anni fa
parent
commit
6ff7bbe163
1 ha cambiato i file con 34 aggiunte e 12 eliminazioni
  1. 34 12
      foodgroup/chat_nav.go

+ 34 - 12
foodgroup/chat_nav.go

@@ -24,6 +24,13 @@ var defaultExchangeCfg = wire.TLVBlock{
 	},
 }
 
+var (
+	errChatNavRoomNameMissing    = errors.New("unable to find chat name in TLV payload")
+	errChatNavRoomCreateFailed   = errors.New("unable to create chat room")
+	errChatNavRetrieveFailed     = errors.New("unable to retrieve chat room chat room")
+	errChatNavMismatchedExchange = errors.New("chat room exchange does not match requested exchange")
+)
+
 // NewChatNavService creates a new instance of NewChatNavService.
 func NewChatNavService(logger *slog.Logger, chatRoomManager ChatRoomRegistry, fnNewChatRoom func() state.ChatRoom) *ChatNavService {
 	return &ChatNavService{
@@ -73,7 +80,8 @@ func (s ChatNavService) RequestChatRights(_ context.Context, inFrame wire.SNACFr
 // chat room.
 func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (wire.SNACMessage, error) {
 	if err := validateExchange(inBody.Exchange); err != nil {
-		return wire.SNACMessage{}, err
+		s.logger.Debug("error validating exchange: " + err.Error())
+		return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNotSupportedByHost)
 	}
 	if inBody.Cookie != "create" {
 		s.logger.Info("got a non-create cookie", "value", inBody.Cookie)
@@ -81,7 +89,7 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 
 	name, hasName := inBody.String(wire.ChatRoomTLVRoomName)
 	if !hasName {
-		return wire.SNACMessage{}, errors.New("unable to find chat name in TLV payload")
+		return wire.SNACMessage{}, errChatNavRoomNameMissing
 	}
 
 	// todo call ChatRoomByName and CreateChatRoom in a txn
@@ -90,8 +98,8 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 	switch {
 	case errors.Is(err, state.ErrChatRoomNotFound):
 		if inBody.Exchange == state.PublicExchange {
-			return wire.SNACMessage{}, fmt.Errorf("community chat rooms can only be created on exchange %d",
-				state.PrivateExchange)
+			s.logger.Debug(fmt.Sprintf("public chat room not found: %s:%d", name, inBody.Exchange))
+			return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNoMatch)
 		}
 
 		room = s.fnNewChatRoom()
@@ -102,14 +110,12 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 		room.Name = name
 
 		if err := s.chatRoomManager.CreateChatRoom(room); err != nil {
-			return wire.SNACMessage{}, fmt.Errorf("unable to create chat room: %w", err)
+			return wire.SNACMessage{}, fmt.Errorf("%w: %w", errChatNavRoomCreateFailed, err)
 		}
 		break
 	case err != nil:
-		return wire.SNACMessage{}, fmt.Errorf("unable to retrieve chat room chat room %s on exchange %d: %w",
-			name, inBody.Exchange, err)
+		return wire.SNACMessage{}, fmt.Errorf("%w: %w", errChatNavRetrieveFailed, err)
 	}
-
 	return wire.SNACMessage{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.ChatNav,
@@ -138,16 +144,17 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 // the chat room specified in the inFrame.hmacCookie.
 func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (wire.SNACMessage, error) {
 	if err := validateExchange(inBody.Exchange); err != nil {
-		return wire.SNACMessage{}, err
+		s.logger.Debug("error validating exchange: " + err.Error())
+		return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNotSupportedByHost)
 	}
 
 	room, err := s.chatRoomManager.ChatRoomByCookie(inBody.Cookie)
 	if err != nil {
-		return wire.SNACMessage{}, fmt.Errorf("unable to find chat room: %w", err)
+		return wire.SNACMessage{}, fmt.Errorf("%w: %w", state.ErrChatRoomNotFound, err)
 	}
 
 	if room.Exchange != inBody.Exchange {
-		return wire.SNACMessage{}, errors.New("chat room exchange does not match requested exchange")
+		return wire.SNACMessage{}, errChatNavMismatchedExchange
 	}
 
 	return wire.SNACMessage{
@@ -176,7 +183,8 @@ func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFram
 
 func (s ChatNavService) ExchangeInfo(_ context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0D_0x03_ChatNavRequestExchangeInfo) (wire.SNACMessage, error) {
 	if err := validateExchange(inBody.Exchange); err != nil {
-		return wire.SNACMessage{}, err
+		s.logger.Debug("error validating exchange: " + err.Error())
+		return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNotSupportedByHost)
 	}
 	return wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -198,6 +206,20 @@ func (s ChatNavService) ExchangeInfo(_ context.Context, inFrame wire.SNACFrame,
 	}, nil
 }
 
+// sendChatNavErrorSNAC returns a ChatNavErr SNAC and logs an error for the operator
+func sendChatNavErrorSNAC(inFrame wire.SNACFrame, errorCode uint16) (wire.SNACMessage, error) {
+	return wire.SNACMessage{
+		Frame: wire.SNACFrame{
+			FoodGroup: wire.ChatNav,
+			SubGroup:  wire.ChatNavErr,
+			RequestID: inFrame.RequestID,
+		},
+		Body: wire.SNACError{
+			Code: errorCode,
+		},
+	}, nil
+}
+
 func validateExchange(exchange uint16) error {
 	if !(exchange == state.PrivateExchange || exchange == state.PublicExchange) {
 		return fmt.Errorf("only exchanges %d and %d are supported", state.PrivateExchange, state.PublicExchange)