2022-10-07 18:51:36 -07:00
|
|
|
<a href="https://nbd.wtf"><img align="right" height="196" src="https://user-images.githubusercontent.com/1653275/194609043-0add674b-dd40-41ed-986c-ab4a2e053092.png" /></a>
|
|
|
|
|
2021-12-16 20:47:53 -03:00
|
|
|
go-nostr
|
|
|
|
========
|
|
|
|
|
2022-11-04 08:24:32 -03:00
|
|
|
A set of useful things for [Nostr Protocol](https://github.com/nostr-protocol/nostr) implementations.
|
2021-12-16 20:47:53 -03:00
|
|
|
|
2022-11-04 08:24:32 -03:00
|
|
|
<a href="https://godoc.org/github.com/nbd-wtf/go-nostr"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
2021-12-16 20:47:53 -03:00
|
|
|
|
2022-01-05 10:16:36 -04:00
|
|
|
### Generating a key
|
|
|
|
|
|
|
|
``` go
|
|
|
|
sk, _ := nostr.GenerateKey()
|
2023-01-13 22:07:08 -05:00
|
|
|
pk, _ := nostr.GetPublicKey(sk)
|
2023-01-13 22:14:21 -05:00
|
|
|
nsec, _ := nip19.EncodePrivateKey(sk)
|
|
|
|
npub, _ := nip19.EncodePublicKey(pk)
|
2022-01-05 10:16:36 -04:00
|
|
|
|
2022-01-23 15:23:53 -03:00
|
|
|
fmt.Println("sk:", sk)
|
|
|
|
fmt.Println("pk:", nostr.GetPublicKey(sk))
|
2023-01-13 22:07:08 -05:00
|
|
|
fmt.Println(nsec)
|
|
|
|
fmt.Println(npub)
|
2022-01-05 10:16:36 -04:00
|
|
|
```
|
2023-01-13 18:50:35 -05:00
|
|
|
|
2023-01-13 22:07:08 -05:00
|
|
|
### 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)
|
|
|
|
}
|
|
|
|
|
2023-01-15 07:19:00 -05:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
sub := relay.Subscribe(ctx, filters)
|
2023-01-13 22:07:08 -05:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-sub.EndOfStoredEvents
|
|
|
|
// handle end of stored events (EOSE, see NIP-15)
|
|
|
|
}()
|
|
|
|
|
|
|
|
for ev := range sub.Events {
|
|
|
|
// handle returned event.
|
2023-01-15 07:19:00 -05:00
|
|
|
// channel will stay open until the ctx is cancelled (in this case, by calling cancel())
|
|
|
|
|
|
|
|
fmt.Println(ev.ID)
|
2023-01-13 22:07:08 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-01-13 22:08:27 -05:00
|
|
|
### Publishing to two relays
|
2023-01-13 22:07:08 -05:00
|
|
|
|
|
|
|
``` 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))
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-01-16 06:27:11 -05:00
|
|
|
### 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)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-01-13 22:07:08 -05:00
|
|
|
### Example script
|
2023-01-13 18:50:35 -05:00
|
|
|
|
|
|
|
```
|
|
|
|
go run example/example.go
|
|
|
|
```
|