mirror of
https://github.com/fiatjaf/nak.git
synced 2025-12-09 17:18:50 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4921f1fe9 | ||
|
|
3dfcec69b7 | ||
|
|
14b69f36cf | ||
|
|
3f7089e27e | ||
|
|
6a75c8aec3 | ||
|
|
b17887fe21 | ||
|
|
77103cae0c | ||
|
|
59a2c16b42 |
@@ -81,3 +81,8 @@ invalid .id, expected 05bd99d54cb835f427e0092c4275ee44c7ff51219eff417c19f70c9e2c
|
|||||||
```shell
|
```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
|
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`.
|
||||||
|
|
||||||
|
|||||||
2
count.go
2
count.go
@@ -139,7 +139,7 @@ var count = &cli.Command{
|
|||||||
var result string
|
var result string
|
||||||
j, _ := json.Marshal([]any{"COUNT", "nak", filter})
|
j, _ := json.Marshal([]any{"COUNT", "nak", filter})
|
||||||
result = string(j)
|
result = string(j)
|
||||||
fmt.Println(result)
|
stdout(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
@@ -68,7 +67,7 @@ var decode = &cli.Command{
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(decodeResult.JSON())
|
stdout(decodeResult.JSON())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
41
encode.go
41
encode.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr"
|
||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
@@ -29,13 +30,13 @@ var encode = &cli.Command{
|
|||||||
Usage: "encode a hex public key into bech32 'npub' format",
|
Usage: "encode a hex public key into bech32 'npub' format",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for target := range getStdinLinesOrFirstArgument(c) {
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if ok := nostr.IsValidPublicKey(target); !ok {
|
||||||
lineProcessingError(c, "invalid public key: %s", target, err)
|
lineProcessingError(c, "invalid public key: %s", target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodePublicKey(target); err == nil {
|
if npub, err := nip19.EncodePublicKey(target); err == nil {
|
||||||
fmt.Println(npub)
|
stdout(npub)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -50,13 +51,13 @@ var encode = &cli.Command{
|
|||||||
Usage: "encode a hex private key into bech32 'nsec' format",
|
Usage: "encode a hex private key into bech32 'nsec' format",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for target := range getStdinLinesOrFirstArgument(c) {
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||||
lineProcessingError(c, "invalid private key: %s", target, err)
|
lineProcessingError(c, "invalid private key: %s", target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodePrivateKey(target); err == nil {
|
if npub, err := nip19.EncodePrivateKey(target); err == nil {
|
||||||
fmt.Println(npub)
|
stdout(npub)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -78,8 +79,8 @@ var encode = &cli.Command{
|
|||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for target := range getStdinLinesOrFirstArgument(c) {
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||||
lineProcessingError(c, "invalid public key: %s", target, err)
|
lineProcessingError(c, "invalid public key: %s", target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ var encode = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodeProfile(target, relays); err == nil {
|
if npub, err := nip19.EncodeProfile(target, relays); err == nil {
|
||||||
fmt.Println(npub)
|
stdout(npub)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -115,15 +116,15 @@ var encode = &cli.Command{
|
|||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for target := range getStdinLinesOrFirstArgument(c) {
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||||
lineProcessingError(c, "invalid event id: %s", target, err)
|
lineProcessingError(c, "invalid event id: %s", target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
author := c.String("author")
|
author := c.String("author")
|
||||||
if author != "" {
|
if author != "" {
|
||||||
if err := validate32BytesHex(author); err != nil {
|
if ok := nostr.IsValidPublicKey(author); !ok {
|
||||||
return err
|
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 {
|
if npub, err := nip19.EncodeEvent(target, relays, author); err == nil {
|
||||||
fmt.Println(npub)
|
stdout(npub)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -174,8 +175,8 @@ var encode = &cli.Command{
|
|||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for d := range getStdinLinesOrBlank() {
|
for d := range getStdinLinesOrBlank() {
|
||||||
pubkey := c.String("pubkey")
|
pubkey := c.String("pubkey")
|
||||||
if err := validate32BytesHex(pubkey); err != nil {
|
if ok := nostr.IsValidPublicKey(pubkey); !ok {
|
||||||
return err
|
return fmt.Errorf("invalid 'pubkey'")
|
||||||
}
|
}
|
||||||
|
|
||||||
kind := c.Int("kind")
|
kind := c.Int("kind")
|
||||||
@@ -197,7 +198,7 @@ var encode = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodeEntity(pubkey, kind, d, relays); err == nil {
|
if npub, err := nip19.EncodeEntity(pubkey, kind, d, relays); err == nil {
|
||||||
fmt.Println(npub)
|
stdout(npub)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -212,13 +213,13 @@ var encode = &cli.Command{
|
|||||||
Usage: "generate note1 event codes (not recommended)",
|
Usage: "generate note1 event codes (not recommended)",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
for target := range getStdinLinesOrFirstArgument(c) {
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if ok := nostr.IsValid32ByteHex(target); !ok {
|
||||||
lineProcessingError(c, "invalid event id: %s", target, err)
|
lineProcessingError(c, "invalid event id: %s", target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if note, err := nip19.EncodeNote(target); err == nil {
|
if note, err := nip19.EncodeNote(target); err == nil {
|
||||||
fmt.Println(note)
|
stdout(note)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
28
event.go
28
event.go
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mailru/easyjson"
|
"github.com/mailru/easyjson"
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
|
"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"
|
"golang.org/x/exp/slices"
|
||||||
@@ -51,6 +52,10 @@ example:
|
|||||||
Name: "auth",
|
Name: "auth",
|
||||||
Usage: "always perform NIP-42 \"AUTH\" when facing an \"auth-required: \" rejection and try again",
|
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{
|
&cli.BoolFlag{
|
||||||
Name: "nson",
|
Name: "nson",
|
||||||
Usage: "encode the event using NSON",
|
Usage: "encode the event using NSON",
|
||||||
@@ -87,6 +92,11 @@ example:
|
|||||||
Usage: "shortcut for --tag p=<value>",
|
Usage: "shortcut for --tag p=<value>",
|
||||||
Category: CATEGORY_EVENT_FIELDS,
|
Category: CATEGORY_EVENT_FIELDS,
|
||||||
},
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "d",
|
||||||
|
Usage: "shortcut for --tag d=<value>",
|
||||||
|
Category: CATEGORY_EVENT_FIELDS,
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "created-at",
|
Name: "created-at",
|
||||||
Aliases: []string{"time", "ts"},
|
Aliases: []string{"time", "ts"},
|
||||||
@@ -165,16 +175,20 @@ example:
|
|||||||
tagValues := strings.Split(tagValue, ";")
|
tagValues := strings.Split(tagValue, ";")
|
||||||
tag = append(tag, tagValues...)
|
tag = append(tag, tagValues...)
|
||||||
// ~
|
// ~
|
||||||
tags = append(tags, tag)
|
tags = tags.AppendUnique(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, etag := range c.StringSlice("e") {
|
for _, etag := range c.StringSlice("e") {
|
||||||
tags = append(tags, []string{"e", etag})
|
tags = tags.AppendUnique([]string{"e", etag})
|
||||||
mustRehashAndResign = true
|
mustRehashAndResign = true
|
||||||
}
|
}
|
||||||
for _, ptag := range c.StringSlice("p") {
|
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
|
mustRehashAndResign = true
|
||||||
}
|
}
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
@@ -217,9 +231,10 @@ example:
|
|||||||
j, _ := easyjson.Marshal(&evt)
|
j, _ := easyjson.Marshal(&evt)
|
||||||
result = string(j)
|
result = string(j)
|
||||||
}
|
}
|
||||||
fmt.Println(result)
|
stdout(result)
|
||||||
|
|
||||||
// publish to relays
|
// publish to relays
|
||||||
|
successRelays := make([]string, 0, len(relays))
|
||||||
if len(relays) > 0 {
|
if len(relays) > 0 {
|
||||||
os.Stdout.Sync()
|
os.Stdout.Sync()
|
||||||
for _, relay := range relays {
|
for _, relay := range relays {
|
||||||
@@ -232,6 +247,7 @@ example:
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// published fine
|
// published fine
|
||||||
log("success.\n")
|
log("success.\n")
|
||||||
|
successRelays = append(successRelays, relay.URL)
|
||||||
continue // continue to next relay
|
continue // continue to next relay
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,6 +266,10 @@ example:
|
|||||||
}
|
}
|
||||||
log("failed: %s\n", err)
|
log("failed: %s\n", err)
|
||||||
}
|
}
|
||||||
|
if len(successRelays) > 0 && c.Bool("nevent") {
|
||||||
|
nevent, _ := nip19.EncodeEvent(evt.ID, successRelays, evt.PubKey)
|
||||||
|
log(nevent + "\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
fetch.go
4
fetch.go
@@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
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}) {
|
for ie := range pool.SubManyEose(c.Context, relays, nostr.Filters{filter}) {
|
||||||
fmt.Println(ie.Event)
|
stdout(ie.Event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -8,7 +8,7 @@ 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/manifoldco/promptui v0.9.0
|
github.com/manifoldco/promptui v0.9.0
|
||||||
github.com/nbd-wtf/go-nostr v0.28.0
|
github.com/nbd-wtf/go-nostr v0.28.2
|
||||||
github.com/nbd-wtf/nostr-sdk v0.0.5
|
github.com/nbd-wtf/nostr-sdk v0.0.5
|
||||||
github.com/urfave/cli/v2 v2.25.7
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||||
@@ -33,5 +33,6 @@ require (
|
|||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
golang.org/x/crypto v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
golang.org/x/sys v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -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/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 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
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.2 h1:KhpGcs6KMLBqYExzKoqt7vP5Re2f8Kpy9SavYZa2PTI=
|
||||||
github.com/nbd-wtf/go-nostr v0.28.0/go.mod h1:OQ8sNLFJnsj17BdqZiLSmjJBIFTfDqckEYC3utS4qoY=
|
github.com/nbd-wtf/go-nostr v0.28.2/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 h1:rec+FcDizDVO0W25PX0lgYMXvP7zNNOgI3Fu9UCm4BY=
|
||||||
github.com/nbd-wtf/nostr-sdk v0.0.5/go.mod h1:iJJsikesCGLNFZ9dLqhLPDzdt924EagUmdQxT3w2Lmk=
|
github.com/nbd-wtf/nostr-sdk v0.0.5/go.mod h1:iJJsikesCGLNFZ9dLqhLPDzdt924EagUmdQxT3w2Lmk=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
@@ -111,6 +111,8 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsr
|
|||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
|||||||
19
helpers.go
19
helpers.go
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -26,6 +25,8 @@ var log = func(msg string, args ...any) {
|
|||||||
fmt.Fprintf(os.Stderr, msg, args...)
|
fmt.Fprintf(os.Stderr, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stdout = fmt.Println
|
||||||
|
|
||||||
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
|
||||||
@@ -96,20 +97,6 @@ func validateRelayURLs(wsurls []string) error {
|
|||||||
return nil
|
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(
|
func connectToAllRelays(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
relayUrls []string,
|
relayUrls []string,
|
||||||
@@ -163,7 +150,7 @@ func gatherSecretKeyFromArguments(c *cli.Context) (string, error) {
|
|||||||
return "", fmt.Errorf("invalid secret key: too large")
|
return "", fmt.Errorf("invalid secret key: too large")
|
||||||
}
|
}
|
||||||
sec = strings.Repeat("0", 64-len(sec)) + sec // left-pad
|
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")
|
return "", fmt.Errorf("invalid secret key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
131
key.go
Normal file
131
key.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr"
|
||||||
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
|
"github.com/nbd-wtf/go-nostr/nip49"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var key = &cli.Command{
|
||||||
|
Name: "key",
|
||||||
|
Usage: "operations on secret keys: generate, derive, encrypt, decrypt.",
|
||||||
|
Description: ``,
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
generate,
|
||||||
|
public,
|
||||||
|
encrypt,
|
||||||
|
decrypt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var generate = &cli.Command{
|
||||||
|
Name: "generate",
|
||||||
|
Usage: "generates a secret key",
|
||||||
|
Description: ``,
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
sec := nostr.GeneratePrivateKey()
|
||||||
|
stdout(sec)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var public = &cli.Command{
|
||||||
|
Name: "public",
|
||||||
|
Usage: "computes a public key from a secret key",
|
||||||
|
Description: ``,
|
||||||
|
ArgsUsage: "[secret]",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c) {
|
||||||
|
pubkey, err := nostr.GetPublicKey(sec)
|
||||||
|
if err != nil {
|
||||||
|
lineProcessingError(c, "failed to derive public key: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stdout(pubkey)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var encrypt = &cli.Command{
|
||||||
|
Name: "encrypt",
|
||||||
|
Usage: "encrypts a secret key and prints an ncryptsec code",
|
||||||
|
Description: `uses the NIP-49 standard.`,
|
||||||
|
ArgsUsage: "<secret> <password>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "logn",
|
||||||
|
Usage: "the bigger the number the harder it will be to bruteforce the password",
|
||||||
|
Value: 16,
|
||||||
|
DefaultText: "16",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
password := c.Args().Get(c.Args().Len() - 1)
|
||||||
|
if password == "" {
|
||||||
|
return fmt.Errorf("no password given")
|
||||||
|
}
|
||||||
|
for sec := range getSecretKeyFromStdinLinesOrFirstArgument(c) {
|
||||||
|
ncryptsec, err := nip49.Encrypt(sec, password, uint8(c.Int("logn")), 0x02)
|
||||||
|
if err != nil {
|
||||||
|
lineProcessingError(c, "failed to encrypt: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stdout(ncryptsec)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var decrypt = &cli.Command{
|
||||||
|
Name: "decrypt",
|
||||||
|
Usage: "takes an ncrypsec and a password and decrypts it into an nsec",
|
||||||
|
Description: `uses the NIP-49 standard.`,
|
||||||
|
ArgsUsage: "<ncryptsec-code> <password>",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
password := c.Args().Get(c.Args().Len() - 1)
|
||||||
|
if password == "" {
|
||||||
|
return fmt.Errorf("no password given")
|
||||||
|
}
|
||||||
|
for ncryptsec := range getStdinLinesOrFirstArgument(c) {
|
||||||
|
sec, err := nip49.Decrypt(ncryptsec, password)
|
||||||
|
if err != nil {
|
||||||
|
lineProcessingError(c, "failed to decrypt: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nsec, _ := nip19.EncodePrivateKey(sec)
|
||||||
|
stdout(nsec)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSecretKeyFromStdinLinesOrFirstArgument(c *cli.Context) chan string {
|
||||||
|
ch := make(chan string)
|
||||||
|
go func() {
|
||||||
|
for sec := range getStdinLinesOrFirstArgument(c) {
|
||||||
|
if sec == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(sec, "nsec1") {
|
||||||
|
_, data, err := nip19.Decode(sec)
|
||||||
|
if err != nil {
|
||||||
|
lineProcessingError(c, "invalid nsec code: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sec = data.(string)
|
||||||
|
}
|
||||||
|
if !nostr.IsValid32ByteHex(sec) {
|
||||||
|
lineProcessingError(c, "invalid hex secret key")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ch <- sec
|
||||||
|
}
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
20
main.go
20
main.go
@@ -1,14 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var q int
|
||||||
|
|
||||||
var app = &cli.App{
|
var app = &cli.App{
|
||||||
Name: "nak",
|
Name: "nak",
|
||||||
|
Suggest: true,
|
||||||
|
UseShortOptionHandling: true,
|
||||||
Usage: "the nostr army knife command-line tool",
|
Usage: "the nostr army knife command-line tool",
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
req,
|
req,
|
||||||
@@ -17,18 +20,23 @@ var app = &cli.App{
|
|||||||
event,
|
event,
|
||||||
decode,
|
decode,
|
||||||
encode,
|
encode,
|
||||||
|
key,
|
||||||
verify,
|
verify,
|
||||||
relay,
|
relay,
|
||||||
bunker,
|
bunker,
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "silent",
|
Name: "quiet",
|
||||||
Usage: "do not print logs and info messages to stderr",
|
Usage: "do not print logs and info messages to stderr, use -qq to also not print anything to stdout",
|
||||||
Aliases: []string{"s"},
|
Count: &q,
|
||||||
|
Aliases: []string{"q"},
|
||||||
Action: func(ctx *cli.Context, b bool) error {
|
Action: func(ctx *cli.Context, b bool) error {
|
||||||
if b {
|
if q >= 1 {
|
||||||
log = func(msg string, args ...any) {}
|
log = func(msg string, args ...any) {}
|
||||||
|
if q >= 2 {
|
||||||
|
stdout = func(a ...any) (int, error) { return 0, nil }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -38,7 +46,7 @@ var app = &cli.App{
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Println(err)
|
stdout(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
relay.go
2
relay.go
@@ -31,7 +31,7 @@ var relay = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
pretty, _ := json.MarshalIndent(info, "", " ")
|
pretty, _ := json.MarshalIndent(info, "", " ")
|
||||||
fmt.Println(string(pretty))
|
stdout(string(pretty))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
12
req.go
12
req.go
@@ -62,6 +62,11 @@ example:
|
|||||||
Usage: "shortcut for --tag p=<value>",
|
Usage: "shortcut for --tag p=<value>",
|
||||||
Category: CATEGORY_FILTER_ATTRIBUTES,
|
Category: CATEGORY_FILTER_ATTRIBUTES,
|
||||||
},
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "d",
|
||||||
|
Usage: "shortcut for --tag d=<value>",
|
||||||
|
Category: CATEGORY_FILTER_ATTRIBUTES,
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "since",
|
Name: "since",
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
@@ -179,6 +184,9 @@ example:
|
|||||||
for _, ptag := range c.StringSlice("p") {
|
for _, ptag := range c.StringSlice("p") {
|
||||||
tags = append(tags, []string{"p", ptag})
|
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 {
|
if len(tags) > 0 && filter.Tags == nil {
|
||||||
filter.Tags = make(nostr.TagMap)
|
filter.Tags = make(nostr.TagMap)
|
||||||
@@ -223,7 +231,7 @@ example:
|
|||||||
fn = pool.SubMany
|
fn = pool.SubMany
|
||||||
}
|
}
|
||||||
for ie := range fn(c.Context, relayUrls, nostr.Filters{filter}) {
|
for ie := range fn(c.Context, relayUrls, nostr.Filters{filter}) {
|
||||||
fmt.Println(ie.Event)
|
stdout(ie.Event)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no relays given, will just print the filter
|
// no relays given, will just print the filter
|
||||||
@@ -235,7 +243,7 @@ example:
|
|||||||
result = string(j)
|
result = string(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(result)
|
stdout(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user