mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-05-06 00:30:14 +02:00
style: using effective go and refactoring
This commit is contained in:
parent
abb66db97e
commit
ac2350c722
8
Makefile
Normal file
8
Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
### Tools needed for development
|
||||||
|
devtools:
|
||||||
|
@echo "Installing devtools"
|
||||||
|
go install mvdan.cc/gofumpt@latest
|
||||||
|
|
||||||
|
### Formatting, linting, and vetting
|
||||||
|
fmt:
|
||||||
|
gofumpt -l -w .
|
14
envelopes.go
14
envelopes.go
@ -54,8 +54,8 @@ type Envelope interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventEnvelope struct {
|
type EventEnvelope struct {
|
||||||
SubscriptionID *string
|
SubscriptionID *string `json:"subscription_id"`
|
||||||
Event
|
Event `json:"event"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -266,9 +266,9 @@ func (v CloseEnvelope) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OKEnvelope struct {
|
type OKEnvelope struct {
|
||||||
EventID string
|
EventID string `json:"event_id"`
|
||||||
OK bool
|
OK bool `json:"ok"`
|
||||||
Reason *string
|
Reason *string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ OKEnvelope) Label() string { return "OK" }
|
func (_ OKEnvelope) Label() string { return "OK" }
|
||||||
@ -307,8 +307,8 @@ func (v OKEnvelope) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AuthEnvelope struct {
|
type AuthEnvelope struct {
|
||||||
Challenge *string
|
Challenge *string `json:"challenge"`
|
||||||
Event Event
|
Event Event `json:"event"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ AuthEnvelope) Label() string { return "AUTH" }
|
func (_ AuthEnvelope) Label() string { return "AUTH" }
|
||||||
|
6
event.go
6
event.go
@ -58,13 +58,13 @@ const (
|
|||||||
KindApplicationSpecificData int = 30078
|
KindApplicationSpecificData int = 30078
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event Stringer interface, just returns the raw JSON as a string
|
// Event Stringer interface, just returns the raw JSON as a string.
|
||||||
func (evt Event) String() string {
|
func (evt Event) String() string {
|
||||||
j, _ := easyjson.Marshal(evt)
|
j, _ := easyjson.Marshal(evt)
|
||||||
return string(j)
|
return string(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID serializes and returns the event ID as a string
|
// GetID serializes and returns the event ID as a string.
|
||||||
func (evt *Event) GetID() string {
|
func (evt *Event) GetID() string {
|
||||||
h := sha256.Sum256(evt.Serialize())
|
h := sha256.Sum256(evt.Serialize())
|
||||||
return hex.EncodeToString(h[:])
|
return hex.EncodeToString(h[:])
|
||||||
@ -128,7 +128,7 @@ func (evt Event) CheckSignature() (bool, error) {
|
|||||||
return sig.Verify(hash[:], pubkey), nil
|
return sig.Verify(hash[:], pubkey), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs an event with a given privateKey
|
// Sign signs an event with a given privateKey.
|
||||||
func (evt *Event) Sign(privateKey string) error {
|
func (evt *Event) Sign(privateKey string) error {
|
||||||
s, err := hex.DecodeString(privateKey)
|
s, err := hex.DecodeString(privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,5 +3,4 @@
|
|||||||
package nostr
|
package nostr
|
||||||
|
|
||||||
func debugLogf(str string, args ...any) {
|
func debugLogf(str string, args ...any) {
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,8 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe
|
|||||||
return nil, fmt.Errorf("hostname doesn't have a dot")
|
return nil, fmt.Errorf("hostname doesn't have a dot")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s/.well-known/nostr.json?name=%s", domain, name), nil)
|
req, err := http.NewRequestWithContext(ctx, "GET",
|
||||||
|
fmt.Sprintf("https://%s/.well-known/nostr.json?name=%s", domain, name), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create a request: %w", err)
|
return nil, fmt.Errorf("failed to create a request: %w", err)
|
||||||
}
|
}
|
||||||
@ -54,6 +55,7 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("request failed: %w", err)
|
return nil, fmt.Errorf("request failed: %w", err)
|
||||||
}
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
var result WellKnownResponse
|
var result WellKnownResponse
|
||||||
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
|
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
|
||||||
@ -62,12 +64,12 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe
|
|||||||
|
|
||||||
pubkey, ok := result.Names[name]
|
pubkey, ok := result.Names[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil
|
return &nostr.ProfilePointer{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pubkey) == 64 {
|
if len(pubkey) == 64 {
|
||||||
if _, err := hex.DecodeString(pubkey); err != nil {
|
if _, err := hex.DecodeString(pubkey); err != nil {
|
||||||
return nil, nil
|
return &nostr.ProfilePointer{}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,15 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// Fetch fetches the NIP-11 RelayInformationDocument.
|
// Fetch fetches the NIP-11 RelayInformationDocument.
|
||||||
func Fetch(ctx context.Context, u string) (info *RelayInformationDocument, err error) {
|
func Fetch(ctx context.Context, u string) (info *RelayInformationDocument, err error) {
|
||||||
if _, ok := ctx.Deadline(); !ok {
|
if _, ok := ctx.Deadline(); !ok {
|
||||||
@ -47,6 +44,7 @@ func Fetch(ctx context.Context, u string) (info *RelayInformationDocument, err e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
info = &RelayInformationDocument{}
|
info = &RelayInformationDocument{}
|
||||||
dec := json.NewDecoder(resp.Body)
|
dec := json.NewDecoder(resp.Body)
|
||||||
err = dec.Decode(info)
|
err = dec.Decode(info)
|
||||||
|
@ -144,8 +144,8 @@ func EncodePublicKey(publicKeyHex string) (string, error) {
|
|||||||
return bech32.Encode("npub", bits5)
|
return bech32.Encode("npub", bits5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeNote(eventIdHex string) (string, error) {
|
func EncodeNote(eventIDHex string) (string, error) {
|
||||||
b, err := hex.DecodeString(eventIdHex)
|
b, err := hex.DecodeString(eventIDHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to decode event id hex: %w", err)
|
return "", fmt.Errorf("failed to decode event id hex: %w", err)
|
||||||
}
|
}
|
||||||
@ -178,11 +178,11 @@ func EncodeProfile(publicKeyHex string, relays []string) (string, error) {
|
|||||||
return bech32.Encode("nprofile", bits5)
|
return bech32.Encode("nprofile", bits5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeEvent(eventIdHex string, relays []string, author string) (string, error) {
|
func EncodeEvent(eventIDHex string, relays []string, author string) (string, error) {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
id, err := hex.DecodeString(eventIdHex)
|
id, err := hex.DecodeString(eventIDHex)
|
||||||
if err != nil || len(id) != 32 {
|
if err != nil || len(id) != 32 {
|
||||||
return "", fmt.Errorf("invalid id '%s': %w", eventIdHex, err)
|
return "", fmt.Errorf("invalid id '%s': %w", eventIDHex, err)
|
||||||
}
|
}
|
||||||
writeTLVEntry(buf, TLVDefault, id)
|
writeTLVEntry(buf, TLVDefault, id)
|
||||||
|
|
||||||
|
@ -55,15 +55,14 @@ func CheckDelegation(ev *nostr.Event) (ok bool, err error) {
|
|||||||
d := new(DelegationToken)
|
d := new(DelegationToken)
|
||||||
if ok, err := d.Parse(ev); ok == true && (err == nil || err == NoDelegationTag) {
|
if ok, err := d.Parse(ev); ok == true && (err == nil || err == NoDelegationTag) {
|
||||||
return true, nil
|
return true, nil
|
||||||
} else {
|
|
||||||
return false, err
|
|
||||||
}
|
}
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import verifies that t is NIP-26 delegation token for the given delegatee.
|
// Import verifies that t is NIP-26 delegation token for the given delegatee.
|
||||||
// The returned DelegationToken object can be used in DelegatedSign.
|
// The returned DelegationToken object can be used in DelegatedSign.
|
||||||
// If the token signature verification fails, the error VerificationFailed will be returned.
|
// If the token signature verification fails, the error VerificationFailed will be returned.
|
||||||
func Import(t nostr.Tag, delegatee_pk string) (d *DelegationToken, e error) {
|
func Import(t nostr.Tag, delegateePk string) (d *DelegationToken, e error) {
|
||||||
d = new(DelegationToken)
|
d = new(DelegationToken)
|
||||||
if len(t) == 4 && t[0] == "delegation" {
|
if len(t) == 4 && t[0] == "delegation" {
|
||||||
copy(d.tag[:], t)
|
copy(d.tag[:], t)
|
||||||
@ -81,16 +80,16 @@ func Import(t nostr.Tag, delegatee_pk string) (d *DelegationToken, e error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute the digest
|
// compute the digest
|
||||||
h := sha256.Sum256([]byte(fmt.Sprintf("nostr:delegation:%s:%s", delegatee_pk, d.tag[2])))
|
h := sha256.Sum256([]byte(fmt.Sprintf("nostr:delegation:%s:%s", delegateePk, d.tag[2])))
|
||||||
|
|
||||||
sig, err := schnorr.ParseSignature(d.token[:])
|
sig, err := schnorr.ParseSignature(d.token[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error: %s", err.Error())
|
return nil, fmt.Errorf("error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey, err := schnorr.ParsePubKey(d.delegator[:])
|
pubkey, err := schnorr.ParsePubKey(d.delegator[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error: %s", err.Error())
|
return nil, fmt.Errorf("error: %s", err.Error())
|
||||||
}
|
}
|
||||||
if !sig.Verify(h[:], pubkey) {
|
if !sig.Verify(h[:], pubkey) {
|
||||||
return nil, VerificationFailed
|
return nil, VerificationFailed
|
||||||
@ -131,15 +130,15 @@ jump1:
|
|||||||
goto jump2
|
goto jump2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, fmt.Errorf("Event kind %d is not allowed in delegation conditions.", ev.Kind)
|
return false, fmt.Errorf("event kind %d is not allowed in delegation condition", ev.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
jump2:
|
jump2:
|
||||||
if d.since != nil && ev.CreatedAt.Time().Before(*d.since) {
|
if d.since != nil && ev.CreatedAt.Time().Before(*d.since) {
|
||||||
return false, fmt.Errorf("Event is created before delegation conditions allow.")
|
return false, fmt.Errorf("event is created before delegation conditions allow")
|
||||||
}
|
}
|
||||||
if d.until != nil && ev.CreatedAt.Time().After(*d.until) {
|
if d.until != nil && ev.CreatedAt.Time().After(*d.until) {
|
||||||
return false, fmt.Errorf("Event is created after delegation conditions allow.")
|
return false, fmt.Errorf("event is created after delegation conditions allow")
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute the digest
|
// compute the digest
|
||||||
@ -147,12 +146,12 @@ jump2:
|
|||||||
|
|
||||||
sig, err := schnorr.ParseSignature(d.token[:])
|
sig, err := schnorr.ParseSignature(d.token[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("Error: %s", err.Error())
|
return false, fmt.Errorf("error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey, err := schnorr.ParsePubKey(d.delegator[:])
|
pubkey, err := schnorr.ParsePubKey(d.delegator[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("Error: %s", err.Error())
|
return false, fmt.Errorf("error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return sig.Verify(h[:], pubkey), nil
|
return sig.Verify(h[:], pubkey), nil
|
||||||
@ -160,14 +159,16 @@ jump2:
|
|||||||
|
|
||||||
// DelegatedSign performs a delegated signature on the event ev.
|
// DelegatedSign performs a delegated signature on the event ev.
|
||||||
// The delegation signature is not verified. If desired, the caller can ensure the delegation signature is correct by calling d.Parse(ev) or CheckDelegation(ev) afterwards.
|
// The delegation signature is not verified. If desired, the caller can ensure the delegation signature is correct by calling d.Parse(ev) or CheckDelegation(ev) afterwards.
|
||||||
func DelegatedSign(ev *nostr.Event, d *DelegationToken, delegatee_sk string) error {
|
func DelegatedSign(ev *nostr.Event,
|
||||||
|
d *DelegationToken, delegateeSk string,
|
||||||
|
) error {
|
||||||
for _, t := range ev.Tags {
|
for _, t := range ev.Tags {
|
||||||
if t[0] == "delegation" {
|
if t[0] == "delegation" {
|
||||||
return fmt.Errorf("event already has delegation token")
|
return fmt.Errorf("event already has delegation token")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d.since != nil && ev.CreatedAt.Time().Before(*d.since) || d.until != nil && ev.CreatedAt.Time().After(*d.until) {
|
if d.since != nil && ev.CreatedAt.Time().Before(*d.since) || d.until != nil && ev.CreatedAt.Time().After(*d.until) {
|
||||||
return fmt.Errorf("event created_at field is not compatible with delegation token time conditions.")
|
return fmt.Errorf("event created_at field is not compatible with delegation token time conditions")
|
||||||
}
|
}
|
||||||
if len(d.kinds) > 0 {
|
if len(d.kinds) > 0 {
|
||||||
for _, k := range d.kinds {
|
for _, k := range d.kinds {
|
||||||
@ -175,34 +176,36 @@ func DelegatedSign(ev *nostr.Event, d *DelegationToken, delegatee_sk string) err
|
|||||||
goto jump
|
goto jump
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("event kind %d is not compatible with delegation token conditions.", ev.Kind)
|
return fmt.Errorf("event kind %d is not compatible with delegation token conditions", ev.Kind)
|
||||||
}
|
}
|
||||||
jump:
|
jump:
|
||||||
if pk, e := nostr.GetPublicKey(delegatee_sk); e != nil {
|
if pk, e := nostr.GetPublicKey(delegateeSk); e != nil {
|
||||||
return fmt.Errorf("invalid delegatee secret key.")
|
return fmt.Errorf("invalid delegatee secret key")
|
||||||
} else {
|
} else {
|
||||||
ev.PubKey = pk
|
ev.PubKey = pk
|
||||||
}
|
}
|
||||||
ev.Tags = append(ev.Tags, d.Tag())
|
ev.Tags = append(ev.Tags, d.Tag())
|
||||||
return ev.Sign(delegatee_sk)
|
return ev.Sign(delegateeSk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateToken creates a DelegationToken according to NIP-26.
|
// CreateToken creates a DelegationToken according to NIP-26.
|
||||||
func CreateToken(delegator_sk string, delegatee_pk string, kinds []int, since *time.Time, until *time.Time) (d *DelegationToken, e error) {
|
func CreateToken(delegator_sk string, delegatee_pk string, kinds []int,
|
||||||
|
since *time.Time, until *time.Time,
|
||||||
|
) (d *DelegationToken, e error) {
|
||||||
d = new(DelegationToken)
|
d = new(DelegationToken)
|
||||||
s, e := hex.DecodeString(delegator_sk)
|
s, e := hex.DecodeString(delegator_sk)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, fmt.Errorf("invalid delegator secret key")
|
return nil, fmt.Errorf("invalid delegator secret key")
|
||||||
}
|
}
|
||||||
|
|
||||||
tee_pk, e := hex.DecodeString(delegatee_pk)
|
teePk, e := hex.DecodeString(delegatee_pk)
|
||||||
if len(tee_pk) != 32 || e != nil {
|
if len(teePk) != 32 || e != nil {
|
||||||
return nil, fmt.Errorf("invalid delegatee pubkey")
|
return nil, fmt.Errorf("invalid delegatee pubkey")
|
||||||
}
|
}
|
||||||
|
|
||||||
// set delegator
|
// set delegator
|
||||||
sk, tor_pk := btcec.PrivKeyFromBytes(s)
|
sk, torPk := btcec.PrivKeyFromBytes(s)
|
||||||
copy(d.delegator[:], schnorr.SerializePubKey(tor_pk))
|
copy(d.delegator[:], schnorr.SerializePubKey(torPk))
|
||||||
|
|
||||||
d.kinds = kinds
|
d.kinds = kinds
|
||||||
d.since = since
|
d.since = since
|
||||||
@ -213,7 +216,7 @@ func CreateToken(delegator_sk string, delegatee_pk string, kinds []int, since *t
|
|||||||
d.tag[1] = fmt.Sprintf("%x", d.delegator)
|
d.tag[1] = fmt.Sprintf("%x", d.delegator)
|
||||||
d.tag[2] = d.Conditions()
|
d.tag[2] = d.Conditions()
|
||||||
|
|
||||||
h := sha256.Sum256([]byte(fmt.Sprintf("nostr:delegation:%x:%s", tee_pk, d.tag[2])))
|
h := sha256.Sum256([]byte(fmt.Sprintf("nostr:delegation:%x:%s", teePk, d.tag[2])))
|
||||||
|
|
||||||
if sig, err := schnorr.Sign(sk, h[:]); err != nil {
|
if sig, err := schnorr.Sign(sk, h[:]); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -10,9 +10,9 @@ import (
|
|||||||
func TestDelegateSign(t *testing.T) {
|
func TestDelegateSign(t *testing.T) {
|
||||||
since := time.Unix(1600000000, 0)
|
since := time.Unix(1600000000, 0)
|
||||||
until := time.Unix(1600000100, 0)
|
until := time.Unix(1600000100, 0)
|
||||||
delegator_secret_key, delegatee_secret_key := "3f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459da", "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b"
|
delegatorSecretKey, delegatee_secret_key := "3f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459da", "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b"
|
||||||
delegatee_pubkey, _ := nostr.GetPublicKey(delegatee_secret_key)
|
delegateePubkey, _ := nostr.GetPublicKey(delegatee_secret_key)
|
||||||
d1, err := CreateToken(delegator_secret_key, delegatee_pubkey, []int{1, 2, 3}, &since, &until)
|
d1, err := CreateToken(delegatorSecretKey, delegateePubkey, []int{1, 2, 3}, &since, &until)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ func TestDelegateSign(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
d2, err := Import(d1.Tag(), delegatee_pubkey)
|
d2, err := Import(d1.Tag(), delegateePubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ func TestDelegateSign(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tag := []string{"delegation", "9ea72be3fcfe38103195a41b67b6f96c14ed92d2091d6d9eb8166a5c27b0c35d", "kind=1&kind=2&kind=3&created_at>1600000000", "8432b8c86f789c2783ef3becb0fabf4def6031c6a615fa7a622f31329d80ed1b2a79ab753c0462f1440503c94e1829158a3a854a1d418ad256ae2cf8aa19fa9a"}
|
tag := []string{"delegation", "9ea72be3fcfe38103195a41b67b6f96c14ed92d2091d6d9eb8166a5c27b0c35d", "kind=1&kind=2&kind=3&created_at>1600000000", "8432b8c86f789c2783ef3becb0fabf4def6031c6a615fa7a622f31329d80ed1b2a79ab753c0462f1440503c94e1829158a3a854a1d418ad256ae2cf8aa19fa9a"}
|
||||||
d3, err := Import(tag, delegatee_pubkey)
|
d3, err := Import(tag, delegateePubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ func CreateUnsignedAuthEvent(challenge, pubkey, relayURL string) nostr.Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function for ValidateAuthEvent
|
// helper function for ValidateAuthEvent.
|
||||||
func parseUrl(input string) (*url.URL, error) {
|
func parseURL(input string) (*url.URL, error) {
|
||||||
return url.Parse(
|
return url.Parse(
|
||||||
strings.ToLower(
|
strings.ToLower(
|
||||||
strings.TrimSuffix(input, "/"),
|
strings.TrimSuffix(input, "/"),
|
||||||
@ -43,12 +43,12 @@ func ValidateAuthEvent(event *nostr.Event, challenge string, relayURL string) (p
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
expected, err := parseUrl(relayURL)
|
expected, err := parseURL(relayURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
found, err := parseUrl(event.Tags.GetFirst([]string{"relay", ""}).Value())
|
found, err := parseURL(event.Tags.GetFirst([]string{"relay", ""}).Value())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,13 @@ const (
|
|||||||
NSON_MARKER_END = 317 // it's just the `,"nson":` (including ,": garbage to reduce false positives) part
|
NSON_MARKER_END = 317 // it's just the `,"nson":` (including ,": garbage to reduce false positives) part
|
||||||
)
|
)
|
||||||
|
|
||||||
var NotNSON = fmt.Errorf("not nson")
|
var ErrNotNSON = fmt.Errorf("not nson")
|
||||||
|
|
||||||
func UnmarshalBytes(data []byte, evt *nostr.Event) (err error) {
|
func UnmarshalBytes(data []byte, evt *nostr.Event) (err error) {
|
||||||
return Unmarshal(unsafe.String(unsafe.SliceData(data), len(data)), evt)
|
return Unmarshal(unsafe.String(unsafe.SliceData(data), len(data)), evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal turns a NSON string into a nostr.Event struct
|
// Unmarshal turns a NSON string into a nostr.Event struct.
|
||||||
func Unmarshal(data string, evt *nostr.Event) (err error) {
|
func Unmarshal(data string, evt *nostr.Event) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -59,7 +59,7 @@ func Unmarshal(data string, evt *nostr.Event) (err error) {
|
|||||||
|
|
||||||
// check if it's nson
|
// check if it's nson
|
||||||
if data[NSON_MARKER_START:NSON_MARKER_END] != ",\"nson\":" {
|
if data[NSON_MARKER_START:NSON_MARKER_END] != ",\"nson\":" {
|
||||||
return NotNSON
|
return ErrNotNSON
|
||||||
}
|
}
|
||||||
|
|
||||||
// nson values
|
// nson values
|
||||||
@ -168,7 +168,8 @@ func Marshal(evt *nostr.Event) (string, error) {
|
|||||||
9 + tagBuilder.Len() + // tags and its label
|
9 + tagBuilder.Len() + // tags and its label
|
||||||
2, // the end
|
2, // the end
|
||||||
)
|
)
|
||||||
base.WriteString(`{"id":"` + evt.ID + `","pubkey":"` + evt.PubKey + `","sig":"` + evt.Sig + `","created_at":` + strconv.FormatInt(int64(evt.CreatedAt), 10) + `,"nson":"`)
|
base.WriteString(`{"id":"` + evt.ID + `","pubkey":"` + evt.PubKey + `","sig":"` + evt.Sig +
|
||||||
|
`","created_at":` + strconv.FormatInt(int64(evt.CreatedAt), 10) + `,"nson":"`)
|
||||||
|
|
||||||
nsonSizeBytes := len(nsonBuf)
|
nsonSizeBytes := len(nsonBuf)
|
||||||
if nsonSizeBytes > 255 {
|
if nsonSizeBytes > 255 {
|
||||||
|
@ -72,7 +72,6 @@ func checkParsedCorrectly(t *testing.T, evt *nostr.Event, jevt string) (isBad bo
|
|||||||
err := json.Unmarshal([]byte(jevt), &canonical)
|
err := json.Unmarshal([]byte(jevt), &canonical)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error unmarshaling normal json: %s", err)
|
t.Fatalf("error unmarshaling normal json: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if evt.ID != canonical.ID {
|
if evt.ID != canonical.ID {
|
||||||
|
5
relay.go
5
relay.go
@ -23,7 +23,7 @@ const (
|
|||||||
PublishStatusSucceeded Status = 1
|
PublishStatusSucceeded Status = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var subscriptionIdCounter atomic.Int32
|
var subscriptionIDCounter atomic.Int32
|
||||||
|
|
||||||
func (s Status) String() string {
|
func (s Status) String() string {
|
||||||
switch s {
|
switch s {
|
||||||
@ -204,7 +204,6 @@ func (r *Relay) Connect(ctx context.Context) error {
|
|||||||
go sub.Unsub()
|
go sub.Unsub()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// queue all write operations here so we don't do mutex spaghetti
|
// queue all write operations here so we don't do mutex spaghetti
|
||||||
@ -479,7 +478,7 @@ func (r *Relay) PrepareSubscription(ctx context.Context, filters Filters, opts .
|
|||||||
panic(fmt.Errorf("must call .Connect() first before calling .Subscribe()"))
|
panic(fmt.Errorf("must call .Connect() first before calling .Subscribe()"))
|
||||||
}
|
}
|
||||||
|
|
||||||
current := subscriptionIdCounter.Add(1)
|
current := subscriptionIDCounter.Add(1)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
sub := &Subscription{
|
sub := &Subscription{
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil)
|
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil).
|
||||||
func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
||||||
// handle if it is a hex string
|
// handle if it is a hex string
|
||||||
if len(input) == 64 {
|
if len(input) == 64 {
|
||||||
@ -38,7 +38,7 @@ func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputToEventPointer turns any note/nevent/hex input into a EventPointer (or nil)
|
// InputToEventPointer turns any note/nevent/hex input into a EventPointer (or nil).
|
||||||
func InputToEventPointer(input string) *nostr.EventPointer {
|
func InputToEventPointer(input string) *nostr.EventPointer {
|
||||||
// handle if it is a hex string
|
// handle if it is a hex string
|
||||||
if len(input) == 64 {
|
if len(input) == 64 {
|
||||||
|
@ -33,7 +33,7 @@ func ParseReferences(evt *nostr.Event) []*Reference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ref[6] == -1 {
|
if ref[6] == -1 {
|
||||||
// didn't find a NIP-10 #[0] reference, so it's it's a NIP-27 mention
|
// didn't find a NIP-10 #[0] reference, so it's a NIP-27 mention
|
||||||
nip19code := content[ref[2]:ref[3]]
|
nip19code := content[ref[2]:ref[3]]
|
||||||
|
|
||||||
if prefix, data, err := nip19.Decode(nip19code); err == nil {
|
if prefix, data, err := nip19.Decode(nip19code); err == nil {
|
||||||
|
@ -117,7 +117,7 @@ func (sub *Subscription) Close() {
|
|||||||
|
|
||||||
// Sub sets sub.Filters and then calls sub.Fire(ctx).
|
// Sub sets sub.Filters and then calls sub.Fire(ctx).
|
||||||
// The subscription will be closed if the context expires.
|
// The subscription will be closed if the context expires.
|
||||||
func (sub *Subscription) Sub(ctx context.Context, filters Filters) {
|
func (sub *Subscription) Sub(_ context.Context, filters Filters) {
|
||||||
sub.Filters = filters
|
sub.Filters = filters
|
||||||
sub.Fire()
|
sub.Fire()
|
||||||
}
|
}
|
||||||
|
8
tags.go
8
tags.go
@ -12,10 +12,15 @@ type Tag []string
|
|||||||
|
|
||||||
// StartsWith checks if a tag contains a prefix.
|
// StartsWith checks if a tag contains a prefix.
|
||||||
// for example,
|
// for example,
|
||||||
|
//
|
||||||
// ["p", "abcdef...", "wss://relay.com"]
|
// ["p", "abcdef...", "wss://relay.com"]
|
||||||
|
//
|
||||||
// would match against
|
// would match against
|
||||||
|
//
|
||||||
// ["p", "abcdef..."]
|
// ["p", "abcdef..."]
|
||||||
|
//
|
||||||
// or even
|
// or even
|
||||||
|
//
|
||||||
// ["p", "abcdef...", "wss://"]
|
// ["p", "abcdef...", "wss://"]
|
||||||
func (tag Tag) StartsWith(prefix []string) bool {
|
func (tag Tag) StartsWith(prefix []string) bool {
|
||||||
prefixLen := len(prefix)
|
prefixLen := len(prefix)
|
||||||
@ -109,9 +114,8 @@ func (tags Tags) AppendUnique(tag Tag) Tags {
|
|||||||
|
|
||||||
if tags.GetFirst(tag[:n]) == nil {
|
if tags.GetFirst(tag[:n]) == nil {
|
||||||
return append(tags, tag)
|
return append(tags, tag)
|
||||||
} else {
|
|
||||||
return tags
|
|
||||||
}
|
}
|
||||||
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tags) Scan(src any) error {
|
func (t *Tags) Scan(src any) error {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user