mirror of
https://github.com/fiatjaf/khatru.git
synced 2025-03-17 21:32:55 +01:00
nip86: add auth checks.
This commit is contained in:
parent
535f4c90e0
commit
91c652ef48
117
nip86.go
117
nip86.go
@ -1,41 +1,78 @@
|
||||
package khatru
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip86"
|
||||
)
|
||||
|
||||
type RelayManagementAPI struct {
|
||||
BanPubKey func(pubkey string, reason string) error
|
||||
ListBannedPubKeys func() ([]nip86.PubKeyReason, error)
|
||||
AllowPubKey func(pubkey string, reason string) error
|
||||
ListAllowedPubKeys func() ([]nip86.PubKeyReason, error)
|
||||
ListEventsNeedingModeration func() ([]nip86.IDReason, error)
|
||||
AllowEvent func(id string, reason string) error
|
||||
BanEvent func(id string, reason string) error
|
||||
ListBannedEvents func() ([]nip86.IDReason, error)
|
||||
ChangeRelayName func(name string) error
|
||||
ChangeRelayDescription func(desc string) error
|
||||
ChangeRelayIcon func(icon string) error
|
||||
AllowKind func(kind int) error
|
||||
DisallowKind func(kind int) error
|
||||
ListAllowedKinds func() ([]int, error)
|
||||
BlockIP func(ip net.IP, reason string) error
|
||||
UnblockIP func(ip net.IP, reason string) error
|
||||
ListBlockedIPs func() ([]nip86.IPReason, error)
|
||||
RejectAPICall []func(ctx context.Context, mp nip86.MethodParams) (reject bool, msg string)
|
||||
|
||||
BanPubKey func(ctx context.Context, pubkey string, reason string) error
|
||||
ListBannedPubKeys func(ctx context.Context) ([]nip86.PubKeyReason, error)
|
||||
AllowPubKey func(ctx context.Context, pubkey string, reason string) error
|
||||
ListAllowedPubKeys func(ctx context.Context) ([]nip86.PubKeyReason, error)
|
||||
ListEventsNeedingModeration func(ctx context.Context) ([]nip86.IDReason, error)
|
||||
AllowEvent func(ctx context.Context, id string, reason string) error
|
||||
BanEvent func(ctx context.Context, id string, reason string) error
|
||||
ListBannedEvents func(ctx context.Context) ([]nip86.IDReason, error)
|
||||
ChangeRelayName func(ctx context.Context, name string) error
|
||||
ChangeRelayDescription func(ctx context.Context, desc string) error
|
||||
ChangeRelayIcon func(ctx context.Context, icon string) error
|
||||
AllowKind func(ctx context.Context, kind int) error
|
||||
DisallowKind func(ctx context.Context, kind int) error
|
||||
ListAllowedKinds func(ctx context.Context) ([]int, error)
|
||||
BlockIP func(ctx context.Context, ip net.IP, reason string) error
|
||||
UnblockIP func(ctx context.Context, ip net.IP, reason string) error
|
||||
ListBlockedIPs func(ctx context.Context) ([]nip86.IPReason, error)
|
||||
}
|
||||
|
||||
func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/nostr+json+rpc")
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "empty request", 400)
|
||||
return
|
||||
}
|
||||
payloadHash := sha256.Sum256(nil)
|
||||
|
||||
auth := r.Header.Get("Authorization")
|
||||
spl := strings.Split(auth, "Nostr ")
|
||||
if len(spl) != 2 {
|
||||
http.Error(w, "missing auth", 403)
|
||||
return
|
||||
}
|
||||
|
||||
var evt nostr.Event
|
||||
if evtj, err := base64.StdEncoding.DecodeString(spl[1]); err != nil {
|
||||
http.Error(w, "invalid base64 auth", 403)
|
||||
return
|
||||
} else if err := json.Unmarshal(evtj, &evt); err != nil {
|
||||
http.Error(w, "invalid auth event json", 403)
|
||||
return
|
||||
} else if ok, _ := evt.CheckSignature(); !ok {
|
||||
http.Error(w, "invalid auth event", 403)
|
||||
return
|
||||
} else if pht := evt.Tags.GetFirst([]string{"payload", hex.EncodeToString(payloadHash[:])}); pht == nil {
|
||||
http.Error(w, "invalid auth event payload hash", 403)
|
||||
return
|
||||
}
|
||||
|
||||
var req nip86.Request
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err := json.Unmarshal(payload, &req); err != nil {
|
||||
http.Error(w, "invalid json body", 400)
|
||||
return
|
||||
}
|
||||
@ -47,6 +84,15 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var resp nip86.Response
|
||||
|
||||
ctx := context.WithValue(r.Context(), nip86HeaderAuthKey, evt.PubKey)
|
||||
for _, rac := range rl.ManagementAPI.RejectAPICall {
|
||||
if reject, msg := rac(ctx, mp); reject {
|
||||
resp.Error = msg
|
||||
goto respond
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := mp.(nip86.SupportedMethods); ok {
|
||||
mat := reflect.TypeOf(rl.ManagementAPI)
|
||||
mav := reflect.ValueOf(rl.ManagementAPI)
|
||||
@ -69,7 +115,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.BanPubKey:
|
||||
if rl.ManagementAPI.BanPubKey == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.BanPubKey(thing.PubKey, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.BanPubKey(ctx, thing.PubKey, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -77,7 +123,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListBannedPubKeys:
|
||||
if rl.ManagementAPI.ListBannedPubKeys == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListBannedPubKeys(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListBannedPubKeys(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -85,7 +131,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.AllowPubKey:
|
||||
if rl.ManagementAPI.AllowPubKey == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.AllowPubKey(thing.PubKey, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.AllowPubKey(ctx, thing.PubKey, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -93,7 +139,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListAllowedPubKeys:
|
||||
if rl.ManagementAPI.ListAllowedPubKeys == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListAllowedPubKeys(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListAllowedPubKeys(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -101,7 +147,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.BanEvent:
|
||||
if rl.ManagementAPI.BanEvent == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.BanEvent(thing.ID, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.BanEvent(ctx, thing.ID, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -109,7 +155,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.AllowEvent:
|
||||
if rl.ManagementAPI.AllowEvent == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.AllowEvent(thing.ID, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.AllowEvent(ctx, thing.ID, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -117,7 +163,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListEventsNeedingModeration:
|
||||
if rl.ManagementAPI.ListEventsNeedingModeration == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -125,7 +171,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListBannedEvents:
|
||||
if rl.ManagementAPI.ListBannedEvents == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -133,7 +179,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ChangeRelayName:
|
||||
if rl.ManagementAPI.ChangeRelayName == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.ChangeRelayName(thing.Name); err != nil {
|
||||
} else if err := rl.ManagementAPI.ChangeRelayName(ctx, thing.Name); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -141,7 +187,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ChangeRelayDescription:
|
||||
if rl.ManagementAPI.ChangeRelayDescription == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.ChangeRelayDescription(thing.Description); err != nil {
|
||||
} else if err := rl.ManagementAPI.ChangeRelayDescription(ctx, thing.Description); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -149,7 +195,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ChangeRelayIcon:
|
||||
if rl.ManagementAPI.ChangeRelayIcon == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.ChangeRelayIcon(thing.IconURL); err != nil {
|
||||
} else if err := rl.ManagementAPI.ChangeRelayIcon(ctx, thing.IconURL); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -157,7 +203,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.AllowKind:
|
||||
if rl.ManagementAPI.AllowKind == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.AllowKind(thing.Kind); err != nil {
|
||||
} else if err := rl.ManagementAPI.AllowKind(ctx, thing.Kind); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -165,7 +211,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.DisallowKind:
|
||||
if rl.ManagementAPI.DisallowKind == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.DisallowKind(thing.Kind); err != nil {
|
||||
} else if err := rl.ManagementAPI.DisallowKind(ctx, thing.Kind); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -173,7 +219,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListAllowedKinds:
|
||||
if rl.ManagementAPI.ListAllowedKinds == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListAllowedKinds(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListAllowedKinds(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -181,7 +227,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.BlockIP:
|
||||
if rl.ManagementAPI.BlockIP == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.BlockIP(thing.IP, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.BlockIP(ctx, thing.IP, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -189,7 +235,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.UnblockIP:
|
||||
if rl.ManagementAPI.UnblockIP == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if err := rl.ManagementAPI.UnblockIP(thing.IP, thing.Reason); err != nil {
|
||||
} else if err := rl.ManagementAPI.UnblockIP(ctx, thing.IP, thing.Reason); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = true
|
||||
@ -197,7 +243,7 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
case nip86.ListBlockedIPs:
|
||||
if rl.ManagementAPI.ListBlockedIPs == nil {
|
||||
resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
|
||||
} else if result, err := rl.ManagementAPI.ListBlockedIPs(); err != nil {
|
||||
} else if result, err := rl.ManagementAPI.ListBlockedIPs(ctx); err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Result = result
|
||||
@ -207,5 +253,6 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
respond:
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
7
utils.go
7
utils.go
@ -9,6 +9,7 @@ import (
|
||||
const (
|
||||
wsKey = iota
|
||||
subscriptionIdKey
|
||||
nip86HeaderAuthKey
|
||||
)
|
||||
|
||||
func RequestAuth(ctx context.Context) {
|
||||
@ -30,10 +31,12 @@ func GetConnection(ctx context.Context) *WebSocket {
|
||||
}
|
||||
|
||||
func GetAuthed(ctx context.Context) string {
|
||||
conn := GetConnection(ctx)
|
||||
if conn != nil {
|
||||
if conn := GetConnection(ctx); conn != nil {
|
||||
return conn.AuthedPublicKey
|
||||
}
|
||||
if nip86Auth := ctx.Value(nip86HeaderAuthKey); nip86Auth != nil {
|
||||
return nip86Auth.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user