chat.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. package admin
  2. // this is endpoint logic
  3. import (
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "strconv"
  9. "github.com/owncast/owncast/controllers"
  10. "github.com/owncast/owncast/core/chat"
  11. "github.com/owncast/owncast/core/chat/events"
  12. "github.com/owncast/owncast/core/data"
  13. "github.com/owncast/owncast/core/user"
  14. "github.com/owncast/owncast/utils"
  15. log "github.com/sirupsen/logrus"
  16. )
  17. // ExternalUpdateMessageVisibility updates an array of message IDs to have the same visiblity.
  18. func ExternalUpdateMessageVisibility(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  19. UpdateMessageVisibility(w, r)
  20. }
  21. // UpdateMessageVisibility updates an array of message IDs to have the same visiblity.
  22. func UpdateMessageVisibility(w http.ResponseWriter, r *http.Request) {
  23. type messageVisibilityUpdateRequest struct {
  24. IDArray []string `json:"idArray"`
  25. Visible bool `json:"visible"`
  26. }
  27. if r.Method != controllers.POST {
  28. // nolint:goconst
  29. controllers.WriteSimpleResponse(w, false, r.Method+" not supported")
  30. return
  31. }
  32. decoder := json.NewDecoder(r.Body)
  33. var request messageVisibilityUpdateRequest
  34. if err := decoder.Decode(&request); err != nil {
  35. log.Errorln(err)
  36. controllers.WriteSimpleResponse(w, false, "")
  37. return
  38. }
  39. if err := chat.SetMessagesVisibility(request.IDArray, request.Visible); err != nil {
  40. controllers.WriteSimpleResponse(w, false, err.Error())
  41. return
  42. }
  43. controllers.WriteSimpleResponse(w, true, "changed")
  44. }
  45. // BanIPAddress will manually ban an IP address.
  46. func BanIPAddress(w http.ResponseWriter, r *http.Request) {
  47. if !requirePOST(w, r) {
  48. return
  49. }
  50. configValue, success := getValueFromRequest(w, r)
  51. if !success {
  52. controllers.WriteSimpleResponse(w, false, "unable to ban IP address")
  53. return
  54. }
  55. if err := data.BanIPAddress(configValue.Value.(string), "manually added"); err != nil {
  56. controllers.WriteSimpleResponse(w, false, "error saving IP address ban")
  57. return
  58. }
  59. controllers.WriteSimpleResponse(w, true, "IP address banned")
  60. }
  61. // UnBanIPAddress will remove an IP address ban.
  62. func UnBanIPAddress(w http.ResponseWriter, r *http.Request) {
  63. if !requirePOST(w, r) {
  64. return
  65. }
  66. configValue, success := getValueFromRequest(w, r)
  67. if !success {
  68. controllers.WriteSimpleResponse(w, false, "unable to unban IP address")
  69. return
  70. }
  71. if err := data.RemoveIPAddressBan(configValue.Value.(string)); err != nil {
  72. controllers.WriteSimpleResponse(w, false, "error removing IP address ban")
  73. return
  74. }
  75. controllers.WriteSimpleResponse(w, true, "IP address unbanned")
  76. }
  77. // GetIPAddressBans will return all the banned IP addresses.
  78. func GetIPAddressBans(w http.ResponseWriter, r *http.Request) {
  79. bans, err := data.GetIPAddressBans()
  80. if err != nil {
  81. controllers.WriteSimpleResponse(w, false, err.Error())
  82. return
  83. }
  84. controllers.WriteResponse(w, bans)
  85. }
  86. // UpdateUserEnabled enable or disable a single user by ID.
  87. func UpdateUserEnabled(w http.ResponseWriter, r *http.Request) {
  88. type blockUserRequest struct {
  89. UserID string `json:"userId"`
  90. Enabled bool `json:"enabled"`
  91. }
  92. if r.Method != controllers.POST {
  93. controllers.WriteSimpleResponse(w, false, r.Method+" not supported")
  94. return
  95. }
  96. decoder := json.NewDecoder(r.Body)
  97. var request blockUserRequest
  98. if err := decoder.Decode(&request); err != nil {
  99. log.Errorln(err)
  100. controllers.WriteSimpleResponse(w, false, err.Error())
  101. return
  102. }
  103. if request.UserID == "" {
  104. controllers.WriteSimpleResponse(w, false, "must provide userId")
  105. return
  106. }
  107. // Disable/enable the user
  108. if err := user.SetEnabled(request.UserID, request.Enabled); err != nil {
  109. log.Errorln("error changing user enabled status", err)
  110. controllers.WriteSimpleResponse(w, false, err.Error())
  111. return
  112. }
  113. // Hide/show the user's chat messages if disabling.
  114. // Leave hidden messages hidden to be safe.
  115. if !request.Enabled {
  116. if err := chat.SetMessageVisibilityForUserID(request.UserID, request.Enabled); err != nil {
  117. log.Errorln("error changing user messages visibility", err)
  118. controllers.WriteSimpleResponse(w, false, err.Error())
  119. return
  120. }
  121. }
  122. // Forcefully disconnect the user from the chat
  123. if !request.Enabled {
  124. clients, err := chat.GetClientsForUser(request.UserID)
  125. if len(clients) == 0 {
  126. // Nothing to do
  127. return
  128. }
  129. if err != nil {
  130. log.Errorln("error fetching clients for user: ", err)
  131. controllers.WriteSimpleResponse(w, false, err.Error())
  132. return
  133. }
  134. chat.DisconnectClients(clients)
  135. disconnectedUser := user.GetUserByID(request.UserID)
  136. _ = chat.SendSystemAction(fmt.Sprintf("**%s** has been removed from chat.", disconnectedUser.DisplayName), true)
  137. localIP4Address := "127.0.0.1"
  138. localIP6Address := "::1"
  139. // Ban this user's IP address.
  140. for _, client := range clients {
  141. ipAddress := client.IPAddress
  142. if ipAddress != localIP4Address && ipAddress != localIP6Address {
  143. reason := fmt.Sprintf("Banning of %s", disconnectedUser.DisplayName)
  144. if err := data.BanIPAddress(ipAddress, reason); err != nil {
  145. log.Errorln("error banning IP address: ", err)
  146. }
  147. }
  148. }
  149. }
  150. controllers.WriteSimpleResponse(w, true, fmt.Sprintf("%s enabled: %t", request.UserID, request.Enabled))
  151. }
  152. // GetDisabledUsers will return all the disabled users.
  153. func GetDisabledUsers(w http.ResponseWriter, r *http.Request) {
  154. w.Header().Set("Content-Type", "application/json")
  155. users := user.GetDisabledUsers()
  156. controllers.WriteResponse(w, users)
  157. }
  158. // UpdateUserModerator will set the moderator status for a user ID.
  159. func UpdateUserModerator(w http.ResponseWriter, r *http.Request) {
  160. type request struct {
  161. UserID string `json:"userId"`
  162. IsModerator bool `json:"isModerator"`
  163. }
  164. if r.Method != controllers.POST {
  165. controllers.WriteSimpleResponse(w, false, r.Method+" not supported")
  166. return
  167. }
  168. decoder := json.NewDecoder(r.Body)
  169. var req request
  170. if err := decoder.Decode(&req); err != nil {
  171. controllers.WriteSimpleResponse(w, false, "")
  172. return
  173. }
  174. // Update the user object with new moderation access.
  175. if err := user.SetModerator(req.UserID, req.IsModerator); err != nil {
  176. controllers.WriteSimpleResponse(w, false, err.Error())
  177. return
  178. }
  179. // Update the clients for this user to know about the moderator access change.
  180. if err := chat.SendConnectedClientInfoToUser(req.UserID); err != nil {
  181. log.Debugln(err)
  182. }
  183. controllers.WriteSimpleResponse(w, true, fmt.Sprintf("%s is moderator: %t", req.UserID, req.IsModerator))
  184. }
  185. // GetModerators will return a list of moderator users.
  186. func GetModerators(w http.ResponseWriter, r *http.Request) {
  187. w.Header().Set("Content-Type", "application/json")
  188. users := user.GetModeratorUsers()
  189. controllers.WriteResponse(w, users)
  190. }
  191. // GetChatMessages returns all of the chat messages, unfiltered.
  192. func GetChatMessages(w http.ResponseWriter, r *http.Request) {
  193. w.Header().Set("Content-Type", "application/json")
  194. messages := chat.GetChatModerationHistory()
  195. controllers.WriteResponse(w, messages)
  196. }
  197. // SendSystemMessage will send an official "SYSTEM" message to chat on behalf of your server.
  198. func SendSystemMessage(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  199. w.Header().Set("Content-Type", "application/json")
  200. var message events.SystemMessageEvent
  201. if err := json.NewDecoder(r.Body).Decode(&message); err != nil {
  202. controllers.InternalErrorHandler(w, err)
  203. return
  204. }
  205. if err := chat.SendSystemMessage(message.Body, false); err != nil {
  206. controllers.BadRequestHandler(w, err)
  207. }
  208. controllers.WriteSimpleResponse(w, true, "sent")
  209. }
  210. // SendSystemMessageToConnectedClient will handle incoming requests to send a single message to a single connected client by ID.
  211. func SendSystemMessageToConnectedClient(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  212. w.Header().Set("Content-Type", "application/json")
  213. clientIDText, err := utils.ReadRestURLParameter(r, "clientId")
  214. if err != nil {
  215. controllers.BadRequestHandler(w, err)
  216. return
  217. }
  218. clientIDNumeric, err := strconv.ParseUint(clientIDText, 10, 32)
  219. if err != nil {
  220. controllers.BadRequestHandler(w, err)
  221. return
  222. }
  223. var message events.SystemMessageEvent
  224. if err := json.NewDecoder(r.Body).Decode(&message); err != nil {
  225. controllers.InternalErrorHandler(w, err)
  226. return
  227. }
  228. chat.SendSystemMessageToClient(uint(clientIDNumeric), message.Body)
  229. controllers.WriteSimpleResponse(w, true, "sent")
  230. }
  231. // SendUserMessage will send a message to chat on behalf of a user. *Depreciated*.
  232. func SendUserMessage(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  233. w.Header().Set("Content-Type", "application/json")
  234. controllers.BadRequestHandler(w, errors.New("no longer supported. see /api/integrations/chat/send"))
  235. }
  236. // SendIntegrationChatMessage will send a chat message on behalf of an external chat integration.
  237. func SendIntegrationChatMessage(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  238. w.Header().Set("Content-Type", "application/json")
  239. name := integration.DisplayName
  240. if name == "" {
  241. controllers.BadRequestHandler(w, errors.New("unknown integration for provided access token"))
  242. return
  243. }
  244. var event events.UserMessageEvent
  245. if err := json.NewDecoder(r.Body).Decode(&event); err != nil {
  246. controllers.InternalErrorHandler(w, err)
  247. return
  248. }
  249. event.SetDefaults()
  250. event.RenderBody()
  251. event.Type = "CHAT"
  252. if event.Empty() {
  253. controllers.BadRequestHandler(w, errors.New("invalid message"))
  254. return
  255. }
  256. event.User = &user.User{
  257. ID: integration.ID,
  258. DisplayName: name,
  259. DisplayColor: integration.DisplayColor,
  260. CreatedAt: integration.CreatedAt,
  261. IsBot: true,
  262. }
  263. if err := chat.Broadcast(&event); err != nil {
  264. controllers.BadRequestHandler(w, err)
  265. return
  266. }
  267. chat.SaveUserMessage(event)
  268. controllers.WriteSimpleResponse(w, true, "sent")
  269. }
  270. // SendChatAction will send a generic chat action.
  271. func SendChatAction(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
  272. w.Header().Set("Content-Type", "application/json")
  273. var message events.SystemActionEvent
  274. if err := json.NewDecoder(r.Body).Decode(&message); err != nil {
  275. controllers.InternalErrorHandler(w, err)
  276. return
  277. }
  278. message.SetDefaults()
  279. message.RenderBody()
  280. if err := chat.SendSystemAction(message.Body, false); err != nil {
  281. controllers.BadRequestHandler(w, err)
  282. return
  283. }
  284. controllers.WriteSimpleResponse(w, true, "sent")
  285. }
  286. // SetEnableEstablishedChatUserMode sets the requirement for a chat user
  287. // to be "established" for some time before taking part in chat.
  288. func SetEnableEstablishedChatUserMode(w http.ResponseWriter, r *http.Request) {
  289. if !requirePOST(w, r) {
  290. return
  291. }
  292. configValue, success := getValueFromRequest(w, r)
  293. if !success {
  294. controllers.WriteSimpleResponse(w, false, "unable to update chat established user only mode")
  295. return
  296. }
  297. if err := data.SetChatEstablishedUsersOnlyMode(configValue.Value.(bool)); err != nil {
  298. controllers.WriteSimpleResponse(w, false, err.Error())
  299. return
  300. }
  301. controllers.WriteSimpleResponse(w, true, "chat established users only mode updated")
  302. }