diff --git a/hoot.go b/hoot.go index 24b2d09..a10ccd6 100644 --- a/hoot.go +++ b/hoot.go @@ -698,7 +698,8 @@ func getDMs(privateKey string) ([]tui.FeedPost, error) { } // Decrypt the DM content - decrypted, err := nip04.Decrypt(ev.Content, []byte(privateKey)) + ss, _ := nip04.ComputeSharedSecret(ev.PubKey, privateKey) + decrypted, err := nip04.Decrypt(ev.Content, ss) if err != nil { continue // Skip if we can't decrypt } @@ -787,6 +788,7 @@ func getReactions(eventID string) ([]tui.FeedPost, error) { // publishPostTUI publishes a note using either NIP-46 or local key func publishPostTUI(content string) error { var event nostr.Event + var err error event.Kind = 1 event.Content = content event.CreatedAt = nostr.Now() @@ -807,22 +809,28 @@ func publishPostTUI(content string) error { if localPrivateKey == "" { return fmt.Errorf("no active session or local key") } - event.PubKey, _ = nostr.GetPublicKey(localPrivateKey) - event.Sign(localPrivateKey) + event.PubKey, err = nostr.GetPublicKey(localPrivateKey) + if err != nil { + return fmt.Errorf("failed to get public key: %w", err) + } + if err := event.Sign(localPrivateKey); err != nil { + return fmt.Errorf("failed to sign event: %w", err) + } } success := 0 for _, url := range relays { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() relay, err := nostr.RelayConnect(ctx, url) if err != nil { + cancel() continue } if err := relay.Publish(ctx, event); err == nil { success++ } relay.Close() + cancel() } if success == 0 { @@ -904,12 +912,12 @@ func editProfile(privateKey, newContent, pubKey string, relays []string) { // registerAsHandler registers the app as a handler for specific kinds. func registerAsHandler(privateKey, publicKey string, kinds []int, platforms map[string]string) error { - // Create a kind 1984 event for handler registration + // Create a kind 31990 event for handler registration (NIP-89) event := nostr.Event{ PubKey: publicKey, CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: 1984, - Tags: nostr.Tags{}, + Kind: 31990, + Tags: nostr.Tags{{"d", "hoot"}}, Content: "", } @@ -955,7 +963,7 @@ func recommendApp(privateKey, publicKey, handlerPubKey, handlerDIdentifier strin CreatedAt: nostr.Timestamp(time.Now().Unix()), Kind: 1985, Tags: nostr.Tags{ - {"a", fmt.Sprintf("%s:%s:%d", handlerPubKey, handlerDIdentifier, kind)}, + {"a", fmt.Sprintf("%d:%s:%s", kind, handlerPubKey, handlerDIdentifier)}, {"p", platform}, }, Content: relayHint, @@ -996,7 +1004,7 @@ func findHandlers(kind int) ([]struct { // Use relay list from file or default relays := getRelayList() filter := nostr.Filter{ - Kinds: []int{1984}, + Kinds: []int{31990}, Tags: nostr.TagMap{"k": []string{fmt.Sprintf("%d", kind)}}, } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -1033,7 +1041,7 @@ func findHandlers(kind int) ([]struct { } for _, tag := range ev.Tags { - if tag[0] == "k" { + if len(tag) > 1 && tag[0] == "k" { kind, err := strconv.Atoi(tag[1]) if err == nil { handler.SupportedKinds = append(handler.SupportedKinds, kind) @@ -1303,7 +1311,8 @@ func extractLud16(pubKey string, relays []string) (string, error) { func main() { // Initialize cache for improved performance configDir := getConfigDir() - eventCache, err := cache.New(configDir) + var err error + eventCache, err = cache.New(configDir) if err != nil { log.Printf("Warning: failed to initialize cache: %v", err) } else { @@ -1769,7 +1778,7 @@ func main() { // Handle DMs action with loading. if *dmsPtr { - _ = withLoading("Loading DMs", func() error { + err = withLoading("Loading DMs", func() error { dms, err := getDMs(sk) if err != nil { return fmt.Errorf("failed to load DMs: %w", err) @@ -1788,7 +1797,7 @@ func main() { // Handle replies action with loading. if *repliesPtr != "" { - _ = withLoading("Loading replies", func() error { + err = withLoading("Loading replies", func() error { replies, err := getReactions(*repliesPtr) if err != nil { return fmt.Errorf("failed to load replies: %w", err) diff --git a/nip46/nip46.go b/nip46/nip46.go index a29607e..b23c5bc 100644 --- a/nip46/nip46.go +++ b/nip46/nip46.go @@ -405,11 +405,18 @@ func (s *Session) publishToAllRelays(ctx context.Context, event *nostr.Event) er } wg.Wait() close(errCh) + successes := 0 + var lastErr error for err := range errCh { if err != nil { - return err + lastErr = err + } else { + successes++ } } + if successes == 0 { + return fmt.Errorf("failed to publish to any relay: %w", lastErr) + } return nil } diff --git a/tui/tui.go b/tui/tui.go index 5269661..af2522a 100644 --- a/tui/tui.go +++ b/tui/tui.go @@ -303,6 +303,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.cursor < limit { m.cursor++ } + case ScreenHome: + if m.cursor < 7 { + m.cursor++ + } default: m.cursor++ } @@ -343,7 +347,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // Update text input - if (m.screen == ScreenLogin && (m.cursor == 50 || m.cursor == 100)) || m.screen == ScreenPost || m.screen == ScreenTip || m.screen == ScreenReplies || (m.screen == ScreenRelays && m.addingRelay) { + if (m.screen == ScreenLogin && (m.cursor == 50 || m.cursor == 51 || m.cursor == 100 || m.cursor == 200)) || m.screen == ScreenPost || m.screen == ScreenTip || m.screen == ScreenReplies || (m.screen == ScreenRelays && m.addingRelay) { // Only update input if we are in input mode (not menu selection mode) // For Login: if hasKey (Input mode) OR if !hasKey and cursor=0 (Nsec Entry? No, cursor 0 is menu choice) // Wait, if !hasKey: @@ -378,7 +382,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // The previous code reused cursor=0 for menu. This is confusing. // Using cursor=50 for Nsec Entry, 100 for Password/Save choice. - if m.cursor == 50 || m.cursor == 100 { + if m.cursor == 50 || m.cursor == 51 || m.cursor == 100 || m.cursor == 200 { m.textInput, cmd = m.textInput.Update(msg) } }