diff --git a/.env b/example.env similarity index 51% rename from .env rename to example.env index 867fb12..2b14eaa 100644 --- a/.env +++ b/example.env @@ -1,8 +1,4 @@ -# Nostr Standard Relay Info RELAY_NAME="Name of the Relay" RELAY_DESCRIPTION="Description of the relay" RELAY_PUBKEY="07adfda9c5adc80881bb2a5220f6e3181e0c043b90fa115c4f183464022968e6" RELAY_CONTACT="email@example.com" - -# Custom invite-relay settings -INVITE_RELAY_MASTER="07adfda9c5adc80881bb2a5220f6e3181e0c043b90fa115c4f183464022968e6" # Master of the relay (pubkey hex) diff --git a/go.mod b/go.mod index d6875ed..5aaa6a3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,9 @@ go 1.20 require ( github.com/fiatjaf/khatru v0.0.0-20231003113207-bbe186494e68 github.com/joho/godotenv v1.5.1 + github.com/kelseyhightower/envconfig v1.4.0 github.com/nbd-wtf/go-nostr v0.20.0 + github.com/rs/zerolog v1.31.0 ) require ( @@ -32,6 +34,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/puzpuzpuz/xsync v1.5.2 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect @@ -45,6 +49,6 @@ require ( go.opencensus.io v0.22.5 // indirect golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.12.0 // indirect google.golang.org/protobuf v1.23.0 // indirect ) diff --git a/go.sum b/go.sum index 0a996d0..a11c682 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -62,6 +63,7 @@ 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -94,6 +96,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA 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/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -101,6 +105,11 @@ github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/d github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/nbd-wtf/go-nostr v0.20.0 h1:97SYhg68jWh5G1bW1g454hA0dTV7btwtPg836n4no0o= github.com/nbd-wtf/go-nostr v0.20.0/go.mod h1:iFfiZr8YYSC1vmdUei0VfDB7GH/RjS3cbmiD1I5BKyo= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -122,6 +131,9 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -188,10 +200,11 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/handler.go b/handler.go index d7a26f8..037bbde 100644 --- a/handler.go +++ b/handler.go @@ -20,8 +20,8 @@ func inviteTreeHandler(w http.ResponseWriter, r *http.Request) { formattedInviteData := buildHTMLTree(whitelist, "") data := map[string]interface{}{ - "Relayname": relayName, - "Relaydescription": relayDescription, + "Relayname": s.RelayName, + "Relaydescription": s.RelayDescription, "Pagetitle": "Invite Hierarchy", "Pagecontent": ` @@ -63,7 +63,7 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) { eTag := ev.Tags.GetFirst([]string{"e"}) if pTag != nil { - var typeReport = eTag.Relay()[6:] + typeReport := eTag.Relay()[6:] if typeReport == "" { typeReport = pTag.Relay()[6:] } @@ -132,8 +132,8 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) { } data := map[string]interface{}{ - "Relayname": relayName, - "Relaydescription": relayDescription, + "Relayname": s.RelayName, + "Relaydescription": s.RelayDescription, "Pagetitle": "Reports Viewer", "Pagecontent": formattedReportsData, } @@ -153,11 +153,11 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) { } func homePageHandler(w http.ResponseWriter, r *http.Request) { - relayOwnerInfo := getUserInfo(context.Background(), relayPubkey) + relayOwnerInfo := getUserInfo(context.Background(), s.RelayPubkey) data := map[string]interface{}{ - "Relayname": relayName, - "Relaydescription": relayDescription, + "Relayname": s.RelayName, + "Relaydescription": s.RelayDescription, "Pagetitle": "Info", "Pagecontent": template.HTML(fmt.Sprintf(`
Relay Name: %v
@@ -166,7 +166,7 @@ func homePageHandler(w http.ResponseWriter, r *http.Request) {
Relay Alternative Contact: %v

This relay uses Khatru Invite, which is build with Khatru
- `, relayName, relayDescription, relayOwnerInfo.Npub, relayOwnerInfo.Name, relayContact)), + `, s.RelayName, s.RelayDescription, relayOwnerInfo.Npub, relayOwnerInfo.Name, s.RelayContact)), } tmpl, err := template.ParseFS(dist, "ui/dist/index.html") diff --git a/main.go b/main.go index 4be1d3d..a4bd461 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "net/http" "os" "os/signal" @@ -12,18 +11,30 @@ import ( "github.com/fiatjaf/khatru" "github.com/fiatjaf/khatru/plugins/storage/badgern" "github.com/joho/godotenv" + "github.com/kelseyhightower/envconfig" + "github.com/rs/zerolog" ) +type Settings struct { + RelayName string `envconfig:"RELAY_NAME" required:"true"` + RelayPubkey string `envconfig:"RELAY_PUBKEY" required:"true"` + RelayDescription string `envconfig:"RELAY_DESCRIPTION"` + RelayContact string `envconfig:"RELAY_CONTACT"` +} + var ( - relayMaster string - db badgern.BadgerBackend - relayName string = "" - relayPubkey string = "" - relayDescription string = "none" - relayContact string = "none" + db badgern.BadgerBackend + s Settings + log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() ) func main() { + err := envconfig.Process("", &s) + if err != nil { + log.Fatal().Err(err).Msg("couldn't process envconfig") + return + } + // save whitelist on shutdown var wg sync.WaitGroup wg.Add(1) @@ -46,18 +57,10 @@ func main() { // init relay relay := khatru.NewRelay() - relayMaster = os.Getenv("INVITE_RELAY_MASTER") - - // add information here! - relayName = os.Getenv("RELAY_NAME") - relayPubkey = os.Getenv("RELAY_PUBKEY") - relayDescription = os.Getenv("RELAY_DESCRIPTION") - relayContact = os.Getenv("RELAY_CONTACT") - - relay.Name = relayName - relay.PubKey = relayPubkey - relay.Description = relayDescription - relay.Contact = relayContact + relay.Name = s.RelayName + relay.PubKey = s.RelayPubkey + relay.Description = s.RelayDescription + relay.Contact = s.RelayContact // load whitelist storage if err := loadWhitelist(); err != nil { @@ -82,7 +85,7 @@ func main() { relay.Router().HandleFunc("/users", inviteTreeHandler) relay.Router().HandleFunc("/", redirectHandler) - fmt.Println("running on :3334") + log.Info().Msg("running on http://127.0.0.1:3334") http.ListenAndServe(":3334", relay) } diff --git a/utils.go b/utils.go index e09257d..2326e33 100644 --- a/utils.go +++ b/utils.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "html/template" - "log" "github.com/nbd-wtf/go-nostr" ) @@ -15,7 +14,7 @@ func buildHTMLTree(entries []WhitelistEntry, invitedBy string) template.HTML { for _, entry := range entries { if entry.InvitedBy == invitedBy { - user := getUserInfo(context.TODO(), entry.Pk) + user := getUserInfo(context.TODO(), entry.PublicKey) html += fmt.Sprintf(`
  • %s @@ -23,8 +22,8 @@ func buildHTMLTree(entries []WhitelistEntry, invitedBy string) template.HTML { %s
  • `, template.HTMLEscapeString(user.Npub), template.HTMLEscapeString(user.Name), - entry.Pk, - buildHTMLTree(entries, entry.Pk)) + entry.PublicKey, + buildHTMLTree(entries, entry.PublicKey)) } } @@ -34,7 +33,7 @@ func buildHTMLTree(entries []WhitelistEntry, invitedBy string) template.HTML { func isPkInWhitelist(targetPk string) bool { for i := 0; i < len(whitelist); i++ { - if whitelist[i].Pk == targetPk { + if whitelist[i].PublicKey == targetPk { return true } } @@ -47,11 +46,11 @@ func deleteFromWhitelistRecursively(ctx context.Context, target string) { // Remove from whitelist for _, user := range whitelist { - if user.Pk != target { + if user.PublicKey != target { updatedWhitelist = append(updatedWhitelist, user) } if user.InvitedBy == target { - queue = append(queue, user.Pk) + queue = append(queue, user.PublicKey) } } whitelist = updatedWhitelist @@ -64,7 +63,7 @@ func deleteFromWhitelistRecursively(ctx context.Context, target string) { for ev := range events { err := db.DeleteEvent(ctx, ev) if err != nil { - log.Println("error while deleting event", err) + log.Error().Err(err).Msg("failed to delete event") } } @@ -80,7 +79,7 @@ func getProfileInfoFromJson(jsonStr string) (string, string) { var data map[string]interface{} err := json.Unmarshal([]byte(jsonStr), &data) if err != nil { - fmt.Println("Error parsing JSON:", err) + log.Error().Err(err).Msg("failed to read profile from json") return "", "" } diff --git a/whitelist.go b/whitelist.go index b32c84f..adb00a8 100644 --- a/whitelist.go +++ b/whitelist.go @@ -3,21 +3,19 @@ package main import ( "context" "encoding/json" - "log" "os" "github.com/nbd-wtf/go-nostr" ) type WhitelistEntry struct { - Pk string `json:"pk"` + PublicKey string `json:"pk"` InvitedBy string `json:"invited_by"` } var whitelist []WhitelistEntry func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg string) { - // check if user in whitelist if !isPkInWhitelist(evt.PubKey) { return true, "You are not invited to this relay" @@ -32,7 +30,7 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg for _, tag := range pTags { if !isPkInWhitelist(tag.Value()) { if nostr.IsValidPublicKeyHex(tag.Value()) { - whitelist = append(whitelist, WhitelistEntry{Pk: tag.Value(), InvitedBy: evt.PubKey}) + whitelist = append(whitelist, WhitelistEntry{PublicKey: tag.Value(), InvitedBy: evt.PubKey}) } } } @@ -52,13 +50,13 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg 2: Cant remove self 3: User should have invited user OR be relay admin */ - if user.Pk == tag.Value() && evt.PubKey != tag.Value() && (user.InvitedBy == evt.PubKey || evt.PubKey == relayMaster) { - log.Println("deleting user", tag.Value()) + if user.PublicKey == tag.Value() && evt.PubKey != tag.Value() && (user.InvitedBy == evt.PubKey || evt.PubKey == s.RelayPubkey) { + log.Info().Str("user", tag.Value()).Msg("deleting user") deleteFromWhitelistRecursively(ctx, tag.Value()) } } } - if evt.PubKey == relayMaster { + if evt.PubKey == s.RelayPubkey { eTags := evt.Tags.GetAll([]string{"e"}) for _, tag := range eTags { filter := nostr.Filter{ @@ -66,11 +64,11 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg } events, _ := db.QueryEvents(ctx, filter) - for ev := range events { - log.Println("deleting event", ev.ID) - err := db.DeleteEvent(ctx, ev) + for evt := range events { + log.Info().Str("event", evt.ID).Msg("deleting event") + err := db.DeleteEvent(ctx, evt) if err != nil { - log.Println("error while deleting event", err) + log.Warn().Err(err).Msg("failed to delete event") } } } @@ -78,7 +76,6 @@ func whitelistRejecter(ctx context.Context, evt *nostr.Event) (reject bool, msg } return false, "" - } func loadWhitelist() error {