well-goknown/nostr/nostr.go
2023-02-04 22:24:30 -05:00

167 lines
4 KiB
Go

package nostr
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
"git.minhas.io/asara/well-goknown/lnd"
"git.minhas.io/asara/well-goknown/redis"
"github.com/davecgh/go-spew/spew"
"github.com/nbd-wtf/go-nostr/nip19"
)
type nostrWellKnown struct {
Names map[string]string `json:"names"`
Relays map[string][]string `json:"relays,omitempty"`
}
type NostrRequest struct {
Name string `json:"name"`
Key string `json:"key"`
Hostname string
Relays []string `json:"relays,omitempty"`
}
func RequestNostrAddr(w http.ResponseWriter, r *http.Request) {
ctx := context.TODO()
switch r.Method {
case "GET":
http.ServeFile(w, r, "html/nostr_form.html")
case "POST":
r.ParseForm()
rKey := getRkey("verified", r.FormValue("Name"), getHostname(r.Host))
// check if the user already exists
redisCli, err := redis.New("localhost:6379", "", redis.NostrDb)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
exists := redisCli.Client.Exists(ctx, rKey)
if exists.Val() == 1 {
w.WriteHeader(http.StatusConflict)
return
}
// get the hexkey
hexKey, err := convertNpubToHex(r.FormValue("Key"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// create the struct
relays := make(map[string][]string)
names := map[string]string{r.FormValue("Name"): hexKey}
user := nostrWellKnown{}
if r.FormValue("Relays") != "" {
relays = map[string][]string{
hexKey: strings.Split(r.FormValue("Relays"), ","),
}
user = nostrWellKnown{Names: names, Relays: relays}
} else {
user = nostrWellKnown{Names: names}
}
jsonUser, _ := json.Marshal(user)
// generate the payment request
paymentReq, err := lnd.Request(rKey, jsonUser)
if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
return
}
requestKey := getRkey("requested", r.FormValue("Name"), getHostname(r.Host))
err = redisCli.Client.Set(ctx, requestKey, jsonUser, 15*time.Minute).Err()
if err != nil {
fmt.Println("FAILED")
}
spew.Dump(paymentReq)
}
}
func GetNostrAddr(w http.ResponseWriter, r *http.Request) {
ctx := context.TODO()
// get query string for username
r.ParseForm()
// connect to redis
redisCli, err := redis.New("localhost:6379", "", redis.NostrDb)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
requestedName := r.FormValue("name")
// search for user@domain
search := getRkey("verified", requestedName, getHostname(r.Host))
addr, err := redisCli.Client.Get(ctx, search).Result()
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, addr)
}
func AddNostrAddr(n NostrRequest) {
ctx := context.TODO()
// transform request to well known struct
relays := make(map[string][]string)
user := nostrWellKnown{}
hexKey, err := convertNpubToHex(n.Key)
if err != nil {
fmt.Printf("Not an npub")
}
names := map[string]string{n.Name: hexKey}
if n.Relays != nil {
relays = map[string][]string{hexKey: n.Relays}
user = nostrWellKnown{Names: names, Relays: relays}
} else {
user = nostrWellKnown{Names: names}
}
jsonUser, _ := json.Marshal(user)
redisCli, err := redis.New("localhost:6379", "", redis.NostrDb)
if err != nil {
fmt.Println("Failed to connect to redis")
}
nameKey := getRkey("verified", n.Name, n.Hostname)
err = redisCli.Client.Set(ctx, nameKey, jsonUser, 0).Err()
if err != nil {
fmt.Println("FAILED")
}
}
func getHostname(hostname string) string {
// remove port for local testing
return hostname
}
func convertNpubToHex(npub string) (string, error) {
if !strings.HasPrefix(npub, "npub1") {
return "", errors.New("Not an npub key")
}
_, hex, err := nip19.Decode(npub)
if err != nil {
spew.Dump(hex)
}
return hex.(string), nil
}
func getRkey(prefix string, user string, hostname string) string {
if strings.Contains(hostname, ":") {
hostname = strings.Split(hostname, ":")[0]
}
return fmt.Sprintf("%s:%s@%s", prefix, user, hostname)
}