khatru-pyramid/main.go

169 lines
5.0 KiB
Go
Raw Permalink Normal View History

2023-09-06 20:49:18 +02:00
package main
import (
"context"
"embed"
2023-10-28 21:40:54 -03:00
"encoding/json"
2023-09-06 20:49:18 +02:00
"net/http"
2023-10-28 21:40:54 -03:00
"net/url"
2023-09-06 20:49:18 +02:00
"os"
"os/signal"
"syscall"
2023-09-06 20:49:18 +02:00
2023-12-05 08:18:31 -03:00
"github.com/fiatjaf/eventstore/lmdb"
2023-09-06 20:49:18 +02:00
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/khatru/policies"
2023-10-16 23:09:12 -03:00
"github.com/kelseyhightower/envconfig"
2023-10-28 21:40:54 -03:00
"github.com/nbd-wtf/go-nostr"
2023-11-18 10:44:48 -03:00
"github.com/nbd-wtf/go-nostr/nip11"
2023-10-16 23:09:12 -03:00
"github.com/rs/zerolog"
"golang.org/x/sync/errgroup"
2023-09-06 20:49:18 +02:00
)
2023-10-16 23:09:12 -03:00
type Settings struct {
2023-10-18 11:58:09 -03:00
Port string `envconfig:"PORT" default:"3334"`
Domain string `envconfig:"DOMAIN" required:"true"`
2023-10-16 23:09:12 -03:00
RelayName string `envconfig:"RELAY_NAME" required:"true"`
RelayPubkey string `envconfig:"RELAY_PUBKEY" required:"true"`
RelayDescription string `envconfig:"RELAY_DESCRIPTION"`
RelayContact string `envconfig:"RELAY_CONTACT"`
2023-11-02 21:25:10 -03:00
RelayIcon string `envconfig:"RELAY_ICON"`
DatabasePath string `envconfig:"DATABASE_PATH" default:"./db"`
2024-02-23 15:20:17 +01:00
UserdataPath string `envconfig:"USERDATA_PATH" default:"./users.json"`
2024-02-02 09:29:54 -03:00
MaxInvitesPerPerson int `envconfig:"MAX_INVITES_PER_PERSON" default:"3"`
2023-10-16 23:09:12 -03:00
}
var (
2025-01-14 12:35:05 -03:00
s Settings
db = &lmdb.LMDBBackend{
MaxLimit: 500,
MaxLimitNegentropy: 999999,
EnableHLLCacheFor: func(kind int) (useCache bool, skipSavingActualEvent bool) {
switch kind {
case 7:
return true, true
default:
return false, false
}
},
}
2023-10-29 13:45:46 -03:00
log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
whitelist = make(Whitelist)
relay = khatru.NewRelay()
)
2023-09-13 19:48:24 +02:00
//go:embed static/*
var static embed.FS
2023-09-06 20:49:18 +02:00
func main() {
2023-10-16 23:09:12 -03:00
err := envconfig.Process("", &s)
if err != nil {
log.Fatal().Err(err).Msg("couldn't process envconfig")
return
}
2025-01-14 12:35:05 -03:00
// enable negentropy
relay.Negentropy = true
// load db
db.Path = s.DatabasePath
if err := db.Init(); err != nil {
log.Fatal().Err(err).Msg("failed to initialize database")
return
}
defer db.Close()
log.Debug().Str("path", db.Path).Msg("initialized database")
2023-09-06 20:49:18 +02:00
// init relay
2023-11-18 10:41:45 -03:00
relay.Info.Name = s.RelayName
relay.Info.PubKey = s.RelayPubkey
relay.Info.Description = s.RelayDescription
relay.Info.Contact = s.RelayContact
relay.Info.Icon = s.RelayIcon
2023-11-18 10:44:48 -03:00
relay.Info.Limitation = &nip11.RelayLimitationDocument{
RestrictedWrites: true,
}
relay.Info.Software = "https://github.com/github-tijlxyz/khatru-pyramid"
2023-09-13 19:48:24 +02:00
policies.ApplySaneDefaults(relay)
2023-09-06 20:49:18 +02:00
relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
2025-01-14 12:35:05 -03:00
relay.CountEventsHLL = append(relay.CountEventsHLL, db.CountEventsHLL)
relay.ReplaceEvent = append(relay.ReplaceEvent, db.ReplaceEvent)
2023-09-06 20:49:18 +02:00
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
relay.RejectEvent = append(relay.RejectEvent,
policies.PreventLargeTags(100),
policies.PreventTooManyIndexableTags(9, []int{3}, nil),
policies.PreventTooManyIndexableTags(1200, nil, []int{3}),
2024-10-22 13:34:23 -03:00
policies.RestrictToSpecifiedKinds(true, supportedKinds...),
rejectEventsFromUsersNotInWhitelist,
validateAndFilterReports,
)
relay.OverwriteFilter = append(relay.OverwriteFilter,
policies.RemoveAllButKinds(supportedKinds...),
removeAuthorsNotWhitelisted,
)
relay.RejectFilter = append(relay.RejectFilter,
policies.NoSearchQueries,
)
relay.ManagementAPI.AllowPubKey = allowPubKeyHandler
relay.ManagementAPI.BanPubKey = banPubKeyHandler
2024-07-11 16:00:45 -03:00
relay.ManagementAPI.ListAllowedPubKeys = listAllowedPubKeysHandler
// load users registry
if err := loadWhitelist(); err != nil {
log.Fatal().Err(err).Msg("failed to load whitelist")
return
}
2023-09-06 20:49:18 +02:00
// http routes
2023-10-28 20:21:15 -03:00
relay.Router().HandleFunc("/add-to-whitelist", addToWhitelistHandler)
relay.Router().HandleFunc("/remove-from-whitelist", removeFromWhitelistHandler)
relay.Router().HandleFunc("/cleanup", cleanupStuffFromExcludedUsersHandler)
relay.Router().HandleFunc("/reports", reportsViewerHandler)
2024-11-14 13:51:10 -03:00
relay.Router().HandleFunc("/browse/", joubleHandler)
relay.Router().Handle("/static/", http.FileServer(http.FS(static)))
relay.Router().HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
if s.RelayIcon != "" {
http.Redirect(w, r, s.RelayIcon, 302)
} else {
http.Redirect(w, r, "/static/icon.png", 302)
}
})
2024-02-01 12:51:05 -03:00
relay.Router().HandleFunc("/", inviteTreeHandler)
2023-09-06 20:49:18 +02:00
2023-10-18 11:58:09 -03:00
log.Info().Msg("running on http://0.0.0.0:" + s.Port)
server := &http.Server{Addr: ":" + s.Port, Handler: relay}
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
g, ctx := errgroup.WithContext(ctx)
g.Go(server.ListenAndServe)
g.Go(func() error {
<-ctx.Done()
return server.Shutdown(context.Background())
})
if err := g.Wait(); err != nil {
log.Debug().Err(err).Msg("exit reason")
2023-10-18 11:58:09 -03:00
}
2023-09-06 20:49:18 +02:00
}
2023-10-28 21:40:54 -03:00
func getLoggedUser(r *http.Request) string {
if cookie, _ := r.Cookie("nip98"); cookie != nil {
if evtj, err := url.QueryUnescape(cookie.Value); err == nil {
var evt nostr.Event
if err := json.Unmarshal([]byte(evtj), &evt); err == nil {
if tag := evt.Tags.GetFirst([]string{"domain", ""}); tag != nil && (*tag)[1] == s.Domain {
if ok, _ := evt.CheckSignature(); ok {
return evt.PubKey
}
}
2023-10-28 21:40:54 -03:00
}
}
}
return ""
}