Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internals.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,16 +379,19 @@ func (cli *Client) decryptMessages(ctx context.Context, info *types.MessageInfo,
return
}
isUnavailable := encType == "skmsg" && !containsDirectMsg && errors.Is(err, signalerror.ErrNoSenderKeyForUser)

retryReason := getRetryReasonFromError(err)

if encType == "msmsg" {
cli.backgroundIfAsyncAck(func() {
cli.sendAck(node, NackMissingMessageSecret)
})
} else if cli.SynchronousAck {
cli.sendRetryReceipt(ctx, node, info, isUnavailable)
cli.sendRetryReceipt(ctx, node, info, isUnavailable, retryReason)
// TODO this probably isn't supposed to ack
cli.sendAck(node, 0)
} else {
go cli.sendRetryReceipt(context.WithoutCancel(ctx), node, info, isUnavailable)
go cli.sendRetryReceipt(context.WithoutCancel(ctx), node, info, isUnavailable, retryReason)
go cli.sendAck(node, 0)
}
cli.dispatchEvent(&events.UndecryptableMessage{
Expand Down
48 changes: 47 additions & 1 deletion retry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"time"

"go.mau.fi/libsignal/signalerror"

"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/groups"
"go.mau.fi/libsignal/keys/prekey"
Expand Down Expand Up @@ -43,6 +46,48 @@ type RecentMessage struct {
fb *waMsgApplication.MessageApplication
}

var (
RetryReasonUnknownError = 0
RetryReasonSignalErrorNoSession = 1
RetryReasonSignalErrorInvalidKey = 2
RetryReasonSignalErrorInvalidKeyId = 3
RetryReasonSignalErrorInvalidMessage = 4
RetryReasonSignalErrorInvalidSignature = 5
RetryReasonSignalErrorFutureMessage = 6
RetryReasonSignalErrorBadMac = 7
RetryReasonSignalErrorInvalidSession = 8
RetryReasonSignalErrorInvalidMsgKey = 9
RetryReasonBadBroadcastEphemeralSetting = 10
RetryReasonUnknownCompanionNoPrekey = 11
RetryReasonAdvFailure = 12
RetryReasonStatusRevokeDelay = 13
)

func getRetryReasonFromError(err error) int {
switch {
case errors.Is(err, signalerror.ErrBadMAC):
return RetryReasonSignalErrorBadMac
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reaching this case (and possibly others) requires some changes to libsignal-protocol-go to make it return the real error. Currently it tries all previous states and then hides the original error by returning signalerror.ErrNoValidSessions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be resolved after tulir/libsignal-protocol-go#7

case errors.Is(err, signalerror.ErrNoSessionForUser):
case errors.Is(err, signalerror.ErrNoSenderKeyForUser):
return RetryReasonSignalErrorNoSession
case errors.Is(err, signalerror.ErrWrongMessageVersion):
case errors.Is(err, signalerror.ErrOldMessageVersion):
case errors.Is(err, signalerror.ErrUnknownMessageVersion):
case errors.Is(err, signalerror.ErrIncompleteMessage):
return RetryReasonSignalErrorInvalidMessage
case errors.Is(err, signalerror.ErrInvalidSignature):
case errors.Is(err, signalerror.ErrSenderKeyStateVerificationFailed):
return RetryReasonSignalErrorInvalidSignature
case errors.Is(err, signalerror.ErrNoSignedPreKey):
return RetryReasonSignalErrorInvalidKey
case errors.Is(err, signalerror.ErrNoSenderKeyStateForID):
return RetryReasonSignalErrorInvalidKeyId
case errors.Is(err, signalerror.ErrTooFarIntoFuture):
return RetryReasonSignalErrorFutureMessage
}
return RetryReasonUnknownError
}

func (rm RecentMessage) IsEmpty() bool {
return rm.wa == nil && rm.fb == nil
}
Expand Down Expand Up @@ -376,7 +421,7 @@ func (cli *Client) clearDelayedMessageRequests() {
}

// sendRetryReceipt sends a retry receipt for an incoming message.
func (cli *Client) sendRetryReceipt(ctx context.Context, node *waBinary.Node, info *types.MessageInfo, forceIncludeIdentity bool) {
func (cli *Client) sendRetryReceipt(ctx context.Context, node *waBinary.Node, info *types.MessageInfo, forceIncludeIdentity bool, errorCode int) {
id, _ := node.Attrs["id"].(string)
children := node.GetChildren()
var retryCountInMsg int
Expand Down Expand Up @@ -421,6 +466,7 @@ func (cli *Client) sendRetryReceipt(ctx context.Context, node *waBinary.Node, in
"id": id,
"t": node.Attrs["t"],
"v": 1,
"error": errorCode, // this can be 0 for the case of Unknown reason
Comment thread
purpshell marked this conversation as resolved.
Outdated
}},
{Tag: "registration", Content: registrationIDBytes[:]},
},
Expand Down