fix(buzz): restore relay-driven NIP-42 subscription

This commit is contained in:
PeterChrz 2026-08-25 00:25:55 -04:00
parent 02961af54f
commit b8bf0ab34f
Signed by untrusted user who does not match committer: pch
GPG key ID: 8F0826ECF7302C63

View file

@ -24,6 +24,8 @@ import (
// kindStreamMessage is the Buzz chat message kind (NIP-29 style).
const kindStreamMessage = 9
const subscribeTimeout = 15 * time.Second
// BuzzChannel implements the Channel interface for a Buzz relay.
type BuzzChannel struct {
*channels.BaseChannel
@ -169,6 +171,60 @@ func (c *BuzzChannel) Start(ctx context.Context) error {
return nil
}
// subscribeAuthed subscribes, performing the NIP-42 handshake if the relay
// demands it. The relay rejection establishes that its challenge has been
// received by go-nostr before Auth signs the response.
func (c *BuzzChannel) subscribeAuthed(
ctx context.Context,
filters nostr.Filters,
) (*nostr.Subscription, error) {
sub, err := c.relay.Subscribe(ctx, filters)
if err != nil {
return nil, fmt.Errorf("buzz subscribe failed: %w", err)
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-sub.EndOfStoredEvents:
return sub, nil
case reason := <-sub.ClosedReason:
if !strings.HasPrefix(reason, "auth-required") {
return nil, fmt.Errorf("buzz relay closed subscription: %s", reason)
}
sub.Unsub()
if err := c.relay.Auth(ctx, func(evt *nostr.Event) error {
return evt.Sign(c.secretKey)
}); err != nil {
return nil, fmt.Errorf("buzz NIP-42 auth failed: %w", err)
}
logger.InfoCF("buzz", "Authenticated to relay", map[string]any{
"relay": c.config.RelayURL, "pubkey": c.publicKey,
})
authed, err := c.relay.Subscribe(ctx, filters)
if err != nil {
return nil, fmt.Errorf("buzz subscribe after auth failed: %w", err)
}
const postAuthGrace = 3 * time.Second
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-authed.EndOfStoredEvents:
return authed, nil
case reason := <-authed.ClosedReason:
return nil, fmt.Errorf("buzz relay rejected subscription after auth: %s", reason)
case <-time.After(postAuthGrace):
logger.InfoCF("buzz", "Subscription accepted after auth (no EOSE)", map[string]any{
"relay": c.config.RelayURL,
})
return authed, nil
}
case <-time.After(subscribeTimeout):
return nil, fmt.Errorf("buzz timed out waiting for relay to accept subscription")
}
}
// Stop closes the subscription and disconnects from the relay.
func (c *BuzzChannel) Stop(ctx context.Context) error {
logger.InfoC("buzz", "Stopping Buzz channel")