Compare commits

...

146 Commits

Author SHA1 Message Date
Barry Deen
929e6f8318
Merge pull request #82 from bitvora/dev-ignoreList
ignore follow list for people who follow spammers
2025-01-04 16:09:18 -05:00
Barry Deen
9a74359210 ignore follow list for people who follow spammers 2025-01-04 15:56:24 -05:00
Barry Deen
f90926d573
Merge pull request #81 from bitvora/v0.1.15
update khatru, evenstore, badger
2024-12-23 08:53:05 -05:00
Barry Deen
b5519e2f74 update khatru, evenstore, badger 2024-12-23 08:52:35 -05:00
Barry Deen
0b9ecaa6cc update eventstore 2024-11-25 20:07:21 -05:00
Barry Deen
89bef01c48
Merge pull request #77 from bitvora/dev-0.1.14
remove kind 4 support
2024-10-16 19:57:21 -04:00
Barry Deen
972b62b823 remove kind 4 support 2024-10-16 19:56:53 -04:00
Barry Deen
17209ceb2d
Merge pull request #76 from bitvora/dev-updateeventstore
update event store, badger fix
2024-10-08 10:57:02 -04:00
Barry Deen
9bb573a73f update event store, badger fix 2024-10-08 10:56:37 -04:00
Barry Deen
b181b2225e
Merge pull request #75 from sudocarlos/patch-1
Removed relays from list
2024-10-08 10:54:40 -04:00
sudocarlos
853d522946
Removed relays from list 2024-10-05 06:34:53 -04:00
Barry Deen
a294071f9f
Merge pull request #74 from goodmorningbitcoin/master
Add relay.GoodMorningBitcoin.com
2024-10-03 09:24:09 -04:00
Good Morning Bitcoin
705a281d39
Add relay.GoodMorningBitcoin.com 2024-10-02 07:43:31 -04:00
Barry Deen
d2a6801f15 revert again 2024-09-30 19:25:56 -04:00
Barry Deen
03a8f6e674 revert eventstore 2024-09-30 19:24:27 -04:00
Barry Deen
ccb6af8714
Merge pull request #73 from bitvora/dev-updateEventStore
update to latest fiatjaf eventstore
2024-09-30 17:42:20 -04:00
Barry Deen
7f7b2c07f8 update to latest fiatjaf eventstore 2024-09-30 17:41:59 -04:00
Barry Deen
c5e9843d41
Merge pull request #72 from aljazceru/master
adding wot.nostr.net
2024-09-30 15:08:11 -04:00
Aljaz Ceru
87b3889746
adding wot.nostr.net 2024-09-29 22:48:24 +04:00
Barry Deen
7770b92e3d
Merge pull request #70 from tealeaf-dot-dev/tealeaf-relay
Add wot.tealeaf.dev relay to README
2024-09-25 19:12:06 -04:00
tf
6626ae768e Add wot.tealeaf.dev relay to README 2024-09-25 18:49:44 +01:00
Barry Deen
bc3653c9b5 clarify readme, add another relay to list 2024-09-25 12:51:38 -04:00
Barry Deen
577e82e5bb
Merge pull request #69 from zmpeters/master
Update README.md
2024-09-25 12:44:09 -04:00
Zach
246ff19253
Update README.md
Added new wot relay to the list wot.zacoos.com. 

