From 001771cb6c97865ba62acb306348f9fff314d07d Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Mon, 29 Sep 2025 12:07:29 -0700 Subject: [PATCH] Tweak config format --- README.md | 16 +++++++--------- zooid/config.go | 30 +++++++++++++++++++++--------- zooid/env.go | 1 + zooid/events.go | 5 ++++- zooid/instance.go | 30 +++++++++++++++++++----------- zooid/management.go | 4 ++-- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 14a53c9..a3a9713 100644 --- a/README.md +++ b/README.md @@ -12,21 +12,19 @@ Zooid supports a few environment variables, which configure shared resources lik - `PORT` - the port the server will listen on for all requests. Defaults to `3334`. - `DATA` - the location of the directory for storing database files and media. Defaults to `./data`. +- `CONF` - the location of the directory for storing relay configuration files. Defaults to `./conf`. ## Configuration -Configuration files are written using [toml](https://toml.io) files placed in the `./config` directory. The name of the configuration file should be the hostname the relay serves, for example `relay.example.com`. Config files contain the following sections: - -### `[self]` - -Contains information for populating the relay's `nip11` document. - -Required: +Configuration files are written using [toml](https://toml.io) files placed in the `CONF` directory. Top level configuration options are required: +- `host` - a hostname to serve this relay on. - `schema` - a string that identifies this relay. This cannot be changed, and must be usable as a sqlite identifier. - `secret` - the nostr secret key of the relay. Will be used to populate the relay's NIP 11 `self` field and sign generated events. -Optional: +### `[info]` + +Contains information for populating the relay's `nip11` document. - `name` - the name of your relay. - `icon` - an icon for your relay. @@ -37,7 +35,7 @@ Optional: Contains policy and access related configuration. -- `strip_signatures` - whether to remove signatures when serving events. This requires clients/users to trust the relay to properly authenticate signatures. Be cautious about using this; a malicious relay will be able to execute all kinds of attacks, including potentially serving events unrelated to a community use case. +- `strip_signatures` - whether to remove signatures when serving events to non-admins. This requires clients/users to trust the relay to properly authenticate signatures. Be cautious about using this; a malicious relay will be able to execute all kinds of attacks, including potentially serving events unrelated to a community use case. ### `[groups]` diff --git a/zooid/config.go b/zooid/config.go index b30362b..4fbe649 100644 --- a/zooid/config.go +++ b/zooid/config.go @@ -15,12 +15,12 @@ type Role struct { } type Config struct { - Host string - Secret nostr.SecretKey - Self struct { + Host string `toml:"host"` + Schema string `toml:"schema"` + Secret string `toml:"secret"` + Info struct { Name string `toml:"name"` Icon string `toml:"icon"` - Schema string `toml:"schema"` Secret string `toml:"secret"` Pubkey string `toml:"pubkey"` Description string `toml:"description"` @@ -46,6 +46,9 @@ type Config struct { } `toml:"blossom"` Roles map[string]Role `toml:"roles"` + + // Private/parsed values + secret nostr.SecretKey } func LoadConfig(hostname string) (*Config, error) { @@ -56,23 +59,32 @@ func LoadConfig(hostname string) (*Config, error) { return nil, fmt.Errorf("failed to parse config file %s: %w", path, err) } - secret, err := nostr.SecretKeyFromHex(config.Self.Secret) + secret, err := nostr.SecretKeyFromHex(config.Secret) if err != nil { return nil, err } - config.Host = hostname - config.Secret = secret + // Make the secret... secret + config.Secret = "" + config.secret = secret return &config, nil } +func (config *Config) GetSelf() nostr.PubKey { + return config.secret.Public() +} + func (config *Config) IsSelf(pubkey nostr.PubKey) bool { - return pubkey == nostr.MustSecretKeyFromHex(config.Self.Secret).Public() + return pubkey == config.GetSelf() +} + +func (config *Config) Sign(event *nostr.Event) error { + return event.Sign(config.secret) } func (config *Config) IsOwner(pubkey nostr.PubKey) bool { - return pubkey == nostr.MustPubKeyFromHex(config.Self.Pubkey) + return pubkey == nostr.MustPubKeyFromHex(config.Info.Pubkey) } func (config *Config) GetRolesForPubkey(pubkey nostr.PubKey) []Role { diff --git a/zooid/env.go b/zooid/env.go index 5b06181..b109c2e 100644 --- a/zooid/env.go +++ b/zooid/env.go @@ -17,6 +17,7 @@ func Env(k string, fallback ...string) (v string) { env["PORT"] = "3334" env["DATA"] = "./data" + env["CONF"] = "./conf" for _, item := range os.Environ() { parts := strings.SplitN(item, "=", 2) diff --git a/zooid/events.go b/zooid/events.go index 80f9454..61240ac 100644 --- a/zooid/events.go +++ b/zooid/events.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "iter" + "log" "fiatjaf.com/nostr" "fiatjaf.com/nostr/eventstore" @@ -356,7 +357,9 @@ func (events *EventStore) GetOrCreateApplicationSpecificData(d string) nostr.Eve }, } - event.Sign(events.Config.Secret) + if err := events.Config.Sign(&event); err != nil { + log.Println("Failed to sign application specific event: %w", err) + } events.SaveEvent(event) diff --git a/zooid/instance.go b/zooid/instance.go index 70f2557..a9a5f1a 100644 --- a/zooid/instance.go +++ b/zooid/instance.go @@ -5,6 +5,7 @@ import ( "iter" "log" "net/http" + "os" "path/filepath" "slices" "strings" @@ -50,6 +51,12 @@ func GetInstance(hostname string) (*Instance, error) { } func MonitorInstances() { + dir := Env("CONF") + + if err := os.MkdirAll(dir, 0755); err != nil { + log.Fatal("Failed to create config directory: %v", err) + } + watcher, err := fsnotify.NewWatcher() if err != nil { log.Printf("Failed to create file watcher: %v", err) @@ -57,7 +64,7 @@ func MonitorInstances() { } defer watcher.Close() - if err := watcher.Add("./config"); err != nil { + if err := watcher.Add(dir); err != nil { log.Printf("Failed to watch config directory: %v", err) return } @@ -108,7 +115,7 @@ func MakeInstance(hostname string) (*Instance, error) { return nil, err } - pubkey, err := nostr.PubKeyFromHex(config.Self.Pubkey) + pubkey, err := nostr.PubKeyFromHex(config.Info.Pubkey) if err != nil { return nil, err } @@ -116,7 +123,7 @@ func MakeInstance(hostname string) (*Instance, error) { events := &EventStore{ Config: config, Schema: &Schema{ - Name: slug.Make(config.Self.Schema), + Name: slug.Make(config.Schema), }, } @@ -139,10 +146,10 @@ func MakeInstance(hostname string) (*Instance, error) { } instance.Relay.Negentropy = true - instance.Relay.Info.Name = config.Self.Name - instance.Relay.Info.Icon = config.Self.Icon + instance.Relay.Info.Name = config.Info.Name + instance.Relay.Info.Icon = config.Info.Icon instance.Relay.Info.PubKey = &pubkey - instance.Relay.Info.Description = config.Self.Description + instance.Relay.Info.Description = config.Info.Description // instance.Relay.Info.Self = nostr.GetPublicKey(secret) instance.Relay.Info.Software = "https://github.com/coracle-social/zooid" instance.Relay.Info.Version = "v0.1.0" @@ -285,11 +292,12 @@ func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event { }, } - event.Sign(instance.Config.Secret) + if err := instance.Config.Sign(&event); err != nil { + log.Printf("Failed to sign invite event: %v", err) + } - err := instance.Events.SaveEvent(event) - if err != nil { - log.Printf("Failed to generate invite event: %v", err) + if err := instance.Events.SaveEvent(event); err != nil { + log.Printf("Failed to save invite event: %v", err) } return event @@ -427,7 +435,7 @@ func (instance *Instance) DeleteEvent(ctx context.Context, id nostr.ID) error { func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) { addEvent := func(newEvent nostr.Event) { - if err := newEvent.Sign(instance.Config.Secret); err != nil { + if err := instance.Config.Sign(&newEvent); err != nil { log.Println(err) } else { if err := instance.Events.SaveEvent(newEvent); err != nil { diff --git a/zooid/management.go b/zooid/management.go index 6364b5e..4824dd8 100644 --- a/zooid/management.go +++ b/zooid/management.go @@ -167,12 +167,12 @@ func (m *ManagementStore) Enable(instance *Instance) { reasons := make([]nip86.PubKeyReason, 0) reasons = append(reasons, nip86.PubKeyReason{ - PubKey: nostr.MustPubKeyFromHex(m.Config.Self.Pubkey), + PubKey: nostr.MustPubKeyFromHex(m.Config.Info.Pubkey), Reason: "relay owner", }) reasons = append(reasons, nip86.PubKeyReason{ - PubKey: m.Config.Secret.Public(), + PubKey: m.Config.GetSelf(), Reason: "relay self", })