2024-01-25 06:19:55 -05:00
|
|
|
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 {
|
2024-03-19 10:34:59 -04:00
|
|
|
for sec := range getSecretKeyFromStdinLinesOrSlice(c, c.Args().Slice()) {
|
2024-01-25 06:19:55 -05:00
|
|
|
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 {
|
2024-02-03 08:03:32 -05:00
|
|
|
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)
|
|
|
|
}
|
2024-01-25 06:19:55 -05:00
|
|
|
if password == "" {
|
|
|
|
return fmt.Errorf("no password given")
|
|
|
|
}
|
2024-03-19 10:34:59 -04:00
|
|
|
for sec := range getSecretKeyFromStdinLinesOrSlice(c, []string{content}) {
|
2024-01-25 06:19:55 -05:00
|
|
|
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 {
|
2024-02-03 08:03:32 -05:00
|
|
|
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)
|
|
|
|
}
|
2024-01-25 06:19:55 -05:00
|
|
|
if password == "" {
|
|
|
|
return fmt.Errorf("no password given")
|
|
|
|
}
|
2024-03-19 10:34:59 -04:00
|
|
|
for ncryptsec := range getStdinLinesOrArgumentsFromSlice([]string{content}) {
|
2024-01-25 06:19:55 -05:00
|
|
|
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
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-03-19 10:34:59 -04:00
|
|
|
func getSecretKeyFromStdinLinesOrSlice(c *cli.Context, keys []string) chan string {
|
2024-01-25 06:19:55 -05:00
|
|
|
ch := make(chan string)
|
|
|
|
go func() {
|
2024-03-19 10:34:59 -04:00
|
|
|
for sec := range getStdinLinesOrArgumentsFromSlice(keys) {
|
2024-01-25 06:19:55 -05:00
|
|
|
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
|
|
|
|
}
|