nip46: allow signers to prevent handling duplicate requests (happens sometimes when switching relays, depending on how stuff is done, it's harmless but still).
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package nip46
|
package nip46
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
"fiatjaf.com/nostr/nip44"
|
"fiatjaf.com/nostr/nip44"
|
||||||
@@ -10,6 +12,9 @@ import (
|
|||||||
type Session struct {
|
type Session struct {
|
||||||
PublicKey nostr.PubKey
|
PublicKey nostr.PubKey
|
||||||
ConversationKey [32]byte
|
ConversationKey [32]byte
|
||||||
|
|
||||||
|
duplicatesBuf [6]string
|
||||||
|
serial int
|
||||||
}
|
}
|
||||||
|
|
||||||
type RelayReadWrite struct {
|
type RelayReadWrite struct {
|
||||||
@@ -17,7 +22,9 @@ type RelayReadWrite struct {
|
|||||||
Write bool `json:"write"`
|
Write bool `json:"write"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Session) ParseRequest(event nostr.Event) (Request, error) {
|
var AlreadyHandled = errors.New("already handled this request")
|
||||||
|
|
||||||
|
func (s *Session) ParseRequest(event nostr.Event) (Request, error) {
|
||||||
var req Request
|
var req Request
|
||||||
|
|
||||||
plain, err := nip44.Decrypt(event.Content, s.ConversationKey)
|
plain, err := nip44.Decrypt(event.Content, s.ConversationKey)
|
||||||
@@ -26,6 +33,15 @@ func (s Session) ParseRequest(event nostr.Event) (Request, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(plain), &req)
|
err = json.Unmarshal([]byte(plain), &req)
|
||||||
|
|
||||||
|
// discard duplicates
|
||||||
|
if slices.Contains(s.duplicatesBuf[:], req.ID) {
|
||||||
|
return req, AlreadyHandled
|
||||||
|
}
|
||||||
|
|
||||||
|
s.duplicatesBuf[s.serial%len(s.duplicatesBuf)] = req.ID
|
||||||
|
s.serial++
|
||||||
|
|
||||||
return req, err
|
return req, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var _ Signer = (*DynamicSigner)(nil)
|
|||||||
|
|
||||||
type DynamicSigner struct {
|
type DynamicSigner struct {
|
||||||
// { [handlePubkey]: {[clientKey]: Session} }
|
// { [handlePubkey]: {[clientKey]: Session} }
|
||||||
sessions map[nostr.PubKey]map[nostr.PubKey]Session
|
sessions map[nostr.PubKey]map[nostr.PubKey]*Session
|
||||||
|
|
||||||
// used for switch_relays call
|
// used for switch_relays call
|
||||||
DefaultRelays []string
|
DefaultRelays []string
|
||||||
@@ -47,7 +47,7 @@ type DynamicSigner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *DynamicSigner) Init() {
|
func (p *DynamicSigner) Init() {
|
||||||
p.sessions = make(map[nostr.PubKey]map[nostr.PubKey]Session)
|
p.sessions = make(map[nostr.PubKey]map[nostr.PubKey]*Session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DynamicSigner) HandleRequest(ctx context.Context, event nostr.Event) (
|
func (p *DynamicSigner) HandleRequest(ctx context.Context, event nostr.Event) (
|
||||||
@@ -85,14 +85,14 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event nostr.Event) (
|
|||||||
|
|
||||||
handlerSessions, exists := p.sessions[handlerPubkey]
|
handlerSessions, exists := p.sessions[handlerPubkey]
|
||||||
if !exists {
|
if !exists {
|
||||||
handlerSessions = make(map[nostr.PubKey]Session)
|
handlerSessions = make(map[nostr.PubKey]*Session)
|
||||||
p.sessions[handlerPubkey] = handlerSessions
|
p.sessions[handlerPubkey] = handlerSessions
|
||||||
}
|
}
|
||||||
|
|
||||||
session, exists := handlerSessions[event.PubKey]
|
session, exists := handlerSessions[event.PubKey]
|
||||||
if !exists {
|
if !exists {
|
||||||
// create session if it doesn't exist
|
// create session if it doesn't exist
|
||||||
session = Session{}
|
session = &Session{}
|
||||||
|
|
||||||
session.ConversationKey, err = nip44.GenerateConversationKey(event.PubKey, handlerSecret)
|
session.ConversationKey, err = nip44.GenerateConversationKey(event.PubKey, handlerSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
var _ Signer = (*StaticKeySigner)(nil)
|
var _ Signer = (*StaticKeySigner)(nil)
|
||||||
|
|
||||||
type StaticKeySigner struct {
|
type StaticKeySigner struct {
|
||||||
secretKey [32]byte
|
secretKey nostr.SecretKey
|
||||||
sessions map[nostr.PubKey]Session
|
sessions map[nostr.PubKey]*Session
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
@@ -29,11 +29,11 @@ type StaticKeySigner struct {
|
|||||||
func NewStaticKeySigner(secretKey [32]byte) StaticKeySigner {
|
func NewStaticKeySigner(secretKey [32]byte) StaticKeySigner {
|
||||||
return StaticKeySigner{
|
return StaticKeySigner{
|
||||||
secretKey: secretKey,
|
secretKey: secretKey,
|
||||||
sessions: make(map[nostr.PubKey]Session),
|
sessions: make(map[nostr.PubKey]*Session),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StaticKeySigner) getOrCreateSession(clientPubkey nostr.PubKey) (Session, error) {
|
func (p *StaticKeySigner) getOrCreateSession(clientPubkey nostr.PubKey) (*Session, error) {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
|
|
||||||
@@ -44,17 +44,16 @@ func (p *StaticKeySigner) getOrCreateSession(clientPubkey nostr.PubKey) (Session
|
|||||||
|
|
||||||
ck, err := nip44.GenerateConversationKey(clientPubkey, p.secretKey)
|
ck, err := nip44.GenerateConversationKey(clientPubkey, p.secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Session{}, fmt.Errorf("failed to compute shared secret: %w", err)
|
return nil, fmt.Errorf("failed to compute shared secret: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey := nostr.GetPublicKey(p.secretKey)
|
session = &Session{
|
||||||
session = Session{
|
PublicKey: p.secretKey.Public(),
|
||||||
PublicKey: pubkey,
|
|
||||||
ConversationKey: ck,
|
ConversationKey: ck,
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to pool
|
// add to pool
|
||||||
p.sessions[pubkey] = session
|
p.sessions[clientPubkey] = session
|
||||||
|
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user