Add signevent method to NIP-86 (nip86 + khatru)

Implements the signevent capability from nostr-protocol/nips#2389: relay admins
can ask the relay to sign an unsigned event template with its own (self) key.

- nip86: SignEvent MethodParams type + "signevent" decode case (round-trips the
  {kind, content, tags, created_at} param into a nostr.Event).
- khatru: RelayManagementAPI.SignEvent hook + dispatch returning the signed event
  as the result.
This commit is contained in:
Claude
2026-06-20 15:06:17 +00:00
parent fefc85d500
commit d1bc98d0f8
2 changed files with 38 additions and 0 deletions
+9
View File
@@ -43,6 +43,7 @@ type RelayManagementAPI struct {
Stats func(ctx context.Context) (nip86.Response, error)
GrantAdmin func(ctx context.Context, pubkey nostr.PubKey, methods []string) error
RevokeAdmin func(ctx context.Context, pubkey nostr.PubKey, methods []string) error
SignEvent func(ctx context.Context, event nostr.Event) (nostr.Event, error)
Generic func(ctx context.Context, request nip86.Request) (nip86.Response, error)
}
@@ -346,6 +347,14 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
} else {
resp.Result = result
}
case nip86.SignEvent:
if rl.ManagementAPI.SignEvent == nil {
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
} else if result, err := rl.ManagementAPI.SignEvent(ctx, thing.Event); err != nil {
resp.Error = err.Error()
} else {
resp.Result = result
}
default:
if rl.ManagementAPI.Generic == nil {
resp.Error = fmt.Sprintf("method '%s' not known", mp.MethodName())
+29
View File
@@ -1,6 +1,7 @@
package nip86
import (
"encoding/json"
"fmt"
"math"
"net"
@@ -242,6 +243,25 @@ func DecodeRequest(req Request) (MethodParams, error) {
}, nil
case "stats":
return Stats{}, nil
case "signevent":
if len(req.Params) == 0 {
return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
}
// params[0] is an unsigned event template {kind, content, tags,
// created_at}; it arrives as a decoded JSON value, so round-trip it
// through JSON into an Event.
evtJSON, err := json.Marshal(req.Params[0])
if err != nil {
return nil, fmt.Errorf("invalid event param for '%s'", req.Method)
}
var evt nostr.Event
if err := json.Unmarshal(evtJSON, &evt); err != nil {
return nil, fmt.Errorf("invalid event param for '%s'", req.Method)
}
return SignEvent{Event: evt}, nil
default:
return nil, fmt.Errorf("unknown method '%s'", req.Method)
}
@@ -277,6 +297,7 @@ var (
_ MethodParams = (*GrantAdmin)(nil)
_ MethodParams = (*RevokeAdmin)(nil)
_ MethodParams = (*Stats)(nil)
_ MethodParams = (*SignEvent)(nil)
)
type SupportedMethods struct{}
@@ -418,3 +439,11 @@ func (RevokeAdmin) MethodName() string { return "revokeadmin" }
type Stats struct{}
func (Stats) MethodName() string { return "stats" }
// SignEvent asks the relay to sign an unsigned event template with its own
// (self) key and return the full signed event. See NIP-86 `signevent`.
type SignEvent struct {
Event nostr.Event
}
func (SignEvent) MethodName() string { return "signevent" }