mirror of
https://github.com/bitvora/wot-relay.git
synced 2025-04-19 18:21:18 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
2ce02fba9c
12
.env.example
12
.env.example
@ -1,7 +1,17 @@
|
||||
# Relay Metadata
|
||||
RELAY_NAME="utxo WoT relay"
|
||||
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb"
|
||||
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb" # not your npub!
|
||||
RELAY_DESCRIPTION="Only notes in utxo WoT"
|
||||
RELAY_URL="wss://wot.utxo.one"
|
||||
|
||||
# where we should store the database
|
||||
DB_PATH="db"
|
||||
|
||||
# where we should store the index.html and static files
|
||||
INDEX_PATH="templates/index.html"
|
||||
STATIC_PATH="templates/static"
|
||||
|
||||
# relay behavior
|
||||
|
||||
# how often to refresh the relay's view of the WoT in HOURS
|
||||
REFRESH_INTERVAL_HOURS=24
|
68
README.md
68
README.md
@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@ -37,6 +37,7 @@ RELAY_DESCRIPTION="Your relay description"
|
||||
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=24 # interval in hours to refresh the web of trust
|
||||
```
|
||||
|
||||
### 4. Build the project
|
||||
@ -65,10 +66,9 @@ 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 #change this to your path
|
||||
WorkingDirectory=/home/ubuntu/wot-relay #change this to your path
|
||||
Restart=always
|
||||
EnvironmentFile=/path/to/.env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -94,7 +94,63 @@ 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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
|
95
main.go
95
main.go
@ -7,6 +7,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -25,6 +26,7 @@ type Config struct {
|
||||
RelayURL string
|
||||
IndexPath string
|
||||
StaticPath string
|
||||
RefreshInterval int
|
||||
}
|
||||
|
||||
var pool *nostr.SimplePool
|
||||
@ -35,19 +37,27 @@ var mu sync.Mutex
|
||||
var trustNetworkFilter *blobloom.Filter
|
||||
var trustNetworkFilterMu sync.Mutex
|
||||
var seedRelays []string
|
||||
var booted bool
|
||||
var oneHopNetwork []string
|
||||
|
||||
func main() {
|
||||
booted = false
|
||||
green := "\033[32m"
|
||||
reset := "\033[0m"
|
||||
|
||||
art := `
|
||||
__ __ ___. _____ ___________ __
|
||||
/ \ / \ ____\_ |__ _____/ ____\ \__ ___/______ __ __ _______/ |_
|
||||
\ \/\/ // __ \| __ \ / _ \ __\ | | \_ __ \ | \/ ___/\ __\
|
||||
\ /\ ___/| \_\ \ ( <_> ) | | | | | \/ | /\___ \ | |
|
||||
\__/\ / \___ >___ / \____/|__| |____| |__| |____//____ > |__|
|
||||
\/ \/ \/ \/
|
||||
`
|
||||
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")
|
||||
@ -101,7 +111,6 @@ func main() {
|
||||
mu.Unlock()
|
||||
|
||||
go refreshTrustNetwork(relay, ctx)
|
||||
go archiveTrustedNotes(relay, ctx)
|
||||
|
||||
mux := relay.Router()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -135,6 +144,13 @@ func main() {
|
||||
func LoadConfig() Config {
|
||||
godotenv.Load(".env")
|
||||
|
||||
if os.Getenv("REFRESH_INTERVAL_HOURS") == "" {
|
||||
os.Setenv("REFRESH_INTERVAL_HOURS", "24")
|
||||
}
|
||||
|
||||
refreshInterval, _ := strconv.Atoi(os.Getenv("REFRESH_INTERVAL_HOURS"))
|
||||
log.Println("🔄 refresh interval set to", refreshInterval, "hours")
|
||||
|
||||
config := Config{
|
||||
RelayName: getEnv("RELAY_NAME"),
|
||||
RelayPubkey: getEnv("RELAY_PUBKEY"),
|
||||
@ -143,6 +159,7 @@ func LoadConfig() Config {
|
||||
RelayURL: getEnv("RELAY_URL"),
|
||||
IndexPath: getEnv("INDEX_PATH"),
|
||||
StaticPath: getEnv("STATIC_PATH"),
|
||||
RefreshInterval: refreshInterval,
|
||||
}
|
||||
|
||||
return config
|
||||
@ -171,10 +188,10 @@ func updateTrustNetworkFilter() {
|
||||
}
|
||||
}
|
||||
|
||||
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
|
||||
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) {
|
||||
|
||||
runTrustNetworkRefresh := func() {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
filters := []nostr.Filter{{
|
||||
@ -185,25 +202,22 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
|
||||
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])
|
||||
appendOneHopNetwork(contact[1])
|
||||
}
|
||||
}
|
||||
|
||||
follows := make([]string, len(trustNetwork))
|
||||
copy(follows, trustNetwork)
|
||||
|
||||
log.Println("🌐 building web of trust graph")
|
||||
for i := 0; i < len(follows); i += 200 {
|
||||
for i := 0; i < len(oneHopNetwork); i += 100 {
|
||||
timeout, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
end := i + 200
|
||||
if end > len(follows) {
|
||||
end = len(follows)
|
||||
end := i + 100
|
||||
if end > len(oneHopNetwork) {
|
||||
end = len(oneHopNetwork)
|
||||
}
|
||||
|
||||
filters = []nostr.Filter{{
|
||||
Authors: follows[i:end],
|
||||
Authors: oneHopNetwork[i:end],
|
||||
Kinds: []int{nostr.KindContactList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
|
||||
}}
|
||||
|
||||
@ -228,18 +242,11 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
|
||||
log.Println("🔗 relays discovered:", len(relays))
|
||||
}
|
||||
|
||||
runTrustNetworkRefresh()
|
||||
updateTrustNetworkFilter()
|
||||
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
for {
|
||||
runTrustNetworkRefresh()
|
||||
updateTrustNetworkFilter()
|
||||
archiveTrustedNotes(relay, ctx)
|
||||
}
|
||||
|
||||
return trustNetwork
|
||||
}
|
||||
|
||||
func appendRelay(relay string) {
|
||||
@ -271,10 +278,25 @@ func appendPubkey(pubkey string) {
|
||||
trustNetwork = append(trustNetwork, pubkey)
|
||||
}
|
||||
|
||||
func appendOneHopNetwork(pubkey string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for _, pk := range oneHopNetwork {
|
||||
if pk == pubkey {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(pubkey) != 64 {
|
||||
return
|
||||
}
|
||||
|
||||
oneHopNetwork = append(oneHopNetwork, pubkey)
|
||||
}
|
||||
|
||||
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
||||
log.Println("⏳ waiting for trust network to be populated")
|
||||
time.Sleep(1 * time.Minute)
|
||||
timeout, cancel := context.WithTimeout(ctx, 24*time.Hour)
|
||||
timeout, cancel := context.WithTimeout(ctx, time.Duration(config.RefreshInterval)*time.Hour)
|
||||
defer cancel()
|
||||
|
||||
filters := []nostr.Filter{{
|
||||
@ -294,7 +316,8 @@ func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
||||
}}
|
||||
|
||||
log.Println("📦 archiving trusted notes...")
|
||||
var i int64
|
||||
var trustedNotes uint64
|
||||
var untrustedNotes uint64
|
||||
trustNetworkFilterMu.Lock()
|
||||
for ev := range pool.SubMany(timeout, seedRelays, filters) {
|
||||
if trustNetworkFilter.Has(xxhash.Sum64([]byte(ev.Event.PubKey))) {
|
||||
@ -302,9 +325,11 @@ func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
||||
continue
|
||||
}
|
||||
relay.AddEvent(ctx, ev.Event)
|
||||
i++
|
||||
trustedNotes++
|
||||
} else {
|
||||
untrustedNotes++
|
||||
}
|
||||
}
|
||||
trustNetworkFilterMu.Unlock()
|
||||
fmt.Println("📦 archived", i, "trusted notes")
|
||||
log.Println("📦 archived", trustedNotes, "trusted notes and discarded", untrustedNotes, "untrusted notes")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user