From b7a7e0504fa073a6ae4bd7b4ebb63132679e3c53 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Tue, 6 Feb 2024 00:58:26 -0300 Subject: [PATCH] --connect to use nip46 as a client to sign event and auth messages. --- bunker.go | 2 +- event.go | 32 ++++++++++++++++++++++++++------ go.mod | 2 +- go.sum | 4 ++-- helpers.go | 21 ++++++++++++++------- req.go | 24 +++++++++++++++++++++--- 6 files changed, 65 insertions(+), 20 deletions(-) diff --git a/bunker.go b/bunker.go index 26dd92e..b8e25bd 100644 --- a/bunker.go +++ b/bunker.go @@ -56,7 +56,7 @@ var bunker = &cli.Command{ } // gather the secret key - sec, err := gatherSecretKeyFromArguments(c) + sec, _, err := gatherSecretKeyOrBunkerFromArguments(c) if err != nil { return err } diff --git a/event.go b/event.go index a752ee8..eb8cd05 100644 --- a/event.go +++ b/event.go @@ -44,6 +44,10 @@ example: Name: "prompt-sec", 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{ Name: "envelope", 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, err := gatherSecretKeyFromArguments(c) + sec, bunker, err := gatherSecretKeyOrBunkerFromArguments(c) if err != nil { return err } @@ -215,7 +218,11 @@ example: } 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) } } @@ -252,11 +259,24 @@ example: } // 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 - 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) - 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 doAuth = false goto publish diff --git a/go.mod b/go.mod index 4b72b35..cd4fe2d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/fatih/color v1.16.0 github.com/mailru/easyjson v0.7.7 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/urfave/cli/v2 v2.25.7 golang.org/x/exp v0.0.0-20231006140011-7918f672742d diff --git a/go.sum b/go.sum index 29a9176..659e784 100644 --- a/go.sum +++ b/go.sum @@ -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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 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.2/go.mod h1:l9NRRaHPN+QwkqrjNKhnfYjQ0+nKP1xZrVxePPGUs+A= +github.com/nbd-wtf/go-nostr v0.28.4 h1:chGBpdCQvM9aInf/vVDishY8GHapgqFc/RLl2WDnHQM= +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/go.mod h1:iJJsikesCGLNFZ9dLqhLPDzdt924EagUmdQxT3w2Lmk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/helpers.go b/helpers.go index b3a6921..6a2ce76 100644 --- a/helpers.go +++ b/helpers.go @@ -13,6 +13,7 @@ import ( "github.com/fatih/color" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" + "github.com/nbd-wtf/go-nostr/nip46" "github.com/nbd-wtf/go-nostr/nip49" "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 + + 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") if c.Bool("prompt-sec") { 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) 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") { sec, err = promptDecrypt(sec) 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 { sec = hex.EncodeToString(bsec) } 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" { sec = hexvalue.(string) } 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) { diff --git a/req.go b/req.go index d164d6a..5801b39 100644 --- a/req.go +++ b/req.go @@ -113,6 +113,10 @@ example: Name: "prompt-sec", 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...]", Action: func(c *cli.Context) error { @@ -124,13 +128,27 @@ example: if !c.Bool("auth") { return fmt.Errorf("auth not authorized") } - sec, err := gatherSecretKeyFromArguments(c) + sec, bunker, err := gatherSecretKeyOrBunkerFromArguments(c) if err != nil { 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) - return evt.Sign(sec) + + if bunker != nil { + return bunker.SignEvent(c.Context, evt) + } else { + return evt.Sign(sec) + } })) if len(relays) == 0 { log("failed to connect to any of the given relays.\n")