keys.go raw
1 package relaytester
2
3 import (
4 "crypto/rand"
5 "fmt"
6 "time"
7
8 "next.orly.dev/pkg/lol/chk"
9 "next.orly.dev/pkg/nostr/interfaces/signer/p8k"
10 "next.orly.dev/pkg/nostr/encoders/bech32encoding"
11 "next.orly.dev/pkg/nostr/encoders/event"
12 "next.orly.dev/pkg/nostr/encoders/hex"
13 "next.orly.dev/pkg/nostr/encoders/kind"
14 "next.orly.dev/pkg/nostr/encoders/tag"
15 )
16
17 // KeyPair represents a test keypair.
18 type KeyPair struct {
19 Secret *p8k.Signer
20 Pubkey []byte
21 Nsec string
22 Npub string
23 }
24
25 // GenerateKeyPair generates a new keypair for testing.
26 func GenerateKeyPair() (kp *KeyPair, err error) {
27 kp = &KeyPair{}
28 if kp.Secret, err = p8k.New(); chk.E(err) {
29 return
30 }
31 if err = kp.Secret.Generate(); chk.E(err) {
32 return
33 }
34 kp.Pubkey = kp.Secret.Pub()
35 nsecBytes, err := bech32encoding.BinToNsec(kp.Secret.Sec())
36 if chk.E(err) {
37 return
38 }
39 kp.Nsec = string(nsecBytes)
40 npubBytes, err := bech32encoding.BinToNpub(kp.Pubkey)
41 if chk.E(err) {
42 return
43 }
44 kp.Npub = string(npubBytes)
45 return
46 }
47
48 // CreateEvent creates a signed event with the given parameters.
49 func CreateEvent(signer *p8k.Signer, kindNum uint16, content string, tags *tag.S) (ev *event.E, err error) {
50 ev = event.New()
51 ev.CreatedAt = time.Now().Unix()
52 ev.Kind = kindNum
53 ev.Content = []byte(content)
54 if tags != nil {
55 ev.Tags = tags
56 } else {
57 ev.Tags = tag.NewS()
58 }
59 if err = ev.Sign(signer); chk.E(err) {
60 return
61 }
62 return
63 }
64
65 // CreateEventWithTags creates an event with specific tags.
66 func CreateEventWithTags(signer *p8k.Signer, kindNum uint16, content string, tagPairs [][]string) (ev *event.E, err error) {
67 tags := tag.NewS()
68 for _, pair := range tagPairs {
69 if len(pair) >= 2 {
70 // Build tag fields as []byte variadic arguments
71 tagFields := make([][]byte, len(pair))
72 tagFields[0] = []byte(pair[0])
73 for i := 1; i < len(pair); i++ {
74 tagFields[i] = []byte(pair[i])
75 }
76 tags.Append(tag.NewFromBytesSlice(tagFields...))
77 }
78 }
79 return CreateEvent(signer, kindNum, content, tags)
80 }
81
82 // CreateReplaceableEvent creates a replaceable event (kind 0-3, 10000-19999).
83 func CreateReplaceableEvent(signer *p8k.Signer, kindNum uint16, content string) (ev *event.E, err error) {
84 return CreateEvent(signer, kindNum, content, nil)
85 }
86
87 // CreateEphemeralEvent creates an ephemeral event (kind 20000-29999).
88 func CreateEphemeralEvent(signer *p8k.Signer, kindNum uint16, content string) (ev *event.E, err error) {
89 return CreateEvent(signer, kindNum, content, nil)
90 }
91
92 // CreateDeleteEvent creates a deletion event (kind 5).
93 func CreateDeleteEvent(signer *p8k.Signer, eventIDs [][]byte, reason string) (ev *event.E, err error) {
94 tags := tag.NewS()
95 for _, id := range eventIDs {
96 // e tags must contain hex-encoded event IDs
97 tags.Append(tag.NewFromBytesSlice([]byte("e"), []byte(hex.Enc(id))))
98 }
99 if reason != "" {
100 tags.Append(tag.NewFromBytesSlice([]byte("content"), []byte(reason)))
101 }
102 return CreateEvent(signer, kind.EventDeletion.K, reason, tags)
103 }
104
105 // CreateParameterizedReplaceableEvent creates a parameterized replaceable event (kind 30000-39999).
106 func CreateParameterizedReplaceableEvent(signer *p8k.Signer, kindNum uint16, content string, dTag string) (ev *event.E, err error) {
107 tags := tag.NewS()
108 tags.Append(tag.NewFromBytesSlice([]byte("d"), []byte(dTag)))
109 return CreateEvent(signer, kindNum, content, tags)
110 }
111
112 // RandomID generates a random 32-byte ID.
113 func RandomID() (id []byte, err error) {
114 id = make([]byte, 32)
115 if _, err = rand.Read(id); err != nil {
116 return nil, fmt.Errorf("failed to generate random ID: %w", err)
117 }
118 return
119 }
120
121 // MustHex decodes a hex string or panics.
122 func MustHex(s string) []byte {
123 b, err := hex.Dec(s)
124 if err != nil {
125 panic(fmt.Sprintf("invalid hex: %s", s))
126 }
127 return b
128 }
129
130 // HexID returns the hex-encoded event ID.
131 func HexID(ev *event.E) string {
132 return hex.Enc(ev.ID)
133 }
134