Compare commits

...

159 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
Barry Deen
62aac83d0a
Merge pull request #8 from bitvora/dev-updateReadme
update readme with better .env paths
2024-09-07 13:31:12 -04:00
Barry Deen
a385e86bad update readme with better .env paths 2024-09-07 13:29:56 -04:00
Barry Deen
5ba7aae9cd
Merge pull request #5 from HolgerHatGarKeineNode/master
feat: update Dockerfile, docker-compose and add Tor support for relay service
2024-09-07 13:25:19 -04:00
Barry Deen
ea3c498e24
Merge pull request #4 from fiatjaf/patch-1
don't fail when a `.env` file is not present
2024-09-07 13:23:31 -04:00
Barry Deen
6115af6ccd
Merge pull request #7 from bitvora/dev-bloomFilter
bloom filters, reduced logging
2024-09-07 13:23:05 -04:00
Barry Deen
3f3e42267e bloom filters, reduced logging 2024-09-07 13:21:22 -04:00
fsociety
3f38d91de6 docs: remove ENABLE_CLEARNET option from README.md 2024-09-07 17:14:06 +02:00
fsociety
3698089a8f feat: remove clearnet option from application configuration
This commit removes the ENABLE_CLEARNET option from the .env.example file and the docker-compose.tor.yml file. The application will now only use the default port 3334.
2024-09-07 17:05:30 +02:00
fsociety
4dc6cab618 feat: add optional Tor support with clearnet toggle
Added support for optionally running the wot-relay service as a Tor hidden service. Updated the docker-compose.tor.yml file to conditionally enable clearnet access, based on the `ENABLE_CLEARNET` environment variable. Updated the README.md file with instructions on how to use this feature.
2024-09-07 16:53:07 +02:00
fsociety
6372f55a7b feat: add Tor support for relay service
Add Tor support for the relay service in the docker-compose file. Also, rename the service from `wot-relay` to `relay`. Add a new `torrc` configuration file and a `.gitignore` file in the `tor/data` directory to prevent sensitive data from being tracked. Also, create a new `docker-compose.tor.yml` file for Tor-specific configurations.
2024-09-07 16:37:58 +02:00
fsociety
8458b2a10f feat: add .dockerignore file to wot-relay repository 2024-09-07 16:08:53 +02:00
fsociety
ca8dde54f1 feat: update Dockerfile, docker-compose and README for better Docker usage
This commit updates the Dockerfile to use a more docker-friendly approach. Instead of cloning the repository inside the Dockerfile, it now copies the files from the host. It also sets some fixed environment variables and uses a .env file for the rest.

The docker-compose.yml file now uses an .env file for more convenient environment variable management. It also maps volumes to the host, allowing you to change the paths of the `db` folder and `templates` folder.

The README.md has been updated with new instructions reflecting these changes. It now includes instructions for running the Docker container in the foreground or background, and for updating the relay.
2024-09-07 15:57:21 +02:00
fiatjaf_
e38dcc71ba
don't fail when a .env file is not present
still try to read it but let people use other ways to set up their environment variables.
2024-09-07 07:10:01 -03:00
17 changed files with 1059 additions and 250 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
db

View File

@ -1,6 +1,30 @@
# Relay Metadata
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_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"
INDEX_PATH="templates/index.html"
# 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/
.env
wot-relay
wot-relay

View File

@ -1,27 +1,31 @@
# Use Golang image based on Debian Bookworm
FROM golang:bookworm
# Set the working directory within the container
WORKDIR /app
# Clone the repository
RUN git clone https://github.com/bitvora/wot-relay .
# Download Go module dependencies
RUN go mod download
# Write the .env file
RUN touch .env && \
echo "RELAY_NAME=${RELAY_NAME}" >> .env && \
echo "RELAY_PUBKEY=${RELAY_PUBKEY}" >> .env && \
echo "RELAY_DESCRIPTION=${RELAY_DESCRIPTION}" >> .env && \
echo "DB_PATH=${DB_PATH}" >> .env
# Build the Go application
RUN go build -o main .
# Expose the port that the application will run on
EXPOSE 3334
# Set the command to run the executable
CMD ["./main"]
# 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 -o main .
# Expose the port that the application will run on
EXPOSE 3334
# Set the command to run the executable
CMD ["./main"]

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"]

