mirror of
https://github.com/fiatjaf/khatru.git
synced 2025-03-26 17:51:49 +01:00
implement nip-42 AUTH and restrict DMs to authed users.
This commit is contained in:
parent
e70a5601c7
commit
fe91197d45
4
go.mod
4
go.mod
@ -13,11 +13,12 @@ require (
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/lib/pq v1.10.3
|
||||
github.com/mmcdole/gofeed v1.1.3
|
||||
github.com/nbd-wtf/go-nostr v0.10.0
|
||||
github.com/nbd-wtf/go-nostr v0.11.1
|
||||
github.com/rif/cache2go v1.0.0
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/stevelacy/daz v0.1.4
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
golang.org/x/exp v0.0.0-20221106115401-f9659909a136
|
||||
)
|
||||
|
||||
require (
|
||||
@ -74,7 +75,6 @@ require (
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/valyala/fastjson v1.6.3 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -320,8 +320,8 @@ github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOA
|
||||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nbd-wtf/go-nostr v0.10.0 h1:95y0VjyplDCInPn7VD2eNvRHwTGib1LxfVKp0Fv2ZQY=
|
||||
github.com/nbd-wtf/go-nostr v0.10.0/go.mod h1:qFFTIxh15H5GGN0WsBI/P73DteqsevnhSEW/yk8nEf4=
|
||||
github.com/nbd-wtf/go-nostr v0.11.1 h1:kJn2Q3v1WJ4fvQ1tmwrL2Ke+t/rTj9jlwD3tdUPMgRI=
|
||||
github.com/nbd-wtf/go-nostr v0.11.1/go.mod h1:qFFTIxh15H5GGN0WsBI/P73DteqsevnhSEW/yk8nEf4=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
|
54
handlers.go
54
handlers.go
@ -1,6 +1,7 @@
|
||||
package relayer
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@ -11,6 +12,8 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip11"
|
||||
"github.com/nbd-wtf/go-nostr/nip42"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// TODO: consdier moving these to Server as config params
|
||||
@ -50,7 +53,14 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
s.clients[conn] = struct{}{}
|
||||
ticker := time.NewTicker(pingPeriod)
|
||||
|
||||
ws := &WebSocket{conn: conn}
|
||||
// nip-42 challenge
|
||||
challenge := make([]byte, 8)
|
||||
rand.Read(challenge)
|
||||
|
||||
ws := &WebSocket{
|
||||
conn: conn,
|
||||
challenge: hex.EncodeToString(challenge),
|
||||
}
|
||||
|
||||
// reader
|
||||
go func() {
|
||||
@ -72,6 +82,11 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
return nil
|
||||
})
|
||||
|
||||
// nip42 auth challenge
|
||||
if _, ok := s.relay.(Auther); ok {
|
||||
ws.WriteJSON([]interface{}{"AUTH", ws.challenge})
|
||||
}
|
||||
|
||||
for {
|
||||
typ, message, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
@ -183,6 +198,25 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
filter := &filters[i]
|
||||
|
||||
// prevent kind-4 events from being returned to unauthed users,
|
||||
// only when authentication is a thing
|
||||
if _, ok := s.relay.(Auther); ok {
|
||||
if slices.Contains(filter.Kinds, 4) {
|
||||
// when fetching kind-4 one must be either on the sending or on the receiving end
|
||||
senders := filter.Authors
|
||||
receivers, _ := filter.Tags["e"]
|
||||
if len(senders) > 1 || len(receivers) > 1 {
|
||||
notice = "restricted: can't serve kind-4 messages to or from more than one key"
|
||||
return
|
||||
}
|
||||
if (len(senders) == 1 && senders[0] != ws.authed) ||
|
||||
(len(receivers) == 1 && receivers[0] != ws.authed) {
|
||||
notice = "restricted: can't serve kind-4 to their participants"
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if advancedQuerier != nil {
|
||||
advancedQuerier.BeforeQuery(filter)
|
||||
}
|
||||
@ -217,6 +251,17 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
removeListenerId(ws, id)
|
||||
break
|
||||
case "AUTH":
|
||||
if auther, ok := s.relay.(Auther); ok {
|
||||
var evt nostr.Event
|
||||
if err := json.Unmarshal(request[1], &evt); err != nil {
|
||||
notice = "failed to decode auth event: " + err.Error()
|
||||
return
|
||||
}
|
||||
if pubkey, ok := nip42.ValidateAuthEvent(&evt, ws.challenge, auther.ServiceURL()); ok {
|
||||
ws.authed = pubkey
|
||||
}
|
||||
}
|
||||
default:
|
||||
if cwh, ok := s.relay.(CustomWebSocketHandler); ok {
|
||||
cwh.HandleUnknownType(ws, typ, request)
|
||||
@ -252,12 +297,17 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleNIP11(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
supportedNIPs := []int{9, 12, 15, 16, 20}
|
||||
if _, ok := s.relay.(Auther); ok {
|
||||
supportedNIPs = append(supportedNIPs, 42)
|
||||
}
|
||||
|
||||
info := nip11.RelayInformationDocument{
|
||||
Name: s.relay.Name(),
|
||||
Description: "relay powered by the relayer framework",
|
||||
PubKey: "~",
|
||||
Contact: "~",
|
||||
SupportedNIPs: []int{9, 15, 16},
|
||||
SupportedNIPs: supportedNIPs,
|
||||
Software: "https://github.com/fiatjaf/relayer",
|
||||
Version: "~",
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ type Relay interface {
|
||||
Storage() Storage
|
||||
}
|
||||
|
||||
type Auther interface {
|
||||
ServiceURL() string
|
||||
}
|
||||
|
||||
type Injector interface {
|
||||
InjectEvents() chan nostr.Event
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ import (
|
||||
type WebSocket struct {
|
||||
conn *websocket.Conn
|
||||
mutex sync.Mutex
|
||||
|
||||
// nip42
|
||||
challenge string
|
||||
authed string
|
||||
}
|
||||
|
||||
func (ws *WebSocket) WriteJSON(any interface{}) error {
|
||||
|
Loading…
x
Reference in New Issue
Block a user