nip46: support nip44 in servers.

This commit is contained in:
fiatjaf 2024-05-15 16:00:30 -03:00
parent 7be82655d3
commit 4a2242e965
2 changed files with 60 additions and 24 deletions

View File

@ -4,11 +4,13 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"slices" "slices"
"strings"
"sync" "sync"
"github.com/mailru/easyjson" "github.com/mailru/easyjson"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip04" "github.com/nbd-wtf/go-nostr/nip04"
"github.com/nbd-wtf/go-nostr/nip44"
) )
var _ Signer = (*DynamicSigner)(nil) var _ Signer = (*DynamicSigner)(nil)
@ -21,24 +23,24 @@ type DynamicSigner struct {
RelaysToAdvertise map[string]RelayReadWrite RelaysToAdvertise map[string]RelayReadWrite
getPrivateKey func(pubkey string) (string, error) getPrivateKey func(pubkey string) (string, error)
authorizeSigning func(event nostr.Event) bool authorizeSigning func(event nostr.Event) bool
onEventSigned func(event nostr.Event) onEventSigned func(event nostr.Event)
authorizeNIP04 func() bool authorizeEncryption func() bool
} }
func NewDynamicSigner( func NewDynamicSigner(
getPrivateKey func(pubkey string) (string, error), getPrivateKey func(pubkey string) (string, error),
authorizeSigning func(event nostr.Event) bool, authorizeSigning func(event nostr.Event) bool,
onEventSigned func(event nostr.Event), onEventSigned func(event nostr.Event),
authorizeNIP04 func() bool, authorizeEncryption func() bool,
) DynamicSigner { ) DynamicSigner {
return DynamicSigner{ return DynamicSigner{
getPrivateKey: getPrivateKey, getPrivateKey: getPrivateKey,
authorizeSigning: authorizeSigning, authorizeSigning: authorizeSigning,
onEventSigned: onEventSigned, onEventSigned: onEventSigned,
authorizeNIP04: authorizeNIP04, authorizeEncryption: authorizeEncryption,
RelaysToAdvertise: make(map[string]RelayReadWrite), RelaysToAdvertise: make(map[string]RelayReadWrite),
} }
} }
@ -143,7 +145,7 @@ func (p *DynamicSigner) HandleRequest(event *nostr.Event) (
case "get_relays": case "get_relays":
jrelays, _ := json.Marshal(p.RelaysToAdvertise) jrelays, _ := json.Marshal(p.RelaysToAdvertise)
result = string(jrelays) result = string(jrelays)
case "nip04_encrypt": case "nip04_encrypt", "nip44_encrypt":
if len(req.Params) != 2 { if len(req.Params) != 2 {
resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'") resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'")
break break
@ -153,23 +155,31 @@ func (p *DynamicSigner) HandleRequest(event *nostr.Event) (
resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a pubkey string") resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a pubkey string")
break break
} }
if !p.authorizeNIP04() { if !p.authorizeEncryption() {
resultErr = fmt.Errorf("refusing to encrypt") resultErr = fmt.Errorf("refusing to encrypt")
break break
} }
plaintext := req.Params[1] plaintext := req.Params[1]
sharedSecret, err := nip04.ComputeSharedSecret(thirdPartyPubkey, privateKey)
getKey := nip04.ComputeSharedSecret
encrypt := nip04.Encrypt
if strings.HasPrefix(req.Method, "nip44") {
getKey = nip44.GenerateConversationKey
encrypt = func(message string, key []byte) (string, error) { return nip44.Encrypt(message, key) }
}
sharedSecret, err := getKey(thirdPartyPubkey, privateKey)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to compute shared secret: %w", err) resultErr = fmt.Errorf("failed to compute shared secret: %w", err)
break break
} }
ciphertext, err := nip04.Encrypt(plaintext, sharedSecret) ciphertext, err := encrypt(plaintext, sharedSecret)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to encrypt: %w", err) resultErr = fmt.Errorf("failed to encrypt: %w", err)
break break
} }
result = ciphertext result = ciphertext
case "nip04_decrypt": case "nip04_decrypt", "nip44_decrypt":
if len(req.Params) != 2 { if len(req.Params) != 2 {
resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'") resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'")
break break
@ -179,17 +189,25 @@ func (p *DynamicSigner) HandleRequest(event *nostr.Event) (
resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a pubkey string") resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a pubkey string")
break break
} }
if !p.authorizeNIP04() { if !p.authorizeEncryption() {
resultErr = fmt.Errorf("refusing to decrypt") resultErr = fmt.Errorf("refusing to decrypt")
break break
} }
ciphertext := req.Params[1] ciphertext := req.Params[1]
sharedSecret, err := nip04.ComputeSharedSecret(thirdPartyPubkey, privateKey)
getKey := nip04.ComputeSharedSecret
decrypt := nip04.Decrypt
if strings.HasPrefix(req.Method, "nip44") {
getKey = nip44.GenerateConversationKey
decrypt = nip44.Decrypt
}
sharedSecret, err := getKey(thirdPartyPubkey, privateKey)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to compute shared secret: %w", err) resultErr = fmt.Errorf("failed to compute shared secret: %w", err)
break break
} }
plaintext, err := nip04.Decrypt(ciphertext, sharedSecret) plaintext, err := decrypt(ciphertext, sharedSecret)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to encrypt: %w", err) resultErr = fmt.Errorf("failed to encrypt: %w", err)
break break

