fix(buzz): retry NIP-42 auth with backoff to fix race condition
The go-nostr RelayConnect returns immediately after the WebSocket handshake, but the relay has not yet sent the AUTH challenge. Calling relay.Auth() right away signs the auth event with an empty challenge tag, which the Buzz relay rejects with 'auth-required: verification failed'. Retry the Auth() call up to 3 times with 1s backoff between attempts, giving the relay time to deliver the challenge.
This commit is contained in:
parent
9b4df86182
commit
735cb0734e
1 changed files with 29 additions and 7 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip19"
|
||||
|
|
@ -117,15 +118,36 @@ func (c *BuzzChannel) Start(ctx context.Context) error {
|
|||
}
|
||||
c.relay = relay
|
||||
|
||||
// NIP-42: the relay challenges, we sign the auth event with the bot identity.
|
||||
// Buzz relays reject subscriptions from unauthenticated clients, so a failure
|
||||
// here is fatal rather than advisory.
|
||||
if err := relay.Auth(c.ctx, func(evt *nostr.Event) error {
|
||||
// NIP-42: the relay sends an AUTH challenge asynchronously after connect.
|
||||
// The go-nostr library stores the challenge in an unexported field that is
|
||||
// populated by the read loop. If we call Auth() too quickly the challenge
|
||||
// is empty and the relay rejects the event with "verification failed".
|
||||
// Retry with backoff to give the relay time to deliver the challenge.
|
||||
const maxAuthAttempts = 3
|
||||
var authErr error
|
||||
for attempt := 0; attempt < maxAuthAttempts; attempt++ {
|
||||
if attempt > 0 {
|
||||
logger.WarnCF("buzz", "Retrying NIP-42 auth", map[string]any{
|
||||
"attempt": attempt + 1,
|
||||
"delay": "1s",
|
||||
})
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
authErr = relay.Auth(c.ctx, func(evt *nostr.Event) error {
|
||||
return evt.Sign(c.secretKey)
|
||||
}); err != nil {
|
||||
})
|
||||
if authErr == nil {
|
||||
break
|
||||
}
|
||||
logger.WarnCF("buzz", "NIP-42 auth attempt failed", map[string]any{
|
||||
"attempt": attempt + 1,
|
||||
"error": authErr.Error(),
|
||||
})
|
||||
}
|
||||
if authErr != nil {
|
||||
_ = relay.Close()
|
||||
c.cancel()
|
||||
return fmt.Errorf("buzz NIP-42 auth failed: %w", err)
|
||||
return fmt.Errorf("buzz NIP-42 auth failed: %w", authErr)
|
||||
}
|
||||
|
||||
channelIDs := []string(c.config.Channels)
|
||||
|
|
|
|||
Loading…
Reference in a new issue