mirror of
https://github.com/github-tijlxyz/khatru-pyramid.git
synced 2025-06-06 18:31:02 +00:00
making everything almost work again.
This commit is contained in:
parent
32c484178f
commit
86509c59b5
20
handler.go
20
handler.go
@ -19,6 +19,26 @@ func inviteTreeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
htmlgo.Fprint(w, baseHTML(content), r.Context())
|
htmlgo.Fprint(w, baseHTML(content), r.Context())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
pubkey := r.PostFormValue("pubkey")
|
||||||
|
if err := addToWhitelist(r.Context(), pubkey, s.RelayPubkey); err != nil {
|
||||||
|
http.Error(w, "failed to add to whitelist: "+err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
content := buildInviteTree(r.Context(), s.RelayPubkey)
|
||||||
|
htmlgo.Fprint(w, content, r.Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
pubkey := r.PostFormValue("pubkey")
|
||||||
|
if err := removeFromWhitelist(r.Context(), pubkey); err != nil {
|
||||||
|
http.Error(w, "failed to remove from whitelist: "+err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
content := buildInviteTree(r.Context(), s.RelayPubkey)
|
||||||
|
htmlgo.Fprint(w, content, r.Context())
|
||||||
|
}
|
||||||
|
|
||||||
func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// var formattedReportsData template.HTML = ""
|
// var formattedReportsData template.HTML = ""
|
||||||
|
|
||||||
|
37
main.go
37
main.go
@ -3,14 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fiatjaf/khatru"
|
"github.com/fiatjaf/khatru"
|
||||||
"github.com/fiatjaf/khatru/plugins/storage/badgern"
|
"github.com/fiatjaf/khatru/plugins/storage/badgern"
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"github.com/kelseyhightower/envconfig"
|
"github.com/kelseyhightower/envconfig"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
@ -36,25 +31,6 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// save whitelist on shutdown
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
handleSignals()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// backup whitelist every hour
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Hour)
|
|
||||||
saveWhitelist()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// init env config
|
|
||||||
godotenv.Load(".env")
|
|
||||||
|
|
||||||
// init relay
|
// init relay
|
||||||
relay := khatru.NewRelay()
|
relay := khatru.NewRelay()
|
||||||
|
|
||||||
@ -78,11 +54,11 @@ func main() {
|
|||||||
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
|
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
|
||||||
relay.CountEvents = append(relay.CountEvents, db.CountEvents)
|
relay.CountEvents = append(relay.CountEvents, db.CountEvents)
|
||||||
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
||||||
|
|
||||||
relay.RejectEvent = append(relay.RejectEvent, whitelistRejecter)
|
relay.RejectEvent = append(relay.RejectEvent, whitelistRejecter)
|
||||||
|
|
||||||
// ui
|
|
||||||
relay.Router().HandleFunc("/reports", reportsViewerHandler)
|
relay.Router().HandleFunc("/reports", reportsViewerHandler)
|
||||||
|
relay.Router().HandleFunc("/add-to-whitelist", addToWhitelistHandler)
|
||||||
|
relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler)
|
||||||
relay.Router().HandleFunc("/users", inviteTreeHandler)
|
relay.Router().HandleFunc("/users", inviteTreeHandler)
|
||||||
relay.Router().HandleFunc("/", homePageHandler)
|
relay.Router().HandleFunc("/", homePageHandler)
|
||||||
|
|
||||||
@ -91,12 +67,3 @@ func main() {
|
|||||||
log.Fatal().Err(err).Msg("failed to serve")
|
log.Fatal().Err(err).Msg("failed to serve")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save whitelist on shutdown
|
|
||||||
func handleSignals() {
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
|
||||||
<-sigCh
|
|
||||||
saveWhitelist()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
40
pages.go
40
pages.go
@ -6,8 +6,10 @@ import (
|
|||||||
. "github.com/theplant/htmlgo"
|
. "github.com/theplant/htmlgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const buttonClass = "rounded-md bg-white p-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
|
||||||
|
|
||||||
func baseHTML(inside HTMLComponent) HTMLComponent {
|
func baseHTML(inside HTMLComponent) HTMLComponent {
|
||||||
navItemClass := "text-gray-300 hover:bg-gray-700 hover:text-white rounded-md px-3 py-2 font-medium"
|
navItemClass := "text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium"
|
||||||
|
|
||||||
return HTML(
|
return HTML(
|
||||||
Head(
|
Head(
|
||||||
@ -15,6 +17,8 @@ func baseHTML(inside HTMLComponent) HTMLComponent {
|
|||||||
Meta().Name("viewport").Content("width=device-width, initial-scale=1"),
|
Meta().Name("viewport").Content("width=device-width, initial-scale=1"),
|
||||||
Title(s.RelayName),
|
Title(s.RelayName),
|
||||||
Script("").Src("https://cdn.tailwindcss.com"),
|
Script("").Src("https://cdn.tailwindcss.com"),
|
||||||
|
Script("").Src("https://unpkg.com/htmx.org@1.9.6"),
|
||||||
|
Script("").Src("https://unpkg.com/hyperscript.org@0.9.12"),
|
||||||
),
|
),
|
||||||
Body(
|
Body(
|
||||||
Div(
|
Div(
|
||||||
@ -22,12 +26,12 @@ func baseHTML(inside HTMLComponent) HTMLComponent {
|
|||||||
P().Text(s.RelayDescription).Class("text-lg"),
|
P().Text(s.RelayDescription).Class("text-lg"),
|
||||||
).Class("mx-auto my-6 text-center"),
|
).Class("mx-auto my-6 text-center"),
|
||||||
Nav(
|
Nav(
|
||||||
A().Text("information").Href("/").Class(navItemClass),
|
A().Text("information").Href("/").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
||||||
A().Text("invite tree").Href("/users").Class(navItemClass),
|
A().Text("invite tree").Href("/users").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
||||||
A().Text("reports").Href("/reports").Class(navItemClass),
|
A().Text("reports").Href("/reports").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
||||||
).Class("flex flex-1 items-center justify-center"),
|
).Class("flex flex-1 items-center justify-center"),
|
||||||
Div(inside).Class("m-4"),
|
Main(inside).Class("m-4"),
|
||||||
).Class("bg-gray-800 mx-4 my-6 text-white"),
|
).Class("mx-4 my-6"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,26 +71,28 @@ func homePageHTML(ctx context.Context, params HomePageParams) HTMLComponent {
|
|||||||
type InviteTreePageParams struct{}
|
type InviteTreePageParams struct{}
|
||||||
|
|
||||||
func inviteTreePageHTML(ctx context.Context, params InviteTreePageParams) HTMLComponent {
|
func inviteTreePageHTML(ctx context.Context, params InviteTreePageParams) HTMLComponent {
|
||||||
return Div(
|
return Form(
|
||||||
Input("").Type("text").Placeholder("npub1..."),
|
Input("pubkey").Type("text").Placeholder("npub1...").Class("w-96 rounded-md border-0 p-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"),
|
||||||
Button("invite"),
|
Button("invite").Class(buttonClass),
|
||||||
buildInviteTree(ctx, ""),
|
Div(
|
||||||
)
|
buildInviteTree(ctx, s.RelayPubkey),
|
||||||
|
).Id("tree").Class("mt-3"),
|
||||||
|
).Attr("hx-post", "/add-to-whitelist", "hx-trigger", "submit", "hx-target", "#tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildInviteTree(ctx context.Context, invitedBy string) HTMLComponent {
|
func buildInviteTree(ctx context.Context, invitedBy string) HTMLComponent {
|
||||||
tree := Ul()
|
children := make([]HTMLComponent, 0, len(whitelist))
|
||||||
for _, entry := range whitelist {
|
for _, entry := range whitelist {
|
||||||
if entry.InvitedBy == invitedBy {
|
if entry.InvitedBy == invitedBy {
|
||||||
user := getUserInfo(ctx, entry.PublicKey)
|
user := getUserInfo(ctx, entry.PublicKey)
|
||||||
tree = tree.Children(
|
children = append(children,
|
||||||
Li(
|
Li(
|
||||||
A().Href("nostr:"+user.Npub).Text(user.Name),
|
A().Href("nostr:"+user.Npub).Text(user.Name).Class("font-mono"),
|
||||||
A().Text("remove"),
|
Button("remove").Class(buttonClass).Attr("hx-post", "/remove-from-whitelist", "hx-trigger", "click", "hx-target", "#tree"),
|
||||||
buildInviteTree(ctx, entry.PublicKey),
|
buildInviteTree(ctx, entry.PublicKey),
|
||||||
),
|
).Class("ml-3"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tree
|
return Ul(children...)
|
||||||
}
|
}
|
||||||
|
26
whitelist.go
26
whitelist.go
@ -6,11 +6,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WhitelistEntry struct {
|
type WhitelistEntry struct {
|
||||||
PublicKey string `json:"pk"`
|
|
||||||
InvitedBy string `json:"invited_by"`
|
InvitedBy string `json:"invited_by"`
|
||||||
|
PublicKey string `json:"pk"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var whitelist []WhitelistEntry
|
var whitelist []WhitelistEntry
|
||||||
@ -26,12 +27,6 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg
|
|||||||
invited/whitelisted user invites new user
|
invited/whitelisted user invites new user
|
||||||
*/
|
*/
|
||||||
if evt.Kind == 20201 {
|
if evt.Kind == 20201 {
|
||||||
pTags := evt.Tags.GetAll([]string{"p"})
|
|
||||||
for _, tag := range pTags {
|
|
||||||
if nostr.IsValidPublicKeyHex(tag.Value()) && !isPublicKeyInWhitelist(tag.Value()) {
|
|
||||||
whitelist = append(whitelist, WhitelistEntry{PublicKey: tag.Value(), InvitedBy: evt.PubKey})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -76,6 +71,23 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg
|
|||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addToWhitelist(ctx context.Context, pubkey string, invitedBy string) error {
|
||||||
|
if nostr.IsValidPublicKeyHex(pubkey) && !isPublicKeyInWhitelist(pubkey) {
|
||||||
|
whitelist = append(whitelist, WhitelistEntry{PublicKey: pubkey, InvitedBy: invitedBy})
|
||||||
|
}
|
||||||
|
return saveWhitelist()
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeFromWhitelist(ctx context.Context, pubkey string) error {
|
||||||
|
idx := slices.IndexFunc(whitelist, func(we WhitelistEntry) bool { return we.PublicKey == pubkey })
|
||||||
|
if idx == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
whitelist = append(whitelist[0:idx], whitelist[idx+1:]...)
|
||||||
|
return saveWhitelist()
|
||||||
|
}
|
||||||
|
|
||||||
func loadWhitelist() error {
|
func loadWhitelist() error {
|
||||||
if _, err := os.Stat("whitelist.json"); os.IsNotExist(err) {
|
if _, err := os.Stat("whitelist.json"); os.IsNotExist(err) {
|
||||||
whitelist = []WhitelistEntry{}
|
whitelist = []WhitelistEntry{}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user