nip42/khatru: clearer AUTH error messages.
This commit is contained in:
@@ -318,8 +318,7 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
rl.removeListenerId(ws, id)
|
rl.removeListenerId(ws, id)
|
||||||
case *nostr.AuthEnvelope:
|
case *nostr.AuthEnvelope:
|
||||||
wsBaseUrl := strings.Replace(rl.getBaseURL(r), "http", "ws", 1)
|
wsBaseUrl := strings.Replace(rl.getBaseURL(r), "http", "ws", 1)
|
||||||
if pubkey, ok := nip42.ValidateAuthEvent(env.Event, ws.Challenge, wsBaseUrl); ok {
|
if pubkey, err := nip42.ValidateAuthEvent(env.Event, ws.Challenge, wsBaseUrl); err == nil {
|
||||||
|
|
||||||
total := len(ws.AuthedPublicKeys)
|
total := len(ws.AuthedPublicKeys)
|
||||||
ws.authLock.Lock()
|
ws.authLock.Lock()
|
||||||
if idx := slices.Index(ws.AuthedPublicKeys, pubkey); idx == -1 {
|
if idx := slices.Index(ws.AuthedPublicKeys, pubkey); idx == -1 {
|
||||||
@@ -339,7 +338,7 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
ws.authLock.Unlock()
|
ws.authLock.Unlock()
|
||||||
ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: true})
|
ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: true})
|
||||||
} else {
|
} else {
|
||||||
ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "error: failed to authenticate"})
|
ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "error: failed to authenticate: " + err.Error()})
|
||||||
}
|
}
|
||||||
case *nip77.OpenEnvelope:
|
case *nip77.OpenEnvelope:
|
||||||
srl := rl
|
srl := rl
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package nip42
|
package nip42
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -43,45 +44,50 @@ func parseURL(input string) (*url.URL, error) {
|
|||||||
|
|
||||||
// ValidateAuthEvent checks whether event is a valid NIP-42 event for given challenge and relayURL.
|
// ValidateAuthEvent checks whether event is a valid NIP-42 event for given challenge and relayURL.
|
||||||
// The result of the validation is encoded in the ok bool.
|
// The result of the validation is encoded in the ok bool.
|
||||||
func ValidateAuthEvent(event nostr.Event, challenge string, relayURL string) (nostr.PubKey, bool) {
|
func ValidateAuthEvent(event nostr.Event, challenge string, relayURL string) (nostr.PubKey, error) {
|
||||||
if event.Kind != nostr.KindClientAuthentication {
|
if event.Kind != nostr.KindClientAuthentication {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("wanted kind %d, got %d", nostr.KindClientAuthentication, event.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.Tags.FindWithValue("challenge", challenge) == nil {
|
if event.Tags.FindWithValue("challenge", challenge) == nil {
|
||||||
return nostr.ZeroPK, false
|
if ctag := event.Tags.Find("challenge"); ctag == nil {
|
||||||
|
return nostr.ZeroPK, fmt.Errorf("missing challenge")
|
||||||
|
} else {
|
||||||
|
return nostr.ZeroPK, fmt.Errorf("expected challenge '%s', got '%s'", challenge, ctag[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expected, err := parseURL(relayURL)
|
expected, err := parseURL(relayURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("server has misconfigured relay url")
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag := event.Tags.Find("relay"); tag == nil {
|
if tag := event.Tags.Find("relay"); tag == nil {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("missing 'relay' tag")
|
||||||
} else {
|
} else {
|
||||||
found, err := parseURL(tag[1])
|
found, err := parseURL(tag[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("invalid 'relay' tag '%s'", tag[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.Scheme != found.Scheme ||
|
if expected.Scheme != found.Scheme ||
|
||||||
expected.Host != found.Host ||
|
expected.Host != found.Host ||
|
||||||
expected.Path != found.Path {
|
expected.Path != found.Path {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("expected relay URL '%s', got '%s'", expected, found)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if event.CreatedAt.Time().After(now.Add(10*time.Minute)) ||
|
if event.CreatedAt.Time().After(now.Add(10 * time.Minute)) {
|
||||||
event.CreatedAt.Time().Before(now.Add(-10*time.Minute)) {
|
return nostr.ZeroPK, fmt.Errorf("auth event too much in the future")
|
||||||
return nostr.ZeroPK, false
|
} else if event.CreatedAt.Time().Before(now.Add(-10 * time.Minute)) {
|
||||||
|
return nostr.ZeroPK, fmt.Errorf("auth event too much in the past")
|
||||||
}
|
}
|
||||||
|
|
||||||
// save for last, as it is most expensive operation
|
// save for last, as it is most expensive operation
|
||||||
if !event.VerifySignature() {
|
if !event.VerifySignature() {
|
||||||
return nostr.ZeroPK, false
|
return nostr.ZeroPK, fmt.Errorf("invalid signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
return event.PubKey, true
|
return event.PubKey, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user