Clean up config file name stuff

This commit is contained in:
Jon Staab
2026-05-26 15:50:14 -07:00
parent 2fcc48abed
commit e9260f40f1
7 changed files with 65 additions and 63 deletions
+3 -2
View File
@@ -25,8 +25,9 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// Load config for the specified relay name := zooid.ConfigNameFromId(*relay)
config, err := zooid.LoadConfigFromId(*relay) path := zooid.ConfigPathFromName(name)
config, err := zooid.LoadConfigFromPath(path)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
+3 -2
View File
@@ -39,8 +39,9 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// Load config for the specified relay name := zooid.ConfigNameFromId(*relay)
config, err := zooid.LoadConfigFromId(*relay) path := zooid.ConfigPathFromName(name)
config, err := zooid.LoadConfigFromPath(path)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
+25 -26
View File
@@ -28,7 +28,7 @@ func NewAPIHandler() *APIHandler {
whitelist: whitelist, whitelist: whitelist,
} }
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("POST /relay/{id}", api.auth(api.createRelay)) mux.HandleFunc("POST /relay/{id}", api.auth(api.createRelay))
mux.HandleFunc("PUT /relay/{id}", api.auth(api.putRelay)) mux.HandleFunc("PUT /relay/{id}", api.auth(api.putRelay))
mux.HandleFunc("PATCH /relay/{id}", api.auth(api.patchRelay)) mux.HandleFunc("PATCH /relay/{id}", api.auth(api.patchRelay))
@@ -37,7 +37,7 @@ func NewAPIHandler() *APIHandler {
api.mux = mux api.mux = mux
return api return api
} }
func (api *APIHandler) auth(next http.HandlerFunc) http.HandlerFunc { func (api *APIHandler) auth(next http.HandlerFunc) http.HandlerFunc {
@@ -72,7 +72,7 @@ func writeJSON(w http.ResponseWriter, status int, v any) {
// Relay CRUD // Relay CRUD
func (api *APIHandler) configFromRequest(r *http.Request) (*Config, error) { func (api *APIHandler) configFromRequest(path string, r *http.Request) (*Config, error) {
r.Body = http.MaxBytesReader(nil, r.Body, 1024*1024) r.Body = http.MaxBytesReader(nil, r.Body, 1024*1024)
defer r.Body.Close() defer r.Body.Close()
@@ -81,16 +81,7 @@ func (api *APIHandler) configFromRequest(r *http.Request) (*Config, error) {
return nil, fmt.Errorf("failed to read body: %w", err) return nil, fmt.Errorf("failed to read body: %w", err)
} }
var config Config return LoadConfigFromJson(path, body)
if err := json.Unmarshal(body, &config); err != nil {
return nil, fmt.Errorf("invalid json config: %w", err)
}
if err := config.Validate(); err != nil {
return nil, err
}
return &config, nil
} }
func (api *APIHandler) patchFromRequest(r *http.Request) (map[string]interface{}, error) { func (api *APIHandler) patchFromRequest(r *http.Request) (map[string]interface{}, error) {
@@ -121,7 +112,9 @@ func (api *APIHandler) checkDuplicateSchemaOrHost(config *Config, excludeFilenam
continue continue
} }
if existing, err := LoadConfigFromName(entry.Name()); err == nil { path := ConfigPathFromName(entry.Name())
if existing, err := LoadConfigFromPath(path); err == nil {
if existing.Schema == config.Schema { if existing.Schema == config.Schema {
return fmt.Errorf("schema %q is already in use", config.Schema) return fmt.Errorf("schema %q is already in use", config.Schema)
} }
@@ -137,13 +130,14 @@ func (api *APIHandler) checkDuplicateSchemaOrHost(config *Config, excludeFilenam
// Create relay // Create relay
func (api *APIHandler) createRelay(w http.ResponseWriter, r *http.Request) { func (api *APIHandler) createRelay(w http.ResponseWriter, r *http.Request) {
path := ConfigPathFromId(r.PathValue("id")) name := ConfigNameFromId(r.PathValue("id"))
path := ConfigPathFromName(name)
if _, err := os.Stat(path); err == nil { if _, err := os.Stat(path); err == nil {
writeError(w, http.StatusConflict, "relay with this id already exists") writeError(w, http.StatusConflict, "relay with this id already exists")
return return
} }
config, err := api.configFromRequest(r) config, err := api.configFromRequest(path, r)
if err != nil { if err != nil {
writeError(w, http.StatusBadRequest, err.Error()) writeError(w, http.StatusBadRequest, err.Error())
return return
@@ -166,19 +160,20 @@ func (api *APIHandler) createRelay(w http.ResponseWriter, r *http.Request) {
func (api *APIHandler) putRelay(w http.ResponseWriter, r *http.Request) { func (api *APIHandler) putRelay(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") id := r.PathValue("id")
path := ConfigPathFromId(id) name := ConfigNameFromId(id)
path := ConfigPathFromName(name)
if _, err := os.Stat(path); err != nil { if _, err := os.Stat(path); err != nil {
writeError(w, http.StatusConflict, "relay not found") writeError(w, http.StatusConflict, "relay not found")
return return
} }
config, err := api.configFromRequest(r) config, err := api.configFromRequest(path, r)
if err != nil { if err != nil {
writeError(w, http.StatusBadRequest, err.Error()) writeError(w, http.StatusBadRequest, err.Error())
return return
} }
if err := api.checkDuplicateSchemaOrHost(config, id+".toml"); err != nil { if err := api.checkDuplicateSchemaOrHost(config, name); err != nil {
writeError(w, http.StatusConflict, err.Error()) writeError(w, http.StatusConflict, err.Error())
return return
} }
@@ -195,7 +190,8 @@ func (api *APIHandler) putRelay(w http.ResponseWriter, r *http.Request) {
func (api *APIHandler) patchRelay(w http.ResponseWriter, r *http.Request) { func (api *APIHandler) patchRelay(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") id := r.PathValue("id")
path := ConfigPathFromId(id) name := ConfigNameFromId(id)
path := ConfigPathFromName(name)
if _, err := os.Stat(path); err != nil { if _, err := os.Stat(path); err != nil {
writeError(w, http.StatusConflict, "relay not found") writeError(w, http.StatusConflict, "relay not found")
return return
@@ -223,7 +219,7 @@ func (api *APIHandler) patchRelay(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := api.checkDuplicateSchemaOrHost(config, id+".toml"); err != nil { if err := api.checkDuplicateSchemaOrHost(config, name); err != nil {
writeError(w, http.StatusConflict, err.Error()) writeError(w, http.StatusConflict, err.Error())
return return
} }
@@ -285,7 +281,8 @@ func deepMerge(base, patch map[string]interface{}) map[string]interface{} {
func (api *APIHandler) deleteRelay(w http.ResponseWriter, r *http.Request) { func (api *APIHandler) deleteRelay(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") id := r.PathValue("id")
path := ConfigPathFromId(id) name := ConfigNameFromId(id)
path := ConfigPathFromName(name)
if _, err := os.Stat(path); err != nil { if _, err := os.Stat(path); err != nil {
writeError(w, http.StatusConflict, "relay not found") writeError(w, http.StatusConflict, "relay not found")
return return
@@ -303,7 +300,8 @@ func (api *APIHandler) deleteRelay(w http.ResponseWriter, r *http.Request) {
func (api *APIHandler) listRelayMembers(w http.ResponseWriter, r *http.Request) { func (api *APIHandler) listRelayMembers(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") id := r.PathValue("id")
members, err := api.resolveRelayMembers(id) name := ConfigNameFromId(id)
members, err := api.resolveRelayMembers(name)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
writeError(w, http.StatusNotFound, "relay not found") writeError(w, http.StatusNotFound, "relay not found")
@@ -316,16 +314,17 @@ func (api *APIHandler) listRelayMembers(w http.ResponseWriter, r *http.Request)
writeJSON(w, http.StatusOK, map[string][]string{"members": members}) writeJSON(w, http.StatusOK, map[string][]string{"members": members})
} }
func (api *APIHandler) resolveRelayMembers(id string) ([]string, error) { func (api *APIHandler) resolveRelayMembers(name string) ([]string, error) {
instancesMux.RLock() instancesMux.RLock()
instance, exists := instancesByName[id+".toml"] instance, exists := instancesByName[name]
instancesMux.RUnlock() instancesMux.RUnlock()
if exists { if exists {
return collectMembers(instance.Management), nil return collectMembers(instance.Management), nil
} }
config, err := LoadConfigFromId(id) path := ConfigPathFromName(name)
config, err := LoadConfigFromPath(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+8 -8
View File
@@ -3,8 +3,8 @@ package zooid
import ( import (
"bytes" "bytes"
"context" "context"
"io"
"fmt" "fmt"
"io"
"log" "log"
"net/url" "net/url"
"path/filepath" "path/filepath"
@@ -34,11 +34,11 @@ func (bl *BlossomStore) Enable(instance *Instance) {
switch bl.Config.Blossom.Adapter { switch bl.Config.Blossom.Adapter {
case "local": case "local":
if err := bl.UseLocalAdapter(backend); err != nil { if err := bl.UseLocalAdapter(backend); err != nil {
log.Fatalf("blossom: failed to use local adapter %q", err) log.Fatalf("blossom: failed to use local adapter %q", err)
} }
case "s3": case "s3":
if err := bl.UseS3Adapter(backend); err != nil { if err := bl.UseS3Adapter(backend); err != nil {
log.Fatalf("blossom: failed to use s3 adapter %q", err) log.Fatalf("blossom: failed to use s3 adapter %q", err)
} }
default: default:
log.Fatalf("blossom: unknown backend %q", bl.Config.Blossom.Adapter) log.Fatalf("blossom: unknown backend %q", bl.Config.Blossom.Adapter)
@@ -128,13 +128,13 @@ func (bl *BlossomStore) UseLocalAdapter(backend *blossom.BlossomServer) error {
// S3 adapter // S3 adapter
func (bl *BlossomStore) S3Key(sha256 string) string { func (bl *BlossomStore) S3Key(sha256 string) string {
key := bl.Config.Schema + "/" + sha256 key := bl.Config.Schema + "/" + sha256
if bl.Config.Blossom.S3.KeyPrefix != "" { if bl.Config.Blossom.S3.KeyPrefix != "" {
key = bl.Config.Blossom.S3.KeyPrefix + "/" + key key = bl.Config.Blossom.S3.KeyPrefix + "/" + key
} }
return key return key
} }
func (bl *BlossomStore) UseS3Adapter(backend *blossom.BlossomServer) error { func (bl *BlossomStore) UseS3Adapter(backend *blossom.BlossomServer) error {
+21 -21
View File
@@ -1,12 +1,13 @@
package zooid package zooid
import ( import (
"encoding/json"
"fiatjaf.com/nostr" "fiatjaf.com/nostr"
"fmt" "fmt"
"regexp"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"slices" "slices"
) )
@@ -60,7 +61,7 @@ type Config struct {
Roles map[string]Role `toml:"roles" json:"roles"` Roles map[string]Role `toml:"roles" json:"roles"`
// Private/parsed values // Parsed values
path string path string
secret nostr.SecretKey secret nostr.SecretKey
} }
@@ -76,22 +77,14 @@ type BlossomS3Settings struct {
KeyPrefix string `toml:"key_prefix" json:"key_prefix"` KeyPrefix string `toml:"key_prefix" json:"key_prefix"`
} }
func ConfigPathFromId(id string) string { func ConfigNameFromId(id string) string {
return filepath.Join(Env("CONFIG"), id+".toml") return id + ".toml"
} }
func ConfigPathFromName(name string) string { func ConfigPathFromName(name string) string {
return filepath.Join(Env("CONFIG"), name) return filepath.Join(Env("CONFIG"), name)
} }
func LoadConfigFromId(id string) (*Config, error) {
return LoadConfigFromPath(ConfigPathFromId(id))
}
func LoadConfigFromName(name string) (*Config, error) {
return LoadConfigFromPath(ConfigPathFromName(name))
}
func LoadConfigFromPath(path string) (*Config, error) { func LoadConfigFromPath(path string) (*Config, error) {
var config Config var config Config
if _, err := toml.DecodeFile(path, &config); err != nil { if _, err := toml.DecodeFile(path, &config); err != nil {
@@ -107,6 +100,21 @@ func LoadConfigFromPath(path string) (*Config, error) {
return &config, nil return &config, nil
} }
func LoadConfigFromJson(path string, body []byte) (*Config, error) {
var config Config
if err := json.Unmarshal(body, &config); err != nil {
return nil, fmt.Errorf("invalid json config: %w", err)
}
config.path = path
if err := config.Validate(); err != nil {
return nil, err
}
return &config, nil
}
func (config *Config) Validate() error { func (config *Config) Validate() error {
if config.Blossom.Adapter == "" { if config.Blossom.Adapter == "" {
config.Blossom.Adapter = "local" config.Blossom.Adapter = "local"
@@ -124,14 +132,12 @@ func (config *Config) Validate() error {
return fmt.Errorf("schema must contain only lowercase letters, numbers, and underscores") return fmt.Errorf("schema must contain only lowercase letters, numbers, and underscores")
} }
secret, err := nostr.SecretKeyFromHex(config.Secret) secret, err := nostr.SecretKeyFromHex(config.Secret)
if err != nil { if err != nil {
return fmt.Errorf("invalid secret key: %w", err) return fmt.Errorf("invalid secret key: %w", err)
} }
// Make the secret... secret
config.Secret = ""
config.secret = secret config.secret = secret
if _, err := nostr.PubKeyFromHex(config.Info.Pubkey); err != nil { if _, err := nostr.PubKeyFromHex(config.Info.Pubkey); err != nil {
@@ -159,9 +165,6 @@ func (config *Config) Validate() error {
} }
func (config *Config) Save() error { func (config *Config) Save() error {
// Restore the secret key to the public field for saving
config.Secret = config.secret.Hex()
file, err := os.Create(config.path) file, err := os.Create(config.path)
if err != nil { if err != nil {
return fmt.Errorf("Failed to open config file %s: %w", config.path, err) return fmt.Errorf("Failed to open config file %s: %w", config.path, err)
@@ -173,9 +176,6 @@ func (config *Config) Save() error {
return fmt.Errorf("Failed to encode config file %s: %w", config.path, err) return fmt.Errorf("Failed to encode config file %s: %w", config.path, err)
} }
// Clear the secret again
config.Secret = ""
return nil return nil
} }
+4 -3
View File
@@ -21,13 +21,14 @@ type Instance struct {
Push *PushManager Push *PushManager
} }
func MakeInstance(filename string) (*Instance, error) { func MakeInstance(name string) (*Instance, error) {
config, err := LoadConfigFromName(filename) path := ConfigPathFromName(name)
config, err := LoadConfigFromPath(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return makeInstance(config, filename) return makeInstance(config, name)
} }
func makeInstance(config *Config, source string) (*Instance, error) { func makeInstance(config *Config, source string) (*Instance, error) {
+1 -1
View File
@@ -183,7 +183,7 @@ func validateNIP98Auth(r *http.Request) (nostr.PubKey, error) {
return nostr.PubKey{}, fmt.Errorf("invalid event signature") return nostr.PubKey{}, fmt.Errorf("invalid event signature")
} }
scheme := "http" scheme := "http"
if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" { if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" {
scheme = scheme + "s" scheme = scheme + "s"
} }