fix conflicts with running bunker connections (client and server apparently) through auth-required relays, clarify "connect-as" and use a special flag for it, let's see.

hopefully fixes https://github.com/fiatjaf/nak/issues/116
This commit is contained in:
fiatjaf
2026-06-20 20:30:37 -03:00
parent 12000232a7
commit 40a934e3f9
6 changed files with 76 additions and 37 deletions

View File

@@ -131,6 +131,45 @@ func getNaturalDate(cmd *cli.Command, name string) nostr.Timestamp {
// //
// //
type (
SecretKeyFlag = cli.FlagBase[nostr.SecretKey, struct{}, secretkeyValue]
)
type secretkeyValue struct {
secretkey nostr.SecretKey
hasBeenSet bool
}
var _ cli.ValueCreator[nostr.SecretKey, struct{}] = secretkeyValue{}
func (t secretkeyValue) Create(val nostr.SecretKey, p *nostr.SecretKey, c struct{}) cli.Value {
*p = val
return &secretkeyValue{
secretkey: val,
}
}
func (t secretkeyValue) ToString(b nostr.SecretKey) string { return t.secretkey.String() }
func (t *secretkeyValue) Set(value string) error {
secretkey, err := parseSecretKey(value)
t.secretkey = secretkey
t.hasBeenSet = true
return err
}
func (t *secretkeyValue) String() string { return fmt.Sprintf("%#v", t.secretkey) }
func (t *secretkeyValue) Value() nostr.SecretKey { return t.secretkey }
func (t *secretkeyValue) Get() any { return t.secretkey }
func getSecretKey(cmd *cli.Command, name string) nostr.SecretKey {
return cmd.Value(name).(nostr.SecretKey)
}
//
//
//
type ( type (
PubKeyFlag = cli.FlagBase[nostr.PubKey, struct{}, pubkeyValue] PubKeyFlag = cli.FlagBase[nostr.PubKey, struct{}, pubkeyValue]
) )

2
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/fiatjaf/nak
go 1.25 go 1.25
require ( require (
fiatjaf.com/nostr v0.0.0-20260615112943-0616b30ab35c fiatjaf.com/nostr v0.0.0-20260620232658-8389bac80c5f
github.com/AlecAivazis/survey/v2 v2.3.7 github.com/AlecAivazis/survey/v2 v2.3.7
github.com/bep/debounce v1.2.1 github.com/bep/debounce v1.2.1
github.com/btcsuite/btcd/btcec/v2 v2.3.6 github.com/btcsuite/btcd/btcec/v2 v2.3.6

4
go.sum
View File

@@ -1,7 +1,7 @@
fiatjaf.com/lib v0.3.7 h1:mXZOn7NrUcjSdy4oNvwQyAmes7Ueb+Zr5hjqMIe2dxI= fiatjaf.com/lib v0.3.7 h1:mXZOn7NrUcjSdy4oNvwQyAmes7Ueb+Zr5hjqMIe2dxI=
fiatjaf.com/lib v0.3.7/go.mod h1:UlHaZvPHj25PtKLh9GjZkUHRmQ2xZ8Jkoa4VRaLeeQ8= fiatjaf.com/lib v0.3.7/go.mod h1:UlHaZvPHj25PtKLh9GjZkUHRmQ2xZ8Jkoa4VRaLeeQ8=
fiatjaf.com/nostr v0.0.0-20260615112943-0616b30ab35c h1:LyUM+6Z8e51OyIRriZooY3+W0ogWBUJe0B/nU1uD04o= fiatjaf.com/nostr v0.0.0-20260620232658-8389bac80c5f h1:dl17ebu+HhtHTS9AdOc27TDUGfSjYVEO4qYLHEwjxOw=
fiatjaf.com/nostr v0.0.0-20260615112943-0616b30ab35c/go.mod h1:b1EIUDnd133Ie8Pg8O/biaKdFyCMz28aD4n64g1GqvM= fiatjaf.com/nostr v0.0.0-20260620232658-8389bac80c5f/go.mod h1:b1EIUDnd133Ie8Pg8O/biaKdFyCMz28aD4n64g1GqvM=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/FastFilter/xorfilter v0.2.1 h1:lbdeLG9BdpquK64ZsleBS8B4xO/QW1IM0gMzF7KaBKc= github.com/FastFilter/xorfilter v0.2.1 h1:lbdeLG9BdpquK64ZsleBS8B4xO/QW1IM0gMzF7KaBKc=

View File

@@ -478,6 +478,19 @@ func parsePubKey(value string) (nostr.PubKey, error) {
return nostr.PubKey{}, fmt.Errorf("invalid pubkey (\"%s\"): expected hex, npub, or nprofile", value) return nostr.PubKey{}, fmt.Errorf("invalid pubkey (\"%s\"): expected hex, npub, or nprofile", value)
} }
func parseSecretKey(input string) (nostr.SecretKey, error) {
if prefix, ski, err := nip19.Decode(input); err == nil && prefix == "nsec" {
return ski.(nostr.SecretKey), nil
}
sk, err := nostr.SecretKeyFromHex(input)
if err != nil {
return nostr.SecretKey{}, fmt.Errorf("invalid secret key: %w", err)
}
return sk, nil
}
func parseEventID(value string) (nostr.ID, error) { func parseEventID(value string) (nostr.ID, error) {
id, err := nostr.IDFromHex(value) id, err := nostr.IDFromHex(value)
if err == nil { if err == nil {

View File

@@ -9,7 +9,6 @@ import (
"fiatjaf.com/nostr" "fiatjaf.com/nostr"
"fiatjaf.com/nostr/keyer" "fiatjaf.com/nostr/keyer"
"fiatjaf.com/nostr/nip19"
"fiatjaf.com/nostr/nip42" "fiatjaf.com/nostr/nip42"
"fiatjaf.com/nostr/nip46" "fiatjaf.com/nostr/nip46"
"fiatjaf.com/nostr/nip49" "fiatjaf.com/nostr/nip49"
@@ -41,10 +40,10 @@ func gatherKeyerFromArguments(ctx context.Context, c *cli.Command) (nostr.Keyer,
} }
var kr nostr.Keyer var kr nostr.Keyer
if bunker != nil { if bunker == nil {
kr = keyer.NewBunkerSignerFromBunkerClient(bunker)
} else {
kr = keyer.NewPlainKeySigner(key) kr = keyer.NewPlainKeySigner(key)
} else {
kr = keyer.NewBunkerSignerFromBunkerClient(bunker)
} }
return kr, key, nil return kr, key, nil
@@ -52,25 +51,15 @@ func gatherKeyerFromArguments(ctx context.Context, c *cli.Command) (nostr.Keyer,
func gatherSecretKeyOrBunkerFromArguments(ctx context.Context, c *cli.Command) (nostr.SecretKey, *nip46.BunkerClient, error) { func gatherSecretKeyOrBunkerFromArguments(ctx context.Context, c *cli.Command) (nostr.SecretKey, *nip46.BunkerClient, error) {
sec := c.String("sec") sec := c.String("sec")
if strings.HasPrefix(sec, "bunker://") { if strings.HasPrefix(sec, "bunker://") {
// it's a bunker // it's a bunker
bunkerURL := sec bunkerURL := sec
clientKeyHex := c.String("connect-as")
var clientKey nostr.SecretKey
if clientKeyHex != "" {
var err error
clientKey, err = nostr.SecretKeyFromHex(clientKeyHex)
if err != nil {
return nostr.SecretKey{}, nil, fmt.Errorf("bunker client key '%s' is invalid: %w", clientKeyHex, err)
}
} else {
clientKey = defaultKey()
}
clientKey := getSecretKey(c, "connect-as")
logverbose("[nip46]: connecting to %s with client key %s\n", bunkerURL, clientKey.Hex()) logverbose("[nip46]: connecting to %s with client key %s\n", bunkerURL, clientKey.Hex())
bunker, err := nip46.ConnectBunker(ctx, clientKey, bunkerURL, nil, func(s string) { bunker, err := nip46.ConnectBunker(ctx, clientKey, bunkerURL, sys.Pool, func(s string) {
log(color.CyanString("[nip46]: open the following URL: %s"), s) log(color.CyanString("[nip46]: open the following URL: %s"), s)
}) })
if err != nil { if err != nil {
@@ -96,16 +85,8 @@ func gatherSecretKeyOrBunkerFromArguments(ctx context.Context, c *cli.Command) (
return sk, nil, nil return sk, nil, nil
} }
if prefix, ski, err := nip19.Decode(sec); err == nil && prefix == "nsec" { sk, err := parseSecretKey(sec)
return ski.(nostr.SecretKey), nil, nil return sk, nil, err
}
sk, err := nostr.SecretKeyFromHex(sec)
if err != nil {
return nostr.SecretKey{}, nil, fmt.Errorf("invalid secret key: %w", err)
}
return sk, nil, nil
} }
func authSigner(ctx context.Context, c *cli.Command, log func(s string, args ...any), authEvent *nostr.Event) (err error) { func authSigner(ctx context.Context, c *cli.Command, log func(s string, args ...any), authEvent *nostr.Event) (err error) {
@@ -120,14 +101,19 @@ func authSigner(ctx context.Context, c *cli.Command, log func(s string, args ...
return fmt.Errorf("auth required, but --auth flag not given") return fmt.Errorf("auth required, but --auth flag not given")
} }
kr, _, err := gatherKeyerFromArguments(ctx, c) var kr nostr.Keyer
if err != nil {
return err if nip46.IsBunkerClientOperation(ctx) {
kr = keyer.NewPlainKeySigner(getSecretKey(c, "connect-as"))
} else {
kr, _, err = gatherKeyerFromArguments(ctx, c)
if err != nil {
return err
}
} }
pk, _ := kr.GetPublicKey(ctx) pk, _ := kr.GetPublicKey(ctx)
npub := nip19.EncodeNpub(pk) log("authenticating as %s... ", color.YellowString("%s…", pk.Hex()[0:16]))
log("authenticating as %s... ", color.YellowString("%s…%s", npub[0:7], npub[58:]))
return kr.SignEvent(ctx, authEvent) return kr.SignEvent(ctx, authEvent)
} }

View File

@@ -43,12 +43,13 @@ var defaultKeyFlags = []cli.Flag{
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",
Category: CATEGORY_SIGNER, Category: CATEGORY_SIGNER,
}, },
&cli.StringFlag{ &SecretKeyFlag{
Name: "connect-as", Name: "connect-as",
Usage: "private key to use when communicating with nip46 bunkers", Usage: "private key to use when communicating with nip46 bunkers",
DefaultText: "the default key (see `nak key default`)",
Category: CATEGORY_SIGNER, Category: CATEGORY_SIGNER,
Sources: cli.EnvVars("NOSTR_CLIENT_KEY"), Sources: cli.EnvVars("NOSTR_CLIENT_KEY"),
Value: defaultKey(),
DefaultText: "the default key (see `nak key default`)",
}, },
} }