Merge pull request #28 from asmogo/lint

lint stuff
This commit is contained in:
asmogo 2024-08-04 14:24:50 +02:00 committed by GitHub
commit 187ce54d12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 98 additions and 62 deletions

View File

@ -6,7 +6,13 @@ import (
"encoding/base32" "encoding/base32"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"log/slog"
"net"
"strings"
"time"
"github.com/asmogo/nws/protocol" "github.com/asmogo/nws/protocol"
"github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/google/uuid" "github.com/google/uuid"
@ -14,10 +20,6 @@ import (
"github.com/nbd-wtf/go-nostr/nip04" "github.com/nbd-wtf/go-nostr/nip04"
"github.com/nbd-wtf/go-nostr/nip19" "github.com/nbd-wtf/go-nostr/nip19"
"github.com/samber/lo" "github.com/samber/lo"
"log/slog"
"net"
"strings"
"time"
) )
// NostrConnection implements the net.Conn interface. // NostrConnection implements the net.Conn interface.
@ -50,13 +52,13 @@ type NostrConnection struct {
// It is used to write incoming events which will be read and processed by the Read method. // It is used to write incoming events which will be read and processed by the Read method.
subscriptionChan chan nostr.IncomingEvent subscriptionChan chan nostr.IncomingEvent
// readIds represents the list of event IDs that have been read by the NostrConnection object. // readIDs represents the list of event IDs that have been read by the NostrConnection object.
readIds []string readIDs []string
// writeIds is a field of type []string in the NostrConnection struct. // writeIDs is a field of type []string in the NostrConnection struct.
// It stores the IDs of the events that have been written to the connection. // It stores the IDs of the events that have been written to the connection.
// This field is used to check if an event has already been written and avoid duplicate writes. // This field is used to check if an event has already been written and avoid duplicate writes.
writeIds []string writeIDs []string
// sentBytes is a field that stores the bytes of data that have been sent by the connection. // sentBytes is a field that stores the bytes of data that have been sent by the connection.
sentBytes [][]byte sentBytes [][]byte
@ -67,6 +69,8 @@ type NostrConnection struct {
targetPublicKey string targetPublicKey string
} }
var errContextCanceled = errors.New("context canceled")
// WriteNostrEvent writes the incoming event to the subscription channel of the NostrConnection. // WriteNostrEvent writes the incoming event to the subscription channel of the NostrConnection.
// The subscription channel is used by the Read method to read events and handle them. // The subscription channel is used by the Read method to read events and handle them.
// Parameters: // Parameters:
@ -78,7 +82,6 @@ func (nc *NostrConnection) WriteNostrEvent(event nostr.IncomingEvent) {
// NewConnection creates a new NostrConnection object with the provided context and options. // NewConnection creates a new NostrConnection object with the provided context and options.
// It initializes the config with default values, processes the options to customize the config, // It initializes the config with default values, processes the options to customize the config,
// and creates a new NostrConnection object using the config. // and creates a new NostrConnection object using the config.
// The NostrConnection object includes the privateKey, dst, pool, ctx, cancel, sub, subscriptionChan, readIds, and sentBytes fields.
// If an uuid is provided in the options, it is assigned to the NostrConnection object. // If an uuid is provided in the options, it is assigned to the NostrConnection object.
// The NostrConnection object is then returned. // The NostrConnection object is then returned.
func NewConnection(ctx context.Context, opts ...NostrConnOption) *NostrConnection { func NewConnection(ctx context.Context, opts ...NostrConnOption) *NostrConnection {
@ -88,7 +91,7 @@ func NewConnection(ctx context.Context, opts ...NostrConnOption) *NostrConnectio
ctx: ctx, ctx: ctx,
cancel: c, cancel: c,
subscriptionChan: make(chan nostr.IncomingEvent), subscriptionChan: make(chan nostr.IncomingEvent),
readIds: make([]string, 0), readIDs: make([]string, 0),
sentBytes: make([][]byte, 0), sentBytes: make([][]byte, 0),
} }
for _, opt := range opts { for _, opt := range opts {
@ -104,8 +107,8 @@ func NewConnection(ctx context.Context, opts ...NostrConnOption) *NostrConnectio
// //
// The number of bytes read is returned as n and any error encountered is returned as err. // The number of bytes read is returned as n and any error encountered is returned as err.
// The content of the decrypted message is then copied to the provided byte slice b. // The content of the decrypted message is then copied to the provided byte slice b.
func (nc *NostrConnection) Read(b []byte) (n int, err error) { func (nc *NostrConnection) Read(b []byte) (int, error) {
return nc.handleNostrRead(b, n) return nc.handleNostrRead(b)
} }
// handleNostrRead reads the incoming events from the subscription channel and processes them. // handleNostrRead reads the incoming events from the subscription channel and processes them.
@ -113,7 +116,7 @@ func (nc *NostrConnection) Read(b []byte) (n int, err error) {
// unmarshals the decoded message and copies the content into the provided byte slice. // unmarshals the decoded message and copies the content into the provided byte slice.
// It returns the number of bytes copied and any error encountered. // It returns the number of bytes copied and any error encountered.
// If the context is canceled, it returns an error with "context canceled" message. // If the context is canceled, it returns an error with "context canceled" message.
func (nc *NostrConnection) handleNostrRead(b []byte, n int) (int, error) { func (nc *NostrConnection) handleNostrRead(buffer []byte) (int, error) {
for { for {
select { select {
case event := <-nc.subscriptionChan: case event := <-nc.subscriptionChan:
@ -121,27 +124,30 @@ func (nc *NostrConnection) handleNostrRead(b []byte, n int) (int, error) {
return 0, nil return 0, nil
} }
// check if we have already read this event // check if we have already read this event
if lo.Contains(nc.readIds, event.ID) { if lo.Contains(nc.readIDs, event.ID) {
continue continue
} }
nc.readIds = append(nc.readIds, event.ID) nc.readIDs = append(nc.readIDs, event.ID)
sharedKey, err := nip04.ComputeSharedSecret(event.PubKey, nc.privateKey) sharedKey, err := nip04.ComputeSharedSecret(event.PubKey, nc.privateKey)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not compute shared key: %w", err)
} }
decodedMessage, err := nip04.Decrypt(event.Content, sharedKey) decodedMessage, err := nip04.Decrypt(event.Content, sharedKey)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not decrypt message: %w", err)
} }
message, err := protocol.UnmarshalJSON([]byte(decodedMessage)) message, err := protocol.UnmarshalJSON([]byte(decodedMessage))
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not unmarshal message: %w", err)
} }
slog.Debug("reading", slog.String("event", event.ID), slog.String("content", base64.StdEncoding.EncodeToString(message.Data))) slog.Debug("reading",
n = copy(b, message.Data) slog.String("event", event.ID),
slog.String("content", base64.StdEncoding.EncodeToString(message.Data)),
)
n := copy(buffer, message.Data)
return n, nil return n, nil
case <-nc.ctx.Done(): case <-nc.ctx.Done():
return 0, fmt.Errorf("context canceled") return 0, errContextCanceled
default: default:
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
} }
@ -155,43 +161,58 @@ func (nc *NostrConnection) Write(b []byte) (int, error) {
return nc.handleNostrWrite(b) return nc.handleNostrWrite(b)
} }
// handleNostrWrite handles the writing of a Nostr event. // Go lang
// It checks if the event has already been sent, parses the destination, func (nc *NostrConnection) handleNostrWrite(buffer []byte) (int, error) {
// creates a message signer, creates message options, signs the event,
// publishes the event to relays, and appends the sent bytes to the connection's sentBytes array.
// The method returns the number of bytes written and any error that occurred.
func (nc *NostrConnection) handleNostrWrite(b []byte) (int, error) {
// check if we have already sent this event
publicKey, relays, err := nc.parseDestination() publicKey, relays, err := nc.parseDestination()
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not parse destination: %w", err)
} }
signer, err := protocol.NewEventSigner(nc.privateKey) signer, err := protocol.NewEventSigner(nc.privateKey)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not create event signer: %w", err)
} }
// create message options signedEvent, err := nc.createSignedEvent(signer, buffer, publicKey, relays)
if err != nil {
return 0, fmt.Errorf("could not create signed event: %w", err)
}
err = nc.publishEventToRelays(signedEvent, relays)
if err != nil {
return 0, fmt.Errorf("could not publish event to relays: %w", err)
}
nc.appendSentBytes(buffer)
slog.Debug("writing",
slog.String("event", signedEvent.ID),
slog.String("content", base64.StdEncoding.EncodeToString(buffer)),
)
return len(buffer), nil
}
func (nc *NostrConnection) createSignedEvent(
signer *protocol.EventSigner,
b []byte,
publicKey string,
relays []string,
) (nostr.Event, error) {
opts := []protocol.MessageOption{ opts := []protocol.MessageOption{
protocol.WithUUID(nc.uuid), protocol.WithUUID(nc.uuid),
protocol.WithType(protocol.MessageTypeSocks5), protocol.WithType(protocol.MessageTypeSocks5),
protocol.WithDestination(nc.dst), protocol.WithDestination(nc.dst),
protocol.WithData(b), protocol.WithData(b),
} }
ev, err := signer.CreateSignedEvent( signedEvent, err := signer.CreateSignedEvent(
publicKey, publicKey,
protocol.KindEphemeralEvent, protocol.KindEphemeralEvent,
nostr.Tags{nostr.Tag{"p", publicKey}}, nostr.Tags{nostr.Tag{"p", publicKey}},
opts..., opts...,
) )
if err != nil { if err != nil {
return 0, err return signedEvent, fmt.Errorf("could not create signed event: %w", err)
} }
if lo.Contains(nc.writeIds, ev.ID) { if lo.Contains(nc.writeIDs, signedEvent.ID) {
slog.Info("event already sent", slog.String("event", ev.ID)) slog.Info("event already sent", slog.String("event", signedEvent.ID))
return 0, nil return signedEvent, nil
} }
nc.writeIds = append(nc.writeIds, ev.ID) nc.writeIDs = append(nc.writeIDs, signedEvent.ID)
if nc.sub { if nc.sub {
nc.sub = false nc.sub = false
now := nostr.Now() now := nostr.Now()
@ -202,27 +223,33 @@ func (nc *NostrConnection) handleNostrWrite(b []byte) (int, error) {
Authors: []string{publicKey}, Authors: []string{publicKey},
Since: &now, Since: &now,
Tags: nostr.TagMap{ Tags: nostr.TagMap{
"p": []string{ev.PubKey}, "p": []string{signedEvent.PubKey},
}, },
}, },
}, },
) )
nc.subscriptionChan = incomingEventChannel nc.subscriptionChan = incomingEventChannel
} }
return signedEvent, nil
}
func (nc *NostrConnection) publishEventToRelays(ev nostr.Event, relays []string) error {
for _, responseRelay := range relays { for _, responseRelay := range relays {
var relay *nostr.Relay var relay *nostr.Relay
relay, err = nc.pool.EnsureRelay(responseRelay) relay, err := nc.pool.EnsureRelay(responseRelay)
if err != nil { if err != nil {
return 0, err return fmt.Errorf("could not ensure relay: %w", err)
} }
err = relay.Publish(nc.ctx, ev) err = relay.Publish(nc.ctx, ev)
if err != nil { if err != nil {
return 0, err return fmt.Errorf("could not publish event to relay: %w", err)
} }
} }
return nil
}
func (nc *NostrConnection) appendSentBytes(b []byte) {
nc.sentBytes = append(nc.sentBytes, b) nc.sentBytes = append(nc.sentBytes, b)
slog.Debug("writing", slog.String("event", ev.ID), slog.String("content", base64.StdEncoding.EncodeToString(b)))
return len(b), nil
} }
// parseDestination takes a destination string and returns a public key and relays. // parseDestination takes a destination string and returns a public key and relays.
@ -237,7 +264,7 @@ func (nc *NostrConnection) parseDestination() (string, []string, error) {
prefix, pubKey, err := nip19.Decode(nc.dst) prefix, pubKey, err := nip19.Decode(nc.dst)
if err != nil { if err != nil {
return "", nil, err return "", nil, fmt.Errorf("could not decode destination: %w", err)
} }
var relays []string var relays []string
@ -278,7 +305,7 @@ func (nc *NostrConnection) parseDestinationDomain() (string, []string, error) {
}*/ }*/
return nc.targetPublicKey, nc.defaultRelays, nil return nc.targetPublicKey, nc.defaultRelays, nil
} }
var subdomains []string subdomains := make([]string, 0)
split := strings.Split(url.SubName, ".") split := strings.Split(url.SubName, ".")
for _, subdomain := range split { for _, subdomain := range split {
decodedSubDomain, err := base32.HexEncoding.WithPadding(base32.NoPadding).DecodeString(strings.ToUpper(subdomain)) decodedSubDomain, err := base32.HexEncoding.WithPadding(base32.NoPadding).DecodeString(strings.ToUpper(subdomain))
@ -315,15 +342,15 @@ func (nc *NostrConnection) RemoteAddr() net.Addr {
return &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0} return &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0}
} }
func (nc *NostrConnection) SetDeadline(t time.Time) error { func (nc *NostrConnection) SetDeadline(_ time.Time) error {
return nil return nil
} }
func (nc *NostrConnection) SetReadDeadline(t time.Time) error { func (nc *NostrConnection) SetReadDeadline(_ time.Time) error {
return nil return nil
} }
func (nc *NostrConnection) SetWriteDeadline(t time.Time) error { func (nc *NostrConnection) SetWriteDeadline(_ time.Time) error {
return nil return nil
} }

