forked from coracle/zooid
Clean up config file name stuff
This commit is contained in:
+3
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user