mirror of
https://github.com/github-tijlxyz/khatru-pyramid.git
synced 2025-04-19 18:31:18 +00:00
init
This commit is contained in:
commit
e47ed79135
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
whitelist.json
|
||||
khatru-invite
|
46
go.mod
Normal file
46
go.mod
Normal file
@ -0,0 +1,46 @@
|
||||
module github.com/github-tijlxyz/khatru-invite
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/fiatjaf/khatru v0.0.2
|
||||
github.com/nbd-wtf/go-nostr v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/dgraph-io/badger/v4 v4.1.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fasthttp/websocket v1.5.3 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.2.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/flatbuffers v1.12.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/puzpuzpuz/xsync v1.5.2 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.47.0 // indirect
|
||||
go.opencensus.io v0.22.5 // indirect
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
149
go.sum
Normal file
149
go.sum
Normal file
@ -0,0 +1,149 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/dgraph-io/badger/v4 v4.1.0 h1:E38jc0f+RATYrycSUf9LMv/t47XAy+3CApyYSq4APOQ=
|
||||
github.com/dgraph-io/badger/v4 v4.1.0/go.mod h1:P50u28d39ibBRmIJuQC/NSdBOg46HnHw7al2SW5QRHg=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
|
||||
github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
|
||||
github.com/fiatjaf/khatru v0.0.2 h1:+OaARQhrColJG1NypLDWgkaERjJhbLAtUk8RIYETeGU=
|
||||
github.com/fiatjaf/khatru v0.0.2/go.mod h1:XDX+UIURFlTrAAw/ya7M5YRC4ft2Qm2gAAvs3ELoVps=
|
||||
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.2.0 h1:u0p9s3xLYpZCA1z5JgCkMeB34CKCMMQbM+G8Ii7YD0I=
|
||||
github.com/gobwas/ws v1.2.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
|
||||
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/nbd-wtf/go-nostr v0.20.0 h1:97SYhg68jWh5G1bW1g454hA0dTV7btwtPg836n4no0o=
|
||||
github.com/nbd-wtf/go-nostr v0.20.0/go.mod h1:iFfiZr8YYSC1vmdUei0VfDB7GH/RjS3cbmiD1I5BKyo=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/puzpuzpuz/xsync v1.5.2 h1:yRAP4wqSOZG+/4pxJ08fPTwrfL0IzE/LKQ/cw509qGY=
|
||||
github.com/puzpuzpuz/xsync v1.5.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
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/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
|
||||
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
20
handler.go
Normal file
20
handler.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func inviteDataApiHandler(w http.ResponseWriter, re *http.Request) {
|
||||
jsonBytes, err := json.Marshal(whitelist)
|
||||
if err != nil {
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := w.Write(jsonBytes); err != nil {
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
71
main.go
Normal file
71
main.go
Normal file
@ -0,0 +1,71 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fiatjaf/khatru"
|
||||
"github.com/fiatjaf/khatru/plugins/storage/badgern"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 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 relay
|
||||
relay := khatru.NewRelay()
|
||||
|
||||
// load whitelist storage
|
||||
if err := loadWhitelist(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// load db
|
||||
db := badgern.BadgerBackend{Path: "/tmp/khatru-badgern-tmp"}
|
||||
if err := db.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
|
||||
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
|
||||
relay.CountEvents = append(relay.CountEvents, db.CountEvents)
|
||||
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
||||
|
||||
|
||||
relay.RejectEvent = append(relay.RejectEvent, whitelistRejecter)
|
||||
|
||||
// invitedata api
|
||||
relay.Router().HandleFunc("/invitedata", inviteDataApiHandler)
|
||||
// ui
|
||||
relay.Router().Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./ui/dist"))))
|
||||
|
||||
fmt.Println("running on :3334")
|
||||
http.ListenAndServe(":3334", relay)
|
||||
}
|
||||
|
||||
// save whitelist on shutdown
|
||||
func handleSignals() {
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
||||
<-sigCh
|
||||
saveWhitelist()
|
||||
os.Exit(0)
|
||||
}
|
13
ui/.eslintignore
Normal file
13
ui/.eslintignore
Normal file
@ -0,0 +1,13 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
30
ui/.eslintrc.cjs
Normal file
30
ui/.eslintrc.cjs
Normal file
@ -0,0 +1,30 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:svelte/recommended",
|
||||
"prettier",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint"],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: [".svelte"],
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.svelte"],
|
||||
parser: "svelte-eslint-parser",
|
||||
parserOptions: {
|
||||
parser: "@typescript-eslint/parser",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
1
ui/.gitignore
vendored
Normal file
1
ui/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
13
ui/.prettierignore
Normal file
13
ui/.prettierignore
Normal file
@ -0,0 +1,13 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
2049
ui/dist/assets/index-0320fb82.js
vendored
Normal file
2049
ui/dist/assets/index-0320fb82.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
ui/dist/assets/index-815d9fe6.css
vendored
Normal file
1
ui/dist/assets/index-815d9fe6.css
vendored
Normal file
File diff suppressed because one or more lines are too long
18
ui/dist/index.html
vendored
Normal file
18
ui/dist/index.html
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Invite Relay</title>
|
||||
<link rel="icon" href="data:," />
|
||||
<meta name="description" content="Invite Relay UI" />
|
||||
<script type="module" crossorigin src="./assets/index-0320fb82.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index-815d9fe6.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>Please enable JavaScript to run this app.</noscript>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
16
ui/index.html
Normal file
16
ui/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Invite Relay</title>
|
||||
<link rel="icon" href="data:," />
|
||||
<meta name="description" content="Invite Relay UI" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>Please enable JavaScript to run this app.</noscript>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
31
ui/package.json
Normal file
31
ui/package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "inviterelay-ui",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||
"format": "prettier --plugin-search-dir . --write ."
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.0.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"postcss": "^8.4.24",
|
||||
"sass": "^1.45.0",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-flatpickr": "^3.2.6",
|
||||
"svelte-spa-router": "^3.2.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"vite": "^4.0.4",
|
||||
"@nostr-dev-kit/ndk": "^0.8.23",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"eslint-plugin-svelte": "^2.33.0",
|
||||
"nostr-tools": "^1.14.2",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-svelte": "^3.0.3"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
6
ui/postcss.config.js
Normal file
6
ui/postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
3
ui/src/App.css
Normal file
3
ui/src/App.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind utilities;
|
||||
@tailwind components;
|
62
ui/src/App.svelte
Normal file
62
ui/src/App.svelte
Normal file
@ -0,0 +1,62 @@
|
||||
<script lang="ts">
|
||||
import "./App.css";
|
||||
import Hieracy from "./components/Hierarchy.svelte";
|
||||
import Invite from "./components/Invite.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { ndk, userPublickey } from "./lib/nostr";
|
||||
import { NDKNip07Signer } from "@nostr-dev-kit/ndk";
|
||||
import { buildHierarchy } from "./lib/utils";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
async function login() {
|
||||
const signer = new NDKNip07Signer();
|
||||
$ndk.signer = signer;
|
||||
ndk.set($ndk);
|
||||
$userPublickey = (await $ndk.signer.user()).npub;
|
||||
userPublickey.set($userPublickey);
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
const response = await fetch("/invitedata");
|
||||
invitedata = Object.values(await response.json());
|
||||
hierarchy = buildHierarchy(invitedata, { pk: "", invited_by: "" });
|
||||
}
|
||||
|
||||
let invitedata = [];
|
||||
let hierarchy = [];
|
||||
|
||||
onMount(() => {
|
||||
addEventListener("load", (e) => {
|
||||
login();
|
||||
});
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<article class="prose font-sans px-4 py-6 lg:max-w-7xl lg:pt-6 lg:pb-28">
|
||||
<h1>Invite Relay</h1>
|
||||
<div>
|
||||
{#if $userPublickey === undefined}
|
||||
<button
|
||||
on:click={login}
|
||||
type="button"
|
||||
class="inline-flex mr-2 items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
|
||||
>Login with NIP07</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if invitedata.find((p) => $userPublickey == nip19.npubEncode(p.pk))}
|
||||
<div>
|
||||
<h3>Invite Someone</h3>
|
||||
<div>
|
||||
<Invite reload={fetchData} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
<h3>Current hieracy</h3>
|
||||
<div>
|
||||
<Hieracy {hierarchy} reload={fetchData} />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
14
ui/src/components/Hierarchy.svelte
Normal file
14
ui/src/components/Hierarchy.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script lang="js">
|
||||
import TreeNode from "./TreeNode.svelte";
|
||||
|
||||
export let reload;
|
||||
export let hierarchy;
|
||||
</script>
|
||||
|
||||
<div class="px-4">
|
||||
<ul class="list-disc ml-4">
|
||||
{#each hierarchy as person (person.pk)}
|
||||
<TreeNode {reload} {person} />
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
52
ui/src/components/Invite.svelte
Normal file
52
ui/src/components/Invite.svelte
Normal file
@ -0,0 +1,52 @@
|
||||
<script lang="js">
|
||||
import { NDKEvent, NDKRelay, NDKRelaySet } from "@nostr-dev-kit/ndk";
|
||||
import { ndk } from "../lib/nostr";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { relayUrl } from "../lib/consts";
|
||||
|
||||
let pubKeyToInvite = "";
|
||||
export let reload;
|
||||
|
||||
async function invite() {
|
||||
if (!pubKeyToInvite) return;
|
||||
try {
|
||||
// only publish to the relay in question, dont know why this needs so much code
|
||||
let specificRelay = [new NDKRelay(relayUrl)];
|
||||
const relaySet = new NDKRelaySet(specificRelay, $ndk);
|
||||
relaySet.relays.forEach(async (relay) => {
|
||||
await relay.connect().catch((err) => {
|
||||
console.log("RELAY CONNECT ERROR");
|
||||
console.error(err);
|
||||
});
|
||||
relay.on("connect", () => {
|
||||
console.log(relay.url, "connected");
|
||||
});
|
||||
});
|
||||
|
||||
const pk = pubKeyToInvite.startsWith("npub")
|
||||
? nip19.decode(pubKeyToInvite).data
|
||||
: pubKeyToInvite;
|
||||
const event = new NDKEvent($ndk);
|
||||
event.kind = 20201;
|
||||
event.tags.push(["p", pk.toString()]);
|
||||
await event.publish(relaySet).then(() => reload());
|
||||
pubKeyToInvite = "";
|
||||
} catch (error) {
|
||||
console.log("error while publishing", error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative flex items-stretch flex-grow focus-within:z-10">
|
||||
<input
|
||||
bind:value={pubKeyToInvite}
|
||||
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300"
|
||||
placeholder="hex or npub"
|
||||
/>
|
||||
<button
|
||||
on:click={invite}
|
||||
type="submit"
|
||||
class="-ml-px relative inline-flex items-center space-x-2 px-3 py-2 border border-gray-300 text-sm font-medium rounded-r-md text-gray-700 bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-white"
|
||||
>Go</button
|
||||
>
|
||||
</div>
|
77
ui/src/components/TreeNode.svelte
Normal file
77
ui/src/components/TreeNode.svelte
Normal file
@ -0,0 +1,77 @@
|
||||
<script lang="js">
|
||||
import { onMount } from "svelte";
|
||||
import { ndk, userPublickey } from "../lib/nostr";
|
||||
import TreeNode from "./TreeNode.svelte";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { NDKEvent, NDKRelay, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk";
|
||||
import { relayUrl } from "../lib/consts";
|
||||
export let person;
|
||||
export let reload;
|
||||
let username = "...";
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
let user = $ndk.getUser({
|
||||
hexpubkey: person.pk,
|
||||
});
|
||||
await user.fetchProfile();
|
||||
username = user.profile.name;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
|
||||
async function removeThisUser() {
|
||||
let confirmation = confirm(
|
||||
`Are you sure you want to remove ${
|
||||
username ? username : person.pk
|
||||
}? All people they invited will also be removed.`,
|
||||
);
|
||||
if (confirmation) {
|
||||
try {
|
||||
// only publish to the relay in question, dont know why this needs so much code
|
||||
let specificRelay = [new NDKRelay(relayUrl)];
|
||||
const relaySet = new NDKRelaySet(specificRelay, $ndk);
|
||||
relaySet.relays.forEach(async (relay) => {
|
||||
await relay.connect().catch((err) => {
|
||||
console.log("RELAY CONNECT ERROR");
|
||||
console.error(err);
|
||||
});
|
||||
relay.on("connect", () => {
|
||||
console.log("connected");
|
||||
});
|
||||
});
|
||||
|
||||
const event = new NDKEvent($ndk);
|
||||
event.kind = 20202;
|
||||
event.tags.push(["p", person.pk]);
|
||||
await event.publish(relaySet).then(() => reload());
|
||||
} catch (error) {
|
||||
console.log("error while publishing", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<li>
|
||||
<span>
|
||||
<a
|
||||
class="inline hover:underline"
|
||||
href={`nostr:${nip19.npubEncode(person.pk)}`}
|
||||
>{#if username}{username}{:else}{nip19.npubEncode(person.pk)}{/if}</a
|
||||
>
|
||||
{#if $userPublickey == nip19.npubEncode(person.invited_by)}<button
|
||||
on:click={removeThisUser}
|
||||
class="inline cusor-pointer font-semibold text-red-500">[-]</button
|
||||
>{/if}{#if $userPublickey == nip19.npubEncode(person.pk)}
|
||||
<span> (you)</span>
|
||||
{/if}
|
||||
</span>
|
||||
{#if person.children && person.children.length > 0}
|
||||
<ul class="list-disc ml-2">
|
||||
{#each person.children as child (child.pk)}
|
||||
<TreeNode {reload} person={child} />
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</li>
|
2
ui/src/lib/consts.ts
Normal file
2
ui/src/lib/consts.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const relayUrl = "ws://localhost:3334";
|
||||
export const someRelays = ["wss://nos.lol", "wss://relay.snort.social"];
|
12
ui/src/lib/nostr.ts
Normal file
12
ui/src/lib/nostr.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import NDK from "@nostr-dev-kit/ndk";
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import { relayUrl, someRelays } from "./consts";
|
||||
|
||||
const relays = [relayUrl, ...someRelays];
|
||||
|
||||
const Ndk: NDK = new NDK({ explicitRelayUrls: relays });
|
||||
|
||||
Ndk.connect().then(() => console.log("ndk connected"));
|
||||
|
||||
export const ndk: Writable<NDK> = writable(Ndk);
|
||||
export const userPublickey: Writable<string | undefined> = writable(undefined);
|
18
ui/src/lib/utils.ts
Normal file
18
ui/src/lib/utils.ts
Normal file
@ -0,0 +1,18 @@
|
||||
interface TreeNodeType {
|
||||
pk: string;
|
||||
invited_by: string;
|
||||
children?: TreeNodeType[];
|
||||
}
|
||||
|
||||
export function buildHierarchy(
|
||||
data: TreeNodeType[],
|
||||
parent: TreeNodeType | null = null,
|
||||
): TreeNodeType[] {
|
||||
const children = data.filter(
|
||||
(item) => item.invited_by === (parent ? parent.pk : null),
|
||||
);
|
||||
return children.map((child) => ({
|
||||
...child,
|
||||
children: buildHierarchy(data, child),
|
||||
}));
|
||||
}
|
7
ui/src/main.js
Normal file
7
ui/src/main.js
Normal file
@ -0,0 +1,7 @@
|
||||
import App from "./App.svelte";
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById("app"),
|
||||
});
|
||||
|
||||
export default app;
|
8
ui/tailwind.config.js
Normal file
8
ui/tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["./src/**/*.{html,js,svelte}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require("@tailwindcss/forms"), require("@tailwindcss/typography")],
|
||||
};
|
26
ui/vite.config.js
Normal file
26
ui/vite.config.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { svelte, vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
||||
import postcss from "postcss";
|
||||
|
||||
// see https://vitejs.dev/config
|
||||
export default defineConfig({
|
||||
envPrefix: "UI",
|
||||
base: "./",
|
||||
build: {
|
||||
chunkSizeWarningLimit: 1000,
|
||||
reportCompressedSize: false,
|
||||
},
|
||||
plugins: [
|
||||
svelte({
|
||||
preprocess: [vitePreprocess()],
|
||||
}),
|
||||
],
|
||||
css: {
|
||||
postcss,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": __dirname + "/src",
|
||||
},
|
||||
},
|
||||
});
|
3273
ui/yarn.lock
Normal file
3273
ui/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
29
utils.go
Normal file
29
utils.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
func isPkInWhitelist(targetPk string) bool {
|
||||
for i := 0; i < len(whitelist); i++ {
|
||||
if whitelist[i].Pk == targetPk {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func deleteFromWhitelistRecursively (target string) {
|
||||
var updatedWhitelist []User
|
||||
var queue []string
|
||||
|
||||
for _, user := range whitelist {
|
||||
if user.Pk != target {
|
||||
updatedWhitelist = append(updatedWhitelist, user)
|
||||
}
|
||||
if user.InvitedBy == target {
|
||||
queue = append(queue, user.Pk);
|
||||
}
|
||||
}
|
||||
|
||||
whitelist = updatedWhitelist
|
||||
for _, pk := range queue {
|
||||
deleteFromWhitelistRecursively(pk)
|
||||
}
|
||||
}
|
82
whitelist.go
Normal file
82
whitelist.go
Normal file
@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Pk string `json:"pk"`
|
||||
InvitedBy string `json:"invited_by"`
|
||||
}
|
||||
|
||||
var whitelist []User
|
||||
|
||||
func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg string) {
|
||||
|
||||
// check if user in whitelist
|
||||
if !isPkInWhitelist(evt.PubKey) {
|
||||
return true, "You are not invited to this relay"
|
||||
}
|
||||
|
||||
// add user(s) if needed
|
||||
if (evt.Kind == 20201) {
|
||||
pTags := evt.Tags.GetAll([]string{"p"})
|
||||
for _, tag := range pTags {
|
||||
if !isPkInWhitelist(tag.Value()) {
|
||||
whitelist = append(whitelist, User{Pk: tag.Value(), InvitedBy: evt.PubKey})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove user(s) if needed
|
||||
if (evt.Kind == 20202) {
|
||||
pTags := evt.Tags.GetAll([]string{"p"})
|
||||
for _, tag := range pTags {
|
||||
for _, user := range whitelist {
|
||||
if user.Pk == tag.Value() && user.InvitedBy == evt.PubKey {
|
||||
deleteFromWhitelistRecursively(tag.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, ""
|
||||
|
||||
}
|
||||
|
||||
func loadWhitelist () error {
|
||||
if _, err := os.Stat("whitelist.json"); os.IsNotExist(err) {
|
||||
whitelist = []User{}
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileContent, err := os.ReadFile("whitelist.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(fileContent, &whitelist); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveWhitelist () error {
|
||||
jsonBytes, err := json.Marshal(whitelist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile("whitelist.json", jsonBytes, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user