Compare commits

...

5 Commits
v0.3.1 ... main

Author SHA1 Message Date
fiatjaf
5e9a09b3c5 fix report page. 2025-04-25 22:02:36 -03:00
fiatjaf
66e0c849fc "browse" goes to jumble instead of self-hosted jouble. 2025-04-25 17:48:41 -03:00
fiatjaf
34ab0272c7 authorize 30023. 2025-04-25 16:01:19 -03:00
fiatjaf
c4a241a99f stop ratelimiting events. 2025-04-24 14:01:48 -03:00
fiatjaf
cbc84a2004 changes, support 1111 counts, 39701 bookmarks. 2025-04-24 14:01:48 -03:00
7 changed files with 69 additions and 67 deletions

8
go.mod
View File

@ -4,8 +4,8 @@ go 1.24.1
require ( require (
github.com/a-h/templ v0.3.857 github.com/a-h/templ v0.3.857
github.com/fiatjaf/eventstore v0.16.4 github.com/fiatjaf/eventstore v0.16.7
github.com/fiatjaf/khatru v0.17.7 github.com/fiatjaf/khatru v0.18.0
github.com/kelseyhightower/envconfig v1.4.0 github.com/kelseyhightower/envconfig v1.4.0
github.com/nbd-wtf/go-nostr v0.51.10 github.com/nbd-wtf/go-nostr v0.51.10
github.com/rs/zerolog v1.33.0 github.com/rs/zerolog v1.33.0
@ -44,7 +44,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/rs/cors v1.11.1 // indirect github.com/rs/cors v1.11.1 // indirect
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 // indirect
github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect
@ -53,6 +53,6 @@ require (
github.com/valyala/fasthttp v1.60.0 // indirect github.com/valyala/fasthttp v1.60.0 // indirect
golang.org/x/arch v0.16.0 // indirect golang.org/x/arch v0.16.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/net v0.38.0 // indirect golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect golang.org/x/sys v0.32.0 // indirect
) )

16
go.sum
View File

@ -72,10 +72,10 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/fasthttp/websocket v1.5.12 h1:e4RGPpWW2HTbL3zV0Y/t7g0ub294LkiuXXUuTOUInlE= github.com/fasthttp/websocket v1.5.12 h1:e4RGPpWW2HTbL3zV0Y/t7g0ub294LkiuXXUuTOUInlE=
github.com/fasthttp/websocket v1.5.12/go.mod h1:I+liyL7/4moHojiOgUOIKEWm9EIxHqxZChS+aMFltyg= github.com/fasthttp/websocket v1.5.12/go.mod h1:I+liyL7/4moHojiOgUOIKEWm9EIxHqxZChS+aMFltyg=
github.com/fiatjaf/eventstore v0.16.4 h1:pENYeuhawxMxlJk8HpRy3pb2oap0fwbphzUgsy7QPws= github.com/fiatjaf/eventstore v0.16.7 h1:QSDuOVkPdXKUQvITD/vz3qLwXhKgaVjPdZx1dQJEOpY=
github.com/fiatjaf/eventstore v0.16.4/go.mod h1:0gU8fzYO/bG+NQAVlHtJWOlt3JKKFefh5Xjj2d1dLIs= github.com/fiatjaf/eventstore v0.16.7/go.mod h1:cm7rn3an71pYrf5CFWhdHTeozvVh0urLun4ziWdvA+Y=
github.com/fiatjaf/khatru v0.17.7 h1:1NB2qe/KPF2hIrlzrZOXHj4xIQsulJw1mVlFXYzmhkk= github.com/fiatjaf/khatru v0.18.0 h1:EXLz53jlasRtim9lljnUGQ53bEzIn4aTdEYaRavINZQ=
github.com/fiatjaf/khatru v0.17.7/go.mod h1:4KW6mom+7ajwrhj5IvLJTBKj6peV8bdZjU6XoDVrX2Q= github.com/fiatjaf/khatru v0.18.0/go.mod h1:4KW6mom+7ajwrhj5IvLJTBKj6peV8bdZjU6XoDVrX2Q=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -146,8 +146,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 h1:qIQ0tWF9vxGtkJa24bR+2i53WBCz1nW/Pc47oVYauC4=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -187,8 +187,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=

View File

@ -91,31 +91,3 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
reportsPage(events, getLoggedUser(r)).Render(r.Context(), w) reportsPage(events, getLoggedUser(r)).Render(r.Context(), w)
} }
func joubleHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>pyramid</title>
<script>
window.relayGroups = [{
groupName: 'pyramid',
relayUrls: [location.href.replace('http', 'ws').replace('/browse', '')],
isActive: true,
}]
window.hideRelaySettings = true
</script>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/jouble@0.0.6/dist/index.js"></script>
<link rel="stylesheet" crossorigin href="https://cdn.jsdelivr.net/npm/jouble@0.0.6/dist/index.css">
</head>
<body>
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/window.nostr.js@0.4.7/dist/window.nostr.min.js"></script>
</body>
</html>
`)
}

View File

@ -21,7 +21,7 @@ templ layout(loggedUser string) {
</div> </div>
<nav class="flex flex-1 items-center justify-center"> <nav class="flex flex-1 items-center justify-center">
<a href="/" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">invite tree</a> <a href="/" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">invite tree</a>
<a href="/browse" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">browse</a> <a target="_blank" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" _="on load set my href to `https://jumble.social/?r=${location.hostname}`">browse</a>
<a href="/reports" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">reports</a> <a href="/reports" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">reports</a>
if loggedUser == s.RelayPubkey { if loggedUser == s.RelayPubkey {
<a href="/cleanup" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">clear stuff</a> <a href="/cleanup" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">clear stuff</a>

14
main.go
View File

@ -9,6 +9,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"time"
"github.com/fiatjaf/eventstore/lmdb" "github.com/fiatjaf/eventstore/lmdb"
"github.com/fiatjaf/khatru" "github.com/fiatjaf/khatru"
@ -43,6 +44,8 @@ var (
switch kind { switch kind {
case 7: case 7:
return true, true return true, true
case 1111:
return true, false
default: default:
return false, false return false, false
} }
@ -63,6 +66,8 @@ func main() {
return return
} }
relay.ServiceURL = "wss://" + s.Domain
// enable negentropy // enable negentropy
relay.Negentropy = true relay.Negentropy = true
@ -86,7 +91,13 @@ func main() {
} }
relay.Info.Software = "https://github.com/github-tijlxyz/khatru-pyramid" relay.Info.Software = "https://github.com/github-tijlxyz/khatru-pyramid"
policies.ApplySaneDefaults(relay) relay.RejectFilter = append(relay.RejectFilter,
policies.NoComplexFilters,
policies.FilterIPRateLimiter(20, time.Minute, 100),
)
relay.RejectConnection = append(relay.RejectConnection,
policies.ConnectionRateLimiter(1, time.Minute*5, 100),
)
relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent) relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents) relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
@ -124,7 +135,6 @@ func main() {
relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler) relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler)
relay.Router().HandleFunc("/cleanup", cleanupStuffFromExcludedUsersHandler) relay.Router().HandleFunc("/cleanup", cleanupStuffFromExcludedUsersHandler)
relay.Router().HandleFunc("/reports", reportsViewerHandler) relay.Router().HandleFunc("/reports", reportsViewerHandler)
relay.Router().HandleFunc("/browse/", joubleHandler)
relay.Router().Handle("/static/", http.FileServer(http.FS(static))) relay.Router().Handle("/static/", http.FileServer(http.FS(static)))
relay.Router().HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { relay.Router().HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
if s.RelayIcon != "" { if s.RelayIcon != "" {

View File

@ -68,6 +68,7 @@ var supportedKinds = []uint16{
30015, 30015,
30818, 30818,
30819, 30819,
30023,
30030, 30030,
30078, 30078,
30311, 30311,
@ -75,6 +76,7 @@ var supportedKinds = []uint16{
31923, 31923,
31924, 31924,
31925, 31925,
39701,
} }
func validateAndFilterReports(ctx context.Context, event *nostr.Event) (reject bool, msg string) { func validateAndFilterReports(ctx context.Context, event *nostr.Event) (reject bool, msg string) {

View File

@ -1,12 +1,13 @@
package main package main
import "github.com/nbd-wtf/go-nostr" import "github.com/nbd-wtf/go-nostr"
import "github.com/nbd-wtf/go-nostr/nip19"
templ reportsPage(reports chan *nostr.Event, loggedUser string) { templ reportsPage(reports chan *nostr.Event, loggedUser string) {
@layout(loggedUser) { @layout(loggedUser) {
<div> <div class="max-w-4xl mx-auto">
<h1 class="text-xl p-4">reports received</h1> <h1 class="text-xl p-4">reports received</h1>
<div> <div class="space-y-4 p-4">
for report := range reports { for report := range reports {
<div> <div>
if e := report.Tags.Find("e"); e != nil { if e := report.Tags.Find("e"); e != nil {
@ -23,28 +24,36 @@ templ reportsPage(reports chan *nostr.Event, loggedUser string) {
templ eventReportComponent(e nostr.Tag, report *nostr.Event) { templ eventReportComponent(e nostr.Tag, report *nostr.Event) {
if res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{e[1]}}); len(res) > 0 { if res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{e[1]}}); len(res) > 0 {
<div> <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div class="font-lg"> <div class="flex justify-between items-start">
<span class="font-semibold"> <div class="font-lg">
if len(e) >= 3 { <span class="font-semibold">
{ e[2] } if len(e) >= 3 {
} { e[2] }
</span> }
{ " report" } </span>
{ " report" }
</div>
<div class="text-sm text-gray-500">
{ report.CreatedAt.Time().Format("Jan 2, 2006 3:04 PM") }
</div>
</div> </div>
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div> {{ npub, _ := nip19.EncodePublicKey(report.PubKey) }}
<div class="p-3">{ report.Content }</div> <div class="mt-2 text-sm text-gray-600">by <a class="hover:underline" title={ report.PubKey } href={ templ.SafeURL("nostr:" + npub) }><nostr-name pubkey={ report.PubKey }></nostr-name></a></div>
<div> if report.Content != "" {
event reported: <div class="mt-3 p-3 bg-gray-50 rounded">{ report.Content }</div>
<div class="text-mono">{ res[0].String() }</div> }
<div class="mt-3">
<div class="text-sm text-gray-600">event reported:</div>
<div class="mt-1 font-mono text-sm bg-gray-50 p-2 rounded overflow-auto whitespace-pre-wrap break-all">{ res[0].String() }</div>
</div> </div>
</div> </div>
} }
} }
templ profileReportComponent(p nostr.Tag, report *nostr.Event) { templ profileReportComponent(p nostr.Tag, report *nostr.Event) {
if isPublicKeyInWhitelist(p[1]) { <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div> <div class="flex justify-between items-start">
<div class="font-lg"> <div class="font-lg">
<span class="font-semibold"> <span class="font-semibold">
if len(p) >= 3 { if len(p) >= 3 {
@ -53,14 +62,23 @@ templ profileReportComponent(p nostr.Tag, report *nostr.Event) {
</span> </span>
{ " report" } { " report" }
</div> </div>
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div> <div class="text-sm text-gray-500">
<div class="p-3">{ report.Content }</div> { report.CreatedAt.Time().Format("Jan 2, 2006 3:04 PM") }
<div> </div>
profile reported: </div>
<a href={ templ.URL("https://njump.me/p/" + report.PubKey) } target="_blank" class="font-mono py-1"> {{ npub, _ := nip19.EncodePublicKey(report.PubKey) }}
<nostr-name pubkey={ report.PubKey }>{ report.PubKey }</nostr-name> <div class="mt-2 text-sm text-gray-600">by <a class="hover:underline" title={ report.PubKey } href={ templ.SafeURL("nostr:" + npub) }><nostr-name pubkey={ report.PubKey }></nostr-name></a></div>
if report.Content != "" {
<div class="mt-3 p-3 bg-gray-50 rounded">{ report.Content }</div>
}
<div class="mt-3">
<div class="text-sm text-gray-600">profile reported:</div>
<div class="mt-1">
{{ npubt, _ := nip19.EncodePublicKey(p[1]) }}
<a href={ templ.URL("nostr:" + npubt) } target="_blank" class="text-sm hover:underline">
<nostr-name pubkey={ p[1] }></nostr-name>
</a> </a>
</div> </div>
</div> </div>
} </div>
} }