--connect to use nip46 as a client to sign event and auth messages.

This commit is contained in:
fiatjaf 2024-02-06 00:58:26 -03:00
parent 01e1f52a70
commit b7a7e0504f
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
6 changed files with 65 additions and 20 deletions

View File

@ -56,7 +56,7 @@ var bunker = &cli.Command{
} }
// gather the secret key // gather the secret key
sec, err := gatherSecretKeyFromArguments(c) sec, _, err := gatherSecretKeyOrBunkerFromArguments(c)
if err != nil { if err != nil {
return err return err
} }

View File

@ -44,6 +44,10 @@ example:
Name: "prompt-sec", Name: "prompt-sec",
Usage: "prompt the user to paste a hex or nsec with which to sign the event", Usage: "prompt the user to paste a hex or nsec with which to sign the event",
}, },
&cli.StringFlag{
Name: "connect",
Usage: "sign event using NIP-46, expects a bunker://... URL",
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "envelope", Name: "envelope",
Usage: "print the event enveloped in a [\"EVENT\", ...] message ready to be sent to a relay", Usage: "print the event enveloped in a [\"EVENT\", ...] message ready to be sent to a relay",
@ -124,8 +128,7 @@ example:
} }
}() }()
// gather the secret key sec, bunker, err := gatherSecretKeyOrBunkerFromArguments(c)
sec, err := gatherSecretKeyFromArguments(c)
if err != nil { if err != nil {
return err return err
} }
@ -215,7 +218,11 @@ example:
} }
if evt.Sig == "" || mustRehashAndResign { if evt.Sig == "" || mustRehashAndResign {
if err := evt.Sign(sec); err != nil { if bunker != nil {
if err := bunker.SignEvent(c.Context, &evt); err != nil {
return fmt.Errorf("failed to sign with bunker: %w", err)
}
} else if err := evt.Sign(sec); err != nil {
return fmt.Errorf("error signing with provided key: %w", err) return fmt.Errorf("error signing with provided key: %w", err)
} }
} }
@ -252,11 +259,24 @@ example:
} }
// error publishing // error publishing
if strings.HasPrefix(err.Error(), "msg: auth-required:") && sec != "" && doAuth { if strings.HasPrefix(err.Error(), "msg: auth-required:") && (sec != "" || bunker != nil) && doAuth {
// if the relay is requesting auth and we can auth, let's do it // if the relay is requesting auth and we can auth, let's do it
pk, _ := nostr.GetPublicKey(sec) var pk string
if bunker != nil {
pk, err = bunker.GetPublicKey(c.Context)
if err != nil {
return fmt.Errorf("failed to get public key from bunker: %w", err)
}
} else {
pk, _ = nostr.GetPublicKey(sec)
}
log("performing auth as %s... ", pk) log("performing auth as %s... ", pk)
if err := relay.Auth(c.Context, func(evt *nostr.Event) error { return evt.Sign(sec) }); err == nil { if err := relay.Auth(c.Context, func(evt *nostr.Event) error {
if bunker != nil {
return bunker.SignEvent(c.Context, evt)
}
return evt.Sign(sec)
}); err == nil {
// try to publish again, but this time don't try to auth again // try to publish again, but this time don't try to auth again
doAuth = false doAuth = false
goto publish goto publish

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/fatih/color v1.16.0 github.com/fatih/color v1.16.0
github.com/mailru/easyjson v0.7.7 github.com/mailru/easyjson v0.7.7
github.com/manifoldco/promptui v0.9.0 github.com/manifoldco/promptui v0.9.0
github.com/nbd-wtf/go-nostr v0.28.2 github.com/nbd-wtf/go-nostr v0.28.4
github.com/nbd-wtf/nostr-sdk v0.0.5 github.com/nbd-wtf/nostr-sdk v0.0.5
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.25.7
golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/exp v0.0.0-20231006140011-7918f672742d

4
go.sum
View File

@ -81,8 +81,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/nbd-wtf/go-nostr v0.28.2 h1:KhpGcs6KMLBqYExzKoqt7vP5Re2f8Kpy9SavYZa2PTI= github.com/nbd-wtf/go-nostr v0.28.4 h1:chGBpdCQvM9aInf/vVDishY8GHapgqFc/RLl2WDnHQM=
github.com/nbd-wtf/go-nostr v0.28.2/go.mod h1:l9NRRaHPN+QwkqrjNKhnfYjQ0+nKP1xZrVxePPGUs+A= github.com/nbd-wtf/go-nostr v0.28.4/go.mod h1:l9NRRaHPN+QwkqrjNKhnfYjQ0+nKP1xZrVxePPGUs+A=
github.com/nbd-wtf/nostr-sdk v0.0.5 h1:rec+FcDizDVO0W25PX0lgYMXvP7zNNOgI3Fu9UCm4BY= github.com/nbd-wtf/nostr-sdk v0.0.5 h1:rec+FcDizDVO0W25PX0lgYMXvP7zNNOgI3Fu9UCm4BY=
github.com/nbd-wtf/nostr-sdk v0.0.5/go.mod h1:iJJsikesCGLNFZ9dLqhLPDzdt924EagUmdQxT3w2Lmk= github.com/nbd-wtf/nostr-sdk v0.0.5/go.mod h1:iJJsikesCGLNFZ9dLqhLPDzdt924EagUmdQxT3w2Lmk=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=

View File

@ -13,6 +13,7 @@ import (
"github.com/fatih/color" "github.com/fatih/color"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19" "github.com/nbd-wtf/go-nostr/nip19"
"github.com/nbd-wtf/go-nostr/nip46"
"github.com/nbd-wtf/go-nostr/nip49" "github.com/nbd-wtf/go-nostr/nip49"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -129,35 +130,41 @@ func exitIfLineProcessingError(c *cli.Context) {
} }
} }
func gatherSecretKeyFromArguments(c *cli.Context) (string, error) { func gatherSecretKeyOrBunkerFromArguments(c *cli.Context) (string, *nip46.BunkerClient, error) {
var err error var err error
if bunkerURL := c.String("connect"); bunkerURL != "" {
clientKey := nostr.GeneratePrivateKey()
bunker, err := nip46.ConnectBunker(c.Context, clientKey, bunkerURL, nil)
return "", bunker, err
}
sec := c.String("sec") sec := c.String("sec")
if c.Bool("prompt-sec") { if c.Bool("prompt-sec") {
if isPiped() { if isPiped() {
return "", fmt.Errorf("can't prompt for a secret key when processing data from a pipe, try again without --prompt-sec") return "", nil, fmt.Errorf("can't prompt for a secret key when processing data from a pipe, try again without --prompt-sec")
} }
sec, err = askPassword("type your secret key as ncryptsec, nsec or hex: ", nil) sec, err = askPassword("type your secret key as ncryptsec, nsec or hex: ", nil)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get secret key: %w", err) return "", nil, fmt.Errorf("failed to get secret key: %w", err)
} }
} }
if strings.HasPrefix(sec, "ncryptsec1") { if strings.HasPrefix(sec, "ncryptsec1") {
sec, err = promptDecrypt(sec) sec, err = promptDecrypt(sec)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to decrypt: %w", err) return "", nil, fmt.Errorf("failed to decrypt: %w", err)
} }
} else if bsec, err := hex.DecodeString(strings.Repeat("0", 64-len(sec)) + sec); err == nil { } else if bsec, err := hex.DecodeString(strings.Repeat("0", 64-len(sec)) + sec); err == nil {
sec = hex.EncodeToString(bsec) sec = hex.EncodeToString(bsec)
} else if prefix, hexvalue, err := nip19.Decode(sec); err != nil { } else if prefix, hexvalue, err := nip19.Decode(sec); err != nil {
return "", fmt.Errorf("invalid nsec: %w", err) return "", nil, fmt.Errorf("invalid nsec: %w", err)
} else if prefix == "nsec" { } else if prefix == "nsec" {
sec = hexvalue.(string) sec = hexvalue.(string)
} }
if ok := nostr.IsValid32ByteHex(sec); !ok { if ok := nostr.IsValid32ByteHex(sec); !ok {
return "", fmt.Errorf("invalid secret key") return "", nil, fmt.Errorf("invalid secret key")
} }
return sec, nil return sec, nil, nil
} }
func promptDecrypt(ncryptsec1 string) (string, error) { func promptDecrypt(ncryptsec1 string) (string, error) {

24
req.go
View File

@ -113,6 +113,10 @@ example:
Name: "prompt-sec", Name: "prompt-sec",
Usage: "prompt the user to paste a hex or nsec with which to sign the AUTH challenge", Usage: "prompt the user to paste a hex or nsec with which to sign the AUTH challenge",
}, },
&cli.StringFlag{
Name: "connect",
Usage: "sign AUTH using NIP-46, expects a bunker://... URL",
},
}, },
ArgsUsage: "[relay...]", ArgsUsage: "[relay...]",
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
@ -124,13 +128,27 @@ example:
if !c.Bool("auth") { if !c.Bool("auth") {
return fmt.Errorf("auth not authorized") return fmt.Errorf("auth not authorized")
} }
sec, err := gatherSecretKeyFromArguments(c) sec, bunker, err := gatherSecretKeyOrBunkerFromArguments(c)
if err != nil { if err != nil {
return err return err
} }
pk, _ := nostr.GetPublicKey(sec)
var pk string
if bunker != nil {
pk, err = bunker.GetPublicKey(c.Context)
if err != nil {
return fmt.Errorf("failed to get public key from bunker: %w", err)
}
} else {
pk, _ = nostr.GetPublicKey(sec)
}
log("performing auth as %s...\n", pk) log("performing auth as %s...\n", pk)
return evt.Sign(sec)
if bunker != nil {
return bunker.SignEvent(c.Context, evt)
} else {
return evt.Sign(sec)
}
})) }))
if len(relays) == 0 { if len(relays) == 0 {
log("failed to connect to any of the given relays.\n") log("failed to connect to any of the given relays.\n")