88 lines
2.1 KiB
Go
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
|
|
}
|