Patrick Bennett ebae5d41e6
Add most NIP-11 extension structures to the RelayInformationDocument struct. (#80)
* Fix race condition on status in Relay.Publish method and failure to send

A race-condition exists between setting of the (unprotected) status and the callback which sets the status upon receiving an OK.
The message is sent which can receive an OK in separate goroutine (setting status) prior to the status being set to 'sent.'
The OK can be received prior to the status being set.

This fix also sets the status to PublishStatusFailed if the WriteJSON call fails.

* Add some NIP-11 extension structures to the RelayInformationDocument struct.

Added additional NIP-11 fields for relays that want to provide additional details based on NIP-11 extensions.
The retention structure has been left out as it doesn't have a clean schema for kinds (array of kinds, or pairs of kinds?)
Specified the fields w/ omitempty so marshaled will be same as original NIP-11 if nothing else is specified.
Nested structs defined as pointers so they are omitted if not specified.

* Fix TestPublishWriteFailed so that the socket is given a brief amount of time to close prior to publish being called.
The test relies on Publish always failing.
2023-04-26 08:06:05 -03:00
2023-02-15 20:25:16 -03:00
2023-04-16 16:25:25 -03:00
2023-03-31 09:30:33 -03:00
2022-01-06 21:57:04 -03:00
2023-03-04 21:04:59 -03:00
2023-03-27 08:47:59 -03:00
2023-04-12 12:14:24 -03:00
2023-04-16 15:56:50 -03:00
2023-04-16 15:56:50 -03:00
2022-10-07 16:52:01 -07:00
2022-12-11 16:35:04 -03:00
2023-03-14 21:56:40 -03:00
2023-03-17 09:09:36 -03:00
2023-04-16 16:25:25 -03:00
2023-04-26 08:04:51 -03:00
2023-04-12 12:14:24 -03:00
2022-11-11 10:52:23 -03:00
2023-04-19 14:40:44 -03:00

go-nostr

A set of useful things for Nostr Protocol implementations.

GoDoc
test every commit

Install go-nostr:

go get github.com/nbd-wtf/go-nostr

Generating a key

package main

import (
    "fmt"

    "github.com/nbd-wtf/go-nostr"
    "github.com/nbd-wtf/go-nostr/nip19"
)

func main() {
    sk := nostr.GeneratePrivateKey()
    pk, _ := nostr.GetPublicKey(sk)
    nsec, _ := nip19.EncodePrivateKey(sk)
    npub, _ := nip19.EncodePublicKey(pk)

    fmt.Println("sk:", sk)
    fmt.Println("pk:", pk)
    fmt.Println(nsec)
    fmt.Println(npub)
}

Subscribing to a single relay

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

sk := nostr.GeneratePrivateKey()
pub, _ := nostr.GetPublicKey(sk)

ev := nostr.Event{
	PubKey:    pub,
	CreatedAt: nostr.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.

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
Description
Nostr library for Golang
Readme 5.6 MiB
Languages
C 83.3%
Go 15.9%
Assembly 0.7%
Just 0.1%