sendfb.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. // Copyright (c) 2024 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 whatsmeow
  7. import (
  8. "context"
  9. "crypto/hmac"
  10. "crypto/sha256"
  11. "errors"
  12. "fmt"
  13. "time"
  14. "github.com/google/uuid"
  15. "go.mau.fi/libsignal/groups"
  16. "go.mau.fi/libsignal/keys/prekey"
  17. "go.mau.fi/libsignal/protocol"
  18. "go.mau.fi/libsignal/session"
  19. "go.mau.fi/libsignal/signalerror"
  20. "go.mau.fi/util/random"
  21. "google.golang.org/protobuf/proto"
  22. waBinary "git.bobomao.top/joey/testwh/binary"
  23. armadillo "git.bobomao.top/joey/testwh/proto"
  24. "git.bobomao.top/joey/testwh/proto/waArmadilloApplication"
  25. "git.bobomao.top/joey/testwh/proto/waCommon"
  26. "git.bobomao.top/joey/testwh/proto/waConsumerApplication"
  27. "git.bobomao.top/joey/testwh/proto/waMsgApplication"
  28. "git.bobomao.top/joey/testwh/proto/waMsgTransport"
  29. "git.bobomao.top/joey/testwh/types"
  30. "git.bobomao.top/joey/testwh/types/events"
  31. )
  32. const FBMessageVersion = 3
  33. const FBMessageApplicationVersion = 2
  34. const IGMessageApplicationVersion = 3
  35. const FBConsumerMessageVersion = 1
  36. const FBArmadilloMessageVersion = 1
  37. // SendFBMessage sends the given v3 message to the given JID.
  38. func (cli *Client) SendFBMessage(
  39. ctx context.Context,
  40. to types.JID,
  41. message armadillo.RealMessageApplicationSub,
  42. metadata *waMsgApplication.MessageApplication_Metadata,
  43. extra ...SendRequestExtra,
  44. ) (resp SendResponse, err error) {
  45. if cli == nil {
  46. err = ErrClientIsNil
  47. return
  48. }
  49. var req SendRequestExtra
  50. if len(extra) > 1 {
  51. err = errors.New("only one extra parameter may be provided to SendMessage")
  52. return
  53. } else if len(extra) == 1 {
  54. req = extra[0]
  55. }
  56. var subproto waMsgApplication.MessageApplication_SubProtocolPayload
  57. subproto.FutureProof = waCommon.FutureProofBehavior_PLACEHOLDER.Enum()
  58. switch typedMsg := message.(type) {
  59. case *waConsumerApplication.ConsumerApplication:
  60. var consumerMessage []byte
  61. consumerMessage, err = proto.Marshal(typedMsg)
  62. if err != nil {
  63. err = fmt.Errorf("failed to marshal consumer message: %w", err)
  64. return
  65. }
  66. subproto.SubProtocol = &waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage{
  67. ConsumerMessage: &waCommon.SubProtocol{
  68. Payload: consumerMessage,
  69. Version: proto.Int32(FBConsumerMessageVersion),
  70. },
  71. }
  72. case *waArmadilloApplication.Armadillo:
  73. var armadilloMessage []byte
  74. armadilloMessage, err = proto.Marshal(typedMsg)
  75. if err != nil {
  76. err = fmt.Errorf("failed to marshal armadillo message: %w", err)
  77. return
  78. }
  79. subproto.SubProtocol = &waMsgApplication.MessageApplication_SubProtocolPayload_Armadillo{
  80. Armadillo: &waCommon.SubProtocol{
  81. Payload: armadilloMessage,
  82. Version: proto.Int32(FBArmadilloMessageVersion),
  83. },
  84. }
  85. default:
  86. err = fmt.Errorf("unsupported message type %T", message)
  87. return
  88. }
  89. if metadata == nil {
  90. metadata = &waMsgApplication.MessageApplication_Metadata{}
  91. }
  92. metadata.FrankingVersion = proto.Int32(0)
  93. metadata.FrankingKey = random.Bytes(32)
  94. msgAttrs := getAttrsFromFBMessage(message)
  95. messageAppProto := &waMsgApplication.MessageApplication{
  96. Payload: &waMsgApplication.MessageApplication_Payload{
  97. Content: &waMsgApplication.MessageApplication_Payload_SubProtocol{
  98. SubProtocol: &subproto,
  99. },
  100. },
  101. Metadata: metadata,
  102. }
  103. messageApp, err := proto.Marshal(messageAppProto)
  104. if err != nil {
  105. return resp, fmt.Errorf("failed to marshal message application: %w", err)
  106. }
  107. frankingHash := hmac.New(sha256.New, metadata.FrankingKey)
  108. frankingHash.Write(messageApp)
  109. frankingTag := frankingHash.Sum(nil)
  110. if to.Device > 0 && !req.Peer {
  111. err = ErrRecipientADJID
  112. return
  113. }
  114. ownID := cli.getOwnID()
  115. if ownID.IsEmpty() {
  116. err = ErrNotLoggedIn
  117. return
  118. }
  119. if req.Timeout == 0 {
  120. req.Timeout = defaultRequestTimeout
  121. }
  122. if len(req.ID) == 0 {
  123. req.ID = cli.GenerateMessageID()
  124. }
  125. resp.ID = req.ID
  126. start := time.Now()
  127. // Sending multiple messages at a time can cause weird issues and makes it harder to retry safely
  128. cli.messageSendLock.Lock()
  129. resp.DebugTimings.Queue = time.Since(start)
  130. defer cli.messageSendLock.Unlock()
  131. respChan := cli.waitResponse(req.ID)
  132. if !req.Peer {
  133. cli.addRecentMessage(to, req.ID, nil, messageAppProto)
  134. }
  135. var phash string
  136. var data []byte
  137. switch to.Server {
  138. case types.GroupServer:
  139. phash, data, err = cli.sendGroupV3(ctx, to, ownID, req.ID, messageApp, msgAttrs, frankingTag, &resp.DebugTimings)
  140. case types.DefaultUserServer, types.MessengerServer:
  141. if req.Peer {
  142. err = fmt.Errorf("peer messages to fb are not yet supported")
  143. //data, err = cli.sendPeerMessage(to, req.ID, message, &resp.DebugTimings)
  144. } else {
  145. data, phash, err = cli.sendDMV3(ctx, to, ownID, req.ID, messageApp, msgAttrs, frankingTag, &resp.DebugTimings)
  146. }
  147. default:
  148. err = fmt.Errorf("%w %s", ErrUnknownServer, to.Server)
  149. }
  150. start = time.Now()
  151. if err != nil {
  152. cli.cancelResponse(req.ID, respChan)
  153. return
  154. }
  155. var respNode *waBinary.Node
  156. var timeoutChan <-chan time.Time
  157. if req.Timeout > 0 {
  158. timeoutChan = time.After(req.Timeout)
  159. } else {
  160. timeoutChan = make(<-chan time.Time)
  161. }
  162. select {
  163. case respNode = <-respChan:
  164. case <-timeoutChan:
  165. cli.cancelResponse(req.ID, respChan)
  166. err = ErrMessageTimedOut
  167. return
  168. case <-ctx.Done():
  169. cli.cancelResponse(req.ID, respChan)
  170. err = ctx.Err()
  171. return
  172. }
  173. resp.DebugTimings.Resp = time.Since(start)
  174. if isDisconnectNode(respNode) {
  175. start = time.Now()
  176. respNode, err = cli.retryFrame(ctx, "message send", req.ID, data, respNode, 0)
  177. resp.DebugTimings.Retry = time.Since(start)
  178. if err != nil {
  179. return
  180. }
  181. }
  182. ag := respNode.AttrGetter()
  183. resp.ServerID = types.MessageServerID(ag.OptionalInt("server_id"))
  184. resp.Timestamp = ag.UnixTime("t")
  185. if errorCode := ag.Int("error"); errorCode != 0 {
  186. err = fmt.Errorf("%w %d", ErrServerReturnedError, errorCode)
  187. }
  188. expectedPHash := ag.OptionalString("phash")
  189. if len(expectedPHash) > 0 && phash != expectedPHash {
  190. cli.Log.Warnf("Server returned different participant list hash when sending to %s. Some devices may not have received the message.", to)
  191. // TODO also invalidate device list caches
  192. cli.groupCacheLock.Lock()
  193. delete(cli.groupCache, to)
  194. cli.groupCacheLock.Unlock()
  195. }
  196. return
  197. }
  198. func (cli *Client) sendGroupV3(
  199. ctx context.Context,
  200. to,
  201. ownID types.JID,
  202. id types.MessageID,
  203. messageApp []byte,
  204. msgAttrs messageAttrs,
  205. frankingTag []byte,
  206. timings *MessageDebugTimings,
  207. ) (string, []byte, error) {
  208. var groupMeta *groupMetaCache
  209. var err error
  210. start := time.Now()
  211. if to.Server == types.GroupServer {
  212. groupMeta, err = cli.getCachedGroupData(ctx, to)
  213. if err != nil {
  214. return "", nil, fmt.Errorf("failed to get group members: %w", err)
  215. }
  216. }
  217. timings.GetParticipants = time.Since(start)
  218. start = time.Now()
  219. builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
  220. senderKeyName := protocol.NewSenderKeyName(to.String(), ownID.SignalAddress())
  221. signalSKDMessage, err := builder.Create(ctx, senderKeyName)
  222. if err != nil {
  223. return "", nil, fmt.Errorf("failed to create sender key distribution message to send %s to %s: %w", id, to, err)
  224. }
  225. skdm := &waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage{
  226. GroupID: proto.String(to.String()),
  227. AxolotlSenderKeyDistributionMessage: signalSKDMessage.Serialize(),
  228. }
  229. cipher := groups.NewGroupCipher(builder, senderKeyName, cli.Store)
  230. plaintext, err := proto.Marshal(&waMsgTransport.MessageTransport{
  231. Payload: &waMsgTransport.MessageTransport_Payload{
  232. ApplicationPayload: &waCommon.SubProtocol{
  233. Payload: messageApp,
  234. Version: proto.Int32(FBMessageApplicationVersion),
  235. },
  236. FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER.Enum(),
  237. },
  238. Protocol: &waMsgTransport.MessageTransport_Protocol{
  239. Integral: &waMsgTransport.MessageTransport_Protocol_Integral{
  240. Padding: padMessage(nil),
  241. DSM: nil,
  242. },
  243. Ancillary: &waMsgTransport.MessageTransport_Protocol_Ancillary{
  244. Skdm: nil,
  245. DeviceListMetadata: nil,
  246. Icdc: nil,
  247. BackupDirective: &waMsgTransport.MessageTransport_Protocol_Ancillary_BackupDirective{
  248. MessageID: &id,
  249. ActionType: waMsgTransport.MessageTransport_Protocol_Ancillary_BackupDirective_UPSERT.Enum(),
  250. },
  251. },
  252. },
  253. })
  254. if err != nil {
  255. return "", nil, fmt.Errorf("failed to marshal message transport: %w", err)
  256. }
  257. encrypted, err := cipher.Encrypt(ctx, plaintext)
  258. if err != nil {
  259. return "", nil, fmt.Errorf("failed to encrypt group message to send %s to %s: %w", id, to, err)
  260. }
  261. ciphertext := encrypted.SignedSerialize()
  262. timings.GroupEncrypt = time.Since(start)
  263. node, allDevices, err := cli.prepareMessageNodeV3(
  264. ctx, to, ownID, id, nil, skdm, msgAttrs, frankingTag, groupMeta.Members, timings,
  265. )
  266. if err != nil {
  267. return "", nil, err
  268. }
  269. phash := participantListHashV2(allDevices)
  270. node.Attrs["phash"] = phash
  271. skMsg := waBinary.Node{
  272. Tag: "enc",
  273. Content: ciphertext,
  274. Attrs: waBinary.Attrs{"v": "3", "type": "skmsg"},
  275. }
  276. if msgAttrs.MediaType != "" {
  277. skMsg.Attrs["mediatype"] = msgAttrs.MediaType
  278. }
  279. node.Content = append(node.GetChildren(), skMsg)
  280. start = time.Now()
  281. data, err := cli.sendNodeAndGetData(ctx, *node)
  282. timings.Send = time.Since(start)
  283. if err != nil {
  284. return "", nil, fmt.Errorf("failed to send message node: %w", err)
  285. }
  286. return phash, data, nil
  287. }
  288. func (cli *Client) sendDMV3(
  289. ctx context.Context,
  290. to,
  291. ownID types.JID,
  292. id types.MessageID,
  293. messageApp []byte,
  294. msgAttrs messageAttrs,
  295. frankingTag []byte,
  296. timings *MessageDebugTimings,
  297. ) ([]byte, string, error) {
  298. payload := &waMsgTransport.MessageTransport_Payload{
  299. ApplicationPayload: &waCommon.SubProtocol{
  300. Payload: messageApp,
  301. Version: proto.Int32(FBMessageApplicationVersion),
  302. },
  303. FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER.Enum(),
  304. }
  305. node, allDevices, err := cli.prepareMessageNodeV3(ctx, to, ownID, id, payload, nil, msgAttrs, frankingTag, []types.JID{to, ownID.ToNonAD()}, timings)
  306. if err != nil {
  307. return nil, "", err
  308. }
  309. start := time.Now()
  310. data, err := cli.sendNodeAndGetData(ctx, *node)
  311. timings.Send = time.Since(start)
  312. if err != nil {
  313. return nil, "", fmt.Errorf("failed to send message node: %w", err)
  314. }
  315. return data, participantListHashV2(allDevices), nil
  316. }
  317. type messageAttrs struct {
  318. Type string
  319. MediaType string
  320. Edit types.EditAttribute
  321. DecryptFail events.DecryptFailMode
  322. PollType string
  323. }
  324. func getAttrsFromFBMessage(msg armadillo.MessageApplicationSub) (attrs messageAttrs) {
  325. switch typedMsg := msg.(type) {
  326. case *waConsumerApplication.ConsumerApplication:
  327. return getAttrsFromFBConsumerMessage(typedMsg)
  328. case *waArmadilloApplication.Armadillo:
  329. attrs.Type = "media"
  330. attrs.MediaType = "document"
  331. default:
  332. attrs.Type = "text"
  333. }
  334. return
  335. }
  336. func getAttrsFromFBConsumerMessage(msg *waConsumerApplication.ConsumerApplication) (attrs messageAttrs) {
  337. switch payload := msg.GetPayload().GetPayload().(type) {
  338. case *waConsumerApplication.ConsumerApplication_Payload_Content:
  339. switch content := payload.Content.GetContent().(type) {
  340. case *waConsumerApplication.ConsumerApplication_Content_MessageText,
  341. *waConsumerApplication.ConsumerApplication_Content_ExtendedTextMessage:
  342. attrs.Type = "text"
  343. case *waConsumerApplication.ConsumerApplication_Content_ImageMessage:
  344. attrs.MediaType = "image"
  345. case *waConsumerApplication.ConsumerApplication_Content_StickerMessage:
  346. attrs.MediaType = "sticker"
  347. case *waConsumerApplication.ConsumerApplication_Content_ViewOnceMessage:
  348. switch content.ViewOnceMessage.GetViewOnceContent().(type) {
  349. case *waConsumerApplication.ConsumerApplication_ViewOnceMessage_ImageMessage:
  350. attrs.MediaType = "image"
  351. case *waConsumerApplication.ConsumerApplication_ViewOnceMessage_VideoMessage:
  352. attrs.MediaType = "video"
  353. }
  354. case *waConsumerApplication.ConsumerApplication_Content_DocumentMessage:
  355. attrs.MediaType = "document"
  356. case *waConsumerApplication.ConsumerApplication_Content_AudioMessage:
  357. if content.AudioMessage.GetPTT() {
  358. attrs.MediaType = "ptt"
  359. } else {
  360. attrs.MediaType = "audio"
  361. }
  362. case *waConsumerApplication.ConsumerApplication_Content_VideoMessage:
  363. // TODO gifPlayback?
  364. attrs.MediaType = "video"
  365. case *waConsumerApplication.ConsumerApplication_Content_LocationMessage:
  366. attrs.MediaType = "location"
  367. case *waConsumerApplication.ConsumerApplication_Content_LiveLocationMessage:
  368. attrs.MediaType = "location"
  369. case *waConsumerApplication.ConsumerApplication_Content_ContactMessage:
  370. attrs.MediaType = "vcard"
  371. case *waConsumerApplication.ConsumerApplication_Content_ContactsArrayMessage:
  372. attrs.MediaType = "contact_array"
  373. case *waConsumerApplication.ConsumerApplication_Content_PollCreationMessage:
  374. attrs.PollType = "creation"
  375. attrs.Type = "poll"
  376. case *waConsumerApplication.ConsumerApplication_Content_PollUpdateMessage:
  377. attrs.PollType = "vote"
  378. attrs.Type = "poll"
  379. attrs.DecryptFail = events.DecryptFailHide
  380. case *waConsumerApplication.ConsumerApplication_Content_ReactionMessage:
  381. attrs.Type = "reaction"
  382. attrs.DecryptFail = events.DecryptFailHide
  383. case *waConsumerApplication.ConsumerApplication_Content_EditMessage:
  384. attrs.Edit = types.EditAttributeMessageEdit
  385. attrs.DecryptFail = events.DecryptFailHide
  386. }
  387. if attrs.MediaType != "" && attrs.Type == "" {
  388. attrs.Type = "media"
  389. }
  390. case *waConsumerApplication.ConsumerApplication_Payload_ApplicationData:
  391. switch content := payload.ApplicationData.GetApplicationContent().(type) {
  392. case *waConsumerApplication.ConsumerApplication_ApplicationData_Revoke:
  393. if content.Revoke.GetKey().GetFromMe() {
  394. attrs.Edit = types.EditAttributeSenderRevoke
  395. } else {
  396. attrs.Edit = types.EditAttributeAdminRevoke
  397. }
  398. attrs.DecryptFail = events.DecryptFailHide
  399. }
  400. case *waConsumerApplication.ConsumerApplication_Payload_Signal:
  401. case *waConsumerApplication.ConsumerApplication_Payload_SubProtocol:
  402. }
  403. if attrs.Type == "" {
  404. attrs.Type = "text"
  405. }
  406. return
  407. }
  408. func (cli *Client) prepareMessageNodeV3(
  409. ctx context.Context,
  410. to,
  411. ownID types.JID,
  412. id types.MessageID,
  413. payload *waMsgTransport.MessageTransport_Payload,
  414. skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
  415. msgAttrs messageAttrs,
  416. frankingTag []byte,
  417. participants []types.JID,
  418. timings *MessageDebugTimings,
  419. ) (*waBinary.Node, []types.JID, error) {
  420. start := time.Now()
  421. allDevices, err := cli.GetUserDevices(ctx, participants)
  422. timings.GetDevices = time.Since(start)
  423. if err != nil {
  424. return nil, nil, fmt.Errorf("failed to get device list: %w", err)
  425. }
  426. encAttrs := waBinary.Attrs{}
  427. attrs := waBinary.Attrs{
  428. "id": id,
  429. "type": msgAttrs.Type,
  430. "to": to,
  431. }
  432. // Only include mediatype on DMs, for groups it's in the skmsg node
  433. if payload != nil && msgAttrs.MediaType != "" {
  434. encAttrs["mediatype"] = msgAttrs.MediaType
  435. }
  436. if msgAttrs.Edit != "" {
  437. attrs["edit"] = string(msgAttrs.Edit)
  438. }
  439. if msgAttrs.DecryptFail != "" {
  440. encAttrs["decrypt-fail"] = string(msgAttrs.DecryptFail)
  441. }
  442. dsm := &waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage{
  443. DestinationJID: proto.String(to.String()),
  444. Phash: proto.String(""),
  445. }
  446. start = time.Now()
  447. participantNodes, err := cli.encryptMessageForDevicesV3(ctx, allDevices, ownID, id, payload, skdm, dsm, encAttrs)
  448. if err != nil {
  449. return nil, nil, err
  450. }
  451. timings.PeerEncrypt = time.Since(start)
  452. content := make([]waBinary.Node, 0, 4)
  453. content = append(content, waBinary.Node{
  454. Tag: "participants",
  455. Content: participantNodes,
  456. })
  457. metaAttrs := make(waBinary.Attrs)
  458. if msgAttrs.PollType != "" {
  459. metaAttrs["polltype"] = msgAttrs.PollType
  460. }
  461. if msgAttrs.DecryptFail != "" {
  462. metaAttrs["decrypt-fail"] = string(msgAttrs.DecryptFail)
  463. }
  464. if len(metaAttrs) > 0 {
  465. content = append(content, waBinary.Node{
  466. Tag: "meta",
  467. Attrs: metaAttrs,
  468. })
  469. }
  470. traceRequestID := uuid.New()
  471. content = append(content, waBinary.Node{
  472. Tag: "franking",
  473. Content: []waBinary.Node{{
  474. Tag: "franking_tag",
  475. Content: frankingTag,
  476. }},
  477. }, waBinary.Node{
  478. Tag: "trace",
  479. Content: []waBinary.Node{{
  480. Tag: "request_id",
  481. Content: traceRequestID[:],
  482. }},
  483. })
  484. return &waBinary.Node{
  485. Tag: "message",
  486. Attrs: attrs,
  487. Content: content,
  488. }, allDevices, nil
  489. }
  490. func (cli *Client) encryptMessageForDevicesV3(
  491. ctx context.Context,
  492. allDevices []types.JID,
  493. ownID types.JID,
  494. id string,
  495. payload *waMsgTransport.MessageTransport_Payload,
  496. skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
  497. dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
  498. encAttrs waBinary.Attrs,
  499. ) ([]waBinary.Node, error) {
  500. participantNodes := make([]waBinary.Node, 0, len(allDevices))
  501. sessionAddressToJID := make(map[string]types.JID, len(allDevices))
  502. sessionAddresses := make([]string, 0, len(allDevices))
  503. for _, jid := range allDevices {
  504. addr := jid.SignalAddress().String()
  505. sessionAddresses = append(sessionAddresses, addr)
  506. sessionAddressToJID[addr] = jid
  507. }
  508. existingSessions, ctx, err := cli.Store.WithCachedSessions(ctx, sessionAddresses)
  509. if err != nil {
  510. return nil, fmt.Errorf("failed to prefetch sessions: %w", err)
  511. }
  512. var retryDevices []types.JID
  513. for addr, exists := range existingSessions {
  514. if !exists {
  515. retryDevices = append(retryDevices, sessionAddressToJID[addr])
  516. }
  517. }
  518. bundles := cli.fetchPreKeysNoError(ctx, retryDevices)
  519. for _, jid := range allDevices {
  520. var dsmForDevice *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage
  521. if jid.User == ownID.User {
  522. if jid == ownID {
  523. continue
  524. }
  525. dsmForDevice = dsm
  526. }
  527. encrypted, err := cli.encryptMessageForDeviceAndWrapV3(ctx, payload, skdm, dsmForDevice, jid, bundles[jid], encAttrs)
  528. if err != nil {
  529. // TODO return these errors if it's a fatal one (like context cancellation or database)
  530. cli.Log.Warnf("Failed to encrypt %s for %s: %v", id, jid, err)
  531. if ctx.Err() != nil {
  532. return nil, err
  533. }
  534. continue
  535. }
  536. participantNodes = append(participantNodes, *encrypted)
  537. }
  538. err = cli.Store.PutCachedSessions(ctx)
  539. if err != nil {
  540. return nil, fmt.Errorf("failed to save cached sessions: %w", err)
  541. }
  542. return participantNodes, nil
  543. }
  544. func (cli *Client) encryptMessageForDeviceAndWrapV3(
  545. ctx context.Context,
  546. payload *waMsgTransport.MessageTransport_Payload,
  547. skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
  548. dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
  549. to types.JID,
  550. bundle *prekey.Bundle,
  551. encAttrs waBinary.Attrs,
  552. ) (*waBinary.Node, error) {
  553. node, err := cli.encryptMessageForDeviceV3(ctx, payload, skdm, dsm, to, bundle, encAttrs)
  554. if err != nil {
  555. return nil, err
  556. }
  557. return &waBinary.Node{
  558. Tag: "to",
  559. Attrs: waBinary.Attrs{"jid": to},
  560. Content: []waBinary.Node{*node},
  561. }, nil
  562. }
  563. func (cli *Client) encryptMessageForDeviceV3(
  564. ctx context.Context,
  565. payload *waMsgTransport.MessageTransport_Payload,
  566. skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
  567. dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
  568. to types.JID,
  569. bundle *prekey.Bundle,
  570. extraAttrs waBinary.Attrs,
  571. ) (*waBinary.Node, error) {
  572. builder := session.NewBuilderFromSignal(cli.Store, to.SignalAddress(), pbSerializer)
  573. if bundle != nil {
  574. cli.Log.Debugf("Processing prekey bundle for %s", to)
  575. err := builder.ProcessBundle(ctx, bundle)
  576. if cli.AutoTrustIdentity && errors.Is(err, signalerror.ErrUntrustedIdentity) {
  577. cli.Log.Warnf("Got %v error while trying to process prekey bundle for %s, clearing stored identity and retrying", err, to)
  578. err = cli.clearUntrustedIdentity(ctx, to)
  579. if err != nil {
  580. return nil, fmt.Errorf("failed to clear untrusted identity: %w", err)
  581. }
  582. err = builder.ProcessBundle(ctx, bundle)
  583. }
  584. if err != nil {
  585. return nil, fmt.Errorf("failed to process prekey bundle: %w", err)
  586. }
  587. } else if contains, err := cli.Store.ContainsSession(ctx, to.SignalAddress()); err != nil {
  588. return nil, err
  589. } else if !contains {
  590. return nil, ErrNoSession
  591. }
  592. cipher := session.NewCipher(builder, to.SignalAddress())
  593. plaintext, err := proto.Marshal(&waMsgTransport.MessageTransport{
  594. Payload: payload,
  595. Protocol: &waMsgTransport.MessageTransport_Protocol{
  596. Integral: &waMsgTransport.MessageTransport_Protocol_Integral{
  597. Padding: padMessage(nil),
  598. DSM: dsm,
  599. },
  600. Ancillary: &waMsgTransport.MessageTransport_Protocol_Ancillary{
  601. Skdm: skdm,
  602. DeviceListMetadata: nil,
  603. Icdc: nil,
  604. BackupDirective: nil,
  605. },
  606. },
  607. })
  608. if err != nil {
  609. return nil, fmt.Errorf("failed to marshal message transport: %w", err)
  610. }
  611. ciphertext, err := cipher.Encrypt(ctx, plaintext)
  612. if err != nil {
  613. return nil, fmt.Errorf("cipher encryption failed: %w", err)
  614. }
  615. encAttrs := waBinary.Attrs{
  616. "v": FBMessageVersion,
  617. "type": "msg",
  618. }
  619. if ciphertext.Type() == protocol.PREKEY_TYPE {
  620. encAttrs["type"] = "pkmsg"
  621. }
  622. copyAttrs(extraAttrs, encAttrs)
  623. return &waBinary.Node{
  624. Tag: "enc",
  625. Attrs: encAttrs,
  626. Content: ciphertext.Serialize(),
  627. }, nil
  628. }