diff --git a/cmd/publicatr/extract.go b/cmd/publicatr/extract.go index d4e06a46..ddab380f 100644 --- a/cmd/publicatr/extract.go +++ b/cmd/publicatr/extract.go @@ -12,22 +12,21 @@ const ( ) var ( - urlRe = regexp.MustCompile(urlPattern) - mentionRe = regexp.MustCompile(mentionPattern) - emojiRe = regexp.MustCompile(emojiPattern) + urlRegexp = regexp.MustCompile(urlPattern) + mentionRegexp = regexp.MustCompile(mentionPattern) + emojiRegexp = regexp.MustCompile(emojiPattern) ) -type entry struct { +type matchLocation struct { start int64 end int64 text string } -func extractLinks(text string) []entry { - var result []entry - matches := urlRe.FindAllStringSubmatchIndex(text, -1) +func extractLinks(text string) (result []matchLocation) { + matches := urlRegexp.FindAllStringSubmatchIndex(text, -1) for _, m := range matches { - result = append(result, entry{ + result = append(result, matchLocation{ text: text[m[0]:m[1]], start: int64(len([]rune(text[0:m[0]]))), end: int64(len([]rune(text[0:m[1]])))}, @@ -36,11 +35,10 @@ func extractLinks(text string) []entry { return result } -func extractMentions(text string) []entry { - var result []entry - matches := mentionRe.FindAllStringSubmatchIndex(text, -1) +func extractMentions(text string) (result []matchLocation) { + matches := mentionRegexp.FindAllStringSubmatchIndex(text, -1) for _, m := range matches { - result = append(result, entry{ + result = append(result, matchLocation{ text: strings.TrimPrefix(text[m[0]:m[1]], "@"), start: int64(len([]rune(text[0:m[0]]))), end: int64(len([]rune(text[0:m[1]])))}, @@ -49,11 +47,10 @@ func extractMentions(text string) []entry { return result } -func extractEmojis(text string) []entry { - var result []entry - matches := emojiRe.FindAllStringSubmatchIndex(text, -1) +func extractEmojis(text string) (result []matchLocation) { + matches := emojiRegexp.FindAllStringSubmatchIndex(text, -1) for _, m := range matches { - result = append(result, entry{ + result = append(result, matchLocation{ text: text[m[0]:m[1]], start: int64(len([]rune(text[0:m[0]]))), end: int64(len([]rune(text[0:m[1]])))}, diff --git a/cmd/publicatr/main.go b/cmd/publicatr/main.go index bd7f9738..0c8b6fa6 100644 --- a/cmd/publicatr/main.go +++ b/cmd/publicatr/main.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "runtime" @@ -32,35 +31,37 @@ const version = "0.0.53" var revision = "HEAD" -// Relay is -type Relay struct { +// relayPerms is +type relayPerms struct { Read bool `json:"read"` Write bool `json:"write"` Search bool `json:"search"` } -// Config is -type Config struct { - Relays map[string]Relay `json:"relays"` - Follows map[string]Profile `json:"follows"` - PrivateKey string `json:"privatekey"` - Updated time.Time `json:"updated"` - Emojis map[string]string `json:"emojis"` - NwcURI string `json:"nwc-uri"` - NwcPub string `json:"nwc-pub"` +type relayPermsMap map[string]relayPerms + +// clientConfig is +type clientConfig struct { + Relays relayPermsMap `json:"relays"` + Follows profilesMap `json:"follows"` + PrivateKey string `json:"privatekey"` + Updated time.Time `json:"updated"` + Emojis map[string]string `json:"emojis"` + NwcURI string `json:"nwc-uri"` + NwcPub string `json:"nwc-pub"` verbose bool tempRelay bool sk string } -// Event is -type Event struct { - Event *nip1.Event `json:"event"` - Profile Profile `json:"profile"` +// associatedEvent is +type associatedEvent struct { + Event *nip1.Event `json:"event"` + Profile *userProfile `json:"profile"` } -// Profile is -type Profile struct { +// userProfile is +type userProfile struct { Website string `json:"website"` Nip05 string `json:"nip05"` Picture string `json:"picture"` @@ -70,12 +71,13 @@ type Profile struct { Name string `json:"name"` } -func configDir() (string, error) { +type profilesMap map[string]userProfile + +func configDir() (dir string, e error) { switch runtime.GOOS { case "darwin": - dir, err := os.UserHomeDir() - if err != nil { - return "", err + if dir, e = os.UserHomeDir(); fails(e) { + return } return filepath.Join(dir, ".config"), nil default: @@ -83,17 +85,17 @@ func configDir() (string, error) { } } -func loadConfig(profile string) (*Config, error) { - dir, err := configDir() - if err != nil { - return nil, err +func loadConfig(profile string) (cc *clientConfig, e error) { + var dir string + if dir, e = configDir(); fails(e) { + return } dir = filepath.Join(dir, appName) - var fp string - if profile == "" { + switch profile { + case "": fp = filepath.Join(dir, "config.json") - } else if profile == "?" { + case "?": names, err := filepath.Glob(filepath.Join(dir, "config-*.json")) if err != nil { return nil, err @@ -104,61 +106,56 @@ func loadConfig(profile string) (*Config, error) { fmt.Println(name) } os.Exit(0) - } else { + default: fp = filepath.Join(dir, "config-"+profile+".json") } - os.MkdirAll(filepath.Dir(fp), 0700) - - b, err := ioutil.ReadFile(fp) - if err != nil { - return nil, err + log.D.Chk(os.MkdirAll(filepath.Dir(fp), 0700)) + var b []byte + if b, e = os.ReadFile(fp); fails(e) { + return } - var cfg Config - err = json.Unmarshal(b, &cfg) - if err != nil { - return nil, err + cfg := &clientConfig{} + if e = json.Unmarshal(b, &cfg); fails(e) { + return } if len(cfg.Relays) == 0 { - cfg.Relays = map[string]Relay{} - cfg.Relays["wss://relay.nostr.band"] = Relay{ + cfg.Relays = relayPermsMap{"wss://relay.nostr.band": { Read: true, Write: true, Search: true, - } + }} } - return &cfg, nil + return } // GetFollows is -func (cfg *Config) GetFollows(profile string) (map[string]Profile, error) { +func (cfg *clientConfig) GetFollows(profile string) (pm profilesMap, e error) { var mu sync.Mutex var pub string - if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { - if pub, err = nip19.GetPublicKey(s.(string)); err != nil { - return nil, err - } - } else { - return nil, err + var s any + if _, s, e = nip19.Decode(cfg.PrivateKey); fails(e) { + return + } + if pub, e = nip19.GetPublicKey(s.(string)); fails(e) { + return } - // get followers if (cfg.Updated.Add(3*time.Hour).Before(time.Now()) && !cfg.tempRelay) || len(cfg.Follows) == 0 { mu.Lock() - cfg.Follows = map[string]Profile{} + cfg.Follows = profilesMap{} mu.Unlock() m := map[string]struct{}{} - - cfg.Do(Relay{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { - evs, err := relay.QuerySync(ctx, &nip1.Filter{ + cfg.Do(relayPerms{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { + evs, e := relay.QuerySync(ctx, &nip1.Filter{ Kinds: kinds.T{kind.ContactList}, Authors: tag.T{pub}, Limit: 1, }) - if err != nil { + if fails(e) { return true } for _, ev := range evs { - var rm map[string]Relay + var rm relayPermsMap if cfg.tempRelay == false { if err := json.Unmarshal([]byte(ev.Content), &rm); err == nil { for k, v1 := range cfg.Relays { @@ -169,10 +166,10 @@ func (cfg *Config) GetFollows(profile string) (map[string]Profile, error) { cfg.Relays = rm } } - for _, tag := range ev.Tags { - if len(tag) >= 2 && tag[0] == "p" { + for _, t := range ev.Tags { + if len(t) >= 2 && t[0] == "p" { mu.Lock() - m[tag[1]] = struct{}{} + m[t[1]] = struct{}{} mu.Unlock() } } @@ -183,20 +180,18 @@ func (cfg *Config) GetFollows(profile string) (map[string]Profile, error) { fmt.Printf("found %d followers\n", len(m)) } if len(m) > 0 { - follows := []string{} + var follows []string for k := range m { follows = append(follows, k) } - for i := 0; i < len(follows); i += 500 { // Calculate the end index based on the current index and slice length end := i + 500 if end > len(follows) { end = len(follows) } - // get follower's descriptions - cfg.Do(Relay{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { evs, err := relay.QuerySync(ctx, &nip1.Filter{ Kinds: kinds.T{kind.ProfileMetadata}, Authors: follows[i:end], // Use the updated end index @@ -205,11 +200,10 @@ func (cfg *Config) GetFollows(profile string) (map[string]Profile, error) { return true } for _, ev := range evs { - var profile Profile - err := json.Unmarshal([]byte(ev.Content), &profile) - if err == nil { + var prf userProfile + if e = json.Unmarshal([]byte(ev.Content), &prf); !fails(e) { mu.Lock() - cfg.Follows[ev.PubKey] = profile + cfg.Follows[ev.PubKey] = prf mu.Unlock() } } @@ -217,109 +211,101 @@ func (cfg *Config) GetFollows(profile string) (map[string]Profile, error) { }) } } - cfg.Updated = time.Now() - if err := cfg.save(profile); err != nil { - return nil, err + if e = cfg.save(profile); fails(e) { + return } } return cfg.Follows, nil } // FindRelay is -func (cfg *Config) FindRelay(ctx context.Context, r Relay) *nostr.Relay { +func (cfg *clientConfig) FindRelay(ctx context.Context, r relayPerms) (relay *nostr.Relay) { + var e error for k, v := range cfg.Relays { - if r.Write && !v.Write { - continue - } - if !cfg.tempRelay && r.Search && !v.Search { - continue - } - if !r.Write && !v.Read { + if (r.Write && !v.Write) || + (!cfg.tempRelay && r.Search && !v.Search) || + (!r.Write && !v.Read) { + continue } if cfg.verbose { - fmt.Printf("trying relay: %s\n", k) + log.I.F("trying relay: %s\n", k) } - relay, err := nostr.RelayConnect(ctx, k) - if err != nil { + if relay, e = nostr.RelayConnect(ctx, k); log.D.Chk(e) { if cfg.verbose { - fmt.Fprintln(os.Stderr, err.Error()) + log.E.Ln(e.Error()) } continue } - return relay + return } - return nil + return } // Do is -func (cfg *Config) Do(r Relay, f func(context.Context, *nostr.Relay) bool) { +func (cfg *clientConfig) Do(r relayPerms, f func(context.Context, *nostr.Relay) bool) { var wg sync.WaitGroup ctx := context.Background() for k, v := range cfg.Relays { - if r.Write && !v.Write { - continue - } - if r.Search && !v.Search { - continue - } - if !r.Write && !v.Read { + if (r.Write && !v.Write) || + (r.Search && !v.Search) || + (!r.Write && !v.Read) { + continue } wg.Add(1) - go func(wg *sync.WaitGroup, k string, v Relay) { + go func(wg *sync.WaitGroup, k string, v relayPerms) { defer wg.Done() - relay, err := nostr.RelayConnect(ctx, k) - if err != nil { + var e error + var relay *nostr.Relay + if relay, e = nostr.RelayConnect(ctx, k); log.D.Chk(e) { if cfg.verbose { - fmt.Fprintln(os.Stderr, err) + log.D.Chk(e) } return } if !f(ctx, relay) { ctx.Done() } - relay.Close() + log.D.Chk(relay.Close()) }(&wg, k, v) } wg.Wait() } -func (cfg *Config) save(profile string) error { +func (cfg *clientConfig) save(profile string) (e error) { if cfg.tempRelay { return nil } - dir, err := configDir() - if err != nil { - return err + var dir string + if dir, e = configDir(); fails(e) { + return } dir = filepath.Join(dir, appName) - var fp string if profile == "" { fp = filepath.Join(dir, "config.json") } else { fp = filepath.Join(dir, "config-"+profile+".json") } - b, err := json.MarshalIndent(&cfg, "", " ") - if err != nil { - return err + var b []byte + if b, e = json.MarshalIndent(&cfg, "", " "); fails(e) { + return } - return ioutil.WriteFile(fp, b, 0644) + return os.WriteFile(fp, b, 0644) } // Decode is -func (cfg *Config) Decode(ev *nip1.Event) error { - var sk string - var pub string - if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { - sk = s.(string) - if pub, err = nip19.GetPublicKey(s.(string)); err != nil { - return err - } - } else { - return err +func (cfg *clientConfig) Decode(ev *nip1.Event) (e error) { + var sk, pub string + var s any + if _, s, e = nip19.Decode(cfg.PrivateKey); fails(e) { + return + } + sk = s.(string) + if pub, e = nip19.GetPublicKey(s.(string)); fails(e) { + return e } tag := ev.Tags.GetFirst([]string{"p"}) if tag == nil { @@ -346,15 +332,15 @@ func (cfg *Config) Decode(ev *nip1.Event) error { } // PrintEvents is -func (cfg *Config) PrintEvents(evs []*nip1.Event, followsMap map[string]Profile, j, extra bool) { +func (cfg *clientConfig) PrintEvents(evs []*nip1.Event, followsMap profilesMap, j, extra bool) { if j { if extra { - var events []Event + var events []associatedEvent for _, ev := range evs { if profile, ok := followsMap[ev.PubKey]; ok { - events = append(events, Event{ + events = append(events, associatedEvent{ Event: ev, - Profile: profile, + Profile: &profile, }) } } @@ -388,11 +374,11 @@ func (cfg *Config) PrintEvents(evs []*nip1.Event, followsMap map[string]Profile, } // Events is -func (cfg *Config) Events(filter *nip1.Filter) []*nip1.Event { +func (cfg *clientConfig) Events(filter *nip1.Filter) []*nip1.Event { var mu sync.Mutex found := false var m sync.Map - cfg.Do(Relay{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { mu.Lock() if found { mu.Unlock() @@ -681,9 +667,9 @@ func main() { cfg.verbose = cCtx.Bool("V") relays := cCtx.String("relays") if strings.TrimSpace(relays) != "" { - cfg.Relays = make(map[string]Relay) + cfg.Relays = make(relayPermsMap) for _, relay := range strings.Split(relays, ",") { - cfg.Relays[relay] = Relay{ + cfg.Relays[relay] = relayPerms{ Read: true, Write: true, } diff --git a/cmd/publicatr/profile.go b/cmd/publicatr/profile.go index 0f0dc0b3..4d347bab 100644 --- a/cmd/publicatr/profile.go +++ b/cmd/publicatr/profile.go @@ -17,25 +17,24 @@ import ( "github.com/Hubmakerlabs/replicatr/pkg/nostr/tag" ) -func doProfile(cCtx *cli.Context) error { +func doProfile(cCtx *cli.Context) (e error) { user := cCtx.String("u") j := cCtx.Bool("json") - cfg := cCtx.App.Metadata["config"].(*Config) - relay := cfg.FindRelay(context.Background(), Relay{Read: true}) + cfg := cCtx.App.Metadata["config"].(*clientConfig) + relay := cfg.FindRelay(context.Background(), relayPerms{Read: true}) if relay == nil { return errors.New("cannot connect relays") } defer relay.Close() - var pub string if user == "" { - if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { - if pub, err = nip19.GetPublicKey(s.(string)); err != nil { - return err - } - } else { - return err + var s any + if _, s, e = nip19.Decode(cfg.PrivateKey); fails(e) { + return + } + if pub, e = nip19.GetPublicKey(s.(string)); fails(e) { + return } } else { if pp := sdk.InputToProfile(context.TODO(), user); pp != nil { @@ -44,31 +43,27 @@ func doProfile(cCtx *cli.Context) error { return fmt.Errorf("failed to parse pubkey from '%s'", user) } } - // get set-metadata filter := &nip1.Filter{ Kinds: kinds.T{kind.ProfileMetadata}, Authors: tag.T{pub}, Limit: 1, } - evs := cfg.Events(filter) if len(evs) == 0 { return errors.New("cannot find user") } - if j { fmt.Fprintln(os.Stdout, evs[0].Content) return nil } - var profile Profile - err := json.Unmarshal([]byte(evs[0].Content), &profile) - if err != nil { - return err + profile := &userProfile{} + if e = json.Unmarshal([]byte(evs[0].Content), profile); fails(e) { + return } - npub, err := nip19.EncodePublicKey(pub) - if err != nil { - return err + var npub string + if npub, e = nip19.EncodePublicKey(pub); fails(e) { + return } fmt.Printf("Pubkey: %v\n", npub) fmt.Printf("Name: %v\n", profile.Name) diff --git a/cmd/publicatr/timeline.go b/cmd/publicatr/timeline.go index cb5c4673..546d9edb 100644 --- a/cmd/publicatr/timeline.go +++ b/cmd/publicatr/timeline.go @@ -30,7 +30,7 @@ import ( func doDMList(cCtx *cli.Context) error { j := cCtx.Bool("json") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) // get followers followsMap, err := cfg.GetFollows(cCtx.String("a")) @@ -104,7 +104,7 @@ func doDMTimeline(cCtx *cli.Context) error { j := cCtx.Bool("json") extra := cCtx.Bool("extra") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string var npub string @@ -154,7 +154,7 @@ func doDMPost(cCtx *cli.Context) error { } sensitive := cCtx.String("sensitive") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -216,7 +216,7 @@ func doDMPost(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) @@ -240,7 +240,7 @@ func doPost(cCtx *cli.Context) error { sensitive := cCtx.String("sensitive") geohash := cCtx.String("geohash") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -324,7 +324,7 @@ func doPost(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) @@ -350,7 +350,7 @@ func doReply(cCtx *cli.Context) error { sensitive := cCtx.String("sensitive") geohash := cCtx.String("geohash") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -426,7 +426,7 @@ func doReply(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { if !quote { ev.Tags = ev.Tags.AppendUnique(tag.T{"e", id, relay.URL, "reply"}) } else { @@ -453,7 +453,7 @@ func doReply(cCtx *cli.Context) error { func doRepost(cCtx *cli.Context) error { id := cCtx.String("id") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) ev := &nip1.Event{} var sk string @@ -490,7 +490,7 @@ func doRepost(cCtx *cli.Context) error { first.Store(true) var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { if first.Load() { evs, err := relay.QuerySync(ctx, filter) if err != nil { @@ -527,7 +527,7 @@ func doUnrepost(cCtx *cli.Context) error { return fmt.Errorf("failed to parse event from '%s'", id) } - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -546,7 +546,7 @@ func doUnrepost(cCtx *cli.Context) error { } var repostID nip1.EventID var mu sync.Mutex - cfg.Do(Relay{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { evs, err := relay.QuerySync(ctx, filter) if err != nil { return true @@ -568,7 +568,7 @@ func doUnrepost(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) @@ -587,7 +587,7 @@ func doUnrepost(cCtx *cli.Context) error { func doLike(cCtx *cli.Context) error { id := cCtx.String("id") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) ev := &nip1.Event{} var sk string @@ -635,7 +635,7 @@ func doLike(cCtx *cli.Context) error { first.Store(true) var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { if first.Load() { evs, err := relay.QuerySync(ctx, filter) if err != nil { @@ -673,7 +673,7 @@ func doUnlike(cCtx *cli.Context) error { return fmt.Errorf("failed to parse event from '%s'", id) } - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -692,7 +692,7 @@ func doUnlike(cCtx *cli.Context) error { } var likeID string var mu sync.Mutex - cfg.Do(Relay{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Read: true}, func(ctx context.Context, relay *nostr.Relay) bool { evs, err := relay.QuerySync(ctx, filter) if err != nil { return true @@ -714,7 +714,7 @@ func doUnlike(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) @@ -733,7 +733,7 @@ func doUnlike(cCtx *cli.Context) error { func doDelete(cCtx *cli.Context) error { id := cCtx.String("id") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) ev := &nip1.Event{} var sk string @@ -764,7 +764,7 @@ func doDelete(cCtx *cli.Context) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) @@ -785,13 +785,13 @@ func doSearch(cCtx *cli.Context) error { j := cCtx.Bool("json") extra := cCtx.Bool("extra") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) // get followers - var followsMap map[string]Profile + var followsMap profilesMap var err error if j && !extra { - followsMap = make(map[string]Profile) + followsMap = make(profilesMap) } else { followsMap, err = cfg.GetFollows(cCtx.String("a")) if err != nil { @@ -828,9 +828,9 @@ func doStream(cCtx *cli.Context) error { } } - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) - relay := cfg.FindRelay(context.Background(), Relay{Read: true}) + relay := cfg.FindRelay(context.Background(), relayPerms{Read: true}) if relay == nil { return errors.New("cannot connect relays") } @@ -888,7 +888,7 @@ func doStream(cCtx *cli.Context) error { if err := evr.Sign(sk); err != nil { return err } - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { relay.Publish(ctx, evr) return true }) @@ -905,7 +905,7 @@ func doTimeline(cCtx *cli.Context) error { j := cCtx.Bool("json") extra := cCtx.Bool("extra") - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) // get followers followsMap, err := cfg.GetFollows(cCtx.String("a")) @@ -930,7 +930,7 @@ func doTimeline(cCtx *cli.Context) error { } func postMsg(cCtx *cli.Context, msg string) error { - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { @@ -957,7 +957,7 @@ func postMsg(cCtx *cli.Context, msg string) error { } var success atomic.Int64 - cfg.Do(Relay{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { + cfg.Do(relayPerms{Write: true}, func(ctx context.Context, relay *nostr.Relay) bool { status, err := relay.Publish(ctx, ev) if cfg.verbose { fmt.Fprintln(os.Stderr, relay.URL, status, err) diff --git a/cmd/publicatr/zap.go b/cmd/publicatr/zap.go index 9bcd0a51..d0d58356 100644 --- a/cmd/publicatr/zap.go +++ b/cmd/publicatr/zap.go @@ -62,7 +62,7 @@ type PayResponse struct { } `json:"result"` } -func pay(cfg *Config, invoice string) error { +func pay(cfg *clientConfig, invoice string) error { uri, err := url.Parse(cfg.NwcURI) if err != nil { return err @@ -141,8 +141,8 @@ func pay(cfg *Config, invoice string) error { } // ZapInfo is -func (cfg *Config) ZapInfo(pub string) (*Lnurlp, error) { - relay := cfg.FindRelay(context.Background(), Relay{Read: true}) +func (cfg *clientConfig) ZapInfo(pub string) (*Lnurlp, error) { + relay := cfg.FindRelay(context.Background(), relayPerms{Read: true}) if relay == nil { return nil, errors.New("cannot connect relays") } @@ -157,7 +157,7 @@ func (cfg *Config) ZapInfo(pub string) (*Lnurlp, error) { if len(evs) == 0 { return nil, errors.New("cannot find user") } - var profile Profile + var profile userProfile err := json.Unmarshal([]byte(evs[0].Content), &profile) if err != nil { return nil, err @@ -191,7 +191,7 @@ func doZap(cCtx *cli.Context) error { if cCtx.Args().Len() == 0 { return cli.ShowSubcommandHelp(cCtx) } - cfg := cCtx.App.Metadata["config"].(*Config) + cfg := cCtx.App.Metadata["config"].(*clientConfig) var sk string if _, s, err := nip19.Decode(cfg.PrivateKey); err == nil { sk = s.(string) @@ -281,7 +281,7 @@ func doZap(cCtx *cli.Context) error { fmt.Println("lightning:" + iv.PR) qrterminal.GenerateWithConfig("lightning:"+iv.PR, config) } else { - pay(cCtx.App.Metadata["config"].(*Config), iv.PR) + pay(cCtx.App.Metadata["config"].(*clientConfig), iv.PR) } return nil } diff --git a/pkg/nostr/nip1/enveloper.go b/pkg/nostr/nip1/enveloper.go index 7a6a6a56..6e760db5 100644 --- a/pkg/nostr/nip1/enveloper.go +++ b/pkg/nostr/nip1/enveloper.go @@ -2,6 +2,7 @@ package nip1 import ( "fmt" + "github.com/Hubmakerlabs/replicatr/pkg/wire/array" "github.com/Hubmakerlabs/replicatr/pkg/wire/text" ) @@ -20,8 +21,10 @@ const ( LReq ) +type EnvelopeLabel map[Label][]byte + // Labels is the nip1 envelope labels, matching the above enums. -var Labels = map[Label][]byte{ +var Labels = EnvelopeLabel{ LNil: nil, LEvent: []byte("EVENT"), LOK: []byte("OK"), @@ -32,6 +35,15 @@ var Labels = map[Label][]byte{ LReq: []byte("REQ"), } +func (l EnvelopeLabel) String() (s string) { + s+= "[" + for i := range Labels { + s += fmt.Sprintf("%d:'%s',", i, Labels[i]) + } + s+="]" + return +} + // With these, labels have easy short names for the strings, as well as neat // consistent 1 byte enum version. Having all 3 versions also makes writing the // recogniser easier. @@ -84,7 +96,7 @@ type Enveloper interface { // ready for some other envelope outside of nip-01 to decode. func ProcessEnvelope(b []byte) (env Enveloper, label []byte, buf *text.Buffer, e error) { - // log.D.F("processing envelope:\n%s", string(b)) + log.D.F("processing envelope:\n%s", string(b)) // The bytes must be valid JSON but we can't assume they are free of // whitespace... So we will use some tools. buf = text.NewBuffer(b) @@ -100,6 +112,7 @@ func ProcessEnvelope(b []byte) (env Enveloper, label []byte, buf *text.Buffer, if candidate, e = buf.ReadUntil('"'); e != nil { return } + // log.D.F("label: '%s' %v", string(candidate), Labels) var differs bool var match Label matched: diff --git a/pkg/nostr/nip1/reqenvelope.go b/pkg/nostr/nip1/reqenvelope.go index ad33a603..25921216 100644 --- a/pkg/nostr/nip1/reqenvelope.go +++ b/pkg/nostr/nip1/reqenvelope.go @@ -3,6 +3,7 @@ package nip1 import ( "encoding/json" "fmt" + "github.com/Hubmakerlabs/replicatr/pkg/wire/array" "github.com/Hubmakerlabs/replicatr/pkg/wire/text" ) @@ -43,28 +44,33 @@ func (E *ReqEnvelope) Unmarshal(buf *text.Buffer) (e error) { if E == nil { return fmt.Errorf("cannot unmarshal to nil pointer") } - log.D.F("REQ '%s'", buf.Buf[buf.Pos:]) + // log.D.F("REQ '%s'", buf.Buf[buf.Pos:]) // Next, find the comma after the label if e = buf.ScanThrough(','); e != nil { return } - // Next character we find will be open quotes for the subscription ID. - if e = buf.ScanThrough('"'); e != nil { - return - } - var sid []byte - // read the string - if sid, e = buf.ReadUntil('"'); fails(e) { - return fmt.Errorf("unterminated quotes in JSON, probably truncated read") + var which byte + // ReqEnvelope can have one or no subscription IDs, if it is present we want + // to collect it before looking for the filters. + which, e = buf.ScanForOneOf(false, '{', '"') + if which == '"' { + // Next character we find will be open quotes for the subscription ID. + if e = buf.ScanThrough('"'); e != nil { + return + } + var sid []byte + // read the string + if sid, e = buf.ReadUntil('"'); fails(e) { + return fmt.Errorf("unterminated quotes in JSON, probably truncated read") + } + log.D.F("Subscription ID: '%s'", sid) + E.SubscriptionID = SubscriptionID(sid) } - log.D.F("Subscription ID: '%s'", sid) - E.SubscriptionID = SubscriptionID(sid) // Next, find the comma (there must be one and at least one object brace // after it if e = buf.ScanThrough(','); e != nil { return } - var which byte for { // find the opening brace of the event object, usually this is the very // next character, we aren't checking for valid whitespace because @@ -79,18 +85,18 @@ func (E *ReqEnvelope) Unmarshal(buf *text.Buffer) (e error) { if filterArray, e = buf.ReadEnclosed(); fails(e) { return } - log.D.F("filter: '%s'", filterArray) + // log.D.F("filter: '%s'", filterArray) f := &Filter{} if e = json.Unmarshal(filterArray, f); fails(e) { return } E.Filters = append(E.Filters, f) - log.D.F("remaining: '%s'", buf.Buf[buf.Pos:]) + // log.D.F("remaining: '%s'", buf.Buf[buf.Pos:]) which = 0 if which, e = buf.ScanForOneOf(true, ',', ']'); fails(e) { return } - log.D.F("'%s'", string(which)) + // log.D.F("'%s'", string(which)) if which == ']' { break } diff --git a/pkg/nostr/nip19/nip19.go b/pkg/nostr/nip19/nip19.go index 44797448..8aa25e12 100644 --- a/pkg/nostr/nip19/nip19.go +++ b/pkg/nostr/nip19/nip19.go @@ -5,31 +5,55 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "reflect" + "github.com/Hubmakerlabs/replicatr/pkg/nostr/kind" "github.com/Hubmakerlabs/replicatr/pkg/nostr/nip1" "github.com/Hubmakerlabs/replicatr/pkg/nostr/pointers" "mleku.online/git/bech32" ) -func Decode(bech32string string) (prefix string, value any, e error) { - prefix, bits5, e := bech32.DecodeNoLimit(bech32string) - if e != nil { - return "", nil, e - } +const ( + NoteHRP = "note" + NsecHRP = "nsec" + NpubHRP = "npub" + NprofileHRP = "nprofile" + NeventHRP = "nevent" + NentityHRP = "naddr" +) - data, e := bech32.ConvertBits(bits5, 5, 8, false) - if e != nil { - return prefix, nil, fmt.Errorf("failed translating data into 8 bits: %s", e.Error()) +func DecodeToString(bech32String string) (prefix, value string, e error) { + var s any + if prefix, s, e = Decode(bech32String); fails(e) { + return + } + var ok bool + if value, ok = s.(string); ok { + return } + e = fmt.Errorf("value was not decoded to a string, found type %s", + reflect.TypeOf(s)) + return +} +func Decode(bech32string string) (prefix string, value any, e error) { + var bits5 []byte + if prefix, bits5, e = bech32.DecodeNoLimit(bech32string); fails(e) { + return + } + var data []byte + if data, e = bech32.ConvertBits(bits5, 5, 8, false); fails(e) { + return prefix, nil, fmt.Errorf("failed translating data into 8 bits: %s", + e.Error()) + } switch prefix { - case "npub", "nsec", "note": + case NpubHRP, NsecHRP, NoteHRP: if len(data) < 32 { - return prefix, nil, fmt.Errorf("data is less than 32 bytes (%d)", len(data)) + return prefix, nil, fmt.Errorf("data is less than 32 bytes (%d)", + len(data)) } - return prefix, hex.EncodeToString(data[0:32]), nil - case "nprofile": + case NprofileHRP: var result pointers.Profile curr := 0 for { @@ -39,14 +63,13 @@ func Decode(bech32string string) (prefix string, value any, e error) { if result.PublicKey == "" { return prefix, result, fmt.Errorf("no pubkey found for nprofile") } - return prefix, result, nil } - switch t { case TLVDefault: if len(v) < 32 { - return prefix, nil, fmt.Errorf("pubkey is less than 32 bytes (%d)", len(v)) + return prefix, nil, fmt.Errorf("pubkey is less than 32 bytes (%d)", + len(v)) } result.PublicKey = hex.EncodeToString(v) case TLVRelay: @@ -54,10 +77,9 @@ func Decode(bech32string string) (prefix string, value any, e error) { default: // ignore } - curr = curr + 2 + len(v) } - case "nevent": + case NeventHRP: var result pointers.Event curr := 0 for { @@ -67,21 +89,21 @@ func Decode(bech32string string) (prefix string, value any, e error) { if result.ID == "" { return prefix, result, fmt.Errorf("no id found for nevent") } - return prefix, result, nil } - switch t { case TLVDefault: if len(v) < 32 { - return prefix, nil, fmt.Errorf("id is less than 32 bytes (%d)", len(v)) + return prefix, nil, fmt.Errorf("id is less than 32 bytes (%d)", + len(v)) } result.ID = nip1.EventID(hex.EncodeToString(v)) case TLVRelay: result.Relays = append(result.Relays, string(v)) case TLVAuthor: if len(v) < 32 { - return prefix, nil, fmt.Errorf("author is less than 32 bytes (%d)", len(v)) + return prefix, nil, fmt.Errorf("author is less than 32 bytes (%d)", + len(v)) } result.Author = hex.EncodeToString(v) case TLVKind: @@ -89,15 +111,15 @@ func Decode(bech32string string) (prefix string, value any, e error) { default: // ignore } - curr = curr + 2 + len(v) } - case "naddr": + case NentityHRP: var result pointers.Entity curr := 0 for { t, v := readTLVEntry(data[curr:]) if v == nil { + // log.D.S(t, v) // end here if result.Kind == 0 || result.Identifier == "" || result.PublicKey == "" { return prefix, result, fmt.Errorf("incomplete naddr") @@ -105,7 +127,6 @@ func Decode(bech32string string) (prefix string, value any, e error) { return prefix, result, nil } - switch t { case TLVDefault: result.Identifier = string(v) @@ -119,13 +140,12 @@ func Decode(bech32string string) (prefix string, value any, e error) { case TLVKind: result.Kind = kind.T(binary.BigEndian.Uint32(v)) default: + log.D.Ln("got a bogus TLV type code", t) // ignore } - curr = curr + 2 + len(v) } } - return prefix, data, fmt.Errorf("unknown tag %s", prefix) } @@ -134,110 +154,104 @@ func EncodePrivateKey(privateKeyHex string) (string, error) { if e != nil { return "", fmt.Errorf("failed to decode private key hex: %w", e) } - bits5, e := bech32.ConvertBits(b, 8, 5, true) if e != nil { return "", e } - - return bech32.Encode("nsec", bits5) + return bech32.Encode(NsecHRP, bits5) } -func EncodePublicKey(publicKeyHex string) (string, error) { - b, e := hex.DecodeString(publicKeyHex) - if e != nil { - return "", fmt.Errorf("failed to decode public key hex: %w", e) +func EncodePublicKey(publicKeyHex string) (s string, e error) { + var b []byte + if b, e = hex.DecodeString(publicKeyHex); fails(e) { + e = fmt.Errorf("failed to decode public key hex: %w", e) + return } - - bits5, e := bech32.ConvertBits(b, 8, 5, true) + var bits5 []byte + bits5, e = bech32.ConvertBits(b, 8, 5, true) if e != nil { return "", e } - - return bech32.Encode("npub", bits5) + return bech32.Encode(NpubHRP, bits5) } -func EncodeNote(eventIDHex string) (string, error) { - b, e := hex.DecodeString(eventIDHex) - if e != nil { - return "", fmt.Errorf("failed to decode event id hex: %w", e) +func EncodeNote(eventIDHex string) (s string, e error) { + var b []byte + if b, e = hex.DecodeString(eventIDHex); fails(e) { + e = fmt.Errorf("failed to decode event id hex: %w", e) + return } - - bits5, e := bech32.ConvertBits(b, 8, 5, true) - if e != nil { - return "", e + var bits5 []byte + if bits5, e = bech32.ConvertBits(b, 8, 5, true); fails(e) { + return } - - return bech32.Encode("note", bits5) + return bech32.Encode(NoteHRP, bits5) } -func EncodeProfile(publicKeyHex string, relays []string) (string, error) { +func EncodeProfile(publicKeyHex string, relays []string) (s string, e error) { buf := &bytes.Buffer{} - pubkey, e := hex.DecodeString(publicKeyHex) - if e != nil { - return "", fmt.Errorf("invalid pubkey '%s': %w", publicKeyHex, e) + var pb []byte + if pb, e = hex.DecodeString(publicKeyHex); fails(e) { + e = fmt.Errorf("invalid pubkey '%s': %w", publicKeyHex, e) + return } - writeTLVEntry(buf, TLVDefault, pubkey) - + writeTLVEntry(buf, TLVDefault, pb) for _, url := range relays { writeTLVEntry(buf, TLVRelay, []byte(url)) } - - bits5, e := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if e != nil { - return "", fmt.Errorf("failed to convert bits: %w", e) + var bits5 []byte + if bits5, e = bech32.ConvertBits(buf.Bytes(), 8, 5, true); fails(e) { + e = fmt.Errorf("failed to convert bits: %w", e) + return } - - return bech32.Encode("nprofile", bits5) + return bech32.Encode(NprofileHRP, bits5) } -func EncodeEvent(eventIDHex string, relays []string, author string) (string, error) { +func EncodeEvent(eventIDHex string, relays []string, + author string) (s string, e error) { + buf := &bytes.Buffer{} - id, e := hex.DecodeString(eventIDHex) + var id []byte + id, e = hex.DecodeString(eventIDHex) if e != nil || len(id) != 32 { return "", fmt.Errorf("invalid id '%s': %w", eventIDHex, e) } writeTLVEntry(buf, TLVDefault, id) - for _, url := range relays { writeTLVEntry(buf, TLVRelay, []byte(url)) } - if pubkey, _ := hex.DecodeString(author); len(pubkey) == 32 { writeTLVEntry(buf, TLVAuthor, pubkey) } - - bits5, e := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if e != nil { - return "", fmt.Errorf("failed to convert bits: %w", e) + var bits5 []byte + if bits5, e = bech32.ConvertBits(buf.Bytes(), 8, 5, true); fails(e) { + e = fmt.Errorf("failed to convert bits: %w", e) + return } - return bech32.Encode("nevent", bits5) + return bech32.Encode(NeventHRP, bits5) } -func EncodeEntity(publicKey string, kind kind.T, identifier string, relays []string) (string, error) { - buf := &bytes.Buffer{} +func EncodeEntity(publicKey string, kind kind.T, identifier string, + relays []string) (s string, e error) { + buf := &bytes.Buffer{} writeTLVEntry(buf, TLVDefault, []byte(identifier)) - for _, url := range relays { writeTLVEntry(buf, TLVRelay, []byte(url)) } - - pubkey, e := hex.DecodeString(publicKey) + var pb []byte + pb, e = hex.DecodeString(publicKey) if e != nil { - return "", fmt.Errorf("invalid pubkey '%s': %w", pubkey, e) + return "", fmt.Errorf("invalid pubkey '%s': %w", pb, e) } - writeTLVEntry(buf, TLVAuthor, pubkey) - + writeTLVEntry(buf, TLVAuthor, pb) kindBytes := make([]byte, 4) binary.BigEndian.PutUint32(kindBytes, uint32(kind)) writeTLVEntry(buf, TLVKind, kindBytes) - - bits5, e := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if e != nil { + var bits5 []byte + if bits5, e = bech32.ConvertBits(buf.Bytes(), 8, 5, true); fails(e) { return "", fmt.Errorf("failed to convert bits: %w", e) } - - return bech32.Encode("naddr", bits5) + return bech32.Encode(NentityHRP, bits5) } diff --git a/pkg/nostr/nip19/nip19_test.go b/pkg/nostr/nip19/nip19_test.go index b9d8c397..72235c12 100644 --- a/pkg/nostr/nip19/nip19_test.go +++ b/pkg/nostr/nip19/nip19_test.go @@ -1,9 +1,11 @@ package nip19 import ( - "github.com/Hubmakerlabs/replicatr/pkg/nostr/kind" - nostr "github.com/Hubmakerlabs/replicatr/pkg/nostr/pointers" + "reflect" "testing" + + "github.com/Hubmakerlabs/replicatr/pkg/nostr/kind" + "github.com/Hubmakerlabs/replicatr/pkg/nostr/pointers" ) func TestEncodeNpub(t *testing.T) { @@ -54,7 +56,7 @@ func TestDecodeNprofile(t *testing.T) { if prefix != "nprofile" { t.Error("what") } - pp, ok := data.(nostr.Profile) + pp, ok := data.(pointers.Profile) if !ok { t.Error("value returned of wrong type") } @@ -79,7 +81,7 @@ func TestDecodeOtherNprofile(t *testing.T) { if prefix != "nprofile" { t.Error("what") } - pp, ok := data.(nostr.Profile) + pp, ok := data.(pointers.Profile) if !ok { t.Error("value returned of wrong type") } @@ -110,7 +112,9 @@ func TestEncodeNprofile(t *testing.T) { } func TestEncodeDecodeNaddr(t *testing.T) { - naddr, e := EncodeEntity( + var naddr string + var e error + naddr, e = EncodeEntity( "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", kind.Article, "banana", @@ -124,15 +128,20 @@ func TestEncodeDecodeNaddr(t *testing.T) { if naddr != "naddr1qqrxyctwv9hxzqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmdqgsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8grqsqqqa28a3lkds" { t.Errorf("produced an unexpected naddr string: %s", naddr) } - - prefix, data, e := Decode(naddr) - if e != nil { + var prefix string + var data any + prefix, data, e = Decode(naddr) + // log.D.S(prefix, data, e) + if fails(e) { t.Errorf("shouldn't error: %s", e) } - if prefix != "naddr" { + if prefix != NentityHRP { t.Error("returned invalid prefix") } - ep := data.(nostr.Entity) + ep, ok := data.(pointers.Entity) + if !ok { + t.Fatalf("did not decode an entity type, got %v", reflect.TypeOf(data)) + } if ep.PublicKey != "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" { t.Error("returned wrong pubkey") } @@ -155,7 +164,7 @@ func TestDecodeNaddrWithoutRelays(t *testing.T) { if prefix != "naddr" { t.Error("returned invalid prefix") } - ep := data.(nostr.Entity) + ep := data.(pointers.Entity) if ep.PublicKey != "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194" { t.Error("returned wrong pubkey") } @@ -189,7 +198,7 @@ func TestEncodeDecodeNEventTestEncodeDecodeNEvent(t *testing.T) { t.Errorf("should have 'nevent' prefix, not '%s'", prefix) } - ep, ok := res.(nostr.Event) + ep, ok := res.(pointers.Event) if !ok { t.Errorf("'%s' should be an nevent, not %v", nevent, res) } diff --git a/pkg/nostr/nip19/utils.go b/pkg/nostr/nip19/utils.go index 08aebe17..86713c06 100644 --- a/pkg/nostr/nip19/utils.go +++ b/pkg/nostr/nip19/utils.go @@ -15,7 +15,6 @@ func readTLVEntry(data []byte) (typ uint8, value []byte) { if len(data) < 2 { return 0, nil } - typ = data[0] length := int(data[1]) value = data[2 : 2+length] diff --git a/pkg/nostr/nip42/auth.go b/pkg/nostr/nip42/auth.go index 7bf4d79c..3c1abde5 100644 --- a/pkg/nostr/nip42/auth.go +++ b/pkg/nostr/nip42/auth.go @@ -4,15 +4,16 @@ import ( "encoding/hex" "encoding/json" "fmt" + "net/url" + "strings" + "time" + "github.com/Hubmakerlabs/replicatr/pkg/nostr/kind" "github.com/Hubmakerlabs/replicatr/pkg/nostr/nip1" "github.com/Hubmakerlabs/replicatr/pkg/nostr/tags" "github.com/Hubmakerlabs/replicatr/pkg/wire/array" "github.com/Hubmakerlabs/replicatr/pkg/wire/text" log2 "mleku.online/git/log" - "net/url" - "strings" - "time" ) var ( @@ -21,7 +22,7 @@ var ( hexDecode, encodeToHex = hex.DecodeString, hex.EncodeToString ) -const LAuth nip1.Label = 7 +var LAuth = nip1.Label(len(nip1.Labels)) const AUTH = "AUTH" func init() {