community.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
  2. // Copyright (C) 2020 Tulir Asokan
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package main
  17. import (
  18. "fmt"
  19. "net/http"
  20. "maunium.net/go/mautrix"
  21. )
  22. func (user *User) inviteToCommunity() {
  23. url := user.bridge.Bot.BuildURL("groups", user.CommunityID, "admin", "users", "invite", user.MXID)
  24. reqBody := map[string]interface{}{}
  25. _, err := user.bridge.Bot.MakeRequest(http.MethodPut, url, &reqBody, nil)
  26. if err != nil {
  27. user.log.Warnfln("Failed to invite user to personal filtering community %s: %v", user.CommunityID, err)
  28. }
  29. }
  30. func (user *User) updateCommunityProfile() {
  31. url := user.bridge.Bot.BuildURL("groups", user.CommunityID, "profile")
  32. profileReq := struct {
  33. Name string `json:"name"`
  34. AvatarURL string `json:"avatar_url"`
  35. ShortDescription string `json:"short_description"`
  36. }{"WhatsApp", user.bridge.Config.AppService.Bot.Avatar, "Your WhatsApp bridged chats"}
  37. _, err := user.bridge.Bot.MakeRequest(http.MethodPost, url, &profileReq, nil)
  38. if err != nil {
  39. user.log.Warnfln("Failed to update metadata of %s: %v", user.CommunityID, err)
  40. }
  41. }
  42. func (user *User) createCommunity() {
  43. if user.IsRelaybot || !user.bridge.Config.Bridge.EnableCommunities() {
  44. return
  45. }
  46. localpart, server, _ := user.MXID.Parse()
  47. community := user.bridge.Config.Bridge.FormatCommunity(localpart, server)
  48. user.log.Debugln("Creating personal filtering community", community)
  49. bot := user.bridge.Bot
  50. req := struct {
  51. Localpart string `json:"localpart"`
  52. }{community}
  53. resp := struct {
  54. GroupID string `json:"group_id"`
  55. }{}
  56. _, err := bot.MakeRequest(http.MethodPost, bot.BuildURL("create_group"), &req, &resp)
  57. if err != nil {
  58. if httpErr, ok := err.(mautrix.HTTPError); ok {
  59. if httpErr.RespError.Err != "Group already exists" {
  60. user.log.Warnln("Server responded with error creating personal filtering community:", err)
  61. return
  62. } else {
  63. user.log.Debugln("Personal filtering community", resp.GroupID, "already existed")
  64. user.CommunityID = fmt.Sprintf("+%s:%s", req.Localpart, user.bridge.Config.Homeserver.Domain)
  65. }
  66. } else {
  67. user.log.Warnln("Unknown error creating personal filtering community:", err)
  68. return
  69. }
  70. } else {
  71. user.log.Infoln("Created personal filtering community %s", resp.GroupID)
  72. user.CommunityID = resp.GroupID
  73. user.inviteToCommunity()
  74. user.updateCommunityProfile()
  75. }
  76. }
  77. func (user *User) addPuppetToCommunity(puppet *Puppet) bool {
  78. if user.IsRelaybot || len(user.CommunityID) == 0 {
  79. return false
  80. }
  81. bot := user.bridge.Bot
  82. url := bot.BuildURL("groups", user.CommunityID, "admin", "users", "invite", puppet.MXID)
  83. blankReqBody := map[string]interface{}{}
  84. _, err := bot.MakeRequest(http.MethodPut, url, &blankReqBody, nil)
  85. if err != nil {
  86. user.log.Warnfln("Failed to invite %s to %s: %v", puppet.MXID, user.CommunityID, err)
  87. return false
  88. }
  89. reqBody := map[string]map[string]string{
  90. "m.visibility": {
  91. "type": "private",
  92. },
  93. }
  94. url = bot.BuildURLWithQuery(mautrix.URLPath{"groups", user.CommunityID, "self", "accept_invite"}, map[string]string{
  95. "user_id": puppet.MXID.String(),
  96. })
  97. _, err = bot.MakeRequest(http.MethodPut, url, &reqBody, nil)
  98. if err != nil {
  99. user.log.Warnfln("Failed to join %s as %s: %v", user.CommunityID, puppet.MXID, err)
  100. return false
  101. }
  102. user.log.Debugln("Added", puppet.MXID, "to", user.CommunityID)
  103. return true
  104. }
  105. func (user *User) addPortalToCommunity(portal *Portal) bool {
  106. if user.IsRelaybot || len(user.CommunityID) == 0 || len(portal.MXID) == 0 {
  107. return false
  108. }
  109. bot := user.bridge.Bot
  110. url := bot.BuildURL("groups", user.CommunityID, "admin", "rooms", portal.MXID)
  111. reqBody := map[string]map[string]string{
  112. "m.visibility": {
  113. "type": "private",
  114. },
  115. }
  116. _, err := bot.MakeRequest(http.MethodPut, url, &reqBody, nil)
  117. if err != nil {
  118. user.log.Warnfln("Failed to add %s to %s: %v", portal.MXID, user.CommunityID, err)
  119. return false
  120. }
  121. user.log.Debugln("Added", portal.MXID, "to", user.CommunityID)
  122. return true
  123. }