I appreciate your consideration.
2024-09-25 10:58:09 -05:00
Barry Deen
1a536bc9f9
Merge pull request #68 from sudocarlos/master
add restart and init to docker compose files
2024-09-25 02:56:03 -04:00
Carlos
1a21abee7f add restart and init to docker compose files 2024-09-24 16:06:47 -04:00
Barry Deen
ba4fa1d031
Merge pull request #66 from bitvora/v0.2.0
swap lmdb for badger
2024-09-22 19:44:30 -04:00
Barry Deen
deed7b7c2d swap lmdb for badger 2024-09-22 19:44:07 -04:00
Barry Deen
e76839077f
Merge pull request #64 from bitvora/dev-disableReactions
disable reaction archiving, use map to allow posting
2024-09-22 14:09:00 -04:00
Barry Deen
46ec59996e disable reaction archiving, use map to allow posting 2024-09-22 14:08:09 -04:00
Barry Deen
3ceeaf77da
Merge pull request #62 from calvadev/patch-2
Added wss://wons.calva.dev to list of available relays
2024-09-22 12:35:41 -04:00
Barry Deen
a2080cbb61
Merge pull request #63 from trinidz/deleteOldNotes
Delete / prune old archived notes from relay.
2024-09-22 12:35:27 -04:00
trinidz
7666d3e9f5 init delete old notes 2024-09-22 13:28:49 +00:00
calvadev⚡️
644afa30d0
Added wss://wons.calva.dev to list of available relays 2024-09-21 22:48:15 -07:00
Barry Deen
7b71d98633
Merge pull request #61 from calvadev/patch-1
Fix connection failures on nginx reverse proxy
2024-09-21 15:11:24 -04:00
calvadev⚡️
8e5dc79f3b
Update README.md
Changed yml file volume path references
2024-09-21 11:55:57 -07:00
calvadev⚡️
38dd6fb13c
Update README.md
Added required response headers for nginx reverse proxy
2024-09-21 11:52:00 -07:00
Barry Deen
5ca37ff165
Merge pull request #60 from Sebastix/fix/docker-volume-paths
fix http: panic serving <local_ip_here>: open public/index.html with docker compose
2024-09-21 11:16:20 -04:00
Sebastix
a5bbfe6165 fix http: panic serving 100.114.176.46:58517: open public/index.html: no such file or directory 2024-09-21 13:59:53 +02:00
Barry Deen
809d87e283
Merge pull request #56 from Michilis/patch-1
Update README.md
2024-09-20 11:29:08 -04:00
Barry Deen
8ce120bcf2
Merge branch 'master' into patch-1 2024-09-20 11:29:01 -04:00
Barry Deen
e5ec9d9e63
Merge pull request #57 from derekross/derekross-patch-1
add new WoT relays to README.md
2024-09-20 11:28:35 -04:00
Barry Deen
ff3079cbb9
Merge branch 'master' into derekross-patch-1 2024-09-20 11:28:27 -04:00
Barry Deen
eb25be49e2
Merge pull request #58 from zatzby/patch-1
Update README.md
2024-09-20 11:27:55 -04:00
zach
295e2f7f95
Update README.md
added satsage.xyz to avail relays
2024-09-19 21:51:00 -07:00
Derek Ross
7fc7fc2019
add new WoT relays to README.md
add wss://wot.swarmstr.com, wss://zap.watch
2024-09-19 20:34:41 -04:00
Michilis
1a1a643d49
Update README.md 2024-09-19 23:54:37 +02:00
Barry Deen
1758708e9a don't force env update 2024-09-19 11:04:47 -04:00
Barry Deen
c0093880c0 change version to github link 2024-09-19 10:59:59 -04:00
Barry Deen
a2b2ac9fd7
Merge pull request #52 from patrickulrich/master
Update README.md
2024-09-19 08:11:13 -04:00
Patrick Ulrich
2bf2945db5
Update README.md
Add relay.lexingtonbitcoin.org
2024-09-19 08:08:51 -04:00
Barry Deen
7f35c801b8
Merge pull request #51 from cr0bar/master
Change to support name and version number for NIP-11
2024-09-18 07:30:22 -04:00
cr0bar
0ce65fb549
Update main.go to support icon and rename contact 2024-09-18 12:12:48 +01:00
cr0bar
d291251887
Update .env.example added RELAY_ICON and renamed CONTACT 2024-09-18 12:10:07 +01:00
cr0bar
a43e1ff9f8
Update .env.example 2024-09-18 09:27:01 +01:00
cr0bar
372ccbe0c0
Update main.go to supp 2024-09-18 09:25:51 +01:00
cr0bar
1309979d1c
Update README.md for change to build command to support version number 2024-09-18 08:51:13 +01:00
cr0bar
845f02b381
Update main.go to support name and version information for NIP-11 2024-09-18 08:50:28 +01:00
Barry Deen
57fb3885ad
Merge pull request #48 from bitvora/dev-filterOnlyOption
update .env.example
2024-09-16 21:59:05 -04:00
Barry Deen
26110bb059 update .env.example 2024-09-16 21:58:45 -04:00
Barry Deen
f5fa8fcafb
Merge pull request #47 from bitvora/dev-filterOnlyOption
update readme
2024-09-16 21:58:01 -04:00
Barry Deen
8a69e7e0af update readme 2024-09-16 21:57:38 -04:00
Barry Deen
71f71ee0a5
Merge pull request #46 from bitvora/dev-filterOnlyOption
option to run relay without syncing from other relays
2024-09-16 21:54:41 -04:00
Barry Deen
aae474531f option to run relay without syncing from other relays 2024-09-16 21:54:16 -04:00
Barry Deen
aaa0047a74
Merge pull request #43 from bitvora/dev-fixFJMistakes
add context to goroutine
2024-09-13 08:12:25 -04:00
Barry Deen
02fc217510 add context to goroutine 2024-09-13 08:11:57 -04:00
Barry Deen
1db8134648
Merge pull request #42 from bitvora/dev-fixFJMistakes
putting back goroutines like i had them before fj told me to remove i…
2024-09-13 08:05:07 -04:00
Barry Deen
51d8a6e6f0 putting back goroutines like i had them before fj told me to remove it then put it back 2024-09-13 08:04:45 -04:00
Barry Deen
11ab126d31
Merge pull request #41 from bitvora/dev-fixFJMistakes
remove verbose logging
2024-09-13 00:39:31 -04:00
Barry Deen
95efd8247a remove verbose logging 2024-09-13 00:39:16 -04:00
Barry Deen
dc935b9565
Merge pull request #40 from bitvora/dev-fixFJMistakes
update khatru and eventstore with new bugfixes
2024-09-12 22:10:45 -04:00
Barry Deen
307967ad6e remove debug timeout 2024-09-12 22:10:16 -04:00
Barry Deen
7232b14a29 back to the original way now the FJ fixed his mistakes 2024-09-12 22:09:21 -04:00
Barry Deen
6cef35e0f1
Merge pull request #39 from bitvora/dev-profileRefresh
Publish directly to db
2024-09-12 20:51:49 -04:00
Barry Deen
cce891e477 Publish directly to db 2024-09-12 20:51:26 -04:00
Barry Deen
47f1b9422b
Merge pull request #38 from bitvora/dev-profileRefresh
broadcast events, process in goroutine
2024-09-12 20:37:02 -04:00
Barry Deen
3c6f93cb33 broadcast events, process in goroutine 2024-09-12 20:33:53 -04:00
Barry Deen
d5ee8a3291
Merge pull request #36 from bitvora/dev-profileRefresh
reduce rate frequencies
2024-09-12 16:05:14 -04:00
Barry Deen
e99c5dd753 reduce rate frequencies 2024-09-12 16:04:46 -04:00
Barry Deen
bbabc0eb1a
Merge pull request #35 from sudocarlos/patch-1
add sudocarlos and otherstuff relays
2024-09-12 16:00:14 -04:00
sudocarlos
7434ee12f1
add sudocarlos and otherstuff relays 2024-09-12 15:51:11 -04:00
Barry Deen
4d97bb361d
Merge pull request #34 from bitvora/dev-profileRefresh
check for tag length before adding
2024-09-12 15:41:22 -04:00
Barry Deen
2bd132cf73 check for tag length before adding 2024-09-12 15:41:00 -04:00
Barry Deen
20b0272ade
Merge pull request #33 from bitvora/dev-profileRefresh
less restrictive rate limits
2024-09-12 15:26:48 -04:00
Barry Deen
ed76ae568e less restrictive rate limits 2024-09-12 15:26:38 -04:00
Barry Deen
37a9e1c0cc
Merge pull request #32 from bitvora/dev-profileRefresh
customize the trust network by follower count
2024-09-12 15:24:57 -04:00
Barry Deen
49bd213942 update readme with minimum followers 2024-09-12 15:24:31 -04:00
Barry Deen
b862a0c21c customize the trust network by follower count 2024-09-12 15:23:32 -04:00
Barry Deen
9124cc3204
Merge pull request #31 from bitvora/dev-profileRefresh
remove bloom filter
2024-09-12 14:17:31 -04:00
Barry Deen
84ec835dcb remove bloom filter 2024-09-12 14:16:56 -04:00
Barry Deen
06d673a190
Merge pull request #30 from bitvora/dev-profileRefresh
reduce profile logging
2024-09-12 12:40:56 -04:00
Barry Deen
067849d1a1 reduce profile logging 2024-09-12 12:40:45 -04:00
Barry Deen
323a801130
Merge pull request #29 from bitvora/dev-profileRefresh
remove mutex and reduce logging
2024-09-12 12:33:58 -04:00
Barry Deen
a4116a31f9 remove mutex and reduce logging 2024-09-12 12:33:36 -04:00
Barry Deen
434b3fb398
Merge pull request #28 from bitvora/dev-profileRefresh
refresh profiles of the trust network
2024-09-12 11:07:28 -04:00
Barry Deen
10b2e071d6 refresh profiles of the trust network 2024-09-12 11:06:57 -04:00
Barry Deen
5193f93900 remove filter ip limiter 2024-09-12 10:34:15 -04:00
Barry Deen
059500b2e9 replace timeout context with timeout channel 2024-09-12 10:20:18 -04:00
Barry Deen
c12335effb increase rate policies 2024-09-12 10:04:06 -04:00
Barry Deen
5d27b71860 reasonable limits, upgrade khatru to latest 2024-09-11 22:06:17 -04:00
Barry Deen
af155c1f48 remove releases, add docker back 2024-09-11 21:10:24 -04:00
Barry Deen
2e7105fbdd add CGO_ENABLED to release build 2024-09-11 21:01:09 -04:00
Barry Deen
5cc3c33ed5
Merge pull request #27 from bitvora/dev-githubWorkflows
Resolve Dependency Errors, Update Release Flow
2024-09-11 20:42:34 -04:00
Barry Deen
49bf83bbab resolve dependabot errors 2024-09-11 20:41:53 -04:00
Barry Deen
2b4c335b59 add build essentials to release 2024-09-11 20:39:23 -04:00
Barry Deen
0740531c26
Merge pull request #26 from bitvora/dev-githubWorkflows
update release builder
2024-09-11 20:33:00 -04:00
Barry Deen
7a59c4cb79 update release builder 2024-09-11 20:32:17 -04:00
Barry Deen
87fb79fd52
Merge pull request #25 from bitvora/dev-githubWorkflows
remove docker build, add release
2024-09-11 20:25:45 -04:00
Barry Deen
0f3578c5a5 remove docker build, add release 2024-09-11 20:25:10 -04:00
Barry Deen
cead2aa446
Merge pull request #24 from bitvora/dev-stuckFix
Bug Fix where SubMany did not timeout - update go-nostr
2024-09-11 20:15:06 -04:00
Barry Deen
58953dacc0 update go-nostr and eventstore 2024-09-11 20:13:56 -04:00
Barry Deen
5d9325793f return when done, remose eose 2024-09-11 13:02:07 -04:00
Barry Deen
f1ff8bb6bb prevent archiving from getting stuck 2024-09-11 12:55:40 -04:00
Barry Deen
3fdc038310
Merge pull request #22 from bitvora/dev-staticHandler
ability to serve any file from /static/
2024-09-10 17:17:39 -04:00
Barry Deen
489e51e274 ability to serve any file from /static/ 2024-09-10 17:17:03 -04:00
Barry Deen
559d0ca1f4
Merge pull request #20 from vazw/master
ADD wot.siamstr.com
2024-09-10 09:06:52 -04:00
vazw
f684c13b7f ADD wot.siamstr.com 2024-09-10 14:31:05 +07:00
Barry Deen
0897e1634b add some public relays to readme 2024-09-09 23:45:48 -04:00
Barry Deen
9efa2149d0 revert db engine 2024-09-09 18:38:12 -04:00
Barry Deen
2aab9f3e49 update refresh interval on readme, add archiving logging 2024-09-09 18:37:31 -04:00
Barry Deen
13d23ee8a2
Merge pull request #17 from bitvora/dev-filterError
remove useless logging, update go-nostr
2024-09-08 10:56:19 -04:00
Barry Deen
c8353369a3 remove useless logging, update go-nostr 2024-09-08 10:55:56 -04:00
Barry Deen
047774a027
Merge pull request #14 from gbozee/master
Optimized dockerfile for small images and Github action to build on new release.
2024-09-08 09:23:00 -04:00
Biola
814706b22c resolved white space issues 2024-09-08 10:11:49 +01:00
Abiola
307eab490d
Merge pull request #1 from gbozee/upstream2-master
added wot-relay in .gitignore
2024-09-08 10:03:32 +01:00
Biola
6a6f1c9108 added wot-relay in .gitignore 2024-09-08 10:02:35 +01:00
Biola
413e6df9e6 fixed inconsistencies with upstream 2024-09-08 09:52:03 +01:00
Biola
89a0552ce8 restart services always 2024-09-08 06:36:35 +01:00
Biola
3bcf881473 added traefik support for easy deployment with ssl certificate 2024-09-08 06:33:58 +01:00
Barry Deen
282f8ef71f
Merge pull request #15 from bitvora/dev-filterError
remove relays that aren't cooperating
2024-09-08 00:53:18 -04:00
Barry Deen
241c94e4d7 remove nos.social because they just return random crap we didnt ask for 2024-09-08 00:52:42 -04:00
Barry Deen
7a114cb3a8
Merge pull request #13 from girino/master
Use compile tags to build for arm64 (switch to badgerdb)
2024-09-08 00:36:58 -04:00
Your Name
2ce02fba9c Merge remote-tracking branch 'upstream/master' 2024-09-08 01:17:24 -03:00
Barry Deen
0505740f1e cleaner logic, fix segfault, update readme 2024-09-07 23:39:23 -04:00
Biola
f2f3d83eba chore: Optimized docker container with github action 2024-09-08 03:25:42 +01:00
Biola
ee2b4eef6d Resolved merge conflicts 2024-09-08 02:56:47 +01:00
Biola
ae947e2f1f initial commit 2024-09-08 02:53:52 +01:00
Your Name
cee4d78223 go.sum and go.add for badger db 2024-09-07 22:09:13 -03:00
Your Name
7fa90fa885 dockerfiles with tag for badgerdb 2024-09-07 22:03:04 -03:00
Your Name
b8ae4a5ccb use tags to select abdger db 2024-09-07 22:01:13 -03:00
Barry Deen
dd9763e967 performance optimization, sexyness upgrade 2024-09-07 20:14:43 -04:00
Barry Deen
55bae27490 explicit cancel 2024-09-07 17:28:42 -04:00
Barry Deen
f60362cd14
Merge pull request #11 from bitvora/dev-stabilityFixCtx
check for blank chunks
2024-09-07 17:26:50 -04:00
Barry Deen
d1198a31b5 check for blank chunks 2024-09-07 17:26:26 -04:00
Barry Deen
6ccb91e652
Merge pull request #10 from bitvora/dev-stabilityFixCtx
new context for each pull, no eose
2024-09-07 17:09:15 -04:00
Barry Deen
a97e0ab2d8 new context for each pull, no eose 2024-09-07 17:08:55 -04:00
14 changed files with 934 additions and 215 deletions

