go-nostr ======== A set of useful things for [Nostr Protocol](https://github.com/nostr-protocol/nostr) implementations. GoDoc ### Generating a key ``` go sk, _ := nostr.GenerateKey() pk, _ := nostr.GetPublicKey(sk) nsec, _ := nip19.EncodePrivateKey(sk) npub, _ := nip19.EncodePublicKey(pk) fmt.Println("sk:", sk) fmt.Println("pk:", nostr.GetPublicKey(sk)) fmt.Println(nsec) fmt.Println(npub) ``` ### Subscribing to a single relay ``` go relay, err := nostr.RelayConnect(context.Background(), "wss://nostr.zebedee.cloud") if err != nil { panic(err) } npub := "npub1422a7ws4yul24p0pf7cacn7cghqkutdnm35z075vy68ggqpqjcyswn8ekc" var filters nostr.Filters if _, v, err := nip19.Decode(npub); err == nil { pub := v.(string) filters = []nostr.Filter{{ Kinds: []int{1}, Authors: []string{pub}, Limit: 1, }} } else { panic(err) } ctx, cancel := context.WithCancel(context.Background()) sub := relay.Subscribe(ctx, filters) go func() { <-sub.EndOfStoredEvents // handle end of stored events (EOSE, see NIP-15) }() for ev := range sub.Events { // handle returned event. // channel will stay open until the ctx is cancelled (in this case, by calling cancel()) fmt.Println(ev.ID) } ``` ### Publishing to two relays ``` go sk := nostr.GeneratePrivateKey() pub, _ := nostr.GetPublicKey(sk) ev := nostr.Event{ PubKey: pub, CreatedAt: time.Now(), Kind: 1, Tags: nil, Content: "Hello World!", } // calling Sign sets the event ID field and the event Sig field ev.Sign(sk) // publish the event to two relays for _, url := range []string{"wss://nostr.zebedee.cloud", "wss://nostr-pub.wellorder.net"} { relay, e := nostr.RelayConnect(context.Background(), url) if e != nil { fmt.Println(e) continue } fmt.Println("published to ", url, relay.Publish(context.Background(), ev)) } ``` ### Authenticating with NIP-42 For this section, the user needs access to a relay implementing NIP-42. E.g., https://github.com/fiatjaf/relayer with a relay implementing the relayer.Auther interface. ``` go func main() { url := "ws://localhost:7447" // Once the connection is initiated the server will send "AUTH" with the challenge string. relay, err := nostr.RelayConnect(context.Background(), url) if err != nil { panic(err) } // Initialize test user. sk := nostr.GeneratePrivateKey() pub, _ := nostr.GetPublicKey(sk) npub, _ := nip19.EncodePublicKey(pub) // Relay.Challenges channel will receive the "AUTH" command. challenge := <-relay.Challenges // Create the auth event to send back. // The user will be authenticated as pub. event := nip42.CreateUnsignedAuthEvent(challenge, pub, url) event.Sign(sk) // Set-up context with 3 second time out. ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() // Send the event by calling relay.Auth. // Returned status is either success, fail, or sent (if no reply given in the 3 second timeout). auth_status := relay.Auth(ctx, event) fmt.Printf("authenticated as %s: %s\n", npub, auth_status) } ``` ### Example script ``` go run example/example.go ```