Compare commits

...

7 Commits

Author SHA1 Message Date
fiatjaf
3dfcec69b7 --nevent flag on nak event to print an nevent at the end. 2024-01-24 22:43:23 -03:00
fiatjaf
14b69f36cf -q to silence stderr, -qq to silence everything. 2024-01-24 22:38:51 -03:00
fiatjaf
3f7089e27e signal that we accept patches over NIP-34. 2024-01-23 10:20:54 -03:00
fiatjaf
6a75c8aec3 UseShortOptionHandling and Suggest 2024-01-23 10:20:54 -03:00
fiatjaf
b17887fe21 replace validate32BytesHex() with native calls from go-nostr. 2024-01-21 07:45:22 -03:00
fiatjaf
77103cae0c req: -d flag too. 2024-01-17 08:50:59 -03:00
fiatjaf
59a2c16b42 event: -d shortcut flag and use .AppendUnique() 2024-01-17 08:49:18 -03:00
12 changed files with 85 additions and 60 deletions

View File

@@ -81,3 +81,8 @@ invalid .id, expected 05bd99d54cb835f427e0092c4275ee44c7ff51219eff417c19f70c9e2c
```shell
nak req -l 100 -k 1 -a 2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884 wss://relay.damus.io | jq -r '.content | match("nostr:((note1|nevent1)[a-z0-9]+)";"g") | .captures[0].string' | nak decode | jq -cr '{ids: [.id]}' | nak req wss://relay.damus.io
```
## Contributing to this repository
Use NIP-34 to send your patches to `naddr1qqpkucttqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9nhwden5te0wfjkccte9ehx7um5wghxyctwvsq3vamnwvaz7tmjv4kxz7fwwpexjmtpdshxuet5qgsg04q5ypr6f4n65mv7e5hs05z50hy7vvgua8uc8szwtp262cfwn6srqsqqqauedy5x7y`.

View File

@@ -139,7 +139,7 @@ var count = &cli.Command{
var result string
j, _ := json.Marshal([]any{"COUNT", "nak", filter})
result = string(j)
fmt.Println(result)
stdout(result)
}
return nil

View File

@@ -3,7 +3,6 @@ package main
import (
"encoding/hex"
"encoding/json"
"fmt"
"strings"
"github.com/nbd-wtf/go-nostr"
@@ -68,7 +67,7 @@ var decode = &cli.Command{
continue
}
fmt.Println(decodeResult.JSON())
stdout(decodeResult.JSON())
}

View File