View File

@ -1,2 +1 @@
db db
templates

View File

@ -1,7 +1,30 @@
# Relay Metadata
RELAY_NAME="utxo WoT relay" RELAY_NAME="utxo WoT relay"
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb" RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb" # the owner's hexkey, not npub. Convert npub to hex here: https://nostrcheck.me/converter/
RELAY_DESCRIPTION="Only notes in utxo WoT" RELAY_DESCRIPTION="Only notes in utxo WoT"
RELAY_URL="wss://wot.utxo.one" RELAY_URL="wss://wot.utxo.one"
RELAY_ICON="https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg"
RELAY_CONTACT="https://utxo.one"
# where we should store the database
DB_PATH="db" DB_PATH="db"
INDEX_PATH="templates/index.html"
STATIC_PATH="templates/static" # where we should store the index.html and static files
INDEX_PATH="/mnt/dev/bitvora/wot-relay/templates/index.html"
STATIC_PATH="/mnt/dev/bitvora/wot-relay/templates/static/"
# relay behavior
# how often to refresh the relay's view of the WoT in HOURS
REFRESH_INTERVAL_HOURS=1
MINIMUM_FOLLOWERS=5
# archive all notes from everyone in your WoT from other relays
ARCHIVAL_SYNC="FALSE"
ARCHIVE_REACTIONS="FALSE" # optional, reactions take up a lot of space and compute
# optional, certain note kinds older than this many days will be deleted
MAX_AGE_DAYS=365
# comma delimited list of pubkeys who follow bots and ruin the WoT
IGNORE_FOLLOWS_LIST=""

36
.github/workflows/docker-build.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Docker Build and Publish
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile-optimized
push: ${{ github.event_name != 'pull_request' }}
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
db/ db/
.env .env
wot-relay wot-relay

44
Dockerfile-optimized Normal file
View File

