github.com/status-im/status-go@v1.1.0/protocol/message_validator.go (about)

     1  package protocol
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	utils "github.com/status-im/status-go/common"
    10  	"github.com/status-im/status-go/protocol/protobuf"
    11  	"github.com/status-im/status-go/protocol/v1"
    12  )
    13  
    14  const maxChatMessageTextLength = 4096
    15  const maxStatusMessageText = 128
    16  
    17  // maxWhisperDrift is how many milliseconds we allow the clock value to differ
    18  // from whisperTimestamp
    19  const maxWhisperFutureDriftMs uint64 = 120000
    20  
    21  func validateClockValue(clock uint64, whisperTimestamp uint64) error {
    22  	if clock == 0 {
    23  		return errors.New("clock can't be 0")
    24  	}
    25  
    26  	if clock > whisperTimestamp && clock-whisperTimestamp > maxWhisperFutureDriftMs {
    27  		return errors.New("clock value too high")
    28  	}
    29  
    30  	return nil
    31  }
    32  
    33  func ValidateMembershipUpdateMessage(message *protocol.MembershipUpdateMessage, timeNowMs uint64) error {
    34  
    35  	for _, e := range message.Events {
    36  		if err := validateClockValue(e.ClockValue, timeNowMs); err != nil {
    37  			return err
    38  		}
    39  
    40  	}
    41  	return nil
    42  }
    43  
    44  func ValidateStatusUpdate(message *protobuf.StatusUpdate) error {
    45  	if message == nil {
    46  		return errors.New("message can't be nil")
    47  	}
    48  	if message.Clock == 0 {
    49  		return errors.New("clock can't be 0")
    50  	}
    51  
    52  	if message.StatusType == protobuf.StatusUpdate_UNKNOWN_STATUS_TYPE {
    53  		return errors.New("unknown status type")
    54  	}
    55  
    56  	if len([]rune(message.CustomText)) > maxStatusMessageText {
    57  		return fmt.Errorf("custom text shouldn't be longer than %d", maxStatusMessageText)
    58  	}
    59  
    60  	return nil
    61  
    62  }
    63  
    64  func ValidateEditMessage(message *protobuf.EditMessage) error {
    65  	if message == nil {
    66  		return errors.New("message can't be nil")
    67  	}
    68  	if message.Clock == 0 {
    69  		return errors.New("clock can't be 0")
    70  	}
    71  	if len(message.ChatId) == 0 {
    72  		return errors.New("chat-id can't be empty")
    73  	}
    74  	if len(message.MessageId) == 0 {
    75  		return errors.New("message-id can't be empty")
    76  	}
    77  
    78  	if message.MessageType == protobuf.MessageType_UNKNOWN_MESSAGE_TYPE || message.MessageType == protobuf.MessageType_SYSTEM_MESSAGE_PRIVATE_GROUP {
    79  		return errors.New("unknown message type")
    80  	}
    81  
    82  	return ValidateText(message.Text)
    83  }
    84  
    85  func ValidateDeleteMessage(message *protobuf.DeleteMessage) error {
    86  	if message == nil {
    87  		return errors.New("message can't be nil")
    88  	}
    89  
    90  	if len(message.ChatId) == 0 {
    91  		return errors.New("chat-id can't be empty")
    92  	}
    93  	if len(message.MessageId) == 0 {
    94  		return errors.New("message-id can't be empty")
    95  	}
    96  
    97  	if message.MessageType == protobuf.MessageType_UNKNOWN_MESSAGE_TYPE || message.MessageType == protobuf.MessageType_SYSTEM_MESSAGE_PRIVATE_GROUP {
    98  		return errors.New("unknown message type")
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  func ValidateDeleteForMeMessage(message *protobuf.SyncDeleteForMeMessage) error {
   105  	if message == nil {
   106  		return errors.New("message can't be nil")
   107  	}
   108  
   109  	if len(message.MessageId) == 0 {
   110  		return errors.New("message-id can't be empty")
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func ValidateReceivedPairInstallation(message *protobuf.SyncPairInstallation, whisperTimestamp uint64) error {
   117  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   118  		return err
   119  	}
   120  
   121  	if len(strings.TrimSpace(message.Name)) == 0 {
   122  		return errors.New("name can't be empty")
   123  	}
   124  
   125  	if len(strings.TrimSpace(message.DeviceType)) == 0 {
   126  		return errors.New("device type can't be empty")
   127  	}
   128  
   129  	if len(strings.TrimSpace(message.InstallationId)) == 0 {
   130  		return errors.New("installationId can't be empty")
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func ValidateReceivedSendTransaction(message *protobuf.SendTransaction, whisperTimestamp uint64) error {
   137  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   138  		return err
   139  	}
   140  
   141  	if len(strings.TrimSpace(message.TransactionHash)) == 0 {
   142  		return errors.New("transaction hash can't be empty")
   143  	}
   144  
   145  	if message.Signature == nil {
   146  		return errors.New("signature can't be nil")
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  func ValidateReceivedRequestAddressForTransaction(message *protobuf.RequestAddressForTransaction, whisperTimestamp uint64) error {
   153  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   154  		return err
   155  	}
   156  
   157  	if len(strings.TrimSpace(message.Value)) == 0 {
   158  		return errors.New("value can't be empty")
   159  	}
   160  
   161  	_, err := strconv.ParseFloat(message.Value, 64)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  func ValidateReceivedRequestTransaction(message *protobuf.RequestTransaction, whisperTimestamp uint64) error {
   170  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   171  		return err
   172  	}
   173  
   174  	if len(strings.TrimSpace(message.Value)) == 0 {
   175  		return errors.New("value can't be empty")
   176  	}
   177  
   178  	if len(strings.TrimSpace(message.Address)) == 0 {
   179  		return errors.New("address can't be empty")
   180  	}
   181  
   182  	_, err := strconv.ParseFloat(message.Value, 64)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	return nil
   188  }
   189  
   190  func ValidateReceivedAcceptRequestAddressForTransaction(message *protobuf.AcceptRequestAddressForTransaction, whisperTimestamp uint64) error {
   191  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   192  		return err
   193  	}
   194  
   195  	if len(message.Id) == 0 {
   196  		return errors.New("messageID can't be empty")
   197  	}
   198  
   199  	if len(strings.TrimSpace(message.Address)) == 0 {
   200  		return errors.New("address can't be empty")
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func ValidateReceivedDeclineRequestAddressForTransaction(message *protobuf.DeclineRequestAddressForTransaction, whisperTimestamp uint64) error {
   207  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   208  		return err
   209  	}
   210  
   211  	if len(message.Id) == 0 {
   212  		return errors.New("messageID can't be empty")
   213  	}
   214  
   215  	return nil
   216  }
   217  
   218  func ValidateReceivedDeclineRequestTransaction(message *protobuf.DeclineRequestTransaction, whisperTimestamp uint64) error {
   219  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   220  		return err
   221  	}
   222  
   223  	if len(message.Id) == 0 {
   224  		return errors.New("messageID can't be empty")
   225  	}
   226  
   227  	return nil
   228  }
   229  
   230  func ValidateText(text string) error {
   231  	if len(strings.TrimSpace(text)) == 0 {
   232  		return errors.New("text can't be empty")
   233  	}
   234  
   235  	if len([]rune(text)) > maxChatMessageTextLength {
   236  		return fmt.Errorf("text shouldn't be longer than %d", maxChatMessageTextLength)
   237  	}
   238  
   239  	return nil
   240  }
   241  
   242  func ValidateReceivedChatMessage(message *protobuf.ChatMessage, whisperTimestamp uint64) error {
   243  	if err := validateClockValue(message.Clock, whisperTimestamp); err != nil {
   244  		return err
   245  	}
   246  
   247  	if message.Timestamp == 0 {
   248  		return errors.New("timestamp can't be 0")
   249  	}
   250  
   251  	if message.ContentType != protobuf.ChatMessage_DISCORD_MESSAGE &&
   252  		message.ContentType != protobuf.ChatMessage_BRIDGE_MESSAGE &&
   253  		(message.ContentType != protobuf.ChatMessage_IMAGE || message.Text != "") {
   254  		if err := ValidateText(message.Text); err != nil {
   255  			return err
   256  		}
   257  	}
   258  
   259  	if len(message.ChatId) == 0 {
   260  		return errors.New("chatId can't be empty")
   261  	}
   262  
   263  	if message.MessageType == protobuf.MessageType_UNKNOWN_MESSAGE_TYPE || message.MessageType == protobuf.MessageType_SYSTEM_MESSAGE_PRIVATE_GROUP {
   264  		return errors.New("unknown message type")
   265  	}
   266  
   267  	switch message.ContentType {
   268  	case protobuf.ChatMessage_UNKNOWN_CONTENT_TYPE:
   269  		return errors.New("unknown content type")
   270  
   271  	case protobuf.ChatMessage_TRANSACTION_COMMAND:
   272  		return errors.New("can't receive request address for transaction from others")
   273  
   274  	case protobuf.ChatMessage_STICKER:
   275  		if message.Payload == nil {
   276  			return errors.New("no sticker content")
   277  		}
   278  		sticker := message.GetSticker()
   279  		if sticker == nil {
   280  			return errors.New("no sticker content")
   281  		}
   282  		if len(sticker.Hash) == 0 {
   283  			return errors.New("sticker hash not set")
   284  		}
   285  
   286  	case protobuf.ChatMessage_IMAGE:
   287  		if message.Payload == nil {
   288  			return errors.New("no image content")
   289  		}
   290  		image := message.GetImage()
   291  		if image == nil {
   292  			return errors.New("no image content")
   293  		}
   294  		if len(image.Payload) == 0 {
   295  			return errors.New("image payload empty")
   296  		}
   297  		if image.Format == protobuf.ImageFormat_UNKNOWN_IMAGE_FORMAT {
   298  			return errors.New("image type unknown")
   299  		}
   300  
   301  	case protobuf.ChatMessage_BRIDGE_MESSAGE:
   302  		if message.Payload == nil {
   303  			return errors.New("no bridge message content")
   304  		}
   305  		bridgeMessage := message.GetBridgeMessage()
   306  		if bridgeMessage == nil {
   307  			return errors.New("no bridge message content")
   308  		}
   309  		if len(bridgeMessage.UserName) == 0 {
   310  			return errors.New("no username")
   311  		}
   312  		if len(bridgeMessage.BridgeName) == 0 {
   313  			return errors.New("no bridge name")
   314  		}
   315  		if len(bridgeMessage.Content) == 0 {
   316  			return errors.New("no bridge message content text")
   317  		}
   318  	}
   319  
   320  	if message.ContentType == protobuf.ChatMessage_AUDIO {
   321  		if message.Payload == nil {
   322  			return errors.New("no audio content")
   323  		}
   324  		audio := message.GetAudio()
   325  		if audio == nil {
   326  			return errors.New("no audio content")
   327  		}
   328  		if len(audio.Payload) == 0 {
   329  			return errors.New("audio payload empty")
   330  		}
   331  
   332  		if audio.Type == protobuf.AudioMessage_UNKNOWN_AUDIO_TYPE {
   333  			return errors.New("audio type unknown")
   334  		}
   335  	}
   336  
   337  	if message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP {
   338  		return errors.New("private group system message content type not allowed")
   339  	}
   340  
   341  	if message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT ||
   342  		message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED ||
   343  		message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED {
   344  		return errors.New("mutual state event system message content type not allowed")
   345  	}
   346  
   347  	if err := utils.ValidateDisplayName(&message.DisplayName); err != nil {
   348  		return err
   349  	}
   350  
   351  	return nil
   352  }
   353  
   354  func ValidateReceivedEmojiReaction(emoji *protobuf.EmojiReaction, whisperTimestamp uint64) error {
   355  	if err := validateClockValue(emoji.Clock, whisperTimestamp); err != nil {
   356  		return err
   357  	}
   358  
   359  	if len(emoji.MessageId) == 0 {
   360  		return errors.New("message-id can't be empty")
   361  	}
   362  
   363  	if len(emoji.ChatId) == 0 {
   364  		return errors.New("chat-id can't be empty")
   365  	}
   366  
   367  	if emoji.Type == protobuf.EmojiReaction_UNKNOWN_EMOJI_REACTION_TYPE {
   368  		return errors.New("unknown emoji reaction type")
   369  	}
   370  
   371  	if emoji.MessageType == protobuf.MessageType_UNKNOWN_MESSAGE_TYPE {
   372  		return errors.New("unknown message type")
   373  	}
   374  
   375  	return nil
   376  }
   377  
   378  func ValidateReceivedGroupChatInvitation(invitation *protobuf.GroupChatInvitation) error {
   379  
   380  	if len(invitation.ChatId) == 0 {
   381  		return errors.New("chat-id can't be empty")
   382  	}
   383  
   384  	return nil
   385  }