View File

@ -1,6 +1,7 @@
package protocol package protocol
import ( import (
"fmt"
"log/slog" "log/slog"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
@ -32,7 +33,7 @@ func NewEventSigner(privateKey string) (*EventSigner, error) {
myPublicKey, err := nostr.GetPublicKey(privateKey) myPublicKey, err := nostr.GetPublicKey(privateKey)
if err != nil { if err != nil {
slog.Error("could not generate pubkey") slog.Error("could not generate pubkey")
return nil, err return nil, fmt.Errorf("could not generate public key: %w", err)
} }
signer := &EventSigner{ signer := &EventSigner{
privateKey: privateKey, privateKey: privateKey,
@ -42,7 +43,7 @@ func NewEventSigner(privateKey string) (*EventSigner, error) {
} }
// CreateEvent creates a new Event with the provided tags. The Public Key and the // CreateEvent creates a new Event with the provided tags. The Public Key and the
// current timestamp are set automatically. The Kind is set to KindEphemeralEvent. // current timestamp are set automatically. The Kind is set to KindEphemeralEvent
func (s *EventSigner) CreateEvent(kind int, tags nostr.Tags) nostr.Event { func (s *EventSigner) CreateEvent(kind int, tags nostr.Tags) nostr.Event {
return nostr.Event{ return nostr.Event{
PubKey: s.PublicKey, PubKey: s.PublicKey,
@ -59,26 +60,34 @@ func (s *EventSigner) CreateEvent(kind int, tags nostr.Tags) nostr.Event {
// The method then calls CreateEvent to create a new unsigned event with the provided tags. // The method then calls CreateEvent to create a new unsigned event with the provided tags.
// The encrypted message is set as the content of the event. // The encrypted message is set as the content of the event.
// Finally, the event is signed with the private key of the EventSigner, setting the event ID and event Sig fields. // Finally, the event is signed with the private key of the EventSigner, setting the event ID and event Sig fields.
// The signed event is returned along with any error that occurs. // The signed event is returned along with any error that occurs
func (s *EventSigner) CreateSignedEvent(targetPublicKey string, kind int, tags nostr.Tags, opts ...MessageOption) (nostr.Event, error) { func (s *EventSigner) CreateSignedEvent(
targetPublicKey string,
kind int,
tags nostr.Tags,
opts ...MessageOption,
) (nostr.Event, error) {
sharedKey, err := nip04.ComputeSharedSecret(targetPublicKey, s.privateKey) sharedKey, err := nip04.ComputeSharedSecret(targetPublicKey, s.privateKey)
if err != nil { if err != nil {
return nostr.Event{}, err return nostr.Event{}, fmt.Errorf("could not compute shared key: %w", err)
} }
message := NewMessage( message := NewMessage(
opts..., opts...,
) )
messageJson, err := MarshalJSON(message) messageJSON, err := MarshalJSON(message)
if err != nil { if err != nil {
return nostr.Event{}, err return nostr.Event{}, fmt.Errorf("could not marshal message: %w", err)
} }
encryptedMessage, err := nip04.Encrypt(string(messageJson), sharedKey) encryptedMessage, err := nip04.Encrypt(string(messageJSON), sharedKey)
ev := s.CreateEvent(kind, tags) if err != nil {
ev.Content = encryptedMessage return nostr.Event{}, fmt.Errorf("could not encrypt message: %w", err)
}
event := s.CreateEvent(kind, tags)
event.Content = encryptedMessage
// calling Sign sets the event ID field and the event Sig field // calling Sign sets the event ID field and the event Sig field
err = ev.Sign(s.privateKey) err = event.Sign(s.privateKey)
if err != nil { if err != nil {
return nostr.Event{}, err return nostr.Event{}, fmt.Errorf("could not sign event: %w", err)
} }
return ev, nil return event, nil
} }