@ -0,0 +1,44 @@
# Stage 1: Build the Go application
FROM golang:bookworm AS builder
# Set the working directory within the container
WORKDIR /app
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the rest of the application source code
COPY . .
# Set fixed environment variables for build
ENV DB_PATH="db"
ENV INDEX_PATH="templates/index.html"
ENV STATIC_PATH="templates/static"
# touch a .env
RUN touch .env
# Build the Go application
RUN go build -o main .
# Stage 2: Create a minimal image to run the Go application
FROM debian:bookworm-slim
# Set the working directory within the container
WORKDIR /app
# Copy the Go binary from the builder stage
COPY --from=builder /app/main /app/
# Copy any necessary files like templates, static assets, etc.
COPY --from=builder /app/templates /app/templates
COPY --from=builder /app/.env /app/
# Expose the port that the application will run on
EXPOSE 3334
# Set the command to run the executable
CMD ["./main"]

109
README.md
View File

@ -1,6 +1,29 @@
# WOT Relay # WoT Relay
WOT Relay is a Nostr relay that saves all the notes that people you follow, and people they follow are posting. WOT Relay is a Nostr relay that saves all the notes that people you follow, and people they follow are posting. It's built on the [Khatru](https://khatru.nostr.technology) framework.
# Available Relays
Don't want to run the relay, just want to connect to some? Here are some available relays:
- [wss://wot.utxo.one](https://wot.utxo.one)
- [wss://nostrelites.org](https://nostrelites.org)
- [wss://wot.nostr.party](https://wot.nostr.party)
- [wss://wot.sovbit.host](https://wot.sovbit.host)
- [wss://wot.girino.org](https://wot.girino.org)
- [wss://relay.lnau.net](https://relay.lnau.net)
- [wss://wot.siamstr.com](https://wot.siamstr.com)
- [wss://relay.lexingtonbitcoin.org](https://relay.lexingtonbitcoin.org)
- [wss://wot.azzamo.net](https://wot.azzamo.net)
- [wss://wot.swarmstr.com](https://wot.swarmstr.com)
- [wss://zap.watch](https://zap.watch)
- [wss://satsage.xyz](https://satsage.xyz)
- [wss://wons.calva.dev](https://wons.calva.dev)
- [wss://wot.zacoos.com](https://wot.zacoos.com)
- [wss://wot.shaving.kiwi](https://wot.shaving.kiwi)
- [wss://wot.tealeaf.dev](https://wot.tealeaf.dev)
- [wss://wot.nostr.net](https://wot.nostr.net)
- [wss://relay.goodmorningbitcoin.com](https://relay.goodmorningbitcoin.com)
## Prerequisites ## Prerequisites
@ -32,11 +55,16 @@ Open the `.env` file and set the necessary environment variables. Example variab
```bash ```bash
RELAY_NAME="YourRelayName" RELAY_NAME="YourRelayName"
RELAY_PUBKEY="YourPublicKey" RELAY_PUBKEY="YourPublicKey" # the owner's hexkey, not npub. Convert npub to hex here: https://nostrcheck.me/converter/
RELAY_DESCRIPTION="Your relay description" RELAY_DESCRIPTION="Your relay description"
DB_PATH="/home/ubuntu/wot-relay/db" # any path you would like the database to be saved. DB_PATH="/home/ubuntu/wot-relay/db" # any path you would like the database to be saved.
INDEX_PATH="/home/ubuntu/wot-relay/templates/index.html" # path to the index.html file INDEX_PATH="/home/ubuntu/wot-relay/templates/index.html" # path to the index.html file
STATIC_PATH="/home/ubuntu/wot-relay/templates/static" # path to the static folder STATIC_PATH="/home/ubuntu/wot-relay/templates/static" # path to the static folder
REFRESH_INTERVAL_HOURS=24 # interval in hours to refresh the web of trust
MINIMUM_FOLLOWERS=3 #how many followers before they're allowed in the WoT
ARCHIVAL_SYNC="FALSE" # set to TRUE to archive every note from every person in the WoT (not recommended)
ARCHIVE_REACTIONS="FALSE" # set to TRUE to archive every reaction from every person in the WoT (not recommended)
IGNORE_FOLLOWS_LIST="" # comma separated list of pubkeys who follow too many bots and ruin the WoT
``` ```
### 4. Build the project ### 4. Build the project
@ -44,12 +72,12 @@ STATIC_PATH="/home/ubuntu/wot-relay/templates/static" # path to the static folde
Run the following command to build the relay: Run the following command to build the relay:
```bash ```bash
go build go build -ldflags "-X main.version=$(git describe --tags --always)"
``` ```
### 5. Create a Systemd Service (optional) ### 5. Create a Systemd Service (optional)
To have the relay run as a service, create a systemd unit file. Here's an example: To have the relay run as a service, create a systemd unit file. Make sure to limit the memory usage to less than your system's total memory to prevent the relay from crashing the system.
1. Create the file: 1. Create the file:
@ -65,10 +93,10 @@ Description=WOT Relay Service
After=network.target After=network.target
[Service] [Service]
ExecStart=/path/to/wot-relay ExecStart=/home/ubuntu/wot-relay/wot-relay
WorkingDirectory=/path/to/wot-relay WorkingDirectory=/home/ubuntu/wot-relay
Restart=always Restart=always
EnvironmentFile=/path/to/.env MemoryLimit=2G
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -94,7 +122,66 @@ sudo systemctl start wot-relay
sudo systemctl enable wot-relay sudo systemctl enable wot-relay
``` ```
### 6. Start the Project with Docker Compose (optional) #### Permission Issues on Some Systems
the relay may not have permissions to read and write to the database. To fix this, you can change the permissions of the database folder:
```bash
sudo chmod -R 777 /path/to/db
```
### 6. Serving over nginx (optional)
You can serve the relay over nginx by adding the following configuration to your nginx configuration file:
```nginx
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3334;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
Replace `yourdomain.com` with your actual domain name.
After adding the configuration, restart nginx:
```bash
sudo systemctl restart nginx
```
### 7. Install Certbot (optional)
If you want to serve the relay over HTTPS, you can use Certbot to generate an SSL certificate.
```bash
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
```
After installing Certbot, run the following command to generate an SSL certificate:
```bash
sudo certbot --nginx
```
Follow the instructions to generate the certificate.
### 8. Access the relay
Once everything is set up, the relay will be running on `localhost:3334` or your domain name if you set up nginx.
## Start the Project with Docker Compose
To start the project using Docker Compose, follow these steps: To start the project using Docker Compose, follow these steps:
@ -106,8 +193,8 @@ To start the project using Docker Compose, follow these steps:
```yaml ```yaml
volumes: volumes:
- "./db:/app/db" # only change the left side before the colon - "./db:/app/db" # only change the left side before the colon
- "./templates/index.html:/app/templates/index.html" # only change the left side before the colon - "./templates/index.html:${INDEX_PATH}" # only change the left side before the colon
- "./templates/static:/app/templates/static" # only change the left side before the colon - "./templates/static:${INDEX_PATH}" # only change the left side before the colon
``` ```
5. Run the following command: 5. Run the following command:

31
arm64.Dockerfile Normal file
View File

@ -0,0 +1,31 @@
# Use Golang image based on Debian Bookworm
FROM golang:bookworm
# Set the working directory within the container
WORKDIR /app
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the rest of the application source code
COPY . .
# Set fixed environment variables
ENV DB_PATH="db"
ENV INDEX_PATH="templates/index.html"
ENV STATIC_PATH="templates/static"
# touch a .env (https://github.com/bitvora/wot-relay/pull/4)
RUN touch .env
# Build the Go application
RUN go build -tags badger -o main .
# Expose the port that the application will run on
EXPOSE 3334
# Set the command to run the executable
CMD ["./main"]

16
docker-compose.arm64.yml Normal file
View File

@ -0,0 +1,16 @@
services:
relay:
container_name: wot-relay
build:
context: .
dockerfile: arm64.Dockerfile
env_file:
- .env
volumes:
- "./db:/app/db"
- "./templates/index.html:${INDEX_PATH}"
- "./templates/static:${STATIC_PATH}"
ports:
- "3334:3334"
restart: unless-stopped
init: true

View File

@ -8,10 +8,12 @@ services:
- .env - .env
volumes: volumes:
- "./db:/app/db" - "./db:/app/db"
- "./templates/index.html:/app/templates/index.html" - "./templates/index.html:${INDEX_PATH}"
- "./templates/static:/app/templates/static" - "./templates/static:${STATIC_PATH}"
ports: ports:
- "3334" - "3334"
restart: unless-stopped
init: true
tor: tor:
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92 image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
@ -23,3 +25,4 @@ services:
- ./tor/data:/var/lib/tor - ./tor/data:/var/lib/tor
restart: on-failure restart: on-failure
stop_grace_period: 10m30s stop_grace_period: 10m30s
init: true

View File

@ -7,8 +7,10 @@ services:
env_file: env_file:
- .env - .env
volumes: volumes:
- "./db:/app/db" # only change the left side before the colon - "./db:/app/db"
- "./templates/index.html:/app/templates/index.html" # only change the left side before the colon - "./templates/index.html:${INDEX_PATH}"
- "./templates/static:/app/templates/static" # only change the left side before the colon - "./templates/static:${STATIC_PATH}"
ports: ports:
- "3334:3334" - "3334:3334"
restart: unless-stopped
init: true

68
go.mod
View File

@ -1,39 +1,55 @@
module github.com/bitvora/wot-relay module github.com/bitvora/wot-relay
go 1.23.0 go 1.23.1
toolchain go1.23.1
require ( require (
github.com/PowerDNS/lmdb-go v1.9.2 // indirect github.com/fiatjaf/eventstore v0.14.4
github.com/andybalholm/brotli v1.0.5 // indirect github.com/fiatjaf/khatru v0.14.0
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/joho/godotenv v1.5.1
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/nbd-wtf/go-nostr v0.44.2
github.com/cespare/xxhash v1.1.0 // indirect )
require (
fiatjaf.com/lib v0.2.0 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/bep/debounce v1.2.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/fasthttp/websocket v1.5.7 // indirect github.com/dgraph-io/badger/v4 v4.5.0 // indirect
github.com/fiatjaf/eventstore v0.8.1 // indirect github.com/dgraph-io/ristretto v1.0.0 // indirect
github.com/fiatjaf/khatru v0.8.0 // indirect github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fasthttp/websocket v1.5.11 // indirect
github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.1 // indirect github.com/gobwas/ws v1.4.0 // indirect
github.com/greatroar/blobloom v0.8.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // 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.17.11 // indirect
github.com/nbd-wtf/go-nostr v0.34.14 // indirect github.com/mailru/easyjson v0.9.0 // 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/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/puzpuzpuz/xsync/v3 v3.4.0 // 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/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.58.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect go.opencensus.io v0.24.0 // indirect
golang.org/x/net v0.18.0 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
golang.org/x/sys v0.20.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
) )

281
go.sum
View File

@ -1,71 +1,175 @@
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
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/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 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 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/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 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/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
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/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.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.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs=
github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak=
github.com/dgraph-io/badger/v4 v4.3.1 h1:7r5wKqmoRpGgSxqa0S/nGdpOpvvzuREGPLSua73C8tw=
github.com/dgraph-io/badger/v4 v4.3.1/go.mod h1:oObz97DImXpd6O/Dt8BqdKLLTDmEmarAimo72VV5whQ=
github.com/dgraph-io/badger/v4 v4.5.0 h1:TeJE3I1pIWLBjYhIYCA1+uxrjWEoJXImFBMEBVSm16g=
github.com/dgraph-io/badger/v4 v4.5.0/go.mod h1:ysgYmIeG8dS/E8kwxT7xHyc7MkmwNYLRoYnFbr7387A=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84=
github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc=
github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ=
github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk=
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/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4= github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4=
github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU= github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
github.com/fiatjaf/eventstore v0.5.1 h1:tTh+JYP0RME51VY2QB2Gvtzj6QTaZAnSVhgZtrYqY2A= github.com/fasthttp/websocket v1.5.11 h1:TCO3H2VSxeTJQ+Ij+w8q7UBvdVedMOy/G7aZ0a6V19s=
github.com/fiatjaf/eventstore v0.5.1/go.mod h1:r5yCFmrVNT2b1xUOuMnDVS3xPGh97y8IgTcLyY2rYP8= github.com/fasthttp/websocket v1.5.11/go.mod h1:QWILjDXurHFN5519nH2Pe9rtRuKZ/OIx/rlBF9coYds=
github.com/fiatjaf/eventstore v0.8.1 h1:51LchQNy0Hpb0YQHwqYR5pKBpfDs/KjySlWCbbz2pkc= github.com/fiatjaf/eventstore v0.10.1 h1:zgXrRhpyjzX0Eub4T6zkMZ60zRnIPJqy/Ipfx5h+yWo=
github.com/fiatjaf/eventstore v0.8.1/go.mod h1:bsp0Ibv0CIcVuFcoM2AEerMWmXRhF8uWXMf+dClhuow= github.com/fiatjaf/eventstore v0.10.1/go.mod h1:h5CdLSF7mEQ7/rWpEABTRIrNuFoSwdQDi/nZkW/vVFU=
github.com/fiatjaf/khatru v0.8.0 h1:hofUi4qbSqkJiKD4rC9EyNdi9obzBvp3ykJOBxuu/h8= github.com/fiatjaf/eventstore v0.11.2 h1:gJTATGOk7RtDGt1qs47cLyTzko9phFyXlmWQb0zR7Lg=
github.com/fiatjaf/khatru v0.8.0/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg= github.com/fiatjaf/eventstore v0.11.2/go.mod h1:oCHPB4TprrNjbhH2kjMKt1O48O1pk3VxAy5iZkB5Fb0=
github.com/fiatjaf/eventstore v0.14.0 h1:eAyugJGFRCrXYJLCc2nC/BIApmBbQN/Z4dxvNz1SIvI=
github.com/fiatjaf/eventstore v0.14.0/go.mod h1:XOl5B6WGBX1a0ww6s3WT94QVOmye/6zDTtyWHVtHQ5U=
github.com/fiatjaf/eventstore v0.14.4 h1:bqJQit/M5E6vwbWwgrL4kTPoWCbt1Hb9H/AH4xf9uVQ=
github.com/fiatjaf/eventstore v0.14.4/go.mod h1:3Kkujc6A8KjpNvSKu1jNCcFjSgEEyCxaDJVgShHz0J8=
github.com/fiatjaf/khatru v0.8.2-0.20240913013357-18fc0dc1dd58 h1:F5Cy44IzxeIhzY8bf34rnORw0pYn6ZT/pIuyMO02Kjs=
github.com/fiatjaf/khatru v0.8.2-0.20240913013357-18fc0dc1dd58/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
github.com/fiatjaf/khatru v0.14.0 h1:zpWlAA87XBpDKBPIDbAuNw/HpKXzyt5XHVDbSvUbmDo=
github.com/fiatjaf/khatru v0.14.0/go.mod h1:uxE5e8DBXPZqbHjr/gfatQas5bEJIMmsOCDcdF4LoRQ=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= 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/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 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= 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.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.2.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/greatroar/blobloom v0.8.0 h1:I9RlEkfqK9/6f1v9mFmDYegDQ/x0mISCpiNpAm23Pt4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/greatroar/blobloom v0.8.0/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv8OvMHJxHKs= 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/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
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.2/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.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
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/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
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.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/nbd-wtf/go-nostr v0.34.14 h1:o4n2LkuAtdIjNYJ23sFbcx68UXLnji4j8hYR1Sd2wgI= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/nbd-wtf/go-nostr v0.34.14/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
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.38.1 h1:D0moEtIpjhWs2zbgeRyokA4TOLzBdumtpL1/O7/frww=
github.com/nbd-wtf/go-nostr v0.38.1/go.mod h1:TGKGj00BmJRXvRe0LlpDN3KKbELhhPXgBwUEhzu3Oq0=
github.com/nbd-wtf/go-nostr v0.42.0 h1:EofWfXEhKic9AYVf4RHuXZr+kKUZE2jVyJtJByNe1rE=
github.com/nbd-wtf/go-nostr v0.42.0/go.mod h1:FBa4FBJO7NuANvkeKSlrf0BIyxGufmrUbuelr6Q4Ick=
github.com/nbd-wtf/go-nostr v0.44.2 h1:+DHDbHuUZS3Fkh9w4j2v64sTLC4fY8ktuiBsNg9GcXg=
github.com/nbd-wtf/go-nostr v0.44.2/go.mod h1:m0ID2gSA2Oak/uaPnM1uN22JhDRZS4UVJG2c8jo19rg=
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= 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/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= 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/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
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.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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
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=
@ -73,17 +177,104 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
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.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
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-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
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.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
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-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-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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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.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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

508
main.go
View File

@ -4,20 +4,26 @@ import (
"context" "context"
"fmt" "fmt"
"html/template" "html/template"
"io"
"log" "log"
"net/http" "net/http"
"os" "os"
"sync" "strconv"
"strings"
"time" "time"
"github.com/cespare/xxhash" "github.com/fiatjaf/eventstore"
"github.com/fiatjaf/eventstore/lmdb" "github.com/fiatjaf/eventstore/badger"
"github.com/fiatjaf/khatru" "github.com/fiatjaf/khatru"
"github.com/greatroar/blobloom" "github.com/fiatjaf/khatru/policies"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
) )
var (
version string
)
type Config struct { type Config struct {
RelayName string RelayName string
RelayPubkey string RelayPubkey string
@ -26,59 +32,109 @@ type Config struct {
RelayURL string RelayURL string
IndexPath string IndexPath string
StaticPath string StaticPath string
RefreshInterval int
MinimumFollowers int
ArchivalSync bool
RelayContact string
RelayIcon string
MaxAgeDays int
ArchiveReactions bool
IgnoredPubkeys []string
} }
var archivePool *nostr.SimplePool var pool *nostr.SimplePool
var fetchingPool *nostr.SimplePool var wdb nostr.RelayStore
var relays []string var relays []string
var config Config var config Config
var trustNetwork []string var trustNetwork []string
var mu sync.Mutex var seedRelays []string
var booted bool
var oneHopNetwork []string
var trustNetworkMap map[string]bool
var pubkeyFollowerCount = make(map[string]int)
var trustedNotes uint64
var untrustedNotes uint64
func main() { func main() {
fmt.Println("starting") nostr.InfoLogger = log.New(io.Discard, "", 0)
booted = false
green := "\033[32m"
reset := "\033[0m"
art := `
888 888 88888888888 8888888b. 888
888 o 888 888 888 Y88b 888
888 d8b 888 888 888 888 888
888 d888b 888 .d88b. 888 888 d88P .d88b. 888 8888b. 888 888
888d88888b888 d88""88b 888 8888888P" d8P Y8b 888 "88b 888 888
88888P Y88888 888 888 888 888 T88b 88888888 888 .d888888 888 888
8888P Y8888 Y88..88P 888 888 T88b Y8b. 888 888 888 Y88b 888
888P Y888 "Y88P" 888 888 T88b "Y8888 888 "Y888888 "Y88888
888
Y8b d88P
powered by: khatru "Y88P"
`
fmt.Println(green + art + reset)
log.Println("🚀 booting up web of trust relay")
relay := khatru.NewRelay() relay := khatru.NewRelay()
ctx := context.Background() ctx := context.Background()
pool = nostr.NewSimplePool(ctx)
config = LoadConfig() config = LoadConfig()
relay.Info.Name = config.RelayName relay.Info.Name = config.RelayName
relay.Info.PubKey = config.RelayPubkey relay.Info.PubKey = config.RelayPubkey
relay.Info.Icon = config.RelayIcon
relay.Info.Contact = config.RelayContact
relay.Info.Description = config.RelayDescription relay.Info.Description = config.RelayDescription
relay.Info.Software = "https://github.com/bitvora/wot-relay"
relay.Info.Version = version
appendPubkey(config.RelayPubkey) appendPubkey(config.RelayPubkey)
db := lmdb.LMDBBackend{ db := getDB()
Path: getEnv("DB_PATH"),
}
if err := db.Init(); err != nil { if err := db.Init(); err != nil {
panic(err) panic(err)
} }
wdb = eventstore.RelayWrapper{Store: &db}
relay.RejectEvent = append(relay.RejectEvent,
policies.RejectEventsWithBase64Media,
policies.EventIPRateLimiter(5, time.Minute*1, 30),
)
relay.RejectFilter = append(relay.RejectFilter,
policies.NoEmptyFilters,
policies.NoComplexFilters,
)
relay.RejectConnection = append(relay.RejectConnection,
policies.ConnectionRateLimiter(10, time.Minute*2, 30),
)
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.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) { relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) {
for _, pk := range trustNetwork { if !trustNetworkMap[event.PubKey] {
if pk == event.PubKey { return true, "we are rebuilding the trust network, please try again later"
return false, ""
}
} }
return true, "you are not in the web of trust" if event.Kind == nostr.KindEncryptedDirectMessage {
return true, "only gift wrapped DMs are allowed"
}
return false, ""
}) })
mu.Lock() seedRelays = []string{
relays = []string{
"wss://nos.lol", "wss://nos.lol",
"wss://nostr.mom", "wss://nostr.mom",
"wss://purplepag.es", "wss://purplepag.es",
"wss://purplerelay.com", "wss://purplerelay.com",
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://relay.mostr.pub",
"wss://relay.nos.social",
"wss://relay.nostr.band", "wss://relay.nostr.band",
"wss://relay.snort.social", "wss://relay.snort.social",
"wss://relayable.org", "wss://relayable.org",
"wss://pyramid.fiatjaf.com",
"wss://relay.primal.net", "wss://relay.primal.net",
"wss://relay.nostr.bg", "wss://relay.nostr.bg",
"wss://no.str.cr", "wss://no.str.cr",
@ -86,12 +142,15 @@ func main() {
"wss://nostrue.com", "wss://nostrue.com",
"wss://relay.siamstr.com", "wss://relay.siamstr.com",
} }
mu.Unlock()
go refreshTrustNetwork(relay, ctx) go refreshTrustNetwork(ctx, relay)
go archiveTrustedNotes(relay, ctx)
mux := relay.Router() mux := relay.Router()
static := http.FileServer(http.Dir(config.StaticPath))
mux.Handle("GET /static/", http.StripPrefix("/static/", static))
mux.Handle("GET /favicon.ico", http.StripPrefix("/", static))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles(os.Getenv("INDEX_PATH"))) tmpl := template.Must(template.ParseFiles(os.Getenv("INDEX_PATH")))
data := struct { data := struct {
@ -111,9 +170,7 @@ func main() {
} }
}) })
mux.Handle("/favicon.ico", http.StripPrefix("/", http.FileServer(http.Dir(config.StaticPath)))) log.Println("🎉 relay running on port :3334")
fmt.Println("running on :3334")
err := http.ListenAndServe(":3334", relay) err := http.ListenAndServe(":3334", relay)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -123,14 +180,61 @@ func main() {
func LoadConfig() Config { func LoadConfig() Config {
godotenv.Load(".env") godotenv.Load(".env")
if os.Getenv("REFRESH_INTERVAL_HOURS") == "" {
os.Setenv("REFRESH_INTERVAL_HOURS", "3")
}
refreshInterval, _ := strconv.Atoi(os.Getenv("REFRESH_INTERVAL_HOURS"))
log.Println("🔄 refresh interval set to", refreshInterval, "hours")
if os.Getenv("MINIMUM_FOLLOWERS") == "" {
os.Setenv("MINIMUM_FOLLOWERS", "1")
}
if os.Getenv("ARCHIVAL_SYNC") == "" {
os.Setenv("ARCHIVAL_SYNC", "TRUE")
}
if os.Getenv("RELAY_ICON") == "" {
os.Setenv("RELAY_ICON", "https://pfp.nostr.build/56306a93a88d4c657d8a3dfa57b55a4ed65b709eee927b5dafaab4d5330db21f.png")
}
if os.Getenv("RELAY_CONTACT") == "" {
os.Setenv("RELAY_CONTACT", getEnv("RELAY_PUBKEY"))
}
if os.Getenv("MAX_AGE_DAYS") == "" {
os.Setenv("MAX_AGE_DAYS", "0")
}
if os.Getenv("ARCHIVE_REACTIONS") == "" {
os.Setenv("ARCHIVE_REACTIONS", "FALSE")
}
ignoredPubkeys := []string{}
if ignoreList := os.Getenv("IGNORE_FOLLOWS_LIST"); ignoreList != "" {
ignoredPubkeys = splitAndTrim(ignoreList)
}
minimumFollowers, _ := strconv.Atoi(os.Getenv("MINIMUM_FOLLOWERS"))
maxAgeDays, _ := strconv.Atoi(os.Getenv("MAX_AGE_DAYS"))
config := Config{ config := Config{
RelayName: getEnv("RELAY_NAME"), RelayName: getEnv("RELAY_NAME"),
RelayPubkey: getEnv("RELAY_PUBKEY"), RelayPubkey: getEnv("RELAY_PUBKEY"),
RelayDescription: getEnv("RELAY_DESCRIPTION"), RelayDescription: getEnv("RELAY_DESCRIPTION"),
RelayContact: getEnv("RELAY_CONTACT"),
RelayIcon: getEnv("RELAY_ICON"),
DBPath: getEnv("DB_PATH"), DBPath: getEnv("DB_PATH"),
RelayURL: getEnv("RELAY_URL"), RelayURL: getEnv("RELAY_URL"),
IndexPath: getEnv("INDEX_PATH"), IndexPath: getEnv("INDEX_PATH"),
StaticPath: getEnv("STATIC_PATH"), StaticPath: getEnv("STATIC_PATH"),
RefreshInterval: refreshInterval,
MinimumFollowers: minimumFollowers,
ArchivalSync: getEnv("ARCHIVAL_SYNC") == "TRUE",
MaxAgeDays: maxAgeDays,
ArchiveReactions: getEnv("ARCHIVE_REACTIONS") == "TRUE",
IgnoredPubkeys: ignoredPubkeys,
} }
return config return config
@ -144,148 +248,308 @@ func getEnv(key string) string {
return value return value
} }
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string { func updateTrustNetworkFilter() {
fetchingPool = nostr.NewSimplePool(ctx) trustNetworkMap = make(map[string]bool)
log.Println("🌐 updating trust network map")
for pubkey, count := range pubkeyFollowerCount {
if count >= config.MinimumFollowers {
trustNetworkMap[pubkey] = true
appendPubkey(pubkey)
}
}
log.Println("🌐 trust network map updated with", len(trustNetwork), "keys")
}
func refreshProfiles(ctx context.Context) {
for i := 0; i < len(trustNetwork); i += 200 {
timeout, cancel := context.WithTimeout(ctx, 4*time.Second)
defer cancel()
end := i + 200
if end > len(trustNetwork) {
end = len(trustNetwork)
}
filters := []nostr.Filter{{
Authors: trustNetwork[i:end],
Kinds: []int{nostr.KindProfileMetadata},
}}
for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
wdb.Publish(ctx, *ev.Event)
}
}
log.Println("👤 profiles refreshed: ", len(trustNetwork))
}
func refreshTrustNetwork(ctx context.Context, relay *khatru.Relay) {
// Function to refresh the trust network
runTrustNetworkRefresh := func() { runTrustNetworkRefresh := func() {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second) timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel() defer cancel()
filters := []nostr.Filter{{ filters := []nostr.Filter{{
Authors: []string{config.RelayPubkey}, Authors: []string{config.RelayPubkey},
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindFollowList},
}} }}
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) { log.Println("🔍 fetching owner's follows")
for ev := range pool.SubManyEose(timeoutCtx, seedRelays, filters) {
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) { for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
appendPubkey(contact[1]) pubkey := contact[1]
if isIgnored(pubkey, config.IgnoredPubkeys) {
fmt.Println("ignoring follows from pubkey: ", pubkey)
continue
}
pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
appendOneHopNetwork(contact[1])
} }
} }
chunks := make([][]string, 0) log.Println("🌐 building web of trust graph")
for i := 0; i < len(trustNetwork); i += 100 { for i := 0; i < len(oneHopNetwork); i += 100 {
timeout, cancel := context.WithTimeout(ctx, 4*time.Second)
defer cancel()
end := i + 100 end := i + 100
if end > len(trustNetwork) { if end > len(oneHopNetwork) {
end = len(trustNetwork) end = len(oneHopNetwork)
} }
chunks = append(chunks, trustNetwork[i:end])
}
for _, chunk := range chunks {
threeTimeoutCtx, tenCancel := context.WithTimeout(ctx, 10*time.Second)
defer tenCancel()
filters = []nostr.Filter{{ filters = []nostr.Filter{{
Authors: chunk, Authors: oneHopNetwork[i:end],
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindFollowList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
}} }}
for ev := range fetchingPool.SubManyEose(threeTimeoutCtx, relays, filters) { for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) { for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
if len(contact) > 1 { if len(contact) > 1 {
appendPubkey(contact[1]) pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
} else {
fmt.Println("Skipping malformed tag: ", contact)
} }
} }
for _, relay := range ev.Event.Tags.GetAll([]string{"r"}) {
appendRelay(relay[1])
}
if ev.Event.Kind == nostr.KindProfileMetadata {
wdb.Publish(ctx, *ev.Event)
}
} }
} }
log.Println("🫂 total network size:", len(pubkeyFollowerCount))
fmt.Println("trust network size:", len(trustNetwork)) log.Println("🔗 relays discovered:", len(relays))
getTrustNetworkProfileMetadata(relay, ctx)
} }
runTrustNetworkRefresh() for {
ticker := time.NewTicker(10 * time.Minute)
defer ticker.Stop()
for range ticker.C {
runTrustNetworkRefresh() runTrustNetworkRefresh()
updateTrustNetworkFilter()
deleteOldNotes(relay)
archiveTrustedNotes(ctx, relay)
} }
return trustNetwork
} }
func getTrustNetworkProfileMetadata(relay *khatru.Relay, ctx context.Context) { func appendRelay(relay string) {
chunks := make([][]string, 0)
for i := 0; i < len(trustNetwork); i += 100 {
end := i + 100
if end > len(trustNetwork) {
end = len(trustNetwork)
}
chunks = append(chunks, trustNetwork[i:end])
}
for _, chunk := range chunks { for _, r := range relays {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second) if r == relay {
defer cancel() return
filters := []nostr.Filter{{
Authors: chunk,
Kinds: []int{nostr.KindProfileMetadata},
}}
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
relay.AddEvent(ctx, ev.Event)
} }
} }
relays = append(relays, relay)
} }
func appendPubkey(pubkey string) { func appendPubkey(pubkey string) {
mu.Lock()
defer mu.Unlock()
for _, pk := range trustNetwork { for _, pk := range trustNetwork {
if pk == pubkey { if pk == pubkey {
return return
} }
} }
if len(pubkey) != 64 {
return
}
trustNetwork = append(trustNetwork, pubkey) trustNetwork = append(trustNetwork, pubkey)
} }
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) { func appendOneHopNetwork(pubkey string) {
ticker := time.NewTicker(1 * time.Minute) for _, pk := range oneHopNetwork {
defer ticker.Stop() if pk == pubkey {
return
archivePool = nostr.NewSimplePool(ctx)
for range ticker.C {
timeout, cancel := context.WithTimeout(ctx, 58*time.Second)
filters := []nostr.Filter{{
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindContactList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindReaction,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
}}
nKeys := uint64(len(trustNetwork))
bloomFilter := blobloom.NewOptimized(blobloom.Config{
Capacity: nKeys,
FPRate: 1e-4,
})
for _, trustedPubkey := range trustNetwork {
bloomFilter.Add(xxhash.Sum64([]byte(trustedPubkey)))
} }
}
for ev := range archivePool.SubManyEose(timeout, relays, filters) { if len(pubkey) != 64 {
return
}
if bloomFilter.Has(xxhash.Sum64([]byte(ev.Event.PubKey))) { oneHopNetwork = append(oneHopNetwork, pubkey)
if len(ev.Event.Tags) > 2000 { }
fmt.Println("skiping note with over 2000 tags")
continue func archiveTrustedNotes(ctx context.Context, relay *khatru.Relay) {
} timeout, cancel := context.WithTimeout(ctx, time.Duration(config.RefreshInterval)*time.Hour)
relay.AddEvent(ctx, ev.Event) defer cancel()
done := make(chan struct{})
go func() {
if config.ArchivalSync {
go refreshProfiles(ctx)
var filters []nostr.Filter
if config.ArchiveReactions {
filters = []nostr.Filter{{
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindReaction,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
}}
} else {
filters = []nostr.Filter{{
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
}}
}
log.Println("📦 archiving trusted notes...")
for ev := range pool.SubMany(timeout, seedRelays, filters) {
go archiveEvent(ctx, relay, *ev.Event)
}
log.Println("📦 archived", trustedNotes, "trusted notes and discarded", untrustedNotes, "untrusted notes")
} else {
log.Println("🔄 web of trust will refresh in", config.RefreshInterval, "hours")
select {
case <-timeout.Done():
} }
} }
cancel()
close(done)
}()
select {
case <-timeout.Done():
log.Println("restarting process")
case <-done:
log.Println("📦 archiving process completed")
} }
} }
func archiveEvent(ctx context.Context, relay *khatru.Relay, ev nostr.Event) {
if trustNetworkMap[ev.PubKey] {
wdb.Publish(ctx, ev)
relay.BroadcastEvent(&ev)
trustedNotes++
} else {
untrustedNotes++
}
}
func deleteOldNotes(relay *khatru.Relay) error {
ctx := context.TODO()
if config.MaxAgeDays <= 0 {
log.Printf("MAX_AGE_DAYS disabled")
return nil
}
maxAgeSecs := nostr.Timestamp(config.MaxAgeDays * 86400)
oldAge := nostr.Now() - maxAgeSecs
if oldAge <= 0 {
log.Printf("MAX_AGE_DAYS too large")
return nil
}
filter := nostr.Filter{
Until: &oldAge,
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindReaction,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
}
ch, err := relay.QueryEvents[0](ctx, filter)
if err != nil {
log.Printf("query error %s", err)
return err
}
events := make([]*nostr.Event, 0)
for evt := range ch {
events = append(events, evt)
}
if len(events) < 1 {
log.Println("0 old notes found")
return nil
}
for num_evt, del_evt := range events {
for _, del := range relay.DeleteEvent {
if err := del(ctx, del_evt); err != nil {
log.Printf("error deleting note %d of %d. event id: %s", num_evt, len(events), del_evt.ID)
return err
}
}
}
log.Printf("%d old (until %d) notes deleted", len(events), oldAge)
return nil
}
func getDB() badger.BadgerBackend {
return badger.BadgerBackend{
Path: getEnv("DB_PATH"),
}
}
func splitAndTrim(input string) []string {
items := strings.Split(input, ",")
for i, item := range items {
items[i] = strings.TrimSpace(item)
}
return items
}
func isIgnored(pubkey string, ignoredPubkeys []string) bool {
for _, ignored := range ignoredPubkeys {
if pubkey == ignored {
return true
}
}
return false
}

View File

@ -44,7 +44,14 @@
<!-- Footer --> <!-- Footer -->
<footer class="text-center py-6 bg-gray-800 w-full"> <footer class="text-center py-6 bg-gray-800 w-full">
<p class="text-lg text-gray-400"> <p class="text-lg text-gray-400">
Proudly powered by Built with love by
<a
href="https://bitvora.com"
target="_blank"
class="text-purple-300 hover:text-purple-400 underline"
>Bitvora</a
>
and Proudly powered by
<a <a
href="https://khatru.nostr.technology/" href="https://khatru.nostr.technology/"
target="_blank" target="_blank"