diff options
Diffstat (limited to 'vendor/go.mau.fi')
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/client.go | 15 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/download.go | 7 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/mediaconn.go | 10 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/message.go | 61 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/send.go | 6 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/store/clientpayload.go | 2 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/upload.go | 7 | ||||
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/user.go | 1 |
8 files changed, 79 insertions, 30 deletions
diff --git a/vendor/go.mau.fi/whatsmeow/client.go b/vendor/go.mau.fi/whatsmeow/client.go index f37b2a25..41bad823 100644 --- a/vendor/go.mau.fi/whatsmeow/client.go +++ b/vendor/go.mau.fi/whatsmeow/client.go @@ -67,11 +67,14 @@ type Client struct { appStateProc *appstate.Processor appStateSyncLock sync.Mutex + historySyncNotifications chan *waProto.HistorySyncNotification + historySyncHandlerStarted uint32 + uploadPreKeysLock sync.Mutex lastPreKeyUpload time.Time - mediaConn *MediaConn - mediaConnLock sync.Mutex + mediaConnCache *MediaConn + mediaConnLock sync.Mutex responseWaiters map[string]chan<- *waBinary.Node responseWaitersLock sync.Mutex @@ -102,6 +105,11 @@ type Client struct { // If it returns false, the accepting will be cancelled and the retry receipt will be ignored. PreRetryCallback func(receipt *events.Receipt, retryCount int, msg *waProto.Message) bool + // Should untrusted identity errors be handled automatically? If true, the stored identity and existing signal + // sessions will be removed on untrusted identity errors, and an events.IdentityChange will be dispatched. + // If false, decrypting a message from untrusted devices will fail. + AutoTrustIdentity bool + uniqueID string idCounter uint32 @@ -150,6 +158,8 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client { handlerQueue: make(chan *waBinary.Node, handlerQueueSize), appStateProc: appstate.NewProcessor(deviceStore, log.Sub("AppState")), + historySyncNotifications: make(chan *waProto.HistorySyncNotification, 32), + groupParticipantsCache: make(map[types.JID][]types.JID), userDevicesCache: make(map[types.JID][]types.JID), @@ -157,6 +167,7 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client { GetMessageForRetry: func(to types.JID, id types.MessageID) *waProto.Message { return nil }, EnableAutoReconnect: true, + AutoTrustIdentity: true, } cli.nodeHandlers = map[string]nodeHandler{ "message": cli.handleEncryptedMessage, diff --git a/vendor/go.mau.fi/whatsmeow/download.go b/vendor/go.mau.fi/whatsmeow/download.go index dd4aade0..6779478f 100644 --- a/vendor/go.mau.fi/whatsmeow/download.go +++ b/vendor/go.mau.fi/whatsmeow/download.go @@ -194,19 +194,20 @@ func (cli *Client) Download(msg DownloadableMessage) ([]byte, error) { // DownloadMediaWithPath downloads an attachment by manually specifying the path and encryption details. func (cli *Client) DownloadMediaWithPath(directPath string, encFileHash, fileHash, mediaKey []byte, fileLength int, mediaType MediaType, mmsType string) (data []byte, err error) { - err = cli.refreshMediaConn(false) + var mediaConn *MediaConn + mediaConn, err = cli.refreshMediaConn(false) if err != nil { return nil, fmt.Errorf("failed to refresh media connections: %w", err) } if len(mmsType) == 0 { mmsType = mediaTypeToMMSType[mediaType] } - for i, host := range cli.mediaConn.Hosts { + for i, host := range mediaConn.Hosts { mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType) data, err = cli.downloadAndDecrypt(mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash) // TODO there are probably some errors that shouldn't retry if err != nil { - if i >= len(cli.mediaConn.Hosts)-1 { + if i >= len(mediaConn.Hosts)-1 { return nil, fmt.Errorf("failed to download media from last host: %w", err) } cli.Log.Warnf("Failed to download media: %s, trying with next host...", err) diff --git a/vendor/go.mau.fi/whatsmeow/mediaconn.go b/vendor/go.mau.fi/whatsmeow/mediaconn.go index 6faa27a6..2e833037 100644 --- a/vendor/go.mau.fi/whatsmeow/mediaconn.go +++ b/vendor/go.mau.fi/whatsmeow/mediaconn.go @@ -40,17 +40,17 @@ func (mc *MediaConn) Expiry() time.Time { return mc.FetchedAt.Add(time.Duration(mc.TTL) * time.Second) } -func (cli *Client) refreshMediaConn(force bool) error { +func (cli *Client) refreshMediaConn(force bool) (*MediaConn, error) { cli.mediaConnLock.Lock() defer cli.mediaConnLock.Unlock() - if cli.mediaConn == nil || force || time.Now().After(cli.mediaConn.Expiry()) { + if cli.mediaConnCache == nil || force || time.Now().After(cli.mediaConnCache.Expiry()) { var err error - cli.mediaConn, err = cli.queryMediaConn() + cli.mediaConnCache, err = cli.queryMediaConn() if err != nil { - return err + return nil, err } } - return nil + return cli.mediaConnCache, nil } func (cli *Client) queryMediaConn() (*MediaConn, error) { diff --git a/vendor/go.mau.fi/whatsmeow/message.go b/vendor/go.mau.fi/whatsmeow/message.go index 3238ba90..85ccb12b 100644 --- a/vendor/go.mau.fi/whatsmeow/message.go +++ b/vendor/go.mau.fi/whatsmeow/message.go @@ -13,7 +13,9 @@ import ( "errors" "fmt" "io" + "runtime/debug" "strconv" + "sync/atomic" "time" "go.mau.fi/libsignal/signalerror" @@ -162,6 +164,18 @@ func (cli *Client) decryptMessages(info *types.MessageInfo, node *waBinary.Node) } } +func (cli *Client) clearUntrustedIdentity(target types.JID) { + err := cli.Store.Identities.DeleteIdentity(target.SignalAddress().String()) + if err != nil { + cli.Log.Warnf("Failed to delete untrusted identity of %s from store: %v", target, err) + } + err = cli.Store.Sessions.DeleteSession(target.SignalAddress().String()) + if err != nil { + cli.Log.Warnf("Failed to delete session with %s (untrusted identity) from store: %v", target, err) + } + cli.dispatchEvent(&events.IdentityChange{JID: target, Timestamp: time.Now(), Implicit: true}) +} + func (cli *Client) decryptDM(child *waBinary.Node, from types.JID, isPreKey bool) ([]byte, error) { content, _ := child.Content.([]byte) @@ -174,17 +188,9 @@ func (cli *Client) decryptDM(child *waBinary.Node, from types.JID, isPreKey bool return nil, fmt.Errorf("failed to parse prekey message: %w", err) } plaintext, _, err = cipher.DecryptMessageReturnKey(preKeyMsg) - if errors.Is(err, signalerror.ErrUntrustedIdentity) { + if cli.AutoTrustIdentity && errors.Is(err, signalerror.ErrUntrustedIdentity) { cli.Log.Warnf("Got %v error while trying to decrypt prekey message from %s, clearing stored identity and retrying", err, from) - err = cli.Store.Identities.DeleteIdentity(from.SignalAddress().String()) - if err != nil { - cli.Log.Warnf("Failed to delete identity of %s from store after decryption error: %v", from, err) - } - err = cli.Store.Sessions.DeleteSession(from.SignalAddress().String()) - if err != nil { - cli.Log.Warnf("Failed to delete session with %s from store after decryption error: %v", from, err) - } - cli.dispatchEvent(&events.IdentityChange{JID: from, Timestamp: time.Now(), Implicit: true}) + cli.clearUntrustedIdentity(from) plaintext, _, err = cipher.DecryptMessageReturnKey(preKeyMsg) } if err != nil { @@ -261,6 +267,26 @@ func (cli *Client) handleSenderKeyDistributionMessage(chat, from types.JID, rawS cli.Log.Debugf("Processed sender key distribution message from %s in %s", senderKeyName.Sender().String(), senderKeyName.GroupID()) } +func (cli *Client) handleHistorySyncNotificationLoop() { + defer func() { + atomic.StoreUint32(&cli.historySyncHandlerStarted, 0) + err := recover() + if err != nil { + cli.Log.Errorf("History sync handler panicked: %v\n%s", err, debug.Stack()) + } + + // Check in case something new appeared in the channel between the loop stopping + // and the atomic variable being updated. If yes, restart the loop. + if len(cli.historySyncNotifications) > 0 && atomic.CompareAndSwapUint32(&cli.historySyncHandlerStarted, 0, 1) { + cli.Log.Warnf("New history sync notifications appeared after loop stopped, restarting loop...") + go cli.handleHistorySyncNotificationLoop() + } + }() + for notif := range cli.historySyncNotifications { + cli.handleHistorySyncNotification(notif) + } +} + func (cli *Client) handleHistorySyncNotification(notif *waProto.HistorySyncNotification) { var historySync waProto.HistorySync if data, err := cli.Download(notif); err != nil { @@ -272,7 +298,7 @@ func (cli *Client) handleHistorySyncNotification(notif *waProto.HistorySyncNotif } else if err = proto.Unmarshal(rawData, &historySync); err != nil { cli.Log.Errorf("Failed to unmarshal history sync data: %v", err) } else { - cli.Log.Debugf("Received history sync") + cli.Log.Debugf("Received history sync (type %s, chunk %d)", historySync.GetSyncType(), historySync.GetChunkOrder()) if historySync.GetSyncType() == waProto.HistorySync_PUSH_NAME { go cli.handleHistoricalPushNames(historySync.GetPushnames()) } @@ -314,16 +340,19 @@ func (cli *Client) handleProtocolMessage(info *types.MessageInfo, msg *waProto.M protoMsg := msg.GetProtocolMessage() if protoMsg.GetHistorySyncNotification() != nil && info.IsFromMe { - cli.handleHistorySyncNotification(protoMsg.HistorySyncNotification) - cli.sendProtocolMessageReceipt(info.ID, "hist_sync") + cli.historySyncNotifications <- protoMsg.HistorySyncNotification + if atomic.CompareAndSwapUint32(&cli.historySyncHandlerStarted, 0, 1) { + go cli.handleHistorySyncNotificationLoop() + } + go cli.sendProtocolMessageReceipt(info.ID, "hist_sync") } if protoMsg.GetAppStateSyncKeyShare() != nil && info.IsFromMe { - cli.handleAppStateSyncKeyShare(protoMsg.AppStateSyncKeyShare) + go cli.handleAppStateSyncKeyShare(protoMsg.AppStateSyncKeyShare) } if info.Category == "peer" { - cli.sendProtocolMessageReceipt(info.ID, "peer_msg") + go cli.sendProtocolMessageReceipt(info.ID, "peer_msg") } } @@ -347,7 +376,7 @@ func (cli *Client) handleDecryptedMessage(info *types.MessageInfo, msg *waProto. } } if msg.GetProtocolMessage() != nil { - go cli.handleProtocolMessage(info, msg) + cli.handleProtocolMessage(info, msg) } // Unwrap ephemeral and view-once messages diff --git a/vendor/go.mau.fi/whatsmeow/send.go b/vendor/go.mau.fi/whatsmeow/send.go index a3eae666..3216156e 100644 --- a/vendor/go.mau.fi/whatsmeow/send.go +++ b/vendor/go.mau.fi/whatsmeow/send.go @@ -17,6 +17,7 @@ import ( "strings" "time" + "go.mau.fi/libsignal/signalerror" "google.golang.org/protobuf/proto" "go.mau.fi/libsignal/groups" @@ -346,6 +347,11 @@ func (cli *Client) encryptMessageForDevice(plaintext []byte, to types.JID, bundl if bundle != nil { cli.Log.Debugf("Processing prekey bundle for %s", to) err := builder.ProcessBundle(bundle) + if cli.AutoTrustIdentity && errors.Is(err, signalerror.ErrUntrustedIdentity) { + cli.Log.Warnf("Got %v error while trying to process prekey bundle for %s, clearing stored identity and retrying", err, to) + cli.clearUntrustedIdentity(to) + err = builder.ProcessBundle(bundle) + } if err != nil { return nil, false, fmt.Errorf("failed to process prekey bundle: %w", err) } diff --git a/vendor/go.mau.fi/whatsmeow/store/clientpayload.go b/vendor/go.mau.fi/whatsmeow/store/clientpayload.go index 6649de2a..2f9496e8 100644 --- a/vendor/go.mau.fi/whatsmeow/store/clientpayload.go +++ b/vendor/go.mau.fi/whatsmeow/store/clientpayload.go @@ -74,7 +74,7 @@ func (vc WAVersionContainer) ProtoAppVersion() *waProto.AppVersion { } // waVersion is the WhatsApp web client version -var waVersion = WAVersionContainer{2, 2208, 14} +var waVersion = WAVersionContainer{2, 2210, 9} // waVersionHash is the md5 hash of a dot-separated waVersion var waVersionHash [16]byte diff --git a/vendor/go.mau.fi/whatsmeow/upload.go b/vendor/go.mau.fi/whatsmeow/upload.go index 6de805c6..b3e71cc4 100644 --- a/vendor/go.mau.fi/whatsmeow/upload.go +++ b/vendor/go.mau.fi/whatsmeow/upload.go @@ -87,7 +87,8 @@ func (cli *Client) Upload(ctx context.Context, plaintext []byte, appInfo MediaTy fileEncSHA256 := sha256.Sum256(dataToUpload) resp.FileEncSHA256 = fileEncSHA256[:] - err = cli.refreshMediaConn(false) + var mediaConn *MediaConn + mediaConn, err = cli.refreshMediaConn(false) if err != nil { err = fmt.Errorf("failed to refresh media connections: %w", err) return @@ -95,13 +96,13 @@ func (cli *Client) Upload(ctx context.Context, plaintext []byte, appInfo MediaTy token := base64.URLEncoding.EncodeToString(resp.FileEncSHA256) q := url.Values{ - "auth": []string{cli.mediaConn.Auth}, + "auth": []string{mediaConn.Auth}, "token": []string{token}, } mmsType := mediaTypeToMMSType[appInfo] uploadURL := url.URL{ Scheme: "https", - Host: cli.mediaConn.Hosts[0].Hostname, + Host: mediaConn.Hosts[0].Hostname, Path: fmt.Sprintf("/mms/%s/%s", mmsType, token), RawQuery: q.Encode(), } diff --git a/vendor/go.mau.fi/whatsmeow/user.go b/vendor/go.mau.fi/whatsmeow/user.go index 1855abaf..fea80521 100644 --- a/vendor/go.mau.fi/whatsmeow/user.go +++ b/vendor/go.mau.fi/whatsmeow/user.go @@ -230,6 +230,7 @@ func (cli *Client) handleHistoricalPushNames(names []*waProto.Pushname) { if cli.Store.Contacts == nil { return } + cli.Log.Infof("Updating contact store with %d push names from history sync", len(names)) for _, user := range names { if user.GetPushname() == "-" { continue |