mirror of
https://github.com/fiatjaf/nak.git
synced 2025-12-09 00:58:50 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7a7e0504f | ||
|
|
01e1f52a70 |
@@ -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
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ var decode = &cli.Command{
|
||||
},
|
||||
ArgsUsage: "<npub | nprofile | nip05 | nevent | naddr | nsec>",
|
||||
Action: func(c *cli.Context) error {
|
||||
for input := range getStdinLinesOrFirstArgument(c) {
|
||||
for input := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if strings.HasPrefix(input, "nostr:") {
|
||||
input = input[6:]
|
||||
}
|
||||
|
||||
10
encode.go
10
encode.go
@@ -29,7 +29,7 @@ var encode = &cli.Command{
|
||||
Name: "npub",
|
||||
Usage: "encode a hex public key into bech32 'npub' format",
|
||||
Action: func(c *cli.Context) error {
|
||||
for target := range getStdinLinesOrFirstArgument(c) {
|
||||
for target := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if ok := nostr.IsValidPublicKey(target); !ok {
|
||||
lineProcessingError(c, "invalid public key: %s", target)
|
||||
continue
|
||||
@@ -50,7 +50,7 @@ var encode = &cli.Command{
|
||||
Name: "nsec",
|
||||
Usage: "encode a hex private key into bech32 'nsec' format",
|
||||
Action: func(c *cli.Context) error {
|
||||
for target := range getStdinLinesOrFirstArgument(c) {
|
||||
for target := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||
lineProcessingError(c, "invalid private key: %s", target)
|
||||
continue
|
||||
@@ -78,7 +78,7 @@ var encode = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
for target := range getStdinLinesOrFirstArgument(c) {
|
||||
for target := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||
lineProcessingError(c, "invalid public key: %s", target)
|
||||
continue
|
||||
@@ -115,7 +115,7 @@ var encode = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
for target := range getStdinLinesOrFirstArgument(c) {
|
||||
for target := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||
lineProcessingError(c, "invalid event id: %s", target)
|
||||
continue
|
||||
@@ -212,7 +212,7 @@ var encode = &cli.Command{
|
||||
Name: "note",
|
||||
Usage: "generate note1 event codes (not recommended)",
|
||||
Action: func(c *cli.Context) error {
|
||||
for target := range getStdinLinesOrFirstArgument(c) {
|
||||
for target := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||
lineProcessingError(c, "invalid event id: %s", target)
|
||||
continue
|
||||
|
||||
32
event.go
32
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
|
||||
|
||||
2
fetch.go
2
fetch.go
@@ -31,7 +31,7 @@ var fetch = &cli.Command{
|
||||
})
|
||||
}()
|
||||
|
||||
for code := range getStdinLinesOrFirstArgument(c) {
|
||||
for code := range getStdinLinesOrFirstArgument(c.Args().First()) {
|
||||
filter := nostr.Filter{}
|
||||
|
||||
prefix, value, err := nip19.Decode(code)
|
||||
|
||||
2
go.mod
2
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
|
||||
|
||||
4
go.sum
4
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=
|
||||
|
||||
28
helpers.go
28
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"
|
||||
)
|
||||
@@ -47,12 +48,11 @@ func getStdinLinesOrBlank() chan string {
|
||||
}
|
||||
}
|
||||
|
||||
func getStdinLinesOrFirstArgument(c *cli.Context) chan string {
|
||||
func getStdinLinesOrFirstArgument(arg string) chan string {
|
||||
// try the first argument
|
||||
target := c.Args().First()
|
||||
if target != "" {
|
||||
if arg != "" {
|
||||
single := make(chan string, 1)
|
||||
single <- target
|
||||
single <- arg
|
||||
close(single)
|
||||
return single
|
||||
}
|
||||
@@ -130,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) {
|
||||
|
||||
32
key.go
32
key.go
@@ -39,7 +39,7 @@ var public = &cli.Command{
|
||||
Description: ``,
|
||||
ArgsUsage: "[secret]",
|
||||
Action: func(c *cli.Context) error {
|
||||
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c) {
|
||||
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c, c.Args().First()) {
|
||||
pubkey, err := nostr.GetPublicKey(sec)
|
||||
if err != nil {
|
||||
lineProcessingError(c, "failed to derive public key: %s", err)
|
||||
@@ -65,11 +65,20 @@ var encrypt = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
password := c.Args().Get(c.Args().Len() - 1)
|
||||
var content string
|
||||
var password string
|
||||
switch c.Args().Len() {
|
||||
case 1:
|
||||
content = ""
|
||||
password = c.Args().Get(0)
|
||||
case 2:
|
||||
content = c.Args().Get(0)
|
||||
password = c.Args().Get(1)
|
||||
}
|
||||
if password == "" {
|
||||
return fmt.Errorf("no password given")
|
||||
}
|
||||
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c) {
|
||||
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c, content) {
|
||||
ncryptsec, err := nip49.Encrypt(sec, password, uint8(c.Int("logn")), 0x02)
|
||||
if err != nil {
|
||||
lineProcessingError(c, "failed to encrypt: %s", err)
|
||||
@@ -87,11 +96,20 @@ var decrypt = &cli.Command{
|
||||
Description: `uses the NIP-49 standard.`,
|
||||
ArgsUsage: "<ncryptsec-code> <password>",
|
||||
Action: func(c *cli.Context) error {
|
||||
password := c.Args().Get(c.Args().Len() - 1)
|
||||
var content string
|
||||
var password string
|
||||
switch c.Args().Len() {
|
||||
case 1:
|
||||
content = ""
|
||||
password = c.Args().Get(0)
|
||||
case 2:
|
||||
content = c.Args().Get(0)
|
||||
password = c.Args().Get(1)
|
||||
}
|
||||
if password == "" {
|
||||
return fmt.Errorf("no password given")
|
||||
}
|
||||
for ncryptsec := range getStdinLinesOrFirstArgument(c) {
|
||||
for ncryptsec := range getStdinLinesOrFirstArgument(content) {
|
||||
sec, err := nip49.Decrypt(ncryptsec, password)
|
||||
if err != nil {
|
||||
lineProcessingError(c, "failed to decrypt: %s", err)
|
||||
@@ -104,10 +122,10 @@ var decrypt = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func getSecretKeyFromStdinLinesOrFirstArgument(c *cli.Context) chan string {
|
||||
func getSecretKeyFromStdinLinesOrFirstArgument(c *cli.Context, content string) chan string {
|
||||
ch := make(chan string)
|
||||
go func() {
|
||||
for sec := range getStdinLinesOrFirstArgument(c) {
|
||||
for sec := range getStdinLinesOrFirstArgument(content) {
|
||||
if sec == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
24
req.go
24
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")
|
||||
|
||||
Reference in New Issue
Block a user