diff --git a/nip05/nip05.go b/nip05/nip05.go index e3e9fa0..83ec599 100644 --- a/nip05/nip05.go +++ b/nip05/nip05.go @@ -2,7 +2,6 @@ package nip05 import ( "context" - "encoding/hex" "encoding/json" "fmt" "net/http" @@ -18,9 +17,31 @@ type WellKnownResponse struct { } func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointer, error) { + result, name, err := Fetch(ctx, fullname) + if err != nil { + return nil, err + } + + pubkey, ok := result.Names[name] + if !ok { + return nil, fmt.Errorf("no entry for name '%s'", name) + } + + if !nostr.IsValidPublicKey(pubkey) { + return nil, fmt.Errorf("got an invalid public key '%s'", pubkey) + } + + relays, _ := result.Relays[pubkey] + return &nostr.ProfilePointer{ + PublicKey: pubkey, + Relays: relays, + }, nil +} + +func Fetch(ctx context.Context, fullname string) (resp WellKnownResponse, name string, err error) { spl := strings.Split(fullname, "@") - var name, domain string + var domain string switch len(spl) { case 1: name = "_" @@ -29,17 +50,13 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe name = spl[0] domain = spl[1] default: - return nil, fmt.Errorf("not a valid nip-05 identifier") - } - - if strings.Index(domain, ".") == -1 { - return nil, fmt.Errorf("hostname doesn't have a dot") + return resp, name, fmt.Errorf("not a valid nip-05 identifier") } req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s/.well-known/nostr.json?name=%s", domain, name), nil) if err != nil { - return nil, fmt.Errorf("failed to create a request: %w", err) + return resp, name, fmt.Errorf("failed to create a request: %w", err) } client := &http.Client{ @@ -49,32 +66,16 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe } res, err := client.Do(req) if err != nil { - return nil, fmt.Errorf("request failed: %w", err) + return resp, name, fmt.Errorf("request failed: %w", err) } defer res.Body.Close() var result WellKnownResponse if err := json.NewDecoder(res.Body).Decode(&result); err != nil { - return nil, fmt.Errorf("failed to decode json response: %w", err) + return resp, name, fmt.Errorf("failed to decode json response: %w", err) } - pubkey, ok := result.Names[name] - if !ok { - return &nostr.ProfilePointer{}, nil - } - - if len(pubkey) == 64 { - if _, err := hex.DecodeString(pubkey); err != nil { - return &nostr.ProfilePointer{}, nil - } - } - - relays, _ := result.Relays[pubkey] - - return &nostr.ProfilePointer{ - PublicKey: pubkey, - Relays: relays, - }, nil + return resp, name, nil } func NormalizeIdentifier(fullname string) string { diff --git a/nip46/client.go b/nip46/client.go index 1a6eca4..dccf2e7 100644 --- a/nip46/client.go +++ b/nip46/client.go @@ -34,26 +34,37 @@ type BunkerClient struct { func ConnectBunker( ctx context.Context, clientSecretKey string, - bunkerURL string, + bunkerURLOrNIP05 string, pool *nostr.SimplePool, ) (*BunkerClient, error) { - parsed, err := url.Parse(bunkerURL) + parsed, err := url.Parse(bunkerURLOrNIP05) if err != nil { return nil, fmt.Errorf("invalid url: %w", err) } - if parsed.Scheme != "bunker" { + // assume it's a bunker url (will fail later if not) + secret := parsed.Query().Get("secret") + relays := parsed.Query()["relay"] + target := parsed.Host + + if parsed.Scheme == "" { + // could be a NIP-05 + pubkey, relays_, err := queryWellKnownNostrJson(ctx, bunkerURLOrNIP05) + if err != nil { + return nil, fmt.Errorf("failed to query nip05: %w", err) + } + target = pubkey + relays = relays_ + } else if parsed.Scheme == "bunker" { + // this is what we were expecting, so just move on + } else { + // otherwise fail here return nil, fmt.Errorf("wrong scheme '%s', must be bunker://", parsed.Scheme) } - - target := parsed.Host if !nostr.IsValidPublicKey(target) { return nil, fmt.Errorf("'%s' is not a valid public key hex", target) } - secret := parsed.Query().Get("secret") - relays := parsed.Query()["relay"] - if pool == nil { pool = nostr.NewSimplePool(ctx) } diff --git a/nip46/wellknownnostrjson.go b/nip46/wellknownnostrjson.go new file mode 100644 index 0000000..82848f7 --- /dev/null +++ b/nip46/wellknownnostrjson.go @@ -0,0 +1,26 @@ +package nip46 + +import ( + "context" + "fmt" + + "github.com/nbd-wtf/go-nostr/nip05" +) + +func queryWellKnownNostrJson(ctx context.Context, fullname string) (pubkey string, relays []string, err error) { + result, name, err := nip05.Fetch(ctx, fullname) + if err != nil { + return "", nil, err + } + + pubkey, ok := result.Names[name] + if !ok { + return "", nil, fmt.Errorf("no entry found for the '%s' name", name) + } + relays, _ = result.NIP46[pubkey] + if !ok { + return "", nil, fmt.Errorf("no bunker relays found for the '%s' name", name) + } + + return pubkey, relays, nil +}