events.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package chat
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "time"
  7. "github.com/owncast/owncast/config"
  8. "github.com/owncast/owncast/core/chat/events"
  9. "github.com/owncast/owncast/core/data"
  10. "github.com/owncast/owncast/core/webhooks"
  11. "github.com/owncast/owncast/persistence/userrepository"
  12. "github.com/owncast/owncast/utils"
  13. log "github.com/sirupsen/logrus"
  14. )
  15. func (s *Server) userNameChanged(eventData chatClientEvent) {
  16. var receivedEvent events.NameChangeEvent
  17. if err := json.Unmarshal(eventData.data, &receivedEvent); err != nil {
  18. log.Errorln("error unmarshalling to NameChangeEvent", err)
  19. return
  20. }
  21. proposedUsername := receivedEvent.NewName
  22. // Check if name is on the blocklist
  23. blocklist := data.GetForbiddenUsernameList()
  24. // Names have a max length
  25. proposedUsername = utils.MakeSafeStringOfLength(proposedUsername, config.MaxChatDisplayNameLength)
  26. for _, blockedName := range blocklist {
  27. normalizedName := strings.TrimSpace(blockedName)
  28. normalizedName = strings.ToLower(normalizedName)
  29. if strings.Contains(normalizedName, proposedUsername) {
  30. // Denied.
  31. log.Debugln(logSanitize(eventData.client.User.DisplayName), "blocked from changing name to", logSanitize(proposedUsername), "due to blocked name", normalizedName)
  32. message := fmt.Sprintf("You cannot change your name to **%s**.", proposedUsername)
  33. s.sendActionToClient(eventData.client, message)
  34. // Resend the client's user so their username is in sync.
  35. eventData.client.sendConnectedClientInfo()
  36. return
  37. }
  38. }
  39. userRepository := userrepository.Get()
  40. // Check if the name is not already assigned to a registered user.
  41. if available, err := userRepository.IsDisplayNameAvailable(proposedUsername); err != nil {
  42. log.Errorln("error checking if name is available", err)
  43. return
  44. } else if !available {
  45. message := fmt.Sprintf("The name **%s** has already been registered. If this is your name, please authenticate.", proposedUsername)
  46. s.sendActionToClient(eventData.client, message)
  47. // Resend the client's user so their username is in sync.
  48. eventData.client.sendConnectedClientInfo()
  49. return
  50. }
  51. savedUser := userRepository.GetUserByToken(eventData.client.accessToken)
  52. oldName := savedUser.DisplayName
  53. // Check that the new name is different from old.
  54. if proposedUsername == oldName {
  55. eventData.client.sendConnectedClientInfo()
  56. return
  57. }
  58. // Save the new name
  59. if err := userRepository.ChangeUsername(eventData.client.User.ID, proposedUsername); err != nil {
  60. log.Errorln("error changing username", err)
  61. }
  62. // Update the connected clients associated user with the new name
  63. now := time.Now()
  64. eventData.client.User = savedUser
  65. eventData.client.User.NameChangedAt = &now
  66. // Send chat event letting everyone about about the name change
  67. savedUser.DisplayName = proposedUsername
  68. broadcastEvent := events.NameChangeBroadcast{
  69. Oldname: oldName,
  70. }
  71. broadcastEvent.User = savedUser
  72. broadcastEvent.SetDefaults()
  73. payload := broadcastEvent.GetBroadcastPayload()
  74. if err := s.Broadcast(payload); err != nil {
  75. log.Errorln("error broadcasting NameChangeEvent", err)
  76. return
  77. }
  78. // Send chat user name changed webhook
  79. receivedEvent.User = savedUser
  80. receivedEvent.ClientID = eventData.client.Id
  81. webhooks.SendChatEventUsernameChanged(receivedEvent)
  82. // Resend the client's user so their username is in sync.
  83. eventData.client.sendConnectedClientInfo()
  84. }
  85. func (s *Server) userColorChanged(eventData chatClientEvent) {
  86. userRepository := userrepository.Get()
  87. var receivedEvent events.ColorChangeEvent
  88. if err := json.Unmarshal(eventData.data, &receivedEvent); err != nil {
  89. log.Errorln("error unmarshalling to ColorChangeEvent", err)
  90. return
  91. }
  92. // Verify this color is valid
  93. if receivedEvent.NewColor > config.MaxUserColor {
  94. log.Errorln("invalid color requested when changing user display color")
  95. return
  96. }
  97. // Save the new color
  98. if err := userRepository.ChangeUserColor(eventData.client.User.ID, receivedEvent.NewColor); err != nil {
  99. log.Errorln("error changing user display color", err)
  100. }
  101. // Resend client's user info with new color, otherwise the name change dialog would still show the old color
  102. eventData.client.User.DisplayColor = receivedEvent.NewColor
  103. eventData.client.sendConnectedClientInfo()
  104. }
  105. func (s *Server) userMessageSent(eventData chatClientEvent) {
  106. userRepository := userrepository.Get()
  107. var event events.UserMessageEvent
  108. if err := json.Unmarshal(eventData.data, &event); err != nil {
  109. log.Errorln("error unmarshalling to UserMessageEvent", err)
  110. return
  111. }
  112. event.SetDefaults()
  113. event.ClientID = eventData.client.Id
  114. // Ignore empty messages
  115. if event.Empty() {
  116. return
  117. }
  118. // Ignore if the stream has been offline
  119. if !getStatus().Online && getStatus().LastDisconnectTime != nil {
  120. disconnectedTime := getStatus().LastDisconnectTime.Time
  121. if time.Since(disconnectedTime) > 5*time.Minute {
  122. return
  123. }
  124. }
  125. event.User = userRepository.GetUserByToken(eventData.client.accessToken)
  126. // Guard against nil users
  127. if event.User == nil {
  128. return
  129. }
  130. payload := event.GetBroadcastPayload()
  131. if err := s.Broadcast(payload); err != nil {
  132. log.Errorln("error broadcasting UserMessageEvent payload", err)
  133. return
  134. }
  135. // Send chat message sent webhook
  136. webhooks.SendChatEvent(&event)
  137. chatMessagesSentCounter.Inc()
  138. SaveUserMessage(event)
  139. eventData.client.MessageCount++
  140. }
  141. func logSanitize(userValue string) string {
  142. // strip carriage return and newline from user-submitted values to prevent log injection
  143. sanitizedValue := strings.ReplaceAll(userValue, "\n", "")
  144. sanitizedValue = strings.ReplaceAll(sanitizedValue, "\r", "")
  145. return fmt.Sprintf("userSuppliedValue(%s)", sanitizedValue)
  146. }