Files
Nip-05-api/internal/dm/encrypt.go
2026-04-29 02:35:00 +00:00

88 lines
2.1 KiB
Go

package dm
import (
"context"
"errors"
"fmt"
gn "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/keyer"
"github.com/nbd-wtf/go-nostr/nip04"
"github.com/nbd-wtf/go-nostr/nip59"
)
var ErrUnsupportedKind = errors.New("unsupported DM kind")
// BuildEvent builds the kind-4 or kind-1059 event(s) for a DM.
// For kind 1059 it returns the gift wrap addressed to the recipient.
// For kind 4 it returns a single signed event.
func BuildEvent(kind int, senderSk, recipientHex, content string) ([]gn.Event, error) {
switch kind {
case 4:
return buildNip04(senderSk, recipientHex, content)
case 1059:
return buildNip17(senderSk, recipientHex, content)
default:
return nil, fmt.Errorf("%w: %d", ErrUnsupportedKind, kind)
}
}
func buildNip04(sk, recipient, content string) ([]gn.Event, error) {
shared, err := nip04.ComputeSharedSecret(recipient, sk)
if err != nil {
return nil, fmt.Errorf("nip04 shared: %w", err)
}
enc, err := nip04.Encrypt(content, shared)
if err != nil {
return nil, fmt.Errorf("nip04 encrypt: %w", err)
}
pk, err := gn.GetPublicKey(sk)
if err != nil {
return nil, err
}
ev := gn.Event{
PubKey: pk,
CreatedAt: gn.Now(),
Kind: 4,
Tags: gn.Tags{{"p", recipient}},
Content: enc,
}
if err := ev.Sign(sk); err != nil {
return nil, fmt.Errorf("sign: %w", err)
}
return []gn.Event{ev}, nil
}
func buildNip17(sk, recipient, content string) ([]gn.Event, error) {
ks, err := keyer.NewPlainKeySigner(sk)
if err != nil {
return nil, fmt.Errorf("keyer: %w", err)
}
ctx := context.Background()
ourPubkey, err := ks.GetPublicKey(ctx)
if err != nil {
return nil, err
}
rumor := gn.Event{
Kind: gn.KindDirectMessage,
Content: content,
Tags: gn.Tags{{"p", recipient}},
CreatedAt: gn.Now(),
PubKey: ourPubkey,
}
rumor.ID = rumor.GetID()
wrap, err := nip59.GiftWrap(
rumor,
recipient,
func(s string) (string, error) { return ks.Encrypt(ctx, s, recipient) },
func(e *gn.Event) error { return ks.SignEvent(ctx, e) },
nil,
)
if err != nil {
return nil, fmt.Errorf("nip17 giftwrap: %w", err)
}
return []gn.Event{wrap}, nil
}