220 lines
5.7 KiB
Go
220 lines
5.7 KiB
Go
package alby
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"git.devvul.com/asara/gologger"
|
|
"git.devvul.com/asara/well-goknown/config"
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/gorilla/schema"
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
var (
|
|
DB *sqlx.DB
|
|
qsDecoder = schema.NewDecoder()
|
|
)
|
|
|
|
type AlbyApp struct {
|
|
Id int32 `json:"id"`
|
|
Name string `json:"name"`
|
|
NostrPubkey string `json:"nostrPubkey"`
|
|
}
|
|
|
|
type AlbyApps []AlbyApp
|
|
|
|
type lnurlp struct {
|
|
Status string `json:"status"`
|
|
Tag string `json:"tag"`
|
|
CommentAllowed int32 `json:"commentAllowed"`
|
|
Callback string `json:"callback"`
|
|
MinSendable int64 `json:"minSendable"`
|
|
MaxSendable int64 `json:"maxSendable"`
|
|
Metadata string `json:"metadata"`
|
|
AllowsNostr bool `json:"allowsNostr"`
|
|
NostrPubkey string `json:"nostrPubkey"`
|
|
}
|
|
|
|
type lnurlpError struct {
|
|
Status string `json:"status"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
|
|
type NWCReqNostr struct {
|
|
Id string `json:"id"`
|
|
Pubkey string `json:"pubkey"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
Kind int32 `json:"kind"`
|
|
Tags [][]string `json:"tags"`
|
|
Content string `json:"content"`
|
|
Signature string `json:"sig"`
|
|
}
|
|
|
|
type NWCReq struct {
|
|
Nostr string `json:"nostr"`
|
|
Amount string `json:"amount"`
|
|
Comment string `json:"comment"`
|
|
}
|
|
|
|
type NWCSecret struct {
|
|
Name string
|
|
Domain string
|
|
Wallet string
|
|
ClientPubkey string
|
|
AppPubkey string
|
|
Relay string
|
|
Secret string
|
|
}
|
|
|
|
func (s *NWCSecret) decodeSecret() {
|
|
l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
|
|
u, err := url.Parse(s.Wallet)
|
|
if err != nil {
|
|
l.Error().Msgf("failed")
|
|
}
|
|
s.AppPubkey = u.Host
|
|
q, _ := url.ParseQuery(u.RawQuery)
|
|
s.Relay = q.Get("relay")
|
|
s.Secret = q.Get("secret")
|
|
|
|
}
|
|
|
|
func GetLnurlp(w http.ResponseWriter, r *http.Request) {
|
|
l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
|
|
albyAdmin := config.GetConfig().AlbyAdminAuth
|
|
|
|
// setup response type
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
// normalize domain
|
|
domain, _, err := net.SplitHostPort(r.Host)
|
|
if err != nil {
|
|
domain = r.Host
|
|
}
|
|
|
|
name := r.PathValue("name")
|
|
|
|
// get all alby apps
|
|
client := http.Client{}
|
|
req, err := http.NewRequest("GET", "https://alby.devvul.com/api/apps", nil)
|
|
if err != nil {
|
|
l.Error().Msgf("unable to generate alby request for %s@%s: %s", name, domain, err.Error())
|
|
lnurlpReturnError := &lnurlpError{Status: "ERROR", Reason: "unknown error"}
|
|
retError, _ := json.Marshal(lnurlpReturnError)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write(retError)
|
|
return
|
|
}
|
|
|
|
req.Header = http.Header{"Authorization": {fmt.Sprintf("Bearer %s", albyAdmin)}}
|
|
resp, err := client.Do(req)
|
|
defer resp.Body.Close()
|
|
|
|
var albyApps AlbyApps
|
|
err = json.NewDecoder(resp.Body).Decode(&albyApps)
|
|
if err != nil {
|
|
l.Error().Msgf("unable to unmarshal alby request for %s@%s: %s", name, domain, err.Error())
|
|
lnurlpReturnError := &lnurlpError{Status: "ERROR", Reason: "unknown error"}
|
|
retError, _ := json.Marshal(lnurlpReturnError)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write(retError)
|
|
return
|
|
}
|
|
|
|
// check if user exists
|
|
var npk string
|
|
for _, element := range albyApps {
|
|
if element.Name == name {
|
|
npk = element.NostrPubkey
|
|
}
|
|
}
|
|
|
|
if len(npk) == 0 {
|
|
l.Debug().Msgf("user doesn't exist in alby %s@%s: %s", name, domain, err.Error())
|
|
lnurlpReturnError := &lnurlpError{Status: "ERROR", Reason: "user does not exist"}
|
|
retError, _ := json.Marshal(lnurlpReturnError)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write(retError)
|
|
return
|
|
}
|
|
|
|
// get server pubkey
|
|
var secret NWCSecret
|
|
err = DB.QueryRow("SELECT name, domain, wallet, pubkey FROM lnwallets WHERE name=$1 AND domain=$2", name, domain).
|
|
Scan(&secret.Name, &secret.Domain, &secret.Wallet, &secret.ClientPubkey)
|
|
if err != nil {
|
|
l.Debug().Msgf("user doesn't exist in alby %s@%s: %s", name, domain, err.Error())
|
|
lnurlpReturnError := &lnurlpError{Status: "ERROR", Reason: "user does not exist"}
|
|
retError, _ := json.Marshal(lnurlpReturnError)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write(retError)
|
|
return
|
|
}
|
|
|
|
secret.decodeSecret()
|
|
spew.Dump(secret)
|
|
|
|
lnurlpReturn := &lnurlp{
|
|
Status: "OK",
|
|
Tag: "payRequest",
|
|
CommentAllowed: 255,
|
|
Callback: fmt.Sprintf("https://%s/.well-known/lnurlp/%s/callback", domain, name),
|
|
MinSendable: 1000,
|
|
MaxSendable: 10000000,
|
|
Metadata: fmt.Sprintf("[[\"text/plain\", \"ln address payment to %s on the devvul server\"],[\"text/identifier\", \"%s@%s\"]]", name, name, domain),
|
|
AllowsNostr: true,
|
|
NostrPubkey: npk,
|
|
}
|
|
|
|
ret, err := json.Marshal(lnurlpReturn)
|
|
if err != nil {
|
|
l.Error().Msgf("unable to marshal json for %s@%s: %s", name, domain, err.Error())
|
|
lnurlpReturnError := &lnurlpError{Status: "ERROR", Reason: "User not found"}
|
|
retError, _ := json.Marshal(lnurlpReturnError)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write(retError)
|
|
return
|
|
}
|
|
|
|
l.Debug().Msgf("returning pay request callback for %s@%s", name, domain)
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(ret)
|
|
return
|
|
}
|
|
|
|
func GetLnurlpCallback(w http.ResponseWriter, r *http.Request) {
|
|
l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
|
|
//ctx := context.Background()
|
|
var nwc NWCReq
|
|
var nwcNostr NWCReqNostr
|
|
|
|
// normalize domain
|
|
domain, _, err := net.SplitHostPort(r.Host)
|
|
if err != nil {
|
|
domain = r.Host
|
|
}
|
|
name := r.PathValue("name")
|
|
|
|
err = qsDecoder.Decode(&nwc, r.URL.Query())
|
|
if err != nil {
|
|
l.Error().Msgf("unable to marshal json for %s@%s: %s", name, domain, err.Error())
|
|
}
|
|
|
|
json.Unmarshal([]byte(nwc.Nostr), &nwcNostr)
|
|
|
|
//
|
|
// ev := nostr.Event{
|
|
// PubKey: nwc.Pubkey,
|
|
// CreatedAt: nostr.Now(),
|
|
// Kind: nostr.KindNWCWalletRequest,
|
|
// Tags: nil,
|
|
// Content: "",
|
|
// }
|
|
//
|
|
// ev.Sign()
|
|
}
|