mirror of
https://github.com/github-tijlxyz/khatru-pyramid.git
synced 2025-04-22 16:51:29 +00:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
41e0492470 | ||
![]() |
bfb7a65905 | ||
![]() |
a05cd3dfd6 | ||
![]() |
e949ed698d | ||
![]() |
35a56ea8ad | ||
![]() |
045e7d2218 | ||
![]() |
36b446c056 | ||
![]() |
a64a12e03d | ||
![]() |
be73687eaf | ||
![]() |
18e098b536 | ||
![]() |
83b962b1fd | ||
![]() |
e10a9b8b5a | ||
![]() |
448e270e6b | ||
![]() |
0a3fe7f97c | ||
![]() |
f8d59b47e2 | ||
![]() |
68c5b29668 | ||
![]() |
e128f802a2 | ||
![]() |
928e801e69 | ||
![]() |
c0c3940530 | ||
![]() |
e162e5fa33 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ users.json
|
|||||||
khatru-pyramid
|
khatru-pyramid
|
||||||
.env
|
.env
|
||||||
db
|
db
|
||||||
|
*_templ.go
|
||||||
|
@ -17,8 +17,8 @@ docker run \
|
|||||||
|
|
||||||
### Deploy with
|
### Deploy with
|
||||||
|
|
||||||
- [YunoHost](https://github.com/YunoHost-Apps/khatru-pyramid_ynh) ([app catalog](https://apps.yunohost.org/catalog) [pending](https://github.com/YunoHost/apps/pull/2077))
|
- [YunoHost](https://github.com/YunoHost-Apps/khatru-pyramid_ynh) ([app catalog](https://apps.yunohost.org/app/khatru-pyramid))
|
||||||
- [Cloudron](https://github.com/github-tijlxyz/khatru-pyramid_cloudron) ([app catalog](https://www.cloudron.io/store/index.html) [pending](https://forum.cloudron.io/topic/11146/khatru-pyramid-a-nostr-relay))
|
- [Cloudron](https://github.com/github-tijlxyz/khatru-pyramid_cloudron) ([app catalog pending](https://forum.cloudron.io/topic/11146/khatru-pyramid-a-nostr-relay))
|
||||||
|
|
||||||
### Manually build
|
### Manually build
|
||||||
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
|
||||||
. "github.com/theplant/htmlgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func inviteTreeComponent(ctx context.Context, inviter string, loggedUser string) HTMLComponent {
|
|
||||||
children := make([]HTMLComponent, 0, len(whitelist)/2)
|
|
||||||
for pubkey, invitedBy := range whitelist {
|
|
||||||
if invitedBy == inviter {
|
|
||||||
profile := sys.FetchOrStoreProfileMetadata(ctx, pubkey)
|
|
||||||
children = append(children, userRowComponent(ctx, profile, loggedUser))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ul(children...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func userRowComponent(ctx context.Context, profile sdk.ProfileMetadata, loggedUser string) HTMLComponent {
|
|
||||||
button := Span("")
|
|
||||||
if isAncestorOf(loggedUser, profile.PubKey) && loggedUser != "" {
|
|
||||||
button = Button("remove").
|
|
||||||
Class(buttonClass+" px-2 bg-red-100 hover:bg-red-300").
|
|
||||||
Attr(
|
|
||||||
"hx-post", "/remove-from-whitelist",
|
|
||||||
"hx-trigger", "click",
|
|
||||||
"hx-target", "#tree",
|
|
||||||
"hx-vals", `{"pubkey": "`+profile.PubKey+`"}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Li(
|
|
||||||
userNameComponent(profile),
|
|
||||||
button,
|
|
||||||
inviteTreeComponent(ctx, profile.PubKey, loggedUser),
|
|
||||||
).Class("ml-6")
|
|
||||||
}
|
|
||||||
|
|
||||||
func userNameComponent(profile sdk.ProfileMetadata) HTMLComponent {
|
|
||||||
return A().Href("https://nosta.me/" + profile.Npub()).Target("_blank").Children(
|
|
||||||
Span(profile.ShortName()).Attr("title", profile.Npub()),
|
|
||||||
).Class("font-mono py-1")
|
|
||||||
}
|
|
76
go.mod
76
go.mod
@ -1,50 +1,58 @@
|
|||||||
module github.com/github-tijlxyz/khatru-pyramid
|
module github.com/github-tijlxyz/khatru-pyramid
|
||||||
|
|
||||||
go 1.23.0
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fiatjaf/eventstore v0.8.2
|
github.com/a-h/templ v0.3.857
|
||||||
github.com/fiatjaf/khatru v0.8.1
|
github.com/fiatjaf/eventstore v0.16.4
|
||||||
|
github.com/fiatjaf/khatru v0.17.7
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
github.com/nbd-wtf/go-nostr v0.35.0
|
github.com/nbd-wtf/go-nostr v0.51.10
|
||||||
github.com/nbd-wtf/nostr-sdk v0.1.0
|
github.com/rs/zerolog v1.33.0
|
||||||
github.com/rs/zerolog v1.31.0
|
golang.org/x/sync v0.13.0
|
||||||
github.com/theplant/htmlgo v1.0.3
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PowerDNS/lmdb-go v1.9.2 // indirect
|
fiatjaf.com/lib v0.2.0 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/FastFilter/xorfilter v0.2.1 // indirect
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
github.com/ImVexed/fasturl v0.0.0-20230304231329-4e41488060f3 // indirect
|
||||||
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
|
github.com/PowerDNS/lmdb-go v1.9.3 // indirect
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
|
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
github.com/btcsuite/btcd/btcutil v1.1.5 // indirect
|
||||||
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
|
||||||
|
github.com/bytedance/sonic v1.13.2 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
|
github.com/coder/websocket v1.8.13 // indirect
|
||||||
|
github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||||
|
github.com/dgraph-io/ristretto v1.0.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fasthttp/websocket v1.5.7 // indirect
|
github.com/fasthttp/websocket v1.5.12 // indirect
|
||||||
github.com/fiatjaf/generic-ristretto v0.0.1 // indirect
|
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
|
||||||
github.com/gobwas/ws v1.3.1 // indirect
|
|
||||||
github.com/golang/glog v1.1.2 // indirect
|
|
||||||
github.com/graph-gophers/dataloader/v7 v7.1.0 // indirect
|
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
|
||||||
github.com/rs/cors v1.7.0 // indirect
|
github.com/rs/cors v1.11.1 // indirect
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||||
github.com/tidwall/gjson v1.17.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
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
github.com/valyala/fasthttp v1.60.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
golang.org/x/arch v0.16.0 // indirect
|
||||||
golang.org/x/net v0.18.0 // indirect
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
)
|
)
|
||||||
|
181
go.sum
181
go.sum
@ -1,23 +1,33 @@
|
|||||||
github.com/PowerDNS/lmdb-go v1.9.2 h1:Cmgerh9y3ZKBZGz1irxSShhfmFyRUh+Zdk4cZk7ZJvU=
|
fiatjaf.com/lib v0.2.0 h1:TgIJESbbND6GjOgGHxF5jsO6EMjuAxIzZHPo5DXYexs=
|
||||||
github.com/PowerDNS/lmdb-go v1.9.2/go.mod h1:TE0l+EZK8Z1B4dx070ZxkWTlp8RG1mjN0/+FkFRQMtU=
|
fiatjaf.com/lib v0.2.0/go.mod h1:Ycqq3+mJ9jAWu7XjbQI1cVr+OFgnHn79dQR5oTII47g=
|
||||||
|
github.com/FastFilter/xorfilter v0.2.1 h1:lbdeLG9BdpquK64ZsleBS8B4xO/QW1IM0gMzF7KaBKc=
|
||||||
|
github.com/FastFilter/xorfilter v0.2.1/go.mod h1:aumvdkhscz6YBZF9ZA/6O4fIoNod4YR50kIVGGZ7l9I=
|
||||||
|
github.com/ImVexed/fasturl v0.0.0-20230304231329-4e41488060f3 h1:ClzzXMDDuUbWfNNZqGeYq4PnYOlwlOVIvSyNaIy0ykg=
|
||||||
|
github.com/ImVexed/fasturl v0.0.0-20230304231329-4e41488060f3/go.mod h1:we0YA5CsBbH5+/NUzC/AlMmxaDtWlXeNsqrwXjTzmzA=
|
||||||
|
github.com/PowerDNS/lmdb-go v1.9.3 h1:AUMY2pZT8WRpkEv39I9Id3MuoHd+NZbTVpNhruVkPTg=
|
||||||
|
github.com/PowerDNS/lmdb-go v1.9.3/go.mod h1:TE0l+EZK8Z1B4dx070ZxkWTlp8RG1mjN0/+FkFRQMtU=
|
||||||
|
github.com/a-h/templ v0.3.857 h1:6EqcJuGZW4OL+2iZ3MD+NnIcG7nGkaQeF2Zq5kf9ZGg=
|
||||||
|
github.com/a-h/templ v0.3.857/go.mod h1:qhrhAkRFubE7khxLZHsBFHfX+gWwVNKbzKeF9GlPV4M=
|
||||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
||||||
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
|
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
|
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
|
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||||
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
|
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
|
||||||
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
|
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
|
||||||
github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ=
|
github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
|
||||||
github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0=
|
github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||||
@ -27,43 +37,48 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
|
|||||||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||||
|
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
||||||
|
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4=
|
github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||||
github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
|
github.com/fasthttp/websocket v1.5.12 h1:e4RGPpWW2HTbL3zV0Y/t7g0ub294LkiuXXUuTOUInlE=
|
||||||
github.com/fiatjaf/eventstore v0.8.2 h1:nCa3UuJNV5Y5t+SDoPQe7PBmKJ6dhm9TQ/WyR4SCbIM=
|
github.com/fasthttp/websocket v1.5.12/go.mod h1:I+liyL7/4moHojiOgUOIKEWm9EIxHqxZChS+aMFltyg=
|
||||||
github.com/fiatjaf/eventstore v0.8.2/go.mod h1:ck3RxufitHUBjID1RLcRxfX+NMywQzMsdfNpSt6m+9U=
|
github.com/fiatjaf/eventstore v0.16.4 h1:pENYeuhawxMxlJk8HpRy3pb2oap0fwbphzUgsy7QPws=
|
||||||
github.com/fiatjaf/generic-ristretto v0.0.1 h1:LUJSU87X/QWFsBXTwnH3moFe4N8AjUxT+Rfa0+bo6YM=
|
github.com/fiatjaf/eventstore v0.16.4/go.mod h1:0gU8fzYO/bG+NQAVlHtJWOlt3JKKFefh5Xjj2d1dLIs=
|
||||||
github.com/fiatjaf/generic-ristretto v0.0.1/go.mod h1:cvV6ANHDA/GrfzVrig7N7i6l8CWnkVZvtQ2/wk9DPVE=
|
github.com/fiatjaf/khatru v0.17.7 h1:1NB2qe/KPF2hIrlzrZOXHj4xIQsulJw1mVlFXYzmhkk=
|
||||||
github.com/fiatjaf/khatru v0.8.1 h1:BWAZqwuT0272ZlyzPkuqAA0eGBOs5G3u0Dn1tlWrm6Q=
|
github.com/fiatjaf/khatru v0.17.7/go.mod h1:4KW6mom+7ajwrhj5IvLJTBKj6peV8bdZjU6XoDVrX2Q=
|
||||||
github.com/fiatjaf/khatru v0.8.1/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
|
|
||||||
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/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
|
||||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
|
||||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
|
||||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
@ -75,30 +90,42 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
|||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/graph-gophers/dataloader/v7 v7.1.0 h1:Wn8HGF/q7MNXcvfaBnLEPEFJttVHR8zuEqP1obys/oc=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/graph-gophers/dataloader/v7 v7.1.0/go.mod h1:1bKE0Dm6OUcTB/OAuYVOZctgIz7Q3d0XrYtlIzTgg6Q=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/nbd-wtf/go-nostr v0.35.0 h1:oINIBr5XE1kowkaz7NXC5vLvj2jUWH6xlzJjChpgV6Q=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/nbd-wtf/go-nostr v0.35.0/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/nbd-wtf/nostr-sdk v0.1.0 h1:uhWH9qzJx4HXp7b/mvPhAxwN5v9pXl4Mb6QFlX0ty7k=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/nbd-wtf/nostr-sdk v0.1.0/go.mod h1:A1dWNqcqw/ZxDhcNpCc+y2u9mMTkWEh0dD11QEKrMNE=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/nbd-wtf/go-nostr v0.51.10 h1:MxyN/bRNqdeLbiN9lODbXduLRkYwy7SDTm73uGrsdU4=
|
||||||
|
github.com/nbd-wtf/go-nostr v0.51.10/go.mod h1:IF30/Cm4AS90wd1GjsFJbBqq7oD1txo+2YUFYXqK3Nc=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
@ -112,50 +139,59 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
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.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
github.com/rs/zerolog v1.31.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-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||||
github.com/theplant/htmlgo v1.0.3 h1:G7/YSf8OrOIRHVQ13avd78T/GV1kDl/jMwpQURrXB0o=
|
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||||
github.com/theplant/htmlgo v1.0.3/go.mod h1:pCKSFJsoVNkyW+yN2i1Mst+8130NSQzIU7L2IbnuyKg=
|
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/theplant/testingutils v0.0.0-20190603093022-26d8b4d95c61 h1:757/ruZNgTsOf5EkQBo0i3Bx/P2wgF5ljVkODeUX/uA=
|
|
||||||
github.com/theplant/testingutils v0.0.0-20190603093022-26d8b4d95c61/go.mod h1:p22Q3Bg5ML+hdI3QSQkB/pZ2+CjfOnGugoQIoyE2Ub8=
|
|
||||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
|
||||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw=
|
||||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc=
|
||||||
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
|
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||||
|
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
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.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
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.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -168,8 +204,8 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -191,3 +227,4 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
84
handler.go
84
handler.go
@ -6,14 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
"github.com/theplant/htmlgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func inviteTreeHandler(w http.ResponseWriter, r *http.Request) {
|
func inviteTreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
content := inviteTreePageHTML(r.Context(), InviteTreePageParams{
|
loggedUser := getLoggedUser(r)
|
||||||
loggedUser: getLoggedUser(r),
|
inviteTreePage(loggedUser).Render(r.Context(), w)
|
||||||
})
|
|
||||||
htmlgo.Fprint(w, baseHTML(content), r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -24,7 +21,7 @@ func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
pubkey = value.(string)
|
pubkey = value.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if loggedUser != s.RelayPubkey && hasInvitedAtLeast(loggedUser, s.MaxInvitesPerPerson) {
|
if !canInviteMore(loggedUser) {
|
||||||
http.Error(w, fmt.Sprintf("cannot invite more than %d", s.MaxInvitesPerPerson), 403)
|
http.Error(w, fmt.Sprintf("cannot invite more than %d", s.MaxInvitesPerPerson), 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -34,8 +31,7 @@ func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := inviteTreeComponent(r.Context(), "", loggedUser)
|
inviteTreeComponent("", loggedUser).Render(r.Context(), w)
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -45,8 +41,42 @@ func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "failed to remove from whitelist: "+err.Error(), 500)
|
http.Error(w, "failed to remove from whitelist: "+err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content := inviteTreeComponent(r.Context(), "", loggedUser)
|
inviteTreeComponent("", loggedUser).Render(r.Context(), w)
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
}
|
||||||
|
|
||||||
|
// this deletes all events from users not in the relay anymore
|
||||||
|
func cleanupStuffFromExcludedUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
loggedUser := getLoggedUser(r)
|
||||||
|
if loggedUser != s.RelayPubkey {
|
||||||
|
http.Error(w, "unauthorized, only the relay owner can do this", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oldLimit := db.MaxLimit
|
||||||
|
db.MaxLimit = 999999
|
||||||
|
ch, err := db.QueryEvents(r.Context(), nostr.Filter{Limit: db.MaxLimit})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "failed to query", 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
db.MaxLimit = oldLimit
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
for evt := range ch {
|
||||||
|
if isPublicKeyInWhitelist(evt.PubKey) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.DeleteEvent(r.Context(), evt); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(
|
||||||
|
"failed to delete %s: %s -- stopping, %d events were deleted before this error", evt, err, count), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "deleted %d events", count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -59,9 +89,33 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := reportsPageHTML(r.Context(), ReportsPageParams{
|
reportsPage(events, getLoggedUser(r)).Render(r.Context(), w)
|
||||||
reports: events,
|
}
|
||||||
loggedUser: getLoggedUser(r),
|
|
||||||
})
|
func joubleHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
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>
|
||||||
|
`)
|
||||||
}
|
}
|
||||||
|
63
invite_tree.templ
Normal file
63
invite_tree.templ
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ inviteTreePage(loggedUser string) {
|
||||||
|
@layout(loggedUser) {
|
||||||
|
<div>
|
||||||
|
if canInviteMore(loggedUser) {
|
||||||
|
<form
|
||||||
|
hx-post="/add-to-whitelist"
|
||||||
|
hx-trigger="submit"
|
||||||
|
hx-target="#tree"
|
||||||
|
_="on htmx:afterRequest(elt, successful) if successful and elt is I call I.reset()"
|
||||||
|
class="flex justify-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="pubkey"
|
||||||
|
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
|
||||||
|
type="submit"
|
||||||
|
class="rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 ml-2 p-2 bg-white hover:bg-gray-50"
|
||||||
|
>
|
||||||
|
invite
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
<div id="tree" class="mt-3 flex justify-center">
|
||||||
|
@inviteTreeComponent("", loggedUser)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ inviteTreeComponent(inviter string, loggedUser string) {
|
||||||
|
<ul>
|
||||||
|
for pubkey, invitedBy := range whitelist {
|
||||||
|
if invitedBy == inviter {
|
||||||
|
<li class="ml-6">
|
||||||
|
<a href={ templ.URL("https://njump.me/p/" + pubkey) } target="_blank" class="font-mono py-1">
|
||||||
|
<nostr-name pubkey={ pubkey }>{ pubkey }</nostr-name>
|
||||||
|
</a>
|
||||||
|
if isAncestorOf(loggedUser, pubkey) && loggedUser != "" {
|
||||||
|
<button
|
||||||
|
class="rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 px-2 ml-2 bg-red-100 hover:bg-red-300"
|
||||||
|
hx-post="/remove-from-whitelist"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#tree"
|
||||||
|
hx-vals={ fmt.Sprintf(`{"pubkey": "%s"}`, pubkey) }
|
||||||
|
>
|
||||||
|
remove
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@inviteTreeComponent(pubkey, loggedUser)
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
7
justfile
7
justfile
@ -1,9 +1,12 @@
|
|||||||
dev:
|
dev:
|
||||||
ag -l --go | entr -r godotenv go run .
|
fd 'go|templ' | entr -r bash -c 'just templ && godotenv go run .'
|
||||||
|
|
||||||
build:
|
build: templ
|
||||||
CC=musl-gcc go build -ldflags='-linkmode external -extldflags "-static"' -o ./khatru-pyramid
|
CC=musl-gcc go build -ldflags='-linkmode external -extldflags "-static"' -o ./khatru-pyramid
|
||||||
|
|
||||||
|
templ:
|
||||||
|
templ generate
|
||||||
|
|
||||||
deploy target: build
|
deploy target: build
|
||||||
ssh root@{{target}} 'systemctl stop pyramid';
|
ssh root@{{target}} 'systemctl stop pyramid';
|
||||||
scp khatru-pyramid {{target}}:pyramid/khatru-invite
|
scp khatru-pyramid {{target}}:pyramid/khatru-invite
|
||||||
|
BIN
khatru-invite
Executable file
BIN
khatru-invite
Executable file
Binary file not shown.
60
layout.templ
Normal file
60
layout.templ
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
templ layout(loggedUser string) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<title>{ s.RelayName }</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/htmx.org@1.9.12/dist/htmx.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/hyperscript.org@0.9.14/dist/_hyperscript.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/nostr-web-components@0.0.12/dist/nostr-name.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="px-3 mx-auto">
|
||||||
|
<div class="mx-auto my-6 text-center">
|
||||||
|
<h1 class="font-bold text-2xl">{ s.RelayName }</h1>
|
||||||
|
if s.RelayDescription != "" {
|
||||||
|
<p class="text-lg">{ s.RelayDescription }</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<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="/browse" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">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>
|
||||||
|
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="#"
|
||||||
|
class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium"
|
||||||
|
_={ `
|
||||||
|
on click if my innerText is equal to 'login'
|
||||||
|
get window.nostr.signEvent({created_at: Math.round(Date.now()/1000), kind: 27235, tags: [['domain', '`+ s.Domain+ `']], content: ''})
|
||||||
|
then get JSON.stringify(it)
|
||||||
|
then set cookies['nip98'] to it
|
||||||
|
otherwise
|
||||||
|
call cookies.clear('nip98')
|
||||||
|
end
|
||||||
|
then call location.reload()
|
||||||
|
` }
|
||||||
|
>
|
||||||
|
if loggedUser != "" {
|
||||||
|
logout
|
||||||
|
} else {
|
||||||
|
login
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
<main class="m-4">
|
||||||
|
{ children... }
|
||||||
|
</main>
|
||||||
|
<p class="text-end my-4 text-sm">
|
||||||
|
powered by
|
||||||
|
<a href="https://github.com/github-tijlxyz/khatru-pyramid" class="hover:underline cursor-pointer text-blue-500">khatru-pyramid</a>
|
||||||
|
</p>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/window.nostr.js@0.4.7/dist/window.nostr.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
40
main.go
40
main.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -35,12 +36,26 @@ type Settings struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
s Settings
|
s Settings
|
||||||
db = lmdb.LMDBBackend{MaxLimit: 500}
|
db = &lmdb.LMDBBackend{
|
||||||
|
MaxLimit: 500,
|
||||||
|
MaxLimitNegentropy: 999999,
|
||||||
|
EnableHLLCacheFor: func(kind int) (useCache bool, skipSavingActualEvent bool) {
|
||||||
|
switch kind {
|
||||||
|
case 7:
|
||||||
|
return true, true
|
||||||
|
default:
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
|
log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
|
||||||
whitelist = make(Whitelist)
|
whitelist = make(Whitelist)
|
||||||
relay = khatru.NewRelay()
|
relay = khatru.NewRelay()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed static/*
|
||||||
|
var static embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := envconfig.Process("", &s)
|
err := envconfig.Process("", &s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,7 +63,8 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.Init()
|
// enable negentropy
|
||||||
|
relay.Negentropy = true
|
||||||
|
|
||||||
// load db
|
// load db
|
||||||
db.Path = s.DatabasePath
|
db.Path = s.DatabasePath
|
||||||
@ -74,12 +90,14 @@ func main() {
|
|||||||
|
|
||||||
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)
|
||||||
|
relay.CountEventsHLL = append(relay.CountEventsHLL, db.CountEventsHLL)
|
||||||
|
relay.ReplaceEvent = append(relay.ReplaceEvent, db.ReplaceEvent)
|
||||||
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
||||||
relay.RejectEvent = append(relay.RejectEvent,
|
relay.RejectEvent = append(relay.RejectEvent,
|
||||||
policies.PreventLargeTags(100),
|
policies.PreventLargeTags(100),
|
||||||
policies.PreventTooManyIndexableTags(8, []int{3, 10002}, nil),
|
policies.PreventTooManyIndexableTags(9, []int{3}, nil),
|
||||||
policies.PreventTooManyIndexableTags(1000, nil, []int{3, 10002}),
|
policies.PreventTooManyIndexableTags(1200, nil, []int{3}),
|
||||||
policies.RestrictToSpecifiedKinds(supportedKinds...),
|
policies.RestrictToSpecifiedKinds(true, supportedKinds...),
|
||||||
rejectEventsFromUsersNotInWhitelist,
|
rejectEventsFromUsersNotInWhitelist,
|
||||||
validateAndFilterReports,
|
validateAndFilterReports,
|
||||||
)
|
)
|
||||||
@ -104,7 +122,17 @@ func main() {
|
|||||||
// http routes
|
// http routes
|
||||||
relay.Router().HandleFunc("/add-to-whitelist", addToWhitelistHandler)
|
relay.Router().HandleFunc("/add-to-whitelist", addToWhitelistHandler)
|
||||||
relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler)
|
relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler)
|
||||||
|
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().HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if s.RelayIcon != "" {
|
||||||
|
http.Redirect(w, r, s.RelayIcon, 302)
|
||||||
|
} else {
|
||||||
|
http.Redirect(w, r, "/static/icon.png", 302)
|
||||||
|
}
|
||||||
|
})
|
||||||
relay.Router().HandleFunc("/", inviteTreeHandler)
|
relay.Router().HandleFunc("/", inviteTreeHandler)
|
||||||
|
|
||||||
log.Info().Msg("running on http://0.0.0.0:" + s.Port)
|
log.Info().Msg("running on http://0.0.0.0:" + s.Port)
|
||||||
@ -128,7 +156,7 @@ func getLoggedUser(r *http.Request) string {
|
|||||||
if evtj, err := url.QueryUnescape(cookie.Value); err == nil {
|
if evtj, err := url.QueryUnescape(cookie.Value); err == nil {
|
||||||
var evt nostr.Event
|
var evt nostr.Event
|
||||||
if err := json.Unmarshal([]byte(evtj), &evt); err == nil {
|
if err := json.Unmarshal([]byte(evtj), &evt); err == nil {
|
||||||
if tag := evt.Tags.GetFirst([]string{"domain", ""}); tag != nil && (*tag)[1] == s.Domain {
|
if tag := evt.Tags.Find("domain"); tag != nil && tag[1] == s.Domain {
|
||||||
if ok, _ := evt.CheckSignature(); ok {
|
if ok, _ := evt.CheckSignature(); ok {
|
||||||
return evt.PubKey
|
return evt.PubKey
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func allowPubKeyHandler(ctx context.Context, pubkey, reason string) error {
|
func allowPubKeyHandler(ctx context.Context, pubkey, reason string) error {
|
||||||
loggedUser := khatru.GetAuthed(ctx)
|
loggedUser := khatru.GetAuthed(ctx)
|
||||||
|
|
||||||
if loggedUser != s.RelayPubkey && hasInvitedAtLeast(loggedUser, s.MaxInvitesPerPerson) {
|
if !canInviteMore(loggedUser) {
|
||||||
return fmt.Errorf("cannot invite more than %d", s.MaxInvitesPerPerson)
|
return fmt.Errorf("cannot invite more than %d", s.MaxInvitesPerPerson)
|
||||||
}
|
}
|
||||||
if err := addToWhitelist(pubkey, loggedUser); err != nil {
|
if err := addToWhitelist(pubkey, loggedUser); err != nil {
|
||||||
|
19
nostr.go
19
nostr.go
@ -1,20 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
sdk "github.com/nbd-wtf/go-nostr/sdk"
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
|
||||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
|
||||||
cache_memory "github.com/nbd-wtf/nostr-sdk/cache/memory"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var sys = sdk.System{
|
var sys = sdk.NewSystem(
|
||||||
Pool: nostr.NewSimplePool(context.Background()),
|
sdk.WithStore(db),
|
||||||
RelaysCache: cache_memory.New32[[]sdk.Relay](1000),
|
)
|
||||||
MetadataCache: cache_memory.New32[sdk.ProfileMetadata](1000),
|
|
||||||
FollowsCache: cache_memory.New32[[]sdk.Follow](1),
|
|
||||||
RelayListRelays: []string{"wss://purplepag.es", "wss://relay.nostr.band"},
|
|
||||||
FollowListRelays: []string{"wss://public.relaying.io", "wss://nos.lol"},
|
|
||||||
MetadataRelays: []string{"wss://nostr-pub.wellorder.net", "wss://purplepag.es", "wss://relay.noswhere.com"},
|
|
||||||
Store: &db,
|
|
||||||
}
|
|
||||||
|
140
pages.go
140
pages.go
@ -1,140 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
|
||||||
. "github.com/theplant/htmlgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
const buttonClass = "rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300"
|
|
||||||
|
|
||||||
func baseHTML(inside HTMLComponent) HTMLComponent {
|
|
||||||
navItemClass := "text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium"
|
|
||||||
|
|
||||||
return HTML(
|
|
||||||
Head(
|
|
||||||
Meta().Charset("utf-8"),
|
|
||||||
Meta().Name("viewport").Content("width=device-width, initial-scale=1"),
|
|
||||||
Title(s.RelayName),
|
|
||||||
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(
|
|
||||||
Div(
|
|
||||||
H1(s.RelayName).Class("font-bold text-2xl"),
|
|
||||||
P().Text(s.RelayDescription).Class("text-lg"),
|
|
||||||
).Class("mx-auto my-6 text-center"),
|
|
||||||
Nav(
|
|
||||||
A().Text("invite tree").Href("/").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
|
||||||
A().Text("reports").Href("/reports").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
|
||||||
A().Text("").Href("#").Class(navItemClass).
|
|
||||||
Attr("_", `
|
|
||||||
on click if my innerText is equal to "login" get window.nostr.signEvent({created_at: Math.round(Date.now()/1000), kind: 27235, tags: [['domain', "`+s.Domain+`"]], content: ''}) then get JSON.stringify(it) then set cookies['nip98'] to it otherwise call cookies.clear('nip98') end then call location.reload()
|
|
||||||
|
|
||||||
on load get cookies['nip98'] then if it is undefined set my innerText to "login" otherwise set my innerText to "logout"`),
|
|
||||||
).Class("flex flex-1 items-center justify-center"),
|
|
||||||
Main(inside).Class("m-4"),
|
|
||||||
P(
|
|
||||||
Text("powered by "),
|
|
||||||
A().Href("https://github.com/github-tijlxyz/khatru-pyramid").Text("khatru-pyramid").Class("hover:underline cursor-pointer text-blue-500"),
|
|
||||||
).Class("text-end my-4 text-sm"),
|
|
||||||
).Class("my-6 mx-auto max-w-min min-w-96"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InviteTreePageParams struct {
|
|
||||||
loggedUser string
|
|
||||||
}
|
|
||||||
|
|
||||||
func inviteTreePageHTML(ctx context.Context, params InviteTreePageParams) HTMLComponent {
|
|
||||||
inviteForm := Div()
|
|
||||||
|
|
||||||
if params.loggedUser != "" && (params.loggedUser == s.RelayPubkey || !hasInvitedAtLeast(params.loggedUser, s.MaxInvitesPerPerson)) {
|
|
||||||
inviteForm = Form(
|
|
||||||
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").Class(buttonClass+" ml-2 p-2 bg-white hover:bg-gray-50"),
|
|
||||||
).Attr(
|
|
||||||
"hx-post", "/add-to-whitelist",
|
|
||||||
"hx-trigger", "submit",
|
|
||||||
"hx-target", "#tree",
|
|
||||||
"_", "on htmx:afterRequest(elt, successful) if successful and elt is I call I.reset()",
|
|
||||||
).Class("flex")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Div(
|
|
||||||
inviteForm,
|
|
||||||
Div(
|
|
||||||
inviteTreeComponent(ctx, "", params.loggedUser),
|
|
||||||
).Id("tree").Class("mt-3"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReportsPageParams struct {
|
|
||||||
reports chan *nostr.Event
|
|
||||||
loggedUser string
|
|
||||||
}
|
|
||||||
|
|
||||||
func reportsPageHTML(ctx context.Context, params ReportsPageParams) HTMLComponent {
|
|
||||||
items := make([]HTMLComponent, 0, 52)
|
|
||||||
for report := range params.reports {
|
|
||||||
var primaryType string
|
|
||||||
var secondaryType string
|
|
||||||
var relatedContent HTMLComponent
|
|
||||||
|
|
||||||
if e := report.Tags.GetFirst([]string{"e", ""}); e != nil {
|
|
||||||
// event report
|
|
||||||
res, _ := sys.StoreRelay().QuerySync(ctx, nostr.Filter{IDs: []string{(*e)[1]}})
|
|
||||||
if len(res) == 0 {
|
|
||||||
sys.Store.DeleteEvent(ctx, report)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*e) >= 3 {
|
|
||||||
primaryType = (*e)[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
relatedEvent := res[0]
|
|
||||||
relatedContent = Div(
|
|
||||||
Text("event reported: "),
|
|
||||||
Div().Text(relatedEvent.String()).Class("text-mono"),
|
|
||||||
)
|
|
||||||
} else if p := report.Tags.GetFirst([]string{"p", ""}); p != nil {
|
|
||||||
// pubkey report
|
|
||||||
if !isPublicKeyInWhitelist((*p)[1]) {
|
|
||||||
sys.Store.DeleteEvent(ctx, report)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*p) >= 3 {
|
|
||||||
primaryType = (*p)[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
relatedProfile := sys.FetchOrStoreProfileMetadata(ctx, (*p)[1])
|
|
||||||
relatedContent = Div(
|
|
||||||
Text("profile reported: "),
|
|
||||||
userNameComponent(relatedProfile),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter := sys.FetchProfileMetadata(ctx, report.PubKey)
|
|
||||||
report := Div(
|
|
||||||
Div(Span(primaryType).Class("font-semibold"), Text(" report")).Class("font-lg"),
|
|
||||||
Div().Text(secondaryType),
|
|
||||||
Div(Text("by "), userNameComponent(reporter)),
|
|
||||||
Div().Text(report.Content).Class("p-3"),
|
|
||||||
relatedContent,
|
|
||||||
)
|
|
||||||
|
|
||||||
items = append(items, report)
|
|
||||||
}
|
|
||||||
return baseHTML(
|
|
||||||
Div(
|
|
||||||
H1("reports received").Class("text-xl p-4"),
|
|
||||||
Div(items...),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
29
relay.go
29
relay.go
@ -10,7 +10,7 @@ func rejectEventsFromUsersNotInWhitelist(ctx context.Context, event *nostr.Event
|
|||||||
if isPublicKeyInWhitelist(event.PubKey) {
|
if isPublicKeyInWhitelist(event.PubKey) {
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
if event.Kind == 1985 {
|
if event.Kind == 1984 {
|
||||||
// we accept reports from anyone (will filter them for relevance in the next function)
|
// we accept reports from anyone (will filter them for relevance in the next function)
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
@ -23,14 +23,25 @@ var supportedKinds = []uint16{
|
|||||||
3,
|
3,
|
||||||
5,
|
5,
|
||||||
6,
|
6,
|
||||||
|
7,
|
||||||
8,
|
8,
|
||||||
|
9,
|
||||||
|
11,
|
||||||
16,
|
16,
|
||||||
|
20,
|
||||||
|
21,
|
||||||
|
22,
|
||||||
818,
|
818,
|
||||||
1040,
|
1040,
|
||||||
1063,
|
1063,
|
||||||
|
1111,
|
||||||
1984,
|
1984,
|
||||||
1985,
|
1985,
|
||||||
|
7375,
|
||||||
|
7376,
|
||||||
|
9321,
|
||||||
9735,
|
9735,
|
||||||
|
9802,
|
||||||
10000,
|
10000,
|
||||||
10001,
|
10001,
|
||||||
10002,
|
10002,
|
||||||
@ -39,10 +50,14 @@ var supportedKinds = []uint16{
|
|||||||
10005,
|
10005,
|
||||||
10006,
|
10006,
|
||||||
10007,
|
10007,
|
||||||
|
10009,
|
||||||
10015,
|
10015,
|
||||||
|
10019,
|
||||||
|
10030,
|
||||||
|
10050,
|
||||||
10101,
|
10101,
|
||||||
10102,
|
10102,
|
||||||
10030,
|
17375,
|
||||||
24133,
|
24133,
|
||||||
30000,
|
30000,
|
||||||
30002,
|
30002,
|
||||||
@ -63,16 +78,16 @@ var supportedKinds = []uint16{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateAndFilterReports(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
|
func validateAndFilterReports(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
|
||||||
if event.Kind == 1985 {
|
if event.Kind == 1984 {
|
||||||
if e := event.Tags.GetFirst([]string{"e", ""}); e != nil {
|
if e := event.Tags.Find("e"); e != nil {
|
||||||
// event report: check if the target event is here
|
// event report: check if the target event is here
|
||||||
res, _ := sys.StoreRelay().QuerySync(ctx, nostr.Filter{IDs: []string{(*e)[1]}})
|
res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{e[1]}})
|
||||||
if len(res) == 0 {
|
if len(res) == 0 {
|
||||||
return true, "we don't know anything about the target event"
|
return true, "we don't know anything about the target event"
|
||||||
}
|
}
|
||||||
} else if p := event.Tags.GetFirst([]string{"p", ""}); p != nil {
|
} else if p := event.Tags.Find("p"); p != nil {
|
||||||
// pubkey report
|
// pubkey report
|
||||||
if !isPublicKeyInWhitelist((*p)[1]) {
|
if !isPublicKeyInWhitelist(p[1]) {
|
||||||
return true, "target pubkey is not a user of this relay"
|
return true, "target pubkey is not a user of this relay"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
66
reports.templ
Normal file
66
reports.templ
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/nbd-wtf/go-nostr"
|
||||||
|
|
||||||
|
templ reportsPage(reports chan *nostr.Event, loggedUser string) {
|
||||||
|
@layout(loggedUser) {
|
||||||
|
<div>
|
||||||
|
<h1 class="text-xl p-4">reports received</h1>
|
||||||
|
<div>
|
||||||
|
for report := range reports {
|
||||||
|
<div>
|
||||||
|
if e := report.Tags.Find("e"); e != nil {
|
||||||
|
@eventReportComponent(e, report)
|
||||||
|
} else if p := report.Tags.Find("p"); p != nil {
|
||||||
|
@profileReportComponent(p, report)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ eventReportComponent(e nostr.Tag, report *nostr.Event) {
|
||||||
|
if res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{e[1]}}); len(res) > 0 {
|
||||||
|
<div>
|
||||||
|
<div class="font-lg">
|
||||||
|
<span class="font-semibold">
|
||||||
|
if len(e) >= 3 {
|
||||||
|
{ e[2] }
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
{ " report" }
|
||||||
|
</div>
|
||||||
|
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div>
|
||||||
|
<div class="p-3">{ report.Content }</div>
|
||||||
|
<div>
|
||||||
|
event reported:
|
||||||
|
<div class="text-mono">{ res[0].String() }</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ profileReportComponent(p nostr.Tag, report *nostr.Event) {
|
||||||
|
if isPublicKeyInWhitelist(p[1]) {
|
||||||
|
<div>
|
||||||
|
<div class="font-lg">
|
||||||
|
<span class="font-semibold">
|
||||||
|
if len(p) >= 3 {
|
||||||
|
{ p[2] }
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
{ " report" }
|
||||||
|
</div>
|
||||||
|
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div>
|
||||||
|
<div class="p-3">{ report.Content }</div>
|
||||||
|
<div>
|
||||||
|
profile reported:
|
||||||
|
<a href={ templ.URL("https://njump.me/p/" + report.PubKey) } target="_blank" class="font-mono py-1">
|
||||||
|
<nostr-name pubkey={ report.PubKey }>{ report.PubKey }</nostr-name>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
BIN
static/icon.png
Normal file
BIN
static/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
26
whitelist.go
26
whitelist.go
@ -33,17 +33,29 @@ func isPublicKeyInWhitelist(pubkey string) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasInvitedAtLeast(ancestor string, target int) bool {
|
func canInviteMore(pubkey string) bool {
|
||||||
count := 0
|
if pubkey == "" {
|
||||||
for _, inviter := range whitelist {
|
return false
|
||||||
if inviter == ancestor {
|
|
||||||
count++
|
|
||||||
}
|
}
|
||||||
if count >= target {
|
|
||||||
|
if pubkey == s.RelayPubkey {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if !isPublicKeyInWhitelist(pubkey) {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for _, inviter := range whitelist {
|
||||||
|
if inviter == pubkey {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if count >= s.MaxInvitesPerPerson {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAncestorOf(ancestor string, target string) bool {
|
func isAncestorOf(ancestor string, target string) bool {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user