diff --git a/utils/config/loader.go b/internals/config/loader.go similarity index 54% rename from utils/config/loader.go rename to internals/config/loader.go index 9c484dd9..b4ca9c8d 100644 --- a/utils/config/loader.go +++ b/internals/config/loader.go @@ -7,7 +7,8 @@ import ( "strconv" "strings" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" + "github.com/codeshelldev/secured-signal-api/utils/configutils" jsonutils "github.com/codeshelldev/secured-signal-api/utils/jsonutils" log "github.com/codeshelldev/secured-signal-api/utils/logger" @@ -24,19 +25,27 @@ var ENV *structure.ENV = &structure.ENV{ INSECURE: false, } +var defaultsConf = configutils.New() +var userConf = configutils.New() +var tokenConf = configutils.New() + +var config = configutils.New() + func Load() { + InitReload() + LoadDefaults() LoadConfig() LoadTokens() - LoadEnv(userLayer) + userConf.LoadEnv() - config = mergeLayers() + config.MergeLayers(defaultsConf.Layer, userConf.Layer) - normalizeKeys(config) - templateConfig(config) + config.NormalizeKeys() + config.TemplateConfig() InitTokens() @@ -44,28 +53,34 @@ func Load() { log.Info("Finished Loading Configuration") - log.Dev("Loaded Config:\n" + jsonutils.ToJson(config.All())) - log.Dev("Loaded Token Configs:\n" + jsonutils.ToJson(tokensLayer.All())) + log.Dev("Loaded Config:\n" + jsonutils.ToJson(config.Layer.All())) + log.Dev("Loaded Token Configs:\n" + jsonutils.ToJson(tokenConf.Layer.All())) +} + +func InitReload() { + defaultsConf.OnLoad(Load) + userConf.OnLoad(Load) + tokenConf.OnLoad(Load) } func InitEnv() { - ENV.PORT = strconv.Itoa(config.Int("service.port")) + ENV.PORT = strconv.Itoa(config.Layer.Int("service.port")) - ENV.LOG_LEVEL = strings.ToLower(config.String("loglevel")) + ENV.LOG_LEVEL = strings.ToLower(config.Layer.String("loglevel")) - ENV.API_URL = config.String("api.url") + ENV.API_URL = config.Layer.String("api.url") var settings structure.SETTINGS - transformChildren(config, "settings.message.variables", transformVariables) + config.TransformChildren("settings.message.variables", transformVariables) - config.Unmarshal("settings", &settings) + config.Layer.Unmarshal("settings", &settings) ENV.SETTINGS["*"] = &settings } func LoadDefaults() { - _, err := LoadFile(ENV.DEFAULTS_PATH, defaultsLayer, yaml.Parser()) + _, err := defaultsConf.LoadFile(ENV.DEFAULTS_PATH, yaml.Parser()) if err != nil { log.Warn("Could not Load Defaults", ENV.DEFAULTS_PATH) @@ -73,7 +88,7 @@ func LoadDefaults() { } func LoadConfig() { - _, err := LoadFile(ENV.CONFIG_PATH, userLayer, yaml.Parser()) + _, err := userConf.LoadFile(ENV.CONFIG_PATH, yaml.Parser()) if err != nil { _, fsErr := os.Stat(ENV.CONFIG_PATH) diff --git a/utils/config/structure/structure.go b/internals/config/structure/structure.go similarity index 100% rename from utils/config/structure/structure.go rename to internals/config/structure/structure.go diff --git a/utils/config/tokens.go b/internals/config/tokens.go similarity index 72% rename from utils/config/tokens.go rename to internals/config/tokens.go index fcc852c5..d963312f 100644 --- a/utils/config/tokens.go +++ b/internals/config/tokens.go @@ -3,7 +3,7 @@ package config import ( "strconv" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" log "github.com/codeshelldev/secured-signal-api/utils/logger" "github.com/knadh/koanf/parsers/yaml" ) @@ -16,25 +16,25 @@ type TOKEN_CONFIG_ struct { func LoadTokens() { log.Debug("Loading Configs in ", ENV.TOKENS_DIR) - err := LoadDir("tokenconfigs", ENV.TOKENS_DIR, tokensLayer, yaml.Parser()) + err := tokenConf.LoadDir("tokenconfigs", ENV.TOKENS_DIR, ".yml", yaml.Parser()) if err != nil { log.Error("Could not Load Configs in ", ENV.TOKENS_DIR, ": ", err.Error()) } - normalizeKeys(tokensLayer) + tokenConf.NormalizeKeys() - templateConfig(tokensLayer) + tokenConf.TemplateConfig() } func InitTokens() { - apiTokens := config.Strings("api.tokens") + apiTokens := config.Layer.Strings("api.tokens") var tokenConfigs []TOKEN_CONFIG_ - transformChildrenUnderArray(tokensLayer, "tokenconfigs", "overrides.message.variables", transformVariables) + tokenConf.TransformChildrenUnderArray("tokenconfigs", "overrides.message.variables", transformVariables) - tokensLayer.Unmarshal("tokenconfigs", &tokenConfigs) + tokenConf.Layer.Unmarshal("tokenconfigs", &tokenConfigs) overrides := parseTokenConfigs(tokenConfigs) @@ -53,7 +53,7 @@ func InitTokens() { // Set Blocked Endpoints on Config to User Layer Value // => effectively ignoring Default Layer - config.Set("settings.access.endpoints", userLayer.Strings("settings.access.endpoints")) + config.Layer.Set("settings.access.endpoints", userConf.Layer.Strings("settings.access.endpoints")) } if len(apiTokens) > 0 { diff --git a/internals/proxy/middlewares/auth.go b/internals/proxy/middlewares/auth.go index 202c0ecd..21e767ae 100644 --- a/internals/proxy/middlewares/auth.go +++ b/internals/proxy/middlewares/auth.go @@ -7,7 +7,7 @@ import ( "slices" "strings" - "github.com/codeshelldev/secured-signal-api/utils/config" + "github.com/codeshelldev/secured-signal-api/internals/config" log "github.com/codeshelldev/secured-signal-api/utils/logger" ) diff --git a/internals/proxy/middlewares/common.go b/internals/proxy/middlewares/common.go index 432fa78a..c3f56bb8 100644 --- a/internals/proxy/middlewares/common.go +++ b/internals/proxy/middlewares/common.go @@ -3,8 +3,8 @@ package middlewares import ( "net/http" - "github.com/codeshelldev/secured-signal-api/utils/config" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" + "github.com/codeshelldev/secured-signal-api/internals/config" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" ) type Context struct { diff --git a/internals/proxy/middlewares/mapping.go b/internals/proxy/middlewares/mapping.go index d66c2ba5..a5f51790 100644 --- a/internals/proxy/middlewares/mapping.go +++ b/internals/proxy/middlewares/mapping.go @@ -6,7 +6,7 @@ import ( "net/http" "strconv" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" jsonutils "github.com/codeshelldev/secured-signal-api/utils/jsonutils" log "github.com/codeshelldev/secured-signal-api/utils/logger" request "github.com/codeshelldev/secured-signal-api/utils/request" diff --git a/internals/proxy/middlewares/policy.go b/internals/proxy/middlewares/policy.go index b252c251..3e3a4558 100644 --- a/internals/proxy/middlewares/policy.go +++ b/internals/proxy/middlewares/policy.go @@ -5,8 +5,7 @@ import ( "net/http" "strings" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" - "github.com/codeshelldev/secured-signal-api/utils/jsonutils" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" log "github.com/codeshelldev/secured-signal-api/utils/logger" request "github.com/codeshelldev/secured-signal-api/utils/request" ) @@ -103,9 +102,6 @@ func doBlock(body map[string]any, headers map[string]any, policies map[string]st for field, policy := range allowed { value, err := getField(field, body, headers) - log.Dev("Checking ", field, "...") - log.Dev("Got Value of ", jsonutils.ToJson(value)) - if value == policy.Value && err == nil { isExplictlyAllowed = true cause = field @@ -116,9 +112,6 @@ func doBlock(body map[string]any, headers map[string]any, policies map[string]st for field, policy := range blocked { value, err := getField(field, body, headers) - log.Dev("Checking ", field, "...") - log.Dev("Got Value of ", jsonutils.ToJson(value)) - if value == policy.Value && err == nil { isExplicitlyBlocked = true cause = field diff --git a/internals/proxy/middlewares/server.go b/internals/proxy/middlewares/server.go index 84af5737..0495d431 100644 --- a/internals/proxy/middlewares/server.go +++ b/internals/proxy/middlewares/server.go @@ -3,7 +3,7 @@ package middlewares import ( "net/http" - "github.com/codeshelldev/secured-signal-api/utils/config" + "github.com/codeshelldev/secured-signal-api/internals/config" ) var Server Middleware = Middleware{ diff --git a/main.go b/main.go index f8dcd2ec..d69ca4f4 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,9 @@ import ( "net/http" "os" + config "github.com/codeshelldev/secured-signal-api/internals/config" + "github.com/codeshelldev/secured-signal-api/internals/config/structure" reverseProxy "github.com/codeshelldev/secured-signal-api/internals/proxy" - config "github.com/codeshelldev/secured-signal-api/utils/config" - "github.com/codeshelldev/secured-signal-api/utils/config/structure" docker "github.com/codeshelldev/secured-signal-api/utils/docker" log "github.com/codeshelldev/secured-signal-api/utils/logger" ) diff --git a/utils/config/config.go b/utils/configutils/configutils.go similarity index 50% rename from utils/config/config.go rename to utils/configutils/configutils.go index 5422647e..df5b0b62 100644 --- a/utils/config/config.go +++ b/utils/configutils/configutils.go @@ -1,4 +1,4 @@ -package config +package configutils import ( "errors" @@ -16,31 +16,43 @@ import ( "github.com/knadh/koanf/v2" ) -var defaultsLayer = koanf.New(".") -var userLayer = koanf.New(".") -var tokensLayer = koanf.New(".") +var configLock sync.Mutex -var config *koanf.Koanf +type Config struct { + Layer *koanf.Koanf + LoadFunc func() +} -var configLock sync.Mutex +func New() *Config { + return &Config{ + Layer: koanf.New("."), + LoadFunc: func() { + log.Dev("Config.LoadFunc not initialized!") + }, + } +} -func LoadFile(path string, config *koanf.Koanf, parser koanf.Parser) (koanf.Provider, error) { +func (config *Config) OnLoad(onLoad func()) { + config.LoadFunc = onLoad +} + +func (config *Config) LoadFile(path string, parser koanf.Parser) (koanf.Provider, error) { log.Debug("Loading Config File: ", path) f := file.Provider(path) - err := config.Load(f, parser) - + err := config.Layer.Load(f, parser) + if err != nil { return nil, err } - WatchFile(path, f) + WatchFile(path, f, config.LoadFunc) return f, err } -func WatchFile(path string, f *file.File) { +func WatchFile(path string, f *file.File, loadFunc func()) { f.Watch(func(event any, err error) { if err != nil { return @@ -51,12 +63,12 @@ func WatchFile(path string, f *file.File) { configLock.Lock() defer configLock.Unlock() - Load() + loadFunc() }) } -func LoadDir(path string, dir string, config *koanf.Koanf, parser koanf.Parser) error { - files, err := filepath.Glob(filepath.Join(dir, "*.yml")) +func (config *Config) LoadDir(path string, dir string, ext string, parser koanf.Parser) error { + files, err := filepath.Glob(filepath.Join(dir, "*" + ext)) if err != nil { return nil @@ -65,30 +77,30 @@ func LoadDir(path string, dir string, config *koanf.Koanf, parser koanf.Parser) var array []any for _, f := range files { - tmp := koanf.New(".") + tmp := New() - _, err := LoadFile(f, tmp, parser) + _, err := tmp.LoadFile(f, parser) if err != nil { return err } - array = append(array, tmp.Raw()) + array = append(array, tmp.Layer.Raw()) } wrapper := map[string]any{ path: array, } - return config.Load(confmap.Provider(wrapper, "."), nil) + return config.Layer.Load(confmap.Provider(wrapper, "."), nil) } -func LoadEnv(config *koanf.Koanf) (koanf.Provider, error) { +func (config *Config) LoadEnv() (koanf.Provider, error) { e := env.Provider(".", env.Opt{ - TransformFunc: normalizeEnv, + TransformFunc: config.NormalizeEnv, }) - err := config.Load(e, nil) + err := config.Layer.Load(e, nil) if err != nil { log.Fatal("Error loading env: ", err.Error()) @@ -97,8 +109,8 @@ func LoadEnv(config *koanf.Koanf) (koanf.Provider, error) { return e, err } -func templateConfig(config *koanf.Koanf) { - data := config.All() +func (config *Config) TemplateConfig() { + data := config.Layer.All() for key, value := range data { str, isStr := value.(string) @@ -112,42 +124,39 @@ func templateConfig(config *koanf.Koanf) { } } - config.Load(confmap.Provider(data, "."), nil) + config.Layer.Load(confmap.Provider(data, "."), nil) } -func mergeLayers() *koanf.Koanf { - final := koanf.New(".") - - final.Merge(defaultsLayer) - final.Merge(userLayer) - - return final +func (config *Config) MergeLayers(layers ...*koanf.Koanf) { + for _, layer := range layers { + config.Layer.Merge(layer) + } } -func normalizeKeys(config *koanf.Koanf) { +func (config *Config) NormalizeKeys() { data := map[string]any{} - for _, key := range config.Keys() { + for _, key := range config.Layer.Keys() { lower := strings.ToLower(key) log.Dev("Lowering key: ", key) - data[lower] = config.Get(key) + data[lower] = config.Layer.Get(key) } - config.Delete("") - config.Load(confmap.Provider(data, "."), nil) + config.Layer.Delete("") + config.Layer.Load(confmap.Provider(data, "."), nil) } // Transforms Children of path -func transformChildren(config *koanf.Koanf, path string, transform func(key string, value any) (string, any)) error { +func (config *Config) TransformChildren(path string, transform func(key string, value any) (string, any)) error { var sub map[string]any - if !config.Exists(path) { + if !config.Layer.Exists(path) { return errors.New("invalid path") } - err := config.Unmarshal(path, &sub) + err := config.Layer.Unmarshal(path, &sub) if err != nil { return err @@ -161,9 +170,9 @@ func transformChildren(config *koanf.Koanf, path string, transform func(key stri transformed[newKey] = newVal } - config.Delete(path) + config.Layer.Delete(path) - config.Load(confmap.Provider(map[string]any{ + config.Layer.Load(confmap.Provider(map[string]any{ path: transformed, }, "."), nil) @@ -171,10 +180,10 @@ func transformChildren(config *koanf.Koanf, path string, transform func(key stri } // Does the same thing as transformChildren() but does it for each Array Item inside of root and transforms subPath -func transformChildrenUnderArray(config *koanf.Koanf, root string, subPath string, transform func(key string, value any) (string, any)) error { +func (config *Config) TransformChildrenUnderArray(root string, subPath string, transform func(key string, value any) (string, any)) error { var array []map[string]any - err := config.Unmarshal(root, &array) + err := config.Layer.Unmarshal(root, &array) if err != nil { return err } @@ -182,19 +191,19 @@ func transformChildrenUnderArray(config *koanf.Koanf, root string, subPath strin transformed := []map[string]any{} for _, data := range array { - tmp := koanf.New(".") + tmp := New() - tmp.Load(confmap.Provider(map[string]any{ + tmp.Layer.Load(confmap.Provider(map[string]any{ "item": data, }, "."), nil) - err := transformChildren(tmp, "item."+subPath, transform) + err := tmp.TransformChildren("item."+subPath, transform) if err != nil { return err } - item := tmp.Get("item") + item := tmp.Layer.Get("item") if item != nil { itemMap, ok := item.(map[string]any) @@ -205,16 +214,16 @@ func transformChildrenUnderArray(config *koanf.Koanf, root string, subPath strin } } - config.Delete(root) + config.Layer.Delete(root) - config.Load(confmap.Provider(map[string]any{ + config.Layer.Load(confmap.Provider(map[string]any{ root: transformed, }, "."), nil) return nil } -func normalizeEnv(key string, value string) (string, any) { +func (config *Config) NormalizeEnv(key string, value string) (string, any) { key = strings.ToLower(key) key = strings.ReplaceAll(key, "__", ".") key = strings.ReplaceAll(key, "_", "")