@@ -3,6 +3,7 @@ package main
import (
"fmt"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/urfave/cli/v2"
)
@@ -29,13 +30,13 @@ var encode = &cli.Command{
Usage: "encode a hex public key into bech32 'npub' format",
Action: func(c *cli.Context) error {
for target := range getStdinLinesOrFirstArgument(c) {
if err := validate32BytesHex(target); err != nil {
lineProcessingError(c, "invalid public key: %s", target, err)
if ok := nostr.IsValidPublicKey(target); !ok {
lineProcessingError(c, "invalid public key: %s", target)
continue
}
if npub, err := nip19.EncodePublicKey(target); err == nil {
fmt.Println(npub)
stdout(npub)
} else {
return err
}
@@ -50,13 +51,13 @@ var encode = &cli.Command{
Usage: "encode a hex private key into bech32 'nsec' format",
Action: func(c *cli.Context) error {
for target := range getStdinLinesOrFirstArgument(c) {
if err := validate32BytesHex(target); err != nil {
lineProcessingError(c, "invalid private key: %s", target, err)
if ok := nostr.IsValid32ByteHex(target); !ok {
lineProcessingError(c, "invalid private key: %s", target)
continue
}
if npub, err := nip19.EncodePrivateKey(target); err == nil {
fmt.Println(npub)
stdout(npub)
} else {
return err
}
@@ -78,8 +79,8 @@ var encode = &cli.Command{
},
Action: func(c *cli.Context) error {
for target := range getStdinLinesOrFirstArgument(c) {
if err := validate32BytesHex(target); err != nil {
lineProcessingError(c, "invalid public key: %s", target, err)
if ok := nostr.IsValid32ByteHex(target); !ok {
lineProcessingError(c, "invalid public key: %s", target)
continue
}
@@ -89,7 +90,7 @@ var encode = &cli.Command{
}
if npub, err := nip19.EncodeProfile(target, relays); err == nil {
fmt.Println(npub)
stdout(npub)
} else {
return err
}
@@ -115,15 +116,15 @@ var encode = &cli.Command{
},
Action: func(c *cli.Context) error {
for target := range getStdinLinesOrFirstArgument(c) {
if err := validate32BytesHex(target); err != nil {
lineProcessingError(c, "invalid event id: %s", target, err)
if ok := nostr.IsValid32ByteHex(target); !ok {
lineProcessingError(c, "invalid event id: %s", target)
continue
}
author := c.String("author")
if author != "" {
if err := validate32BytesHex(author); err != nil {
return err
if ok := nostr.IsValidPublicKey(author); !ok {
return fmt.Errorf("invalid 'author' public key")
}
}
@@ -133,7 +134,7 @@ var encode = &cli.Command{
}
if npub, err := nip19.EncodeEvent(target, relays, author); err == nil {
fmt.Println(npub)
stdout(npub)
} else {
return err
}
@@ -174,8 +175,8 @@ var encode = &cli.Command{
Action: func(c *cli.Context) error {
for d := range getStdinLinesOrBlank() {
pubkey := c.String("pubkey")
if err := validate32BytesHex(pubkey); err != nil {
return err
if ok := nostr.IsValidPublicKey(pubkey); !ok {
return fmt.Errorf("invalid 'pubkey'")
}
kind := c.Int("kind")
@@ -197,7 +198,7 @@ var encode = &cli.Command{
}
if npub, err := nip19.EncodeEntity(pubkey, kind, d, relays); err == nil {
fmt.Println(npub)
stdout(npub)
} else {
return err
}
@@ -212,13 +213,13 @@ var encode = &cli.Command{
Usage: "generate note1 event codes (not recommended)",
Action: func(c *cli.Context) error {
for target := range getStdinLinesOrFirstArgument(c) {
if err := validate32BytesHex(target); err != nil {
lineProcessingError(c, "invalid event id: %s", target, err)
if ok := nostr.IsValid32ByteHex(target); !ok {
lineProcessingError(c, "invalid event id: %s", target)
continue
}
if note, err := nip19.EncodeNote(target); err == nil {
fmt.Println(note)
stdout(note)
} else {
return err
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/mailru/easyjson"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/nbd-wtf/go-nostr/nson"
"github.com/urfave/cli/v2"
"golang.org/x/exp/slices"
@@ -51,6 +52,10 @@ example:
Name: "auth",
Usage: "always perform NIP-42 \"AUTH\" when facing an \"auth-required: \" rejection and try again",
},
&cli.BoolFlag{
Name: "nevent",
Usage: "print the nevent code (to stderr) after the event is published",
},
&cli.BoolFlag{
Name: "nson",
Usage: "encode the event using NSON",
@@ -87,6 +92,11 @@ example:
Usage: "shortcut for --tag p=<value>",
Category: CATEGORY_EVENT_FIELDS,
},
&cli.StringSliceFlag{
Name: "d",
Usage: "shortcut for --tag d=<value>",
Category: CATEGORY_EVENT_FIELDS,
},
&cli.StringFlag{
Name: "created-at",
Aliases: []string{"time", "ts"},
@@ -165,16 +175,20 @@ example:
tagValues := strings.Split(tagValue, ";")
tag = append(tag, tagValues...)
// ~
tags = append(tags, tag)
tags = tags.AppendUnique(tag)
}
}
for _, etag := range c.StringSlice("e") {
tags = append(tags, []string{"e", etag})
tags = tags.AppendUnique([]string{"e", etag})
mustRehashAndResign = true
}
for _, ptag := range c.StringSlice("p") {
tags = append(tags, []string{"p", ptag})
tags = tags.AppendUnique([]string{"p", ptag})
mustRehashAndResign = true
}
for _, dtag := range c.StringSlice("d") {
tags = tags.AppendUnique([]string{"d", dtag})
mustRehashAndResign = true
}
if len(tags) > 0 {
@@ -217,9 +231,10 @@ example:
j, _ := easyjson.Marshal(&evt)
result = string(j)
}
fmt.Println(result)
stdout(result)
// publish to relays
successRelays := make([]string, 0, len(relays))
if len(relays) > 0 {
os.Stdout.Sync()
for _, relay := range relays {
@@ -232,6 +247,7 @@ example:
if err == nil {
// published fine
log("success.\n")
successRelays = append(successRelays, relay.URL)
continue // continue to next relay
}
@@ -250,6 +266,10 @@ example:
}
log("failed: %s\n", err)
}
if len(successRelays) > 0 && c.Bool("nevent") {
nevent, _ := nip19.EncodeEvent(evt.ID, successRelays, evt.PubKey)
log(nevent + "\n")
}
}
}

View File

@@ -1,8 +1,6 @@
package main
import (
"fmt"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
sdk "github.com/nbd-wtf/nostr-sdk"
@@ -93,7 +91,7 @@ var fetch = &cli.Command{
}
for ie := range pool.SubManyEose(c.Context, relays, nostr.Filters{filter}) {
fmt.Println(ie.Event)
stdout(ie.Event)
}
}

2
go.mod
View File

@@ -8,7 +8,7 @@ require (
github.com/bgentry/speakeasy v0.1.0
github.com/mailru/easyjson v0.7.7
github.com/manifoldco/promptui v0.9.0
github.com/nbd-wtf/go-nostr v0.28.0
github.com/nbd-wtf/go-nostr v0.28.1
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
View File

@@ -76,8 +76,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/nbd-wtf/go-nostr v0.28.0 h1:SLYyoFeCNYb7HyWtmPUzD6rifBOMR66Spj5fzCk+5GE=
github.com/nbd-wtf/go-nostr v0.28.0/go.mod h1:OQ8sNLFJnsj17BdqZiLSmjJBIFTfDqckEYC3utS4qoY=
github.com/nbd-wtf/go-nostr v0.28.1 h1:XQi/lBsigBXHRm7IDBJE7SR9citCh9srgf8sA5iVW3A=
github.com/nbd-wtf/go-nostr v0.28.1/go.mod h1:OQ8sNLFJnsj17BdqZiLSmjJBIFTfDqckEYC3utS4qoY=
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=

View File

@@ -3,7 +3,6 @@ package main
import (
"bufio"
"context"
"encoding/hex"
"fmt"
"net/url"
"os"
@@ -26,6 +25,8 @@ var log = func(msg string, args ...any) {
fmt.Fprintf(os.Stderr, msg, args...)
}
var stdout = fmt.Println
func isPiped() bool {
stat, _ := os.Stdin.Stat()
return stat.Mode()&os.ModeCharDevice == 0
@@ -96,20 +97,6 @@ func validateRelayURLs(wsurls []string) error {
return nil
}
func validate32BytesHex(target string) error {
if _, err := hex.DecodeString(target); err != nil {
return fmt.Errorf("target '%s' is not valid hex: %s", target, err)
}
if len(target) != 64 {
return fmt.Errorf("expected '%s' to be 64 characters (32 bytes), got %d", target, len(target))
}
if strings.ToLower(target) != target {
return fmt.Errorf("expected target to be all lowercase hex. try again with '%s'", strings.ToLower(target))
}
return nil
}
func connectToAllRelays(
ctx context.Context,
relayUrls []string,
@@ -163,7 +150,7 @@ func gatherSecretKeyFromArguments(c *cli.Context) (string, error) {
return "", fmt.Errorf("invalid secret key: too large")
}
sec = strings.Repeat("0", 64-len(sec)) + sec // left-pad
if err := validate32BytesHex(sec); err != nil {
if ok := nostr.IsValid32ByteHex(sec); !ok {
return "", fmt.Errorf("invalid secret key")
}

23
main.go
View File

@@ -1,15 +1,18 @@
package main
import (
"fmt"
"os"
"github.com/urfave/cli/v2"
)
var q int
var app = &cli.App{
Name: "nak",
Usage: "the nostr army knife command-line tool",
Name: "nak",
Suggest: true,
UseShortOptionHandling: true,
Usage: "the nostr army knife command-line tool",
Commands: []*cli.Command{
req,
count,
@@ -23,12 +26,16 @@ var app = &cli.App{
},
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "silent",
Usage: "do not print logs and info messages to stderr",
Aliases: []string{"s"},
Name: "quiet",
Usage: "do not print logs and info messages to stderr, use -qq to also not print anything to stdout",
Count: &q,
Aliases: []string{"q"},
Action: func(ctx *cli.Context, b bool) error {
if b {
if q >= 1 {
log = func(msg string, args ...any) {}
if q >= 2 {
stdout = func(a ...any) (int, error) { return 0, nil }
}
}
return nil
},
@@ -38,7 +45,7 @@ var app = &cli.App{
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Println(err)
stdout(err)
os.Exit(1)
}
}

View File

@@ -31,7 +31,7 @@ var relay = &cli.Command{
}
pretty, _ := json.MarshalIndent(info, "", " ")
fmt.Println(string(pretty))
stdout(string(pretty))
return nil
},
}

12
req.go
View File

@@ -62,6 +62,11 @@ example:
Usage: "shortcut for --tag p=<value>",
Category: CATEGORY_FILTER_ATTRIBUTES,
},
&cli.StringSliceFlag{
Name: "d",
Usage: "shortcut for --tag d=<value>",
Category: CATEGORY_FILTER_ATTRIBUTES,
},
&cli.StringFlag{
Name: "since",
Aliases: []string{"s"},
@@ -179,6 +184,9 @@ example:
for _, ptag := range c.StringSlice("p") {
tags = append(tags, []string{"p", ptag})
}
for _, dtag := range c.StringSlice("d") {
tags = append(tags, []string{"d", dtag})
}
if len(tags) > 0 && filter.Tags == nil {
filter.Tags = make(nostr.TagMap)
@@ -223,7 +231,7 @@ example:
fn = pool.SubMany
}
for ie := range fn(c.Context, relayUrls, nostr.Filters{filter}) {
fmt.Println(ie.Event)
stdout(ie.Event)
}
} else {
// no relays given, will just print the filter
@@ -235,7 +243,7 @@ example:
result = string(j)
}
fmt.Println(result)
stdout(result)
}
}