puppet.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
  2. // Copyright (C) 2018 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. "maunium.net/go/mautrix-whatsapp/database"
  19. log "maunium.net/go/maulogger"
  20. "fmt"
  21. "regexp"
  22. "maunium.net/go/mautrix-whatsapp/types"
  23. "strings"
  24. "maunium.net/go/mautrix-appservice"
  25. "github.com/Rhymen/go-whatsapp"
  26. )
  27. const puppetJIDStrippedSuffix = "@s.whatsapp.net"
  28. func (bridge *Bridge) ParsePuppetMXID(mxid types.MatrixUserID) (types.MatrixUserID, types.WhatsAppID, bool) {
  29. userIDRegex, err := regexp.Compile(fmt.Sprintf("^@%s:%s$",
  30. bridge.Config.Bridge.FormatUsername("([0-9]+)", "([0-9]+)"),
  31. bridge.Config.Homeserver.Domain))
  32. if err != nil {
  33. bridge.Log.Warnln("Failed to compile puppet user ID regex:", err)
  34. return "", "", false
  35. }
  36. match := userIDRegex.FindStringSubmatch(string(mxid))
  37. if match == nil || len(match) != 3 {
  38. return "", "", false
  39. }
  40. receiver := types.MatrixUserID(match[1])
  41. receiver = strings.Replace(receiver, "=40", "@", 1)
  42. colonIndex := strings.LastIndex(receiver, "=3")
  43. receiver = receiver[:colonIndex] + ":" + receiver[colonIndex+len("=3"):]
  44. jid := types.WhatsAppID(match[2] + puppetJIDStrippedSuffix)
  45. return receiver, jid, true
  46. }
  47. func (bridge *Bridge) GetPuppetByMXID(mxid types.MatrixUserID) *Puppet {
  48. receiver, jid, ok := bridge.ParsePuppetMXID(mxid)
  49. if !ok {
  50. return nil
  51. }
  52. user := bridge.GetUser(receiver)
  53. if user == nil {
  54. return nil
  55. }
  56. return user.GetPuppetByJID(jid)
  57. }
  58. func (user *User) GetPuppetByMXID(mxid types.MatrixUserID) *Puppet {
  59. receiver, jid, ok := user.bridge.ParsePuppetMXID(mxid)
  60. if !ok || receiver != user.ID {
  61. return nil
  62. }
  63. return user.GetPuppetByJID(jid)
  64. }
  65. func (user *User) GetPuppetByJID(jid types.WhatsAppID) *Puppet {
  66. puppet, ok := user.puppets[jid]
  67. if !ok {
  68. dbPuppet := user.bridge.DB.Puppet.Get(jid, user.ID)
  69. if dbPuppet == nil {
  70. dbPuppet = user.bridge.DB.Puppet.New()
  71. dbPuppet.JID = jid
  72. dbPuppet.Receiver = user.ID
  73. dbPuppet.Insert()
  74. }
  75. puppet = user.NewPuppet(dbPuppet)
  76. user.puppets[puppet.JID] = puppet
  77. }
  78. return puppet
  79. }
  80. func (user *User) GetAllPuppets() []*Puppet {
  81. dbPuppets := user.bridge.DB.Puppet.GetAll(user.ID)
  82. output := make([]*Puppet, len(dbPuppets))
  83. for index, dbPuppet := range dbPuppets {
  84. puppet, ok := user.puppets[dbPuppet.JID]
  85. if !ok {
  86. puppet = user.NewPuppet(dbPuppet)
  87. user.puppets[dbPuppet.JID] = puppet
  88. }
  89. output[index] = puppet
  90. }
  91. return output
  92. }
  93. func (user *User) NewPuppet(dbPuppet *database.Puppet) *Puppet {
  94. return &Puppet{
  95. Puppet: dbPuppet,
  96. user: user,
  97. bridge: user.bridge,
  98. log: user.log.Sub(fmt.Sprintf("Puppet/%s", dbPuppet.JID)),
  99. MXID: fmt.Sprintf("@%s:%s",
  100. user.bridge.Config.Bridge.FormatUsername(
  101. dbPuppet.Receiver,
  102. strings.Replace(
  103. dbPuppet.JID,
  104. puppetJIDStrippedSuffix, "", 1)),
  105. user.bridge.Config.Homeserver.Domain),
  106. }
  107. }
  108. type Puppet struct {
  109. *database.Puppet
  110. user *User
  111. bridge *Bridge
  112. log log.Logger
  113. MXID types.MatrixUserID
  114. }
  115. func (puppet *Puppet) Intent() *appservice.IntentAPI {
  116. return puppet.bridge.AppService.Intent(puppet.MXID)
  117. }
  118. func (puppet *Puppet) Sync(contact whatsapp.Contact) {
  119. puppet.Intent().EnsureRegistered()
  120. newName := puppet.bridge.Config.Bridge.FormatDisplayname(contact)
  121. if puppet.Displayname != newName {
  122. puppet.Displayname = newName
  123. puppet.Update()
  124. puppet.Intent().SetDisplayName(puppet.Displayname)
  125. }
  126. }