jid.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Copyright (c) 2021 Tulir Asokan
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. // Package types contains various structs and other types used by whatsmeow.
  7. package types
  8. import (
  9. "database/sql"
  10. "database/sql/driver"
  11. "fmt"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. signalProtocol "go.mau.fi/libsignal/protocol"
  16. )
  17. // Known JID servers on WhatsApp
  18. const (
  19. DefaultUserServer = "s.whatsapp.net"
  20. GroupServer = "g.us"
  21. LegacyUserServer = "c.us"
  22. BroadcastServer = "broadcast"
  23. HiddenUserServer = "lid"
  24. MessengerServer = "msgr"
  25. InteropServer = "interop"
  26. NewsletterServer = "newsletter"
  27. HostedServer = "hosted"
  28. HostedLIDServer = "hosted.lid"
  29. BotServer = "bot"
  30. )
  31. // Some JIDs that are contacted often.
  32. var (
  33. EmptyJID = JID{}
  34. GroupServerJID = NewJID("", GroupServer)
  35. ServerJID = NewJID("", DefaultUserServer)
  36. BroadcastServerJID = NewJID("", BroadcastServer)
  37. StatusBroadcastJID = NewJID("status", BroadcastServer)
  38. LegacyPSAJID = NewJID("0", LegacyUserServer)
  39. PSAJID = NewJID("0", DefaultUserServer)
  40. OfficialBusinessJID = NewJID("16505361212", LegacyUserServer)
  41. MetaAIJID = NewJID("13135550002", DefaultUserServer)
  42. NewMetaAIJID = NewJID("867051314767696", BotServer)
  43. )
  44. var (
  45. WhatsAppDomain = uint8(0) // This is the main domain type that whatsapp uses
  46. LIDDomain = uint8(1) // This is the domain for LID type JIDs
  47. HostedDomain = uint8(128) // This is the domain for Hosted type JIDs
  48. HostedLIDDomain = uint8(129) // This is the domain for Hosted LID type JIDs
  49. )
  50. // MessageID is the internal ID of a WhatsApp message.
  51. type MessageID = string
  52. // MessageServerID is the server ID of a WhatsApp newsletter message.
  53. type MessageServerID = int
  54. // JID represents a WhatsApp user ID.
  55. //
  56. // There are two types of JIDs: regular JID pairs (user and server) and AD-JIDs (user, agent and device).
  57. // AD JIDs are only used to refer to specific devices of users, so the server is always s.whatsapp.net (DefaultUserServer).
  58. // Regular JIDs can be used for entities on any servers (users, groups, broadcasts).
  59. type JID struct {
  60. User string
  61. RawAgent uint8
  62. Device uint16
  63. Integrator uint16
  64. Server string
  65. }
  66. func (jid JID) ActualAgent() uint8 {
  67. switch jid.Server {
  68. case DefaultUserServer:
  69. return WhatsAppDomain
  70. case HiddenUserServer:
  71. return LIDDomain
  72. case HostedServer:
  73. return HostedDomain
  74. case HostedLIDServer:
  75. return HostedLIDDomain
  76. default:
  77. return jid.RawAgent
  78. }
  79. }
  80. // UserInt returns the user as an integer. This is only safe to run on normal users, not on groups or broadcast lists.
  81. func (jid JID) UserInt() uint64 {
  82. number, _ := strconv.ParseUint(jid.User, 10, 64)
  83. return number
  84. }
  85. // ToNonAD returns a version of the JID struct that doesn't have the agent and device set.
  86. func (jid JID) ToNonAD() JID {
  87. return JID{
  88. User: jid.User,
  89. Server: jid.Server,
  90. Integrator: jid.Integrator,
  91. }
  92. }
  93. // SignalAddress returns the Signal protocol address for the user.
  94. func (jid JID) SignalAddress() *signalProtocol.SignalAddress {
  95. return signalProtocol.NewSignalAddress(jid.SignalAddressUser(), uint32(jid.Device))
  96. }
  97. func (jid JID) SignalAddressUser() string {
  98. user := jid.User
  99. agent := jid.ActualAgent()
  100. if agent != 0 {
  101. user = fmt.Sprintf("%s_%d", jid.User, agent)
  102. }
  103. return user
  104. }
  105. // IsBroadcastList returns true if the JID is a broadcast list, but not the status broadcast.
  106. func (jid JID) IsBroadcastList() bool {
  107. return jid.Server == BroadcastServer && jid.User != StatusBroadcastJID.User
  108. }
  109. var botUserRegex = regexp.MustCompile(`^1313555\d{4}$|^131655500\d{2}$`)
  110. func (jid JID) IsBot() bool {
  111. return (jid.Server == DefaultUserServer && botUserRegex.MatchString(jid.User) && jid.Device == 0) || jid.Server == BotServer
  112. }
  113. // NewADJID creates a new AD JID.
  114. func NewADJID(user string, agent, device uint8) JID {
  115. var server string
  116. // agent terminology isn't 100% correct here, these are the domainType, but whatsapp usually places them in the same place (if the switch case below doesn't process it, then it is an agent instead)
  117. switch agent {
  118. case LIDDomain:
  119. server = HiddenUserServer
  120. agent = 0
  121. case HostedDomain:
  122. server = HostedServer
  123. agent = 0
  124. case HostedLIDDomain:
  125. server = HostedLIDServer
  126. agent = 0
  127. default:
  128. case WhatsAppDomain:
  129. server = DefaultUserServer // will just default to the normal server
  130. }
  131. return JID{
  132. User: user,
  133. RawAgent: agent,
  134. Device: uint16(device),
  135. Server: server,
  136. }
  137. }
  138. // ParseJID parses a JID out of the given string. It supports both regular and AD JIDs.
  139. func ParseJID(jid string) (JID, error) {
  140. parts := strings.Split(jid, "@")
  141. if len(parts) == 1 {
  142. return NewJID("", parts[0]), nil
  143. }
  144. parsedJID := JID{User: parts[0], Server: parts[1]}
  145. if strings.ContainsRune(parsedJID.User, '.') {
  146. parts = strings.Split(parsedJID.User, ".")
  147. if len(parts) != 2 {
  148. return parsedJID, fmt.Errorf("unexpected number of dots in JID")
  149. }
  150. parsedJID.User = parts[0]
  151. ad := parts[1]
  152. parts = strings.Split(ad, ":")
  153. if len(parts) > 2 {
  154. return parsedJID, fmt.Errorf("unexpected number of colons in JID")
  155. }
  156. agent, err := strconv.Atoi(parts[0])
  157. if err != nil {
  158. return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
  159. }
  160. parsedJID.RawAgent = uint8(agent)
  161. if len(parts) == 2 {
  162. device, err := strconv.Atoi(parts[1])
  163. if err != nil {
  164. return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
  165. }
  166. parsedJID.Device = uint16(device)
  167. }
  168. } else if strings.ContainsRune(parsedJID.User, ':') {
  169. parts = strings.Split(parsedJID.User, ":")
  170. if len(parts) != 2 {
  171. return parsedJID, fmt.Errorf("unexpected number of colons in JID")
  172. }
  173. parsedJID.User = parts[0]
  174. device, err := strconv.Atoi(parts[1])
  175. if err != nil {
  176. return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
  177. }
  178. parsedJID.Device = uint16(device)
  179. }
  180. return parsedJID, nil
  181. }
  182. // NewJID creates a new regular JID.
  183. func NewJID(user, server string) JID {
  184. return JID{
  185. User: user,
  186. Server: server,
  187. }
  188. }
  189. func (jid JID) ADString() string {
  190. return fmt.Sprintf("%s.%d:%d@%s", jid.User, jid.RawAgent, jid.Device, jid.Server)
  191. }
  192. // String converts the JID to a string representation.
  193. // The output string can be parsed with ParseJID.
  194. func (jid JID) String() string {
  195. if jid.RawAgent > 0 {
  196. return fmt.Sprintf("%s.%d:%d@%s", jid.User, jid.RawAgent, jid.Device, jid.Server)
  197. } else if jid.Device > 0 {
  198. return fmt.Sprintf("%s:%d@%s", jid.User, jid.Device, jid.Server)
  199. } else if len(jid.User) > 0 {
  200. return fmt.Sprintf("%s@%s", jid.User, jid.Server)
  201. } else {
  202. return jid.Server
  203. }
  204. }
  205. // MarshalText implements encoding.TextMarshaler for JID
  206. func (jid JID) MarshalText() ([]byte, error) {
  207. return []byte(jid.String()), nil
  208. }
  209. // UnmarshalText implements encoding.TextUnmarshaler for JID
  210. func (jid *JID) UnmarshalText(val []byte) error {
  211. out, err := ParseJID(string(val))
  212. if err != nil {
  213. return err
  214. }
  215. *jid = out
  216. return nil
  217. }
  218. // IsEmpty returns true if the JID has no server (which is required for all JIDs).
  219. func (jid JID) IsEmpty() bool {
  220. return len(jid.Server) == 0
  221. }
  222. var _ sql.Scanner = (*JID)(nil)
  223. // Scan scans the given SQL value into this JID.
  224. func (jid *JID) Scan(src interface{}) error {
  225. if src == nil {
  226. return nil
  227. }
  228. var out JID
  229. var err error
  230. switch val := src.(type) {
  231. case string:
  232. out, err = ParseJID(val)
  233. case []byte:
  234. out, err = ParseJID(string(val))
  235. default:
  236. err = fmt.Errorf("unsupported type %T for scanning JID", val)
  237. }
  238. if err != nil {
  239. return err
  240. }
  241. *jid = out
  242. return nil
  243. }
  244. // Value returns the string representation of the JID as a value that the SQL package can use.
  245. func (jid JID) Value() (driver.Value, error) {
  246. if len(jid.Server) == 0 {
  247. return nil, nil
  248. }
  249. return jid.String(), nil
  250. }