fix: surface QR pairing failures

This commit is contained in:
Peter Steinberger 2026-05-04 04:16:15 +01:00
parent 3077e626a3
commit 9568cbfb42
No known key found for this signature in database
3 changed files with 57 additions and 8 deletions

View File

@ -22,6 +22,7 @@
### Fixed
- Auth: propagate QR channel setup errors and surface actionable QR pairing failures. (#100 — thanks @pmatheus)
- Groups: hide groups after `groups leave`, mark missing joined groups as left during refresh, and show them again if a later refresh reports membership. (#125, #129 — thanks @SeifBenayed and @ImLukeF)
- History: cap on-demand backfill at 500 messages per request and 100 requests per run.
- Messages: normalize device-specific `@s.whatsapp.net` JIDs before storing chats, contacts, and senders.

View File

@ -94,7 +94,10 @@ func (c *Client) Connect(ctx context.Context, opts ConnectOptions) error {
var qrChan <-chan whatsmeow.QRChannelItem
if !authed {
ch, _ := cli.GetQRChannel(ctx)
ch, err := cli.GetQRChannel(ctx)
if err != nil {
return fmt.Errorf("get QR channel: %w", err)
}
qrChan = ch
}
@ -115,24 +118,44 @@ func (c *Client) Connect(ctx context.Context, opts ConnectOptions) error {
if !ok {
return fmt.Errorf("QR channel closed")
}
switch evt.Event {
case "code":
switch {
case evt.Event == whatsmeow.QRChannelEventCode:
if opts.OnQRCode != nil {
opts.OnQRCode(evt.Code)
} else {
qrterminal.GenerateHalfBlock(evt.Code, qrterminal.M, os.Stdout)
}
case "success":
case evt == whatsmeow.QRChannelSuccess:
return nil
case "timeout":
return fmt.Errorf("QR code timed out")
case "error":
return fmt.Errorf("QR error")
default:
if err := qrChannelEventError(evt); err != nil {
return err
}
}
}
}
}
func qrChannelEventError(evt whatsmeow.QRChannelItem) error {
switch {
case evt == whatsmeow.QRChannelTimeout:
return fmt.Errorf("QR code timed out; run `wacli auth` again to get a new code")
case evt == whatsmeow.QRChannelClientOutdated:
return fmt.Errorf("WhatsApp client outdated; update wacli and try again")
case evt == whatsmeow.QRChannelScannedWithoutMultidevice:
return fmt.Errorf("QR scanned, but multi-device is not enabled on the phone")
case evt == whatsmeow.QRChannelErrUnexpectedEvent:
return fmt.Errorf("unexpected QR pairing state; run `wacli auth` again")
case evt.Event == whatsmeow.QRChannelEventError:
if evt.Error != nil {
return fmt.Errorf("QR pairing failed: %w", evt.Error)
}
return fmt.Errorf("QR pairing failed")
default:
return nil
}
}
func (c *Client) AddEventHandler(handler func(interface{})) uint32 {
c.mu.Lock()
cli := c.client

View File

@ -1,9 +1,12 @@
package wa
import (
"errors"
"path/filepath"
"strings"
"testing"
"go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/types"
)
@ -68,6 +71,28 @@ func TestParseUserOrJID(t *testing.T) {
}
}
func TestQRChannelEventError(t *testing.T) {
cases := []struct {
name string
evt whatsmeow.QRChannelItem
want string
}{
{name: "timeout", evt: whatsmeow.QRChannelTimeout, want: "QR code timed out"},
{name: "client outdated", evt: whatsmeow.QRChannelClientOutdated, want: "WhatsApp client outdated"},
{name: "multidevice disabled", evt: whatsmeow.QRChannelScannedWithoutMultidevice, want: "multi-device is not enabled"},
{name: "unexpected state", evt: whatsmeow.QRChannelErrUnexpectedEvent, want: "unexpected QR pairing state"},
{name: "pair error", evt: whatsmeow.QRChannelItem{Event: whatsmeow.QRChannelEventError, Error: errors.New("bad code")}, want: "bad code"},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
err := qrChannelEventError(tt.evt)
if err == nil || !strings.Contains(err.Error(), tt.want) {
t.Fatalf("error = %v, want substring %q", err, tt.want)
}
})
}
}
func TestBestContactName(t *testing.T) {
if BestContactName(types.ContactInfo{Found: false, FullName: "x"}) != "" {
t.Fatalf("expected empty for not found")