mirror of
https://github.com/fiatjaf/nak.git
synced 2025-12-09 17:18:50 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2f9dda33a | ||
|
|
53cb2c0490 | ||
|
|
4a3c7dc825 | ||
|
|
05f2275c9e | ||
|
|
082be94614 | ||
|
|
15217f2466 | ||
|
|
8fbfdc65c8 | ||
|
|
11fe6b5809 | ||
|
|
6a7a5eb26e |
34
event.go
34
event.go
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
"github.com/nbd-wtf/go-nostr/nson"
|
"github.com/nbd-wtf/go-nostr/nson"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CATEGORY_EVENT_FIELDS = "EVENT FIELDS"
|
const CATEGORY_EVENT_FIELDS = "EVENT FIELDS"
|
||||||
@@ -32,8 +33,7 @@ if an event -- or a partial event -- is given on stdin, the flags can be used to
|
|||||||
|
|
||||||
example:
|
example:
|
||||||
echo '{"id":"a889df6a387419ff204305f4c2d296ee328c3cd4f8b62f205648a541b4554dfb","pubkey":"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5","created_at":1698623783,"kind":1,"tags":[],"content":"hello from the nostr army knife","sig":"84876e1ee3e726da84e5d195eb79358b2b3eaa4d9bd38456fde3e8a2af3f1cd4cda23f23fda454869975b3688797d4c66e12f4c51c1b43c6d2997c5e61865661"}' | nak event wss://offchain.pub
|
echo '{"id":"a889df6a387419ff204305f4c2d296ee328c3cd4f8b62f205648a541b4554dfb","pubkey":"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5","created_at":1698623783,"kind":1,"tags":[],"content":"hello from the nostr army knife","sig":"84876e1ee3e726da84e5d195eb79358b2b3eaa4d9bd38456fde3e8a2af3f1cd4cda23f23fda454869975b3688797d4c66e12f4c51c1b43c6d2997c5e61865661"}' | nak event wss://offchain.pub
|
||||||
echo '{"tags": [["t", "spam"]]}' | nak event -c 'this is spam'
|
echo '{"tags": [["t", "spam"]]}' | nak event -c 'this is spam'`,
|
||||||
`,
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "sec",
|
Name: "sec",
|
||||||
@@ -96,6 +96,16 @@ example:
|
|||||||
},
|
},
|
||||||
ArgsUsage: "[relay...]",
|
ArgsUsage: "[relay...]",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
|
// try to connect to the relays here
|
||||||
|
var relays []*nostr.Relay
|
||||||
|
if relayUrls := c.Args().Slice(); len(relayUrls) > 0 {
|
||||||
|
_, relays = connectToAllRelays(c.Context, relayUrls)
|
||||||
|
if len(relays) == 0 {
|
||||||
|
log("failed to connect to any of the given relays.\n")
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// gather the secret key first
|
// gather the secret key first
|
||||||
sec := c.String("sec")
|
sec := c.String("sec")
|
||||||
if c.Bool("prompt-sec") {
|
if c.Bool("prompt-sec") {
|
||||||
@@ -129,18 +139,20 @@ example:
|
|||||||
Tags: make(nostr.Tags, 0, 3),
|
Tags: make(nostr.Tags, 0, 3),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kindWasSupplied := false
|
||||||
mustRehashAndResign := false
|
mustRehashAndResign := false
|
||||||
if stdinEvent != "" {
|
if stdinEvent != "" {
|
||||||
if err := json.Unmarshal([]byte(stdinEvent), &evt); err != nil {
|
if err := json.Unmarshal([]byte(stdinEvent), &evt); err != nil {
|
||||||
lineProcessingError(c, "invalid event received from stdin: %s", err)
|
lineProcessingError(c, "invalid event received from stdin: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
kindWasSupplied = strings.Contains(stdinEvent, `"kind"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind := c.Int("kind"); kind != 0 {
|
if kind := c.Int("kind"); slices.Contains(c.FlagNames(), "kind") {
|
||||||
evt.Kind = kind
|
evt.Kind = kind
|
||||||
mustRehashAndResign = true
|
mustRehashAndResign = true
|
||||||
} else if evt.Kind == 0 {
|
} else if !kindWasSupplied {
|
||||||
evt.Kind = 1
|
evt.Kind = 1
|
||||||
mustRehashAndResign = true
|
mustRehashAndResign = true
|
||||||
}
|
}
|
||||||
@@ -203,20 +215,20 @@ example:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relays := c.Args().Slice()
|
|
||||||
if len(relays) > 0 {
|
if len(relays) > 0 {
|
||||||
fmt.Println(evt.String())
|
fmt.Println(evt.String())
|
||||||
for _, url := range relays {
|
os.Stdout.Sync()
|
||||||
fmt.Fprintf(os.Stderr, "publishing to %s... ", url)
|
for _, relay := range relays {
|
||||||
if relay, err := nostr.RelayConnect(c.Context, url); err != nil {
|
log("publishing to %s... ", relay.URL)
|
||||||
fmt.Fprintf(os.Stderr, "failed to connect: %s\n", err)
|
if relay, err := nostr.RelayConnect(c.Context, relay.URL); err != nil {
|
||||||
|
log("failed to connect: %s\n", err)
|
||||||
} else {
|
} else {
|
||||||
ctx, cancel := context.WithTimeout(c.Context, 10*time.Second)
|
ctx, cancel := context.WithTimeout(c.Context, 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if status, err := relay.Publish(ctx, evt); err != nil {
|
if status, err := relay.Publish(ctx, evt); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "failed: %s\n", err)
|
log("failed: %s\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "%s.\n", status)
|
log("%s.\n", status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
fetch.go
6
fetch.go
@@ -46,20 +46,20 @@ var fetch = &cli.Command{
|
|||||||
if v.Author != "" {
|
if v.Author != "" {
|
||||||
authorHint = v.Author
|
authorHint = v.Author
|
||||||
}
|
}
|
||||||
relays = v.Relays
|
relays = append(relays, v.Relays...)
|
||||||
case "naddr":
|
case "naddr":
|
||||||
v := value.(nostr.EntityPointer)
|
v := value.(nostr.EntityPointer)
|
||||||
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
||||||
filter.Kinds = append(filter.Kinds, v.Kind)
|
filter.Kinds = append(filter.Kinds, v.Kind)
|
||||||
filter.Authors = append(filter.Authors, v.PublicKey)
|
filter.Authors = append(filter.Authors, v.PublicKey)
|
||||||
authorHint = v.PublicKey
|
authorHint = v.PublicKey
|
||||||
relays = v.Relays
|
relays = append(relays, v.Relays...)
|
||||||
case "nprofile":
|
case "nprofile":
|
||||||
v := value.(nostr.ProfilePointer)
|
v := value.(nostr.ProfilePointer)
|
||||||
filter.Authors = append(filter.Authors, v.PublicKey)
|
filter.Authors = append(filter.Authors, v.PublicKey)
|
||||||
filter.Kinds = append(filter.Kinds, 0)
|
filter.Kinds = append(filter.Kinds, 0)
|
||||||
authorHint = v.PublicKey
|
authorHint = v.PublicKey
|
||||||
relays = v.Relays
|
relays = append(relays, v.Relays...)
|
||||||
case "npub":
|
case "npub":
|
||||||
v := value.(string)
|
v := value.(string)
|
||||||
filter.Authors = append(filter.Authors, v)
|
filter.Authors = append(filter.Authors, v)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -7,7 +7,7 @@ toolchain go1.21.0
|
|||||||
require (
|
require (
|
||||||
github.com/bgentry/speakeasy v0.1.0
|
github.com/bgentry/speakeasy v0.1.0
|
||||||
github.com/mailru/easyjson v0.7.7
|
github.com/mailru/easyjson v0.7.7
|
||||||
github.com/nbd-wtf/go-nostr v0.25.3
|
github.com/nbd-wtf/go-nostr v0.25.7
|
||||||
github.com/nbd-wtf/nostr-sdk v0.0.2
|
github.com/nbd-wtf/nostr-sdk v0.0.2
|
||||||
github.com/urfave/cli/v2 v2.25.3
|
github.com/urfave/cli/v2 v2.25.3
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -82,6 +82,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
|
|||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/nbd-wtf/go-nostr v0.25.3 h1:RPPh4cOosw0OZi5KG627pZ3GlKxiKsjARluzen/mB9g=
|
github.com/nbd-wtf/go-nostr v0.25.3 h1:RPPh4cOosw0OZi5KG627pZ3GlKxiKsjARluzen/mB9g=
|
||||||
github.com/nbd-wtf/go-nostr v0.25.3/go.mod h1:bkffJI+x914sPQWum9ZRUn66D7NpDnAoWo1yICvj3/0=
|
github.com/nbd-wtf/go-nostr v0.25.3/go.mod h1:bkffJI+x914sPQWum9ZRUn66D7NpDnAoWo1yICvj3/0=
|
||||||
|
github.com/nbd-wtf/go-nostr v0.25.7 h1:DcGOSgKVr/L6w62tRtKeV2t46sRyFcq9pWcyIFkh0eM=
|
||||||
|
github.com/nbd-wtf/go-nostr v0.25.7/go.mod h1:bkffJI+x914sPQWum9ZRUn66D7NpDnAoWo1yICvj3/0=
|
||||||
github.com/nbd-wtf/nostr-sdk v0.0.2 h1:mZIeti+DOF0D1179q+NLL/h0LVMMOPRQAYpOuUrn5Zk=
|
github.com/nbd-wtf/nostr-sdk v0.0.2 h1:mZIeti+DOF0D1179q+NLL/h0LVMMOPRQAYpOuUrn5Zk=
|
||||||
github.com/nbd-wtf/nostr-sdk v0.0.2/go.mod h1:KQZOtzcrXBlVhpZYG1tw83ADIONNMMPjUU3ZAH5U2RY=
|
github.com/nbd-wtf/nostr-sdk v0.0.2/go.mod h1:KQZOtzcrXBlVhpZYG1tw83ADIONNMMPjUU3ZAH5U2RY=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
|||||||
22
helpers.go
22
helpers.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,6 +17,10 @@ const (
|
|||||||
LINE_PROCESSING_ERROR = iota
|
LINE_PROCESSING_ERROR = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var log = func(msg string, args ...any) {
|
||||||
|
fmt.Fprintf(os.Stderr, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func isPiped() bool {
|
func isPiped() bool {
|
||||||
stat, _ := os.Stdin.Stat()
|
stat, _ := os.Stdin.Stat()
|
||||||
return stat.Mode()&os.ModeCharDevice == 0
|
return stat.Mode()&os.ModeCharDevice == 0
|
||||||
@@ -99,9 +104,24 @@ func validate32BytesHex(target string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func connectToAllRelays(ctx context.Context, relayUrls []string) (*nostr.SimplePool, []*nostr.Relay) {
|
||||||
|
relays := make([]*nostr.Relay, 0, len(relayUrls))
|
||||||
|
pool := nostr.NewSimplePool(ctx)
|
||||||
|
for _, url := range relayUrls {
|
||||||
|
log("connecting to %s... ", url)
|
||||||
|
if relay, err := pool.EnsureRelay(url); err == nil {
|
||||||
|
relays = append(relays, relay)
|
||||||
|
log("ok.\n")
|
||||||
|
} else {
|
||||||
|
log(err.Error() + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pool, relays
|
||||||
|
}
|
||||||
|
|
||||||
func lineProcessingError(c *cli.Context, msg string, args ...any) {
|
func lineProcessingError(c *cli.Context, msg string, args ...any) {
|
||||||
c.Context = context.WithValue(c.Context, LINE_PROCESSING_ERROR, true)
|
c.Context = context.WithValue(c.Context, LINE_PROCESSING_ERROR, true)
|
||||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
log(msg+"\n", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exitIfLineProcessingError(c *cli.Context) {
|
func exitIfLineProcessingError(c *cli.Context) {
|
||||||
|
|||||||
14
main.go
14
main.go
@@ -18,6 +18,20 @@ var app = &cli.App{
|
|||||||
decode,
|
decode,
|
||||||
encode,
|
encode,
|
||||||
verify,
|
verify,
|
||||||
|
relay,
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "silent",
|
||||||
|
Usage: "do not print logs and info messages to stderr",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Action: func(ctx *cli.Context, b bool) error {
|
||||||
|
if b {
|
||||||
|
log = func(msg string, args ...any) {}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
relay.go
Normal file
37
relay.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr/nip11"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var relay = &cli.Command{
|
||||||
|
Name: "relay",
|
||||||
|
Usage: "gets the relay information document for the given relay, as JSON",
|
||||||
|
Description: `example:
|
||||||
|
nak relay nostr.wine`,
|
||||||
|
ArgsUsage: "<relay-url>",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
url := c.Args().First()
|
||||||
|
if url == "" {
|
||||||
|
return fmt.Errorf("specify the <relay-url>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(url, "wss://") && !strings.HasPrefix(url, "ws://") {
|
||||||
|
url = "wss://" + url
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := nip11.Fetch(c.Context, url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch '%s' information document: %w", url, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pretty, _ := json.MarshalIndent(info, "", " ")
|
||||||
|
fmt.Println(string(pretty))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
25
req.go
25
req.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
@@ -23,8 +24,7 @@ example:
|
|||||||
it can also take a filter from stdin, optionally modify it with flags and send it to specific relays (or just print it).
|
it can also take a filter from stdin, optionally modify it with flags and send it to specific relays (or just print it).
|
||||||
|
|
||||||
example:
|
example:
|
||||||
echo '{"kinds": [1], "#t": ["test"]}' | nak req -l 5 -k 4549 --tag t=spam wss://nostr-pub.wellorder.net
|
echo '{"kinds": [1], "#t": ["test"]}' | nak req -l 5 -k 4549 --tag t=spam wss://nostr-pub.wellorder.net`,
|
||||||
`,
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "author",
|
Name: "author",
|
||||||
@@ -95,6 +95,21 @@ example:
|
|||||||
},
|
},
|
||||||
ArgsUsage: "[relay...]",
|
ArgsUsage: "[relay...]",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
|
var pool *nostr.SimplePool
|
||||||
|
relayUrls := c.Args().Slice()
|
||||||
|
if len(relayUrls) > 0 {
|
||||||
|
var relays []*nostr.Relay
|
||||||
|
pool, relays = connectToAllRelays(c.Context, relayUrls)
|
||||||
|
if len(relays) == 0 {
|
||||||
|
log("failed to connect to any of the given relays.\n")
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
relayUrls = make([]string, len(relays))
|
||||||
|
for i, relay := range relays {
|
||||||
|
relayUrls[i] = relay.URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for stdinFilter := range getStdinLinesOrBlank() {
|
for stdinFilter := range getStdinLinesOrBlank() {
|
||||||
filter := nostr.Filter{}
|
filter := nostr.Filter{}
|
||||||
if stdinFilter != "" {
|
if stdinFilter != "" {
|
||||||
@@ -155,14 +170,12 @@ example:
|
|||||||
filter.Limit = limit
|
filter.Limit = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
relays := c.Args().Slice()
|
if len(relayUrls) > 0 {
|
||||||
if len(relays) > 0 {
|
|
||||||
pool := nostr.NewSimplePool(c.Context)
|
|
||||||
fn := pool.SubManyEose
|
fn := pool.SubManyEose
|
||||||
if c.Bool("stream") {
|
if c.Bool("stream") {
|
||||||
fn = pool.SubMany
|
fn = pool.SubMany
|
||||||
}
|
}
|
||||||
for ie := range fn(c.Context, relays, nostr.Filters{filter}) {
|
for ie := range fn(c.Context, relayUrls, nostr.Filters{filter}) {
|
||||||
fmt.Println(ie.Event)
|
fmt.Println(ie.Event)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ var verify = &cli.Command{
|
|||||||
Description: `example:
|
Description: `example:
|
||||||
echo '{"id":"a889df6a387419ff204305f4c2d296ee328c3cd4f8b62f205648a541b4554dfb","pubkey":"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5","created_at":1698623783,"kind":1,"tags":[],"content":"hello from the nostr army knife","sig":"84876e1ee3e726da84e5d195eb79358b2b3eaa4d9bd38456fde3e8a2af3f1cd4cda23f23fda454869975b3688797d4c66e12f4c51c1b43c6d2997c5e61865661"}' | nak verify
|
echo '{"id":"a889df6a387419ff204305f4c2d296ee328c3cd4f8b62f205648a541b4554dfb","pubkey":"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5","created_at":1698623783,"kind":1,"tags":[],"content":"hello from the nostr army knife","sig":"84876e1ee3e726da84e5d195eb79358b2b3eaa4d9bd38456fde3e8a2af3f1cd4cda23f23fda454869975b3688797d4c66e12f4c51c1b43c6d2997c5e61865661"}' | nak verify
|
||||||
|
|
||||||
it outputs nothing if the verification is successful.
|
it outputs nothing if the verification is successful.`,
|
||||||
`,
|
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for stdinEvent := range getStdinLinesOrBlank() {
|
for stdinEvent := range getStdinLinesOrBlank() {
|
||||||
evt := nostr.Event{}
|
evt := nostr.Event{}
|
||||||
|
|||||||
Reference in New Issue
Block a user