style: using effective go and refactoring

This commit is contained in:
Kay 2023-08-21 20:17:25 +08:00 committed by fiatjaf_
parent abb66db97e
commit ac2350c722
17 changed files with 81 additions and 68 deletions

8
Makefile Normal file
View 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 .

View File

@ -54,8 +54,8 @@ type Envelope interface {
}
type EventEnvelope struct {
SubscriptionID *string
Event
SubscriptionID *string `json:"subscription_id"`
Event `json:"event"`
}
var (
@ -266,9 +266,9 @@ func (v CloseEnvelope) MarshalJSON() ([]byte, error) {
}
type OKEnvelope struct {
EventID string
OK bool
Reason *string
EventID string `json:"event_id"`
OK bool `json:"ok"`
Reason *string `json:"reason"`
}
func (_ OKEnvelope) Label() string { return "OK" }
@ -307,8 +307,8 @@ func (v OKEnvelope) MarshalJSON() ([]byte, error) {
}
type AuthEnvelope struct {
Challenge *string
Event Event
Challenge *string `json:"challenge"`
Event Event `json:"event"`
}
func (_ AuthEnvelope) Label() string { return "AUTH" }

View File

@ -58,13 +58,13 @@ const (
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 {
j, _ := easyjson.Marshal(evt)
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 {
h := sha256.Sum256(evt.Serialize())
return hex.EncodeToString(h[:])
@ -128,7 +128,7 @@ func (evt Event) CheckSignature() (bool, error) {
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 {
s, err := hex.DecodeString(privateKey)
if err != nil {

View File

@ -3,5 +3,4 @@
package nostr
func debugLogf(str string, args ...any) {
return
}

View File

@ -40,7 +40,8 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe
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 {
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 {
return nil, fmt.Errorf("request failed: %w", err)
}
defer res.Body.Close()
var result WellKnownResponse
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]
if !ok {
return nil, nil
return &nostr.ProfilePointer{}, nil
}
if len(pubkey) == 64 {
if _, err := hex.DecodeString(pubkey); err != nil {
return nil, nil
return &nostr.ProfilePointer{}, nil
}
}

View File

@ -4,15 +4,12 @@ import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
// Fetch fetches the NIP-11 RelayInformationDocument.
func Fetch(ctx context.Context, u string) (info *RelayInformationDocument, err error) {
if _, ok := ctx.Deadline(); !ok {
@ -47,6 +44,7 @@ func Fetch(ctx context.Context, u string) (info *RelayInformationDocument, err e
if err != nil {
return nil, err
}
defer resp.Body.Close()
info = &RelayInformationDocument{}
dec := json.NewDecoder(resp.Body)
err = dec.Decode(info)

View File

@ -144,8 +144,8 @@ func EncodePublicKey(publicKeyHex string) (string, error) {
return bech32.Encode("npub", bits5)
}
func EncodeNote(eventIdHex string) (string, error) {
b, err := hex.DecodeString(eventIdHex)
func EncodeNote(eventIDHex string) (string, error) {
b, err := hex.DecodeString(eventIDHex)
if err != nil {
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)
}
func EncodeEvent(eventIdHex string, relays []string, author string) (string, error) {
func EncodeEvent(eventIDHex string, relays []string, author string) (string, error) {
buf := &bytes.Buffer{}
id, err := hex.DecodeString(eventIdHex)
id, err := hex.DecodeString(eventIDHex)
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)

View File

@ -55,15 +55,14 @@ func CheckDelegation(ev *nostr.Event) (ok bool, err error) {
d := new(DelegationToken)
if ok, err := d.Parse(ev); ok == true && (err == nil || err == NoDelegationTag) {
return true, nil
} else {
return false, err
}
return false, err
}
// Import verifies that t is NIP-26 delegation token for the given delegatee.
// The returned DelegationToken object can be used in DelegatedSign.
// 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)
if len(t) == 4 && t[0] == "delegation" {
copy(d.tag[:], t)
@ -81,16 +80,16 @@ func Import(t nostr.Tag, delegatee_pk string) (d *DelegationToken, e error) {
}
// 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[:])
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[:])
if err != nil {
return nil, fmt.Errorf("Error: %s", err.Error())
return nil, fmt.Errorf("error: %s", err.Error())
}
if !sig.Verify(h[:], pubkey) {
return nil, VerificationFailed
@ -131,15 +130,15 @@ jump1:
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:
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) {
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
@ -147,12 +146,12 @@ jump2:
sig, err := schnorr.ParseSignature(d.token[:])
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[:])
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
@ -160,14 +159,16 @@ jump2:
// 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.
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 {
if t[0] == "delegation" {
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) {
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 {
for _, k := range d.kinds {
@ -175,34 +176,36 @@ func DelegatedSign(ev *nostr.Event, d *DelegationToken, delegatee_sk string) err
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:
if pk, e := nostr.GetPublicKey(delegatee_sk); e != nil {
return fmt.Errorf("invalid delegatee secret key.")
if pk, e := nostr.GetPublicKey(delegateeSk); e != nil {
return fmt.Errorf("invalid delegatee secret key")
} else {
ev.PubKey = pk
}
ev.Tags = append(ev.Tags, d.Tag())
return ev.Sign(delegatee_sk)
return ev.Sign(delegateeSk)
}
// 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)
s, e := hex.DecodeString(delegator_sk)
if e != nil {
return nil, fmt.Errorf("invalid delegator secret key")
}
tee_pk, e := hex.DecodeString(delegatee_pk)
if len(tee_pk) != 32 || e != nil {
teePk, e := hex.DecodeString(delegatee_pk)
if len(teePk) != 32 || e != nil {
return nil, fmt.Errorf("invalid delegatee pubkey")
}
// set delegator
sk, tor_pk := btcec.PrivKeyFromBytes(s)
copy(d.delegator[:], schnorr.SerializePubKey(tor_pk))
sk, torPk := btcec.PrivKeyFromBytes(s)
copy(d.delegator[:], schnorr.SerializePubKey(torPk))
d.kinds = kinds
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[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 {
panic(err)

View File

@ -10,9 +10,9 @@ import (
func TestDelegateSign(t *testing.T) {
since := time.Unix(1600000000, 0)
until := time.Unix(1600000100, 0)
delegator_secret_key, delegatee_secret_key := "3f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459da", "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b"
delegatee_pubkey, _ := nostr.GetPublicKey(delegatee_secret_key)
d1, err := CreateToken(delegator_secret_key, delegatee_pubkey, []int{1, 2, 3}, &since, &until)
delegatorSecretKey, delegatee_secret_key := "3f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459da", "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b"
delegateePubkey, _ := nostr.GetPublicKey(delegatee_secret_key)
d1, err := CreateToken(delegatorSecretKey, delegateePubkey, []int{1, 2, 3}, &since, &until)
if err != nil {
t.Error(err)
}
@ -23,7 +23,7 @@ func TestDelegateSign(t *testing.T) {
if err != nil {
t.Error(err)
}
d2, err := Import(d1.Tag(), delegatee_pubkey)
d2, err := Import(d1.Tag(), delegateePubkey)
if err != nil {
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"}
d3, err := Import(tag, delegatee_pubkey)
d3, err := Import(tag, delegateePubkey)
if err != nil {
t.Error(err)
}

View File

@ -23,8 +23,8 @@ func CreateUnsignedAuthEvent(challenge, pubkey, relayURL string) nostr.Event {
}
}
// helper function for ValidateAuthEvent
func parseUrl(input string) (*url.URL, error) {
// helper function for ValidateAuthEvent.
func parseURL(input string) (*url.URL, error) {
return url.Parse(
strings.ToLower(
strings.TrimSuffix(input, "/"),
@ -43,12 +43,12 @@ func ValidateAuthEvent(event *nostr.Event, challenge string, relayURL string) (p
return "", false
}
expected, err := parseUrl(relayURL)
expected, err := parseURL(relayURL)
if err != nil {
return "", false
}
found, err := parseUrl(event.Tags.GetFirst([]string{"relay", ""}).Value())
found, err := parseURL(event.Tags.GetFirst([]string{"relay", ""}).Value())
if err != nil {
return "", false
}

View File

@ -43,13 +43,13 @@ const (
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) {
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) {
defer func() {
if r := recover(); r != nil {
@ -59,7 +59,7 @@ func Unmarshal(data string, evt *nostr.Event) (err error) {
// check if it's nson
if data[NSON_MARKER_START:NSON_MARKER_END] != ",\"nson\":" {
return NotNSON
return ErrNotNSON
}
// nson values
@ -168,7 +168,8 @@ func Marshal(evt *nostr.Event) (string, error) {
9 + tagBuilder.Len() + // tags and its label
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)
if nsonSizeBytes > 255 {

View File

@ -72,7 +72,6 @@ func checkParsedCorrectly(t *testing.T, evt *nostr.Event, jevt string) (isBad bo
err := json.Unmarshal([]byte(jevt), &canonical)
if err != nil {
t.Fatalf("error unmarshaling normal json: %s", err)
return
}
if evt.ID != canonical.ID {

View File

@ -23,7 +23,7 @@ const (
PublishStatusSucceeded Status = 1
)
var subscriptionIdCounter atomic.Int32
var subscriptionIDCounter atomic.Int32
func (s Status) String() string {
switch s {
@ -204,7 +204,6 @@ func (r *Relay) Connect(ctx context.Context) error {
go sub.Unsub()
return true
})
return
}()
// 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()"))
}
current := subscriptionIdCounter.Add(1)
current := subscriptionIDCounter.Add(1)
ctx, cancel := context.WithCancel(ctx)
sub := &Subscription{

View File

@ -9,7 +9,7 @@ import (
"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 {
// handle if it is a hex string
if len(input) == 64 {
@ -38,7 +38,7 @@ func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
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 {
// handle if it is a hex string
if len(input) == 64 {

View File

@ -33,7 +33,7 @@ func ParseReferences(evt *nostr.Event) []*Reference {
}
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]]
if prefix, data, err := nip19.Decode(nip19code); err == nil {

View File

@ -117,7 +117,7 @@ func (sub *Subscription) Close() {
// Sub sets sub.Filters and then calls sub.Fire(ctx).
// 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.Fire()
}

View File

@ -12,10 +12,15 @@ type Tag []string
// StartsWith checks if a tag contains a prefix.
// for example,
//
// ["p", "abcdef...", "wss://relay.com"]
//
// would match against
//
// ["p", "abcdef..."]
//
// or even
//
// ["p", "abcdef...", "wss://"]
func (tag Tag) StartsWith(prefix []string) bool {
prefixLen := len(prefix)
@ -109,9 +114,8 @@ func (tags Tags) AppendUnique(tag Tag) Tags {
if tags.GetFirst(tag[:n]) == nil {
return append(tags, tag)
} else {
return tags
}
return tags
}
func (t *Tags) Scan(src any) error {