162
README.md
View File

@ -1,10 +1,34 @@
# 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
- **Go**: Ensure you have Go installed on your system. You can download it from [here](https://golang.org/dl/).
- **Build Essentials**: If you're using Linux, you may need to install build essentials. You can do this by running `sudo apt install build-essential`.
## Setup Instructions
@ -31,9 +55,16 @@ Open the `.env` file and set the necessary environment variables. Example variab
```bash
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"
DB_PATH="/path/to/your/database"
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
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
@ -41,12 +72,12 @@ DB_PATH="/path/to/your/database"
Run the following command to build the relay:
```bash
go build
go build -ldflags "-X main.version=$(git describe --tags --always)"
```
### 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:
@ -62,10 +93,10 @@ Description=WOT Relay Service
After=network.target
[Service]
ExecStart=/path/to/wot-relay
WorkingDirectory=/path/to/wot-relay
ExecStart=/home/ubuntu/wot-relay/wot-relay
WorkingDirectory=/home/ubuntu/wot-relay
Restart=always
EnvironmentFile=/path/to/.env
MemoryLimit=2G
[Install]
WantedBy=multi-user.target
@ -91,32 +122,117 @@ sudo systemctl start 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:
1. Ensure Docker and Docker Compose are installed on your system.
2. Navigate to the project directory.
3. Edit the `docker-compose.yml` file to update the environment variables as needed:
3. Ensure the `.env` file is present in the project directory and has the necessary environment variables set.
4. You can also change the paths of the `db` folder and `templates` folder in the `docker-compose.yml` file.
```yaml
environment:
RELAY_NAME: "utxo WoT relay"
RELAY_PUBKEY: "YOURPUBKEY"
RELAY_DESCRIPTION: "Only notes in utxo WoT"
DB_PATH: "./db"
```
```yaml
volumes:
- "./db:/app/db" # only change the left side before the colon
- "./templates/index.html:${INDEX_PATH}" # only change the left side before the colon
- "./templates/static:${INDEX_PATH}" # only change the left side before the colon
```
4. Run the following command:
5. Run the following command:
```sh
docker-compose up --build
```
```sh
# in foreground
docker compose up --build
# in background
docker compose up --build -d
```
6. For updating the relay, run the following command:
```sh
git pull
docker compose build --no-cache
# in foreground
docker compose up
# in background
docker compose up -d
```
This will build the Docker image and start the `wot-relay` service as defined in the `docker-compose.yml` file. The application will be accessible on port 3334.
### 7. Hidden Service with Tor (optional)
### 7. Access the relay
Same as the step 6, but with the following command:
```sh
# in foreground
docker compose -f docker-compose.tor.yml up --build
# in background
docker compose -f docker-compose.tor.yml up --build -d
```
You can find the onion address here: `tor/data/relay/hostname`
### 8. Access the relay
Once everything is set up, the relay will be running on `localhost:3334`.

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

28
docker-compose.tor.yml Normal file
View File

@ -0,0 +1,28 @@
services:
relay:
container_name: wot-relay
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
volumes:
- "./db:/app/db"
- "./templates/index.html:${INDEX_PATH}"
- "./templates/static:${STATIC_PATH}"
ports:
- "3334"
restart: unless-stopped
init: true
tor:
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
container_name: wot-relay-tor
depends_on:
- relay
volumes:
- ./tor/torrc:/etc/tor/torrc
- ./tor/data:/var/lib/tor
restart: on-failure
stop_grace_period: 10m30s
init: true

View File

@ -1,14 +1,16 @@
services:
wot-relay:
build:
context: .
dockerfile: Dockerfile
environment:
RELAY_NAME: "utxo WoT relay"
RELAY_PUBKEY: "e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb"
RELAY_DESCRIPTION: "Only notes in utxo WoT"
DB_PATH: "./db"
volumes:
- "./db:/app/db"
ports:
- "3334:3334"
services:
relay:
container_name: wot-relay
build:
context: .
dockerfile: 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

67
go.mod
View File

@ -1,36 +1,55 @@
module github.com/bitvora/wot-relay
go 1.23.0
toolchain go1.23.1
go 1.23.1
require (
github.com/PowerDNS/lmdb-go v1.9.2 // indirect
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/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/fasthttp/websocket v1.5.7 // indirect
github.com/fiatjaf/eventstore v0.8.1 // indirect
github.com/fiatjaf/khatru v0.8.0 // indirect
github.com/fiatjaf/eventstore v0.14.4
github.com/fiatjaf/khatru v0.14.0
github.com/joho/godotenv v1.5.1
github.com/nbd-wtf/go-nostr v0.44.2
)
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/decred/dcrd/crypto/blake256 v1.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.0 // indirect
github.com/dgraph-io/ristretto v1.0.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/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // 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/klauspost/compress v1.17.8 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/nbd-wtf/go-nostr v0.34.14 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // 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/rs/cors v1.7.0 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tidwall/gjson v1.17.0 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.20.0 // indirect
github.com/valyala/fasthttp v1.58.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // 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
)

287
go.sum
View File

@ -1,56 +1,175 @@
github.com/PowerDNS/lmdb-go v1.9.2 h1:Cmgerh9y3ZKBZGz1irxSShhfmFyRUh+Zdk4cZk7ZJvU=
github.com/PowerDNS/lmdb-go v1.9.2/go.mod h1:TE0l+EZK8Z1B4dx070ZxkWTlp8RG1mjN0/+FkFRQMtU=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
fiatjaf.com/lib v0.2.0 h1:TgIJESbbND6GjOgGHxF5jsO6EMjuAxIzZHPo5DXYexs=
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/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/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/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
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/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.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.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
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/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
github.com/fiatjaf/eventstore v0.5.1 h1:tTh+JYP0RME51VY2QB2Gvtzj6QTaZAnSVhgZtrYqY2A=
github.com/fiatjaf/eventstore v0.5.1/go.mod h1:r5yCFmrVNT2b1xUOuMnDVS3xPGh97y8IgTcLyY2rYP8=
github.com/fiatjaf/eventstore v0.8.1 h1:51LchQNy0Hpb0YQHwqYR5pKBpfDs/KjySlWCbbz2pkc=
github.com/fiatjaf/eventstore v0.8.1/go.mod h1:bsp0Ibv0CIcVuFcoM2AEerMWmXRhF8uWXMf+dClhuow=
github.com/fiatjaf/khatru v0.8.0 h1:hofUi4qbSqkJiKD4rC9EyNdi9obzBvp3ykJOBxuu/h8=
github.com/fiatjaf/khatru v0.8.0/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
github.com/fasthttp/websocket v1.5.11 h1:TCO3H2VSxeTJQ+Ij+w8q7UBvdVedMOy/G7aZ0a6V19s=
github.com/fasthttp/websocket v1.5.11/go.mod h1:QWILjDXurHFN5519nH2Pe9rtRuKZ/OIx/rlBF9coYds=
github.com/fiatjaf/eventstore v0.10.1 h1:zgXrRhpyjzX0Eub4T6zkMZ60zRnIPJqy/Ipfx5h+yWo=
github.com/fiatjaf/eventstore v0.10.1/go.mod h1:h5CdLSF7mEQ7/rWpEABTRIrNuFoSwdQDi/nZkW/vVFU=
github.com/fiatjaf/eventstore v0.11.2 h1:gJTATGOk7RtDGt1qs47cLyTzko9phFyXlmWQb0zR7Lg=
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/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/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
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/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
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/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/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/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/nbd-wtf/go-nostr v0.34.14 h1:o4n2LkuAtdIjNYJ23sFbcx68UXLnji4j8hYR1Sd2wgI=
github.com/nbd-wtf/go-nostr v0.34.14/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew=
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
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/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.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/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
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.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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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/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.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@ -58,14 +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/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
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/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
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.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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
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=

506
main.go
View File

@ -4,18 +4,26 @@ import (
"context"
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
"sync"
"strconv"
"strings"
"time"
"github.com/fiatjaf/eventstore/lmdb"
"github.com/fiatjaf/eventstore"
"github.com/fiatjaf/eventstore/badger"
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/khatru/policies"
"github.com/joho/godotenv"
"github.com/nbd-wtf/go-nostr"
)
var (
version string
)
type Config struct {
RelayName string
RelayPubkey string
@ -24,59 +32,109 @@ type Config struct {
RelayURL string
IndexPath string
StaticPath string
RefreshInterval int
MinimumFollowers int
ArchivalSync bool
RelayContact string
RelayIcon string
MaxAgeDays int
ArchiveReactions bool
IgnoredPubkeys []string
}
var archivePool *nostr.SimplePool
var fetchingPool *nostr.SimplePool
var pool *nostr.SimplePool
var wdb nostr.RelayStore
var relays []string
var config Config
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() {
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()
ctx := context.Background()
pool = nostr.NewSimplePool(ctx)
config = LoadConfig()
relay.Info.Name = config.RelayName
relay.Info.PubKey = config.RelayPubkey
relay.Info.Icon = config.RelayIcon
relay.Info.Contact = config.RelayContact
relay.Info.Description = config.RelayDescription
relay.Info.Software = "https://github.com/bitvora/wot-relay"
relay.Info.Version = version
appendPubkey(config.RelayPubkey)
db := lmdb.LMDBBackend{
Path: getEnv("DB_PATH"),
}
db := getDB()
if err := db.Init(); err != nil {
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.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) {
for _, pk := range trustNetwork {
if pk == event.PubKey {
return false, ""
}
if !trustNetworkMap[event.PubKey] {
return true, "we are rebuilding the trust network, please try again later"
}
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()
relays = []string{
seedRelays = []string{
"wss://nos.lol",
"wss://nostr.mom",
"wss://purplepag.es",
"wss://purplerelay.com",
"wss://relay.damus.io",
"wss://relay.mostr.pub",
"wss://relay.nos.social",
"wss://relay.nostr.band",
"wss://relay.snort.social",
"wss://relayable.org",
"wss://pyramid.fiatjaf.com",
"wss://relay.primal.net",
"wss://relay.nostr.bg",
"wss://no.str.cr",
@ -84,12 +142,15 @@ func main() {
"wss://nostrue.com",
"wss://relay.siamstr.com",
}
mu.Unlock()
go refreshTrustNetwork(relay, ctx)
go archiveTrustedNotes(relay, ctx)
go refreshTrustNetwork(ctx, relay)
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) {
tmpl := template.Must(template.ParseFiles(os.Getenv("INDEX_PATH")))
data := struct {
@ -109,9 +170,7 @@ func main() {
}
})
mux.Handle("/favicon.ico", http.StripPrefix("/", http.FileServer(http.Dir(config.StaticPath))))
fmt.Println("running on :3334")
log.Println("🎉 relay running on port :3334")
err := http.ListenAndServe(":3334", relay)
if err != nil {
log.Fatal(err)
@ -119,19 +178,63 @@ func main() {
}
func LoadConfig() Config {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
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{
RelayName: getEnv("RELAY_NAME"),
RelayPubkey: getEnv("RELAY_PUBKEY"),
RelayDescription: getEnv("RELAY_DESCRIPTION"),
RelayContact: getEnv("RELAY_CONTACT"),
RelayIcon: getEnv("RELAY_ICON"),
DBPath: getEnv("DB_PATH"),
RelayURL: getEnv("RELAY_URL"),
IndexPath: getEnv("INDEX_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
@ -145,143 +248,308 @@ func getEnv(key string) string {
return value
}
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
fetchingPool = nostr.NewSimplePool(ctx)
func updateTrustNetworkFilter() {
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() {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
filters := []nostr.Filter{{
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"}) {
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)
for i := 0; i < len(trustNetwork); i += 100 {
log.Println("🌐 building web of trust graph")
for i := 0; i < len(oneHopNetwork); i += 100 {
timeout, cancel := context.WithTimeout(ctx, 4*time.Second)
defer cancel()
end := i + 100
if end > len(trustNetwork) {
end = len(trustNetwork)
if end > len(oneHopNetwork) {
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{{
Authors: chunk,
Kinds: []int{nostr.KindContactList},
Authors: oneHopNetwork[i:end],
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"}) {
if len(contact) > 1 {
appendPubkey(contact[1])
} else {
fmt.Println("Skipping malformed tag: ", contact)
pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
}
}
for _, relay := range ev.Event.Tags.GetAll([]string{"r"}) {
appendRelay(relay[1])
}
if ev.Event.Kind == nostr.KindProfileMetadata {
wdb.Publish(ctx, *ev.Event)
}
}
}
fmt.Println("trust network size:", len(trustNetwork))
getTrustNetworkProfileMetadata(relay, ctx)
log.Println("🫂 total network size:", len(pubkeyFollowerCount))
log.Println("🔗 relays discovered:", len(relays))
}
runTrustNetworkRefresh()
ticker := time.NewTicker(10 * time.Minute)
defer ticker.Stop()
for range ticker.C {
for {
runTrustNetworkRefresh()
updateTrustNetworkFilter()
deleteOldNotes(relay)
archiveTrustedNotes(ctx, relay)
}
return trustNetwork
}
func getTrustNetworkProfileMetadata(relay *khatru.Relay, ctx context.Context) {
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])
}
func appendRelay(relay string) {
for _, chunk := range chunks {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
filters := []nostr.Filter{{
Authors: chunk,
Kinds: []int{nostr.KindProfileMetadata},
}}
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
relay.AddEvent(ctx, ev.Event)
for _, r := range relays {
if r == relay {
return
}
}
relays = append(relays, relay)
}
func appendPubkey(pubkey string) {
mu.Lock()
defer mu.Unlock()
for _, pk := range trustNetwork {
if pk == pubkey {
return
}
}
if len(pubkey) != 64 {
return
}
trustNetwork = append(trustNetwork, pubkey)
}
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
func appendOneHopNetwork(pubkey string) {
for _, pk := range oneHopNetwork {
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,
},
}}
if len(pubkey) != 64 {
return
}
for ev := range archivePool.SubManyEose(timeout, relays, filters) {
for _, trustedPubkey := range trustNetwork {
if ev.Event.PubKey == trustedPubkey {
if ev.Event.Kind == nostr.KindContactList {
if len(ev.Event.Tags.GetAll([]string{"p"})) > 2000 {
fmt.Println("archiveTrustedNotes: skipping contact list with more than 2000 contacts. NoteID: ", ev.Event.ID)
continue
}
}
relay.AddEvent(ctx, ev.Event)
fmt.Println("archived trusted note: ", ev.Event.ID)
}
oneHopNetwork = append(oneHopNetwork, pubkey)
}
func archiveTrustedNotes(ctx context.Context, relay *khatru.Relay) {
timeout, cancel := context.WithTimeout(ctx, time.Duration(config.RefreshInterval)*time.Hour)
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 class="text-center py-6 bg-gray-800 w-full">
<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
href="https://khatru.nostr.technology/"
target="_blank"

2
tor/data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tor/torrc Normal file
View File

@ -0,0 +1,2 @@
HiddenServiceDir /var/lib/tor/relay
HiddenServicePort 80 relay:3334