View File

@ -4,11 +4,13 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"slices" "slices"
"strings"
"sync" "sync"
"github.com/mailru/easyjson" "github.com/mailru/easyjson"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip04" "github.com/nbd-wtf/go-nostr/nip04"
"github.com/nbd-wtf/go-nostr/nip44"
) )
var _ Signer = (*StaticKeySigner)(nil) var _ Signer = (*StaticKeySigner)(nil)
@ -129,7 +131,7 @@ func (p *StaticKeySigner) HandleRequest(event *nostr.Event) (
jrelays, _ := json.Marshal(p.RelaysToAdvertise) jrelays, _ := json.Marshal(p.RelaysToAdvertise)
result = string(jrelays) result = string(jrelays)
harmless = true harmless = true
case "nip04_encrypt": case "nip04_encrypt", "nip44_encrypt":
if len(req.Params) != 2 { if len(req.Params) != 2 {
resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'") resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'")
break break
@ -140,18 +142,26 @@ func (p *StaticKeySigner) HandleRequest(event *nostr.Event) (
break break
} }
plaintext := req.Params[1] plaintext := req.Params[1]
sharedSecret, err := nip04.ComputeSharedSecret(thirdPartyPubkey, p.secretKey)
getKey := nip04.ComputeSharedSecret
encrypt := nip04.Encrypt
if strings.HasPrefix(req.Method, "nip44") {
getKey = nip44.GenerateConversationKey
encrypt = func(message string, key []byte) (string, error) { return nip44.Encrypt(message, key) }
}
sharedSecret, err := getKey(thirdPartyPubkey, p.secretKey)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to compute shared secret: %w", err) resultErr = fmt.Errorf("failed to compute shared secret: %w", err)
break break
} }
ciphertext, err := nip04.Encrypt(plaintext, sharedSecret) ciphertext, err := encrypt(plaintext, sharedSecret)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to encrypt: %w", err) resultErr = fmt.Errorf("failed to encrypt: %w", err)
break break
} }
result = ciphertext result = ciphertext
case "nip04_decrypt": case "nip04_decrypt", "nip44_decrypt":
if len(req.Params) != 2 { if len(req.Params) != 2 {
resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'") resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'")
break break
@ -162,12 +172,20 @@ func (p *StaticKeySigner) HandleRequest(event *nostr.Event) (
break break
} }
ciphertext := req.Params[1] ciphertext := req.Params[1]
sharedSecret, err := nip04.ComputeSharedSecret(thirdPartyPubkey, p.secretKey)
getKey := nip04.ComputeSharedSecret
decrypt := nip04.Decrypt
if strings.HasPrefix(req.Method, "nip44") {
getKey = nip44.GenerateConversationKey
decrypt = nip44.Decrypt
}
sharedSecret, err := getKey(thirdPartyPubkey, p.secretKey)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to compute shared secret: %w", err) resultErr = fmt.Errorf("failed to compute shared secret: %w", err)
break break
} }
plaintext, err := nip04.Decrypt(ciphertext, sharedSecret) plaintext, err := decrypt(ciphertext, sharedSecret)
if err != nil { if err != nil {
resultErr = fmt.Errorf("failed to encrypt: %w", err) resultErr = fmt.Errorf("failed to encrypt: %w", err)
break break