github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/msgchecker/plaintext_checker.go (about)

     1  package msgchecker
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  
     8  	"github.com/keybase/client/go/protocol/chat1"
     9  )
    10  
    11  var validTopicNameRegex = regexp.MustCompile(`^[0-9a-zA-Z_-]+$`)
    12  
    13  type validateTopicNameRes int
    14  
    15  const (
    16  	validateTopicNameResOK            validateTopicNameRes = 0
    17  	validateTopicNameResInvalidLength validateTopicNameRes = 1
    18  	validateTopicNameResInvalidChar   validateTopicNameRes = 2
    19  )
    20  
    21  func (r validateTopicNameRes) String() string {
    22  	switch r {
    23  	case validateTopicNameResInvalidChar:
    24  		return "invalid characters in channel name, please use alphanumeric, underscores, or dashes"
    25  	case validateTopicNameResInvalidLength:
    26  		return "invalid channel name length. Must be greater than 0 and less than or equal to 20"
    27  	case validateTopicNameResOK:
    28  		return "OK"
    29  	}
    30  	return ""
    31  }
    32  
    33  func validateTopicName(topicName string) validateTopicNameRes {
    34  	if len(topicName) == 0 || len(topicName) > TopicMaxLength {
    35  		return validateTopicNameResInvalidLength
    36  	}
    37  	if !validTopicNameRegex.MatchString(topicName) {
    38  		return validateTopicNameResInvalidChar
    39  	}
    40  	return validateTopicNameResOK
    41  }
    42  
    43  type MessagePlaintextLengthExceedingError struct {
    44  	ActualLength         int
    45  	MaxLength            int
    46  	DescriptibleItemName string
    47  }
    48  
    49  func (e MessagePlaintextLengthExceedingError) Error() string {
    50  	return fmt.Sprintf("%s of size %d bytes exceeds the maximum length of %d bytes", e.DescriptibleItemName, e.ActualLength, e.MaxLength)
    51  }
    52  
    53  func (e MessagePlaintextLengthExceedingError) IsImmediateFail() (chat1.OutboxErrorType, bool) {
    54  	return chat1.OutboxErrorType_TOOLONG, true
    55  }
    56  
    57  func plaintextFieldLengthChecker(descriptibleItemName string, actualLength int, maxLength int) error {
    58  	if actualLength > maxLength {
    59  		return MessagePlaintextLengthExceedingError{
    60  			ActualLength:         actualLength,
    61  			MaxLength:            maxLength,
    62  			DescriptibleItemName: descriptibleItemName,
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func checkMessagePlaintextLength(msg chat1.MessagePlaintext) error {
    69  	mtype, err := msg.MessageBody.MessageType()
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	textMsgLength := getMaxTextLength(msg.ClientHeader.Conv.TopicType)
    75  	switch mtype {
    76  	case chat1.MessageType_ATTACHMENT,
    77  		chat1.MessageType_DELETE,
    78  		chat1.MessageType_NONE,
    79  		chat1.MessageType_TLFNAME,
    80  		chat1.MessageType_ATTACHMENTUPLOADED,
    81  		chat1.MessageType_JOIN,
    82  		chat1.MessageType_PIN,
    83  		chat1.MessageType_LEAVE,
    84  		chat1.MessageType_SYSTEM,
    85  		chat1.MessageType_DELETEHISTORY,
    86  		chat1.MessageType_SENDPAYMENT,
    87  		chat1.MessageType_UNFURL:
    88  		return nil
    89  	case chat1.MessageType_TEXT:
    90  		return plaintextFieldLengthChecker("message", len(msg.MessageBody.Text().Body), textMsgLength)
    91  	case chat1.MessageType_FLIP:
    92  		return plaintextFieldLengthChecker("flip", len(msg.MessageBody.Flip().Text), textMsgLength)
    93  	case chat1.MessageType_EDIT:
    94  		return plaintextFieldLengthChecker("message edit", len(msg.MessageBody.Edit().Body),
    95  			textMsgLength)
    96  	case chat1.MessageType_REACTION:
    97  		return plaintextFieldLengthChecker("message reaction", len(msg.MessageBody.Reaction().Body),
    98  			ReactionMessageMaxLength)
    99  	case chat1.MessageType_HEADLINE:
   100  		return plaintextFieldLengthChecker("headline", len(msg.MessageBody.Headline().Headline),
   101  			HeadlineMaxLength)
   102  	case chat1.MessageType_METADATA:
   103  		if msg.ClientHeader.Conv.TopicType == chat1.TopicType_CHAT {
   104  			topicNameRes := validateTopicName(msg.MessageBody.Metadata().ConversationTitle)
   105  			if validateTopicNameResOK != topicNameRes {
   106  				return errors.New(topicNameRes.String())
   107  			}
   108  		}
   109  		return nil
   110  	case chat1.MessageType_REQUESTPAYMENT:
   111  		return plaintextFieldLengthChecker("request payment note",
   112  			len(msg.MessageBody.Requestpayment().Note), RequestPaymentTextMaxLength)
   113  	default:
   114  		typ, err := msg.MessageBody.MessageType()
   115  		if err != nil {
   116  			return fmt.Errorf("unknown message type: %v", err)
   117  		}
   118  		return fmt.Errorf("unknown message type: %v", typ)
   119  	}
   120  }
   121  
   122  func CheckMessagePlaintext(msg chat1.MessagePlaintext) error {
   123  	return checkMessagePlaintextLength(msg)
   124  }