From 0242464af938c26de3fdbd5322fd2d4f70dddb01 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 13:55:23 +0200 Subject: [PATCH 01/12] restructure --- data/defaults.yml | 62 ++++++++++++++++++++++-------------------- utils/config/loader.go | 11 ++++---- utils/config/tokens.go | 4 +-- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/data/defaults.yml b/data/defaults.yml index 229832b8..bf058d25 100644 --- a/data/defaults.yml +++ b/data/defaults.yml @@ -4,37 +4,39 @@ service: logLevel: info settings: - dataAliases: - "@message": - [ - { alias: msg, score: 100 }, - { alias: content, score: 99 }, - { alias: description, score: 98 }, - { alias: text, score: 20 }, - { alias: summary, score: 15 }, - { alias: details, score: 14 }, + message: + fieldMappings: + "@message": + [ + { alias: msg, score: 100 }, + { alias: content, score: 99 }, + { alias: description, score: 98 }, + { alias: text, score: 20 }, + { alias: summary, score: 15 }, + { alias: details, score: 14 }, - { alias: data.message, score: 10 }, - { alias: data.content, score: 9 }, - { alias: data.description, score: 8 }, - { alias: data.text, score: 7 }, - { alias: data.summary, score: 6 }, - { alias: data.details, score: 5 }, + { alias: data.message, score: 10 }, + { alias: data.content, score: 9 }, + { alias: data.description, score: 8 }, + { alias: data.text, score: 7 }, + { alias: data.summary, score: 6 }, + { alias: data.details, score: 5 }, - { alias: body, score: 2 }, - { alias: data, score: 1 }, - ] + { alias: body, score: 2 }, + { alias: data, score: 1 }, + ] - variables: - recipients: ${RECIPIENTS} - number: ${NUMBER} + variables: + recipients: ${RECIPIENTS} + number: ${NUMBER} - blockedEndpoints: - - /v1/about - - /v1/configuration - - /v1/devices - - /v1/register - - /v1/unregister - - /v1/qrcodelink - - /v1/accounts - - /v1/contacts + access: + endpoints: + - !/v1/about + - !/v1/configuration + - !/v1/devices + - !/v1/register + - !/v1/unregister + - !/v1/qrcodelink + - !/v1/accounts + - !/v1/contacts diff --git a/utils/config/loader.go b/utils/config/loader.go index 7455c155..5450ba69 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -28,11 +28,10 @@ type ENV_ struct { } type SETTING_ struct { - BLOCKED_ENDPOINTS []string `koanf:"blockedendpoints"` - ALLOWED_ENDPOINTS []string `koanf:"allowedendpoints"` - VARIABLES map[string]any `koanf:"variables"` - DATA_ALIASES map[string][]middlewareTypes.DataAlias `koanf:"dataaliases"` - MESSAGE_TEMPLATE string `koanf:"messagetemplate"` + ENDPOINTS []string `koanf:"blockedendpoints"` + VARIABLES map[string]any `koanf:"message.variables"` + DATA_ALIASES map[string][]middlewareTypes.DataAlias `koanf:"message.fieldMappings"` + MESSAGE_TEMPLATE string `koanf:"message.template"` } var ENV *ENV_ = &ENV_{ @@ -78,7 +77,7 @@ func InitEnv() { var settings SETTING_ - transformChildren(config, "settings.variables", transformVariables) + transformChildren(config, "settings.message.variables", transformVariables) config.Unmarshal("settings", &settings) diff --git a/utils/config/tokens.go b/utils/config/tokens.go index f5e1417e..c8978332 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -27,7 +27,7 @@ func InitTokens() { var tokenConfigs []TOKEN_CONFIG_ - transformChildrenUnderArray(tokensLayer, "tokenconfigs", "overrides.variables", transformVariables) + transformChildrenUnderArray(tokensLayer, "tokenconfigs", "overrides.message.variables", transformVariables) tokensLayer.Unmarshal("tokenconfigs", &tokenConfigs) @@ -48,7 +48,7 @@ func InitTokens() { // Set Blocked Endpoints on Config to User Layer Value // => effectively ignoring Default Layer - config.Set("blockedendpoints", userLayer.Strings("blockeendpoints")) + config.Set("endpoints", userLayer.Strings("endpoints")) } if len(apiTokens) > 0 { From a02f4653569ff95334195975bf10622cbe87fdad Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 13:55:57 +0200 Subject: [PATCH 02/12] merged endpoint settings use `!` for blocking and ` ` for allowing --- internals/proxy/middlewares/endpoints.go | 32 ++++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index de1fa97c..a836e36c 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -18,16 +18,15 @@ func (data EndpointsMiddleware) Use() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { settings := getSettingsByReq(req) - blockedEndpoints := settings.BLOCKED_ENDPOINTS - allowedEndpoints := settings.ALLOWED_ENDPOINTS + endpoints := settings.ENDPOINTS - if blockedEndpoints == nil && allowedEndpoints == nil { - blockedEndpoints = getSettings("*").BLOCKED_ENDPOINTS + if endpoints == nil { + endpoints = getSettings("*").ENDPOINTS } reqPath := req.URL.Path - if isBlocked(reqPath, allowedEndpoints, blockedEndpoints) { + if isBlocked(reqPath, endpoints) { log.Warn("User tried to access blocked endpoint: ", reqPath) http.Error(w, "Forbidden", http.StatusForbidden) return @@ -37,15 +36,26 @@ func (data EndpointsMiddleware) Use() http.Handler { }) } -func isBlocked(endpoint string, allowed []string, blocked []string) bool { - if blocked == nil { - blocked = []string{} - } +func getEndpoints(endpoints []string) ([]string, []string) { + blockedEndpoints := []string{} + allowedEndpoints := []string{} + + for i, endpoint := range endpoints { + endpoint, block := strings.CutPrefix(endpoint, "!") - if allowed == nil { - allowed = []string{} + if block { + blockedEndpoints[i] = endpoint + } else { + allowedEndpoints[i] = endpoint + } } + return allowedEndpoints, blockedEndpoints +} + +func isBlocked(endpoint string, endpoints []string) bool { + allowed, blocked := getEndpoints(endpoints) + isExplicitlyBlocked := slices.ContainsFunc(blocked, func(try string) bool { return strings.HasPrefix(endpoint, try) }) From fc57c0468167f916e9c716263fe228c6f7de1c0f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 13:56:51 +0200 Subject: [PATCH 03/12] changed endpoins path --- utils/config/loader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/config/loader.go b/utils/config/loader.go index 5450ba69..73afa643 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -28,7 +28,7 @@ type ENV_ struct { } type SETTING_ struct { - ENDPOINTS []string `koanf:"blockedendpoints"` + ENDPOINTS []string `koanf:"access.endpoints"` VARIABLES map[string]any `koanf:"message.variables"` DATA_ALIASES map[string][]middlewareTypes.DataAlias `koanf:"message.fieldMappings"` MESSAGE_TEMPLATE string `koanf:"message.template"` From 05328a0cb30e9cae9017e568a13404a4c6e842b7 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:05:21 +0200 Subject: [PATCH 04/12] restructure and rename - renamed dataAliases to fieldMappings - moved structs to structure.go - moved fieldMappings to structure.go - update defaults.yml --- data/defaults.yml | 28 +++++++++---------- internals/proxy/middlewares/common.go | 5 ++-- .../middlewares/{aliases.go => mapping.go} | 26 ++++++++--------- internals/proxy/middlewares/types/types.go | 9 ------ main.go | 5 ++-- utils/config/loader.go | 28 +++---------------- utils/config/structure/structure.go | 26 +++++++++++++++++ utils/config/tokens.go | 9 +++--- 8 files changed, 68 insertions(+), 68 deletions(-) rename internals/proxy/middlewares/{aliases.go => mapping.go} (72%) delete mode 100644 internals/proxy/middlewares/types/types.go create mode 100644 utils/config/structure/structure.go diff --git a/data/defaults.yml b/data/defaults.yml index bf058d25..08681bc5 100644 --- a/data/defaults.yml +++ b/data/defaults.yml @@ -8,22 +8,22 @@ settings: fieldMappings: "@message": [ - { alias: msg, score: 100 }, - { alias: content, score: 99 }, - { alias: description, score: 98 }, - { alias: text, score: 20 }, - { alias: summary, score: 15 }, - { alias: details, score: 14 }, + { field: msg, score: 100 }, + { field: content, score: 99 }, + { field: description, score: 98 }, + { field: text, score: 20 }, + { field: summary, score: 15 }, + { field: details, score: 14 }, - { alias: data.message, score: 10 }, - { alias: data.content, score: 9 }, - { alias: data.description, score: 8 }, - { alias: data.text, score: 7 }, - { alias: data.summary, score: 6 }, - { alias: data.details, score: 5 }, + { field: data.message, score: 10 }, + { field: data.content, score: 9 }, + { field: data.description, score: 8 }, + { field: data.text, score: 7 }, + { field: data.summary, score: 6 }, + { field: data.details, score: 5 }, - { alias: body, score: 2 }, - { alias: data, score: 1 }, + { field: body, score: 2 }, + { field: data, score: 1 }, ] variables: diff --git a/internals/proxy/middlewares/common.go b/internals/proxy/middlewares/common.go index 15ba8fbc..37c057aa 100644 --- a/internals/proxy/middlewares/common.go +++ b/internals/proxy/middlewares/common.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/codeshelldev/secured-signal-api/utils/config" + "github.com/codeshelldev/secured-signal-api/utils/config/structure" ) type Context struct { @@ -23,7 +24,7 @@ type contextKey string const tokenKey contextKey = "token" -func getSettingsByReq(req *http.Request) *config.SETTING_ { +func getSettingsByReq(req *http.Request) *structure.SETTING_ { token, ok := req.Context().Value(tokenKey).(string) if !ok { @@ -33,7 +34,7 @@ func getSettingsByReq(req *http.Request) *config.SETTING_ { return getSettings(token) } -func getSettings(token string) *config.SETTING_ { +func getSettings(token string) *structure.SETTING_ { settings, exists := config.ENV.SETTINGS[token] if !exists || settings == nil { diff --git a/internals/proxy/middlewares/aliases.go b/internals/proxy/middlewares/mapping.go similarity index 72% rename from internals/proxy/middlewares/aliases.go rename to internals/proxy/middlewares/mapping.go index 287b09fa..d4ae070f 100644 --- a/internals/proxy/middlewares/aliases.go +++ b/internals/proxy/middlewares/mapping.go @@ -6,26 +6,26 @@ import ( "net/http" "strconv" - middlewareTypes "github.com/codeshelldev/secured-signal-api/internals/proxy/middlewares/types" + "github.com/codeshelldev/secured-signal-api/utils/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" ) -type AliasMiddleware struct { +type MappingMiddleware struct { Next http.Handler } -func (data AliasMiddleware) Use() http.Handler { +func (data MappingMiddleware) Use() http.Handler { next := data.Next return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { settings := getSettingsByReq(req) - dataAliases := settings.DATA_ALIASES + fieldMappings := settings.FIELD_MAPPINGS - if dataAliases == nil { - dataAliases = getSettings("*").DATA_ALIASES + if fieldMappings == nil { + fieldMappings = getSettings("*").FIELD_MAPPINGS } if settings.VARIABLES == nil { @@ -44,7 +44,7 @@ func (data AliasMiddleware) Use() http.Handler { if !body.Empty { bodyData = body.Data - aliasData := processDataAliases(dataAliases, bodyData) + aliasData := processFieldMappings(fieldMappings, bodyData) for key, value := range aliasData { prefix := key[:1] @@ -85,7 +85,7 @@ func (data AliasMiddleware) Use() http.Handler { }) } -func processDataAliases(aliases map[string][]middlewareTypes.DataAlias, data map[string]any) map[string]any { +func processFieldMappings(aliases map[string][]structure.FieldMapping, data map[string]any) map[string]any { aliasData := map[string]any{} for key, alias := range aliases { @@ -99,27 +99,27 @@ func processDataAliases(aliases map[string][]middlewareTypes.DataAlias, data map return aliasData } -func getData(key string, aliases []middlewareTypes.DataAlias, data map[string]any) (string, any) { +func getData(key string, aliases []structure.FieldMapping, data map[string]any) (string, any) { var best int var value any for _, alias := range aliases { - aliasValue, score, ok := processAlias(alias, data) + aliasValue, score, ok := processFieldMapping(alias, data) if ok { if score > best { value = aliasValue } - delete(data, alias.Alias) + delete(data, alias.Field) } } return key, value } -func processAlias(alias middlewareTypes.DataAlias, data map[string]any) (any, int, bool) { - aliasKey := alias.Alias +func processFieldMapping(alias structure.FieldMapping, data map[string]any) (any, int, bool) { + aliasKey := alias.Field value, ok := jsonutils.GetByPath(aliasKey, data) diff --git a/internals/proxy/middlewares/types/types.go b/internals/proxy/middlewares/types/types.go deleted file mode 100644 index 689ee4e5..00000000 --- a/internals/proxy/middlewares/types/types.go +++ /dev/null @@ -1,9 +0,0 @@ -// Pretty useless, but go requires separate package -// since import cycles are not allowed - -package middlewareTypes - -type DataAlias struct { - Alias string `koanf:"alias"` - Score int `koanf:"score"` -} diff --git a/main.go b/main.go index f13d7ce7..4ff0fa05 100644 --- a/main.go +++ b/main.go @@ -8,13 +8,14 @@ import ( proxy "github.com/codeshelldev/secured-signal-api/internals/proxy" middlewares "github.com/codeshelldev/secured-signal-api/internals/proxy/middlewares" 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" ) var proxy_last *httputil.ReverseProxy -var ENV *config.ENV_ +var ENV *structure.ENV_ func main() { logLevel := os.Getenv("LOG_LEVEL") @@ -39,7 +40,7 @@ func main() { Next: proxy_last, } - alias_m5 := middlewares.AliasMiddleware{ + alias_m5 := middlewares.MappingMiddleware{ Next: mesg_m6.Use(), } diff --git a/utils/config/loader.go b/utils/config/loader.go index 73afa643..66385fff 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -7,40 +7,20 @@ import ( "strconv" "strings" - middlewareTypes "github.com/codeshelldev/secured-signal-api/internals/proxy/middlewares/types" + "github.com/codeshelldev/secured-signal-api/utils/config/structure" jsonutils "github.com/codeshelldev/secured-signal-api/utils/jsonutils" log "github.com/codeshelldev/secured-signal-api/utils/logger" "github.com/knadh/koanf/parsers/yaml" ) -type ENV_ struct { - CONFIG_PATH string - DEFAULTS_PATH string - FAVICON_PATH string - TOKENS_DIR string - LOG_LEVEL string - PORT string - API_URL string - API_TOKENS []string - SETTINGS map[string]*SETTING_ - INSECURE bool -} - -type SETTING_ struct { - ENDPOINTS []string `koanf:"access.endpoints"` - VARIABLES map[string]any `koanf:"message.variables"` - DATA_ALIASES map[string][]middlewareTypes.DataAlias `koanf:"message.fieldMappings"` - MESSAGE_TEMPLATE string `koanf:"message.template"` -} - -var ENV *ENV_ = &ENV_{ +var ENV *structure.ENV_ = &structure.ENV_{ CONFIG_PATH: os.Getenv("CONFIG_PATH"), DEFAULTS_PATH: os.Getenv("DEFAULTS_PATH"), TOKENS_DIR: os.Getenv("TOKENS_DIR"), FAVICON_PATH: os.Getenv("FAVICON_PATH"), API_TOKENS: []string{}, - SETTINGS: map[string]*SETTING_{}, + SETTINGS: map[string]*structure.SETTING_{}, INSECURE: false, } @@ -75,7 +55,7 @@ func InitEnv() { ENV.API_URL = config.String("api.url") - var settings SETTING_ + var settings structure.SETTING_ transformChildren(config, "settings.message.variables", transformVariables) diff --git a/utils/config/structure/structure.go b/utils/config/structure/structure.go new file mode 100644 index 00000000..b95d8618 --- /dev/null +++ b/utils/config/structure/structure.go @@ -0,0 +1,26 @@ +package structure + +type FieldMapping struct { + Field string `koanf:"field"` + Score int `koanf:"score"` +} + +type ENV_ struct { + CONFIG_PATH string + DEFAULTS_PATH string + FAVICON_PATH string + TOKENS_DIR string + LOG_LEVEL string + PORT string + API_URL string + API_TOKENS []string + SETTINGS map[string]*SETTING_ + INSECURE bool +} + +type SETTING_ struct { + ENDPOINTS []string `koanf:"access.endpoints"` + VARIABLES map[string]any `koanf:"message.variables"` + FIELD_MAPPINGS map[string][]FieldMapping `koanf:"message.fieldMappings"` + MESSAGE_TEMPLATE string `koanf:"message.template"` +} \ No newline at end of file diff --git a/utils/config/tokens.go b/utils/config/tokens.go index c8978332..40976453 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -3,13 +3,14 @@ package config import ( "strconv" + "github.com/codeshelldev/secured-signal-api/utils/config/structure" log "github.com/codeshelldev/secured-signal-api/utils/logger" "github.com/knadh/koanf/parsers/yaml" ) type TOKEN_CONFIG_ struct { - TOKENS []string `koanf:"tokens"` - OVERRIDES SETTING_ `koanf:"overrides"` + TOKENS []string `koanf:"tokens"` + OVERRIDES structure.SETTING_ `koanf:"overrides"` } func LoadTokens() { @@ -58,8 +59,8 @@ func InitTokens() { } } -func parseTokenConfigs(configs []TOKEN_CONFIG_) map[string]SETTING_ { - settings := map[string]SETTING_{} +func parseTokenConfigs(configs []TOKEN_CONFIG_) map[string]structure.SETTING_ { + settings := map[string]structure.SETTING_{} for _, config := range configs { for _, token := range config.TOKENS { From 73a2af751561e8f664a38eb7e312c899a3fd2316 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:27:51 +0200 Subject: [PATCH 05/12] restructure and split - split settings into `access` and `message` --- internals/proxy/middlewares/common.go | 4 +-- internals/proxy/middlewares/endpoints.go | 4 +-- internals/proxy/middlewares/mapping.go | 10 +++--- internals/proxy/middlewares/message.go | 8 ++--- internals/proxy/middlewares/template.go | 4 +-- main.go | 2 +- utils/config/loader.go | 6 ++-- utils/config/structure/structure.go | 44 ++++++++++++++---------- utils/config/tokens.go | 6 ++-- 9 files changed, 48 insertions(+), 40 deletions(-) diff --git a/internals/proxy/middlewares/common.go b/internals/proxy/middlewares/common.go index 37c057aa..432fa78a 100644 --- a/internals/proxy/middlewares/common.go +++ b/internals/proxy/middlewares/common.go @@ -24,7 +24,7 @@ type contextKey string const tokenKey contextKey = "token" -func getSettingsByReq(req *http.Request) *structure.SETTING_ { +func getSettingsByReq(req *http.Request) *structure.SETTINGS { token, ok := req.Context().Value(tokenKey).(string) if !ok { @@ -34,7 +34,7 @@ func getSettingsByReq(req *http.Request) *structure.SETTING_ { return getSettings(token) } -func getSettings(token string) *structure.SETTING_ { +func getSettings(token string) *structure.SETTINGS { settings, exists := config.ENV.SETTINGS[token] if !exists || settings == nil { diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index a836e36c..2e34c97f 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -18,10 +18,10 @@ func (data EndpointsMiddleware) Use() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { settings := getSettingsByReq(req) - endpoints := settings.ENDPOINTS + endpoints := settings.ACCESS.ENDPOINTS if endpoints == nil { - endpoints = getSettings("*").ENDPOINTS + endpoints = getSettings("*").ACCESS.ENDPOINTS } reqPath := req.URL.Path diff --git a/internals/proxy/middlewares/mapping.go b/internals/proxy/middlewares/mapping.go index d4ae070f..c2cabedc 100644 --- a/internals/proxy/middlewares/mapping.go +++ b/internals/proxy/middlewares/mapping.go @@ -22,14 +22,14 @@ func (data MappingMiddleware) Use() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { settings := getSettingsByReq(req) - fieldMappings := settings.FIELD_MAPPINGS + fieldMappings := settings.MESSAGE.FIELD_MAPPINGS if fieldMappings == nil { - fieldMappings = getSettings("*").FIELD_MAPPINGS + fieldMappings = getSettings("*").MESSAGE.FIELD_MAPPINGS } - if settings.VARIABLES == nil { - settings.VARIABLES = getSettings("*").VARIABLES + if settings.MESSAGE.VARIABLES == nil { + settings.MESSAGE.VARIABLES = getSettings("*").MESSAGE.VARIABLES } body, err := request.GetReqBody(w, req) @@ -56,7 +56,7 @@ func (data MappingMiddleware) Use() http.Handler { bodyData[keyWithoutPrefix] = value modifiedBody = true case ".": - settings.VARIABLES[keyWithoutPrefix] = value + settings.MESSAGE.VARIABLES[keyWithoutPrefix] = value } } } diff --git a/internals/proxy/middlewares/message.go b/internals/proxy/middlewares/message.go index f9ac9b8c..1e624180 100644 --- a/internals/proxy/middlewares/message.go +++ b/internals/proxy/middlewares/message.go @@ -20,15 +20,15 @@ func (data MessageMiddleware) Use() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { settings := getSettingsByReq(req) - variables := settings.VARIABLES - messageTemplate := settings.MESSAGE_TEMPLATE + variables := settings.MESSAGE.VARIABLES + messageTemplate := settings.MESSAGE.TEMPLATE if variables == nil { - variables = getSettings("*").VARIABLES + variables = getSettings("*").MESSAGE.VARIABLES } if messageTemplate == "" { - messageTemplate = getSettings("*").MESSAGE_TEMPLATE + messageTemplate = getSettings("*").MESSAGE.TEMPLATE } body, err := request.GetReqBody(w, req) diff --git a/internals/proxy/middlewares/template.go b/internals/proxy/middlewares/template.go index 3f006476..931aa231 100644 --- a/internals/proxy/middlewares/template.go +++ b/internals/proxy/middlewares/template.go @@ -25,10 +25,10 @@ func (data TemplateMiddleware) Use() http.Handler { next := data.Next return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - variables := getSettingsByReq(req).VARIABLES + variables := getSettingsByReq(req).MESSAGE.VARIABLES if variables == nil { - variables = getSettings("*").VARIABLES + variables = getSettings("*").MESSAGE.VARIABLES } body, err := request.GetReqBody(w, req) diff --git a/main.go b/main.go index 4ff0fa05..f086925c 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( var proxy_last *httputil.ReverseProxy -var ENV *structure.ENV_ +var ENV *structure.ENV func main() { logLevel := os.Getenv("LOG_LEVEL") diff --git a/utils/config/loader.go b/utils/config/loader.go index 66385fff..44298ce5 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -14,13 +14,13 @@ import ( "github.com/knadh/koanf/parsers/yaml" ) -var ENV *structure.ENV_ = &structure.ENV_{ +var ENV *structure.ENV = &structure.ENV{ CONFIG_PATH: os.Getenv("CONFIG_PATH"), DEFAULTS_PATH: os.Getenv("DEFAULTS_PATH"), TOKENS_DIR: os.Getenv("TOKENS_DIR"), FAVICON_PATH: os.Getenv("FAVICON_PATH"), API_TOKENS: []string{}, - SETTINGS: map[string]*structure.SETTING_{}, + SETTINGS: map[string]*structure.SETTINGS{}, INSECURE: false, } @@ -55,7 +55,7 @@ func InitEnv() { ENV.API_URL = config.String("api.url") - var settings structure.SETTING_ + var settings structure.SETTINGS transformChildren(config, "settings.message.variables", transformVariables) diff --git a/utils/config/structure/structure.go b/utils/config/structure/structure.go index b95d8618..15a8974e 100644 --- a/utils/config/structure/structure.go +++ b/utils/config/structure/structure.go @@ -1,26 +1,34 @@ package structure +type ENV struct { + CONFIG_PATH string + DEFAULTS_PATH string + FAVICON_PATH string + TOKENS_DIR string + LOG_LEVEL string + PORT string + API_URL string + API_TOKENS []string + SETTINGS map[string]*SETTINGS + INSECURE bool +} + +type MESSAGE_SETTINGS struct { + VARIABLES map[string]any `koanf:"variables"` + FIELD_MAPPINGS map[string][]FieldMapping `koanf:"fieldMappings"` + TEMPLATE string `koanf:"template"` +} + type FieldMapping struct { - Field string `koanf:"field"` - Score int `koanf:"score"` + Field string `koanf:"field"` + Score int `koanf:"score"` } -type ENV_ struct { - CONFIG_PATH string - DEFAULTS_PATH string - FAVICON_PATH string - TOKENS_DIR string - LOG_LEVEL string - PORT string - API_URL string - API_TOKENS []string - SETTINGS map[string]*SETTING_ - INSECURE bool +type ACCESS_SETTINGS struct { + ENDPOINTS []string `koanf:"endpoints"` } -type SETTING_ struct { - ENDPOINTS []string `koanf:"access.endpoints"` - VARIABLES map[string]any `koanf:"message.variables"` - FIELD_MAPPINGS map[string][]FieldMapping `koanf:"message.fieldMappings"` - MESSAGE_TEMPLATE string `koanf:"message.template"` +type SETTINGS struct { + ACCESS ACCESS_SETTINGS `koanf:"access"` + MESSAGE MESSAGE_SETTINGS `koanf:"message"` } \ No newline at end of file diff --git a/utils/config/tokens.go b/utils/config/tokens.go index 40976453..f8901453 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -10,7 +10,7 @@ import ( type TOKEN_CONFIG_ struct { TOKENS []string `koanf:"tokens"` - OVERRIDES structure.SETTING_ `koanf:"overrides"` + OVERRIDES structure.SETTINGS `koanf:"overrides"` } func LoadTokens() { @@ -59,8 +59,8 @@ func InitTokens() { } } -func parseTokenConfigs(configs []TOKEN_CONFIG_) map[string]structure.SETTING_ { - settings := map[string]structure.SETTING_{} +func parseTokenConfigs(configs []TOKEN_CONFIG_) map[string]structure.SETTINGS { + settings := map[string]structure.SETTINGS{} for _, config := range configs { for _, token := range config.TOKENS { From c9b32ab45d224dbdf58bc23fc8852908ef8d1290 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:28:24 +0200 Subject: [PATCH 06/12] remove examples --- examples/config.yml | 28 ---------------- examples/reverse-proxy/nginx/nginx.conf | 28 ---------------- .../nginx/nginx.docker-compose.yaml | 33 ------------------- .../traefik/traefik.docker-compose.yaml | 30 ----------------- examples/token.yml | 7 ---- 5 files changed, 126 deletions(-) delete mode 100644 examples/config.yml delete mode 100644 examples/reverse-proxy/nginx/nginx.conf delete mode 100644 examples/reverse-proxy/nginx/nginx.docker-compose.yaml delete mode 100644 examples/reverse-proxy/traefik/traefik.docker-compose.yaml delete mode 100644 examples/token.yml diff --git a/examples/config.yml b/examples/config.yml deleted file mode 100644 index 20058922..00000000 --- a/examples/config.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Example Config (all configurations shown) -service: - port: 8880 - -api: - url: http://signal-api:8080 - tokens: [token1, token2] - -logLevel: info - -settings: - messageTemplate: | - You've got a Notification: - {{@message}} - At {{@data.timestamp}} on {{@data.date}}. - Send using {{.NUMBER}}. - - variables: - number: "+123400001" - recipients: ["+123400002", "group.id", "user.id"] - - dataAliases: - "@message": [{ alias: "msg", score: 100 }] - - blockedEndpoints: - - /v1/about - allowedEndpoints: - - /v2/send diff --git a/examples/reverse-proxy/nginx/nginx.conf b/examples/reverse-proxy/nginx/nginx.conf deleted file mode 100644 index 0e8afbbf..00000000 --- a/examples/reverse-proxy/nginx/nginx.conf +++ /dev/null @@ -1,28 +0,0 @@ -server { - # Allow SSL on Port 443 - listen 443 ssl; - - # Add allowed hostnames which nginx should respond to - # `_` for any - server_name localhost; - - ssl_certificate /etc/nginx/ssl/cert.crt; - ssl_certificate_key /etc/nginx/ssl/cert.key; - - location / { - # Use whatever network alias you set in the docker-compose file - proxy_pass http://secured-signal-api:8880; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Fowarded-Proto $scheme; - } -} - -# Redirect HTTP to HTTPs -server { - listen 80; - server_name localhost; - return 301 https://$host$request_uri; -} \ No newline at end of file diff --git a/examples/reverse-proxy/nginx/nginx.docker-compose.yaml b/examples/reverse-proxy/nginx/nginx.docker-compose.yaml deleted file mode 100644 index 105b5130..00000000 --- a/examples/reverse-proxy/nginx/nginx.docker-compose.yaml +++ /dev/null @@ -1,33 +0,0 @@ -services: - secured-signal: - image: ghcr.io/codeshelldev/secured-signal-api:latest - container_name: secured-signal-api - environment: - API__URL: http://signal-api:8080 - SETTINGS__VARIABLES__RECIPIENTS: "[+123400002,+123400003,+123400004]" - SETTINGS__VARIABLES__NUMBER: "+123400001" - API__TOKENS: "[LOOOOOONG_STRING]" - restart: unless-stopped - networks: - backend: - aliases: - - secured-signal-api - - nginx: - image: nginx:latest - container_name: secured-signal-proxy - volumes: - - ./nginx.conf:/etc/nginx/conf.d/default.conf - # Load SSL certificates: cert.key, cert.crt - - ./certs:/etc/nginx/ssl - ports: - - "443:443" - - "80:80" - restart: unless-stopped - networks: - frontend: - backend: - -networks: - backend: - frontend: diff --git a/examples/reverse-proxy/traefik/traefik.docker-compose.yaml b/examples/reverse-proxy/traefik/traefik.docker-compose.yaml deleted file mode 100644 index a4654974..00000000 --- a/examples/reverse-proxy/traefik/traefik.docker-compose.yaml +++ /dev/null @@ -1,30 +0,0 @@ -services: - secured-signal: - image: ghcr.io/codeshelldev/secured-signal-api:latest - container_name: secured-signal - environment: - API__URL: http://signal-api:8080 - SETTINGS__VARIABLES__RECIPIENTS: - '[+123400002,+123400003,+123400004]' - SETTINGS__VARIABLES__NUMBER: "+123400001" - API__TOKENS: '[LOOOOOONG_STRING]' - labels: - - traefik.enable=true - - traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`) - - traefik.http.routers.signal-api.entrypoints=websecure - - traefik.http.routers.signal-api.tls=true - - traefik.http.routers.signal-api.tls.certresolver=cloudflare - - traefik.http.routers.signal-api.service=signal-api-svc - - traefik.http.services.signal-api-svc.loadbalancer.server.port=8880 - - traefik.docker.network=proxy - restart: unless-stopped - networks: - proxy: - backend: - aliases: - - secured-signal-api - -networks: - backend: - proxy: - external: true diff --git a/examples/token.yml b/examples/token.yml deleted file mode 100644 index b3723e21..00000000 --- a/examples/token.yml +++ /dev/null @@ -1,7 +0,0 @@ -tokens: [LOOOONG_STRING] - -overrides: - variables: # Disable Placeholder - blockedEndpoints: # Disable Sending - - /v2/send - dataAliases: # Disable Aliases From ea42096c4ac39047123d63cdd2d7bc006564b070 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:31:27 +0200 Subject: [PATCH 07/12] move based on hierachy --- utils/config/structure/structure.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/config/structure/structure.go b/utils/config/structure/structure.go index 15a8974e..2a768199 100644 --- a/utils/config/structure/structure.go +++ b/utils/config/structure/structure.go @@ -13,6 +13,11 @@ type ENV struct { INSECURE bool } +type SETTINGS struct { + ACCESS ACCESS_SETTINGS `koanf:"access"` + MESSAGE MESSAGE_SETTINGS `koanf:"message"` +} + type MESSAGE_SETTINGS struct { VARIABLES map[string]any `koanf:"variables"` FIELD_MAPPINGS map[string][]FieldMapping `koanf:"fieldMappings"` @@ -26,9 +31,4 @@ type FieldMapping struct { type ACCESS_SETTINGS struct { ENDPOINTS []string `koanf:"endpoints"` -} - -type SETTINGS struct { - ACCESS ACCESS_SETTINGS `koanf:"access"` - MESSAGE MESSAGE_SETTINGS `koanf:"message"` } \ No newline at end of file From 23e232ec7cce51262a435c1122006adc373a96ac Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:50:01 +0200 Subject: [PATCH 08/12] add more robust error handling / reporting --- utils/config/loader.go | 18 +++++++++++------- utils/config/tokens.go | 9 +++++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/utils/config/loader.go b/utils/config/loader.go index 44298ce5..a3b5e9bd 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -65,23 +65,27 @@ func InitEnv() { } func LoadDefaults() { - _, defErr := LoadFile(ENV.DEFAULTS_PATH, defaultsLayer, yaml.Parser()) + _, err := LoadFile(ENV.DEFAULTS_PATH, defaultsLayer, yaml.Parser()) - if defErr != nil { + if err != nil { log.Warn("Could not Load Defaults", ENV.DEFAULTS_PATH) } } func LoadConfig() { - _, conErr := LoadFile(ENV.CONFIG_PATH, userLayer, yaml.Parser()) + _, err := LoadFile(ENV.CONFIG_PATH, userLayer, yaml.Parser()) - if conErr != nil { - _, err := os.Stat(ENV.CONFIG_PATH) + if err != nil { + _, fsErr := os.Stat(ENV.CONFIG_PATH) - if !errors.Is(err, fs.ErrNotExist) { - log.Error("Could not Load Config ", ENV.CONFIG_PATH, ": ", conErr.Error()) + // Config File doesn't exist + // => User is using Environment + if errors.Is(fsErr, fs.ErrNotExist) { + return } } + + log.Error("Could not Load Config ", ENV.CONFIG_PATH, ": ", err.Error()) } func transformVariables(key string, value any) (string, any) { diff --git a/utils/config/tokens.go b/utils/config/tokens.go index f8901453..54ec9c8d 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -14,9 +14,13 @@ type TOKEN_CONFIG_ struct { } func LoadTokens() { - log.Debug("Loading Configs ", ENV.TOKENS_DIR) + log.Debug("Loading Configs in ", ENV.TOKENS_DIR) - LoadDir("tokenconfigs", ENV.TOKENS_DIR, tokensLayer, yaml.Parser()) + err := LoadDir("tokenconfigs", ENV.TOKENS_DIR, tokensLayer, yaml.Parser()) + + if err != nil { + log.Error("Could not Load Configs in ", ENV.TOKENS_DIR, ": ", err.Error()) + } normalizeKeys(tokensLayer) @@ -49,6 +53,7 @@ func InitTokens() { // Set Blocked Endpoints on Config to User Layer Value // => effectively ignoring Default Layer + // TODO: check this, `endpoints` might be wrong and instead `access.endpoints` config.Set("endpoints", userLayer.Strings("endpoints")) } From bf61a872a4de4bdec0c5c774d4a3c808e08714fb Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 18:54:04 +0200 Subject: [PATCH 09/12] fixed endpoints reset --- utils/config/tokens.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/config/tokens.go b/utils/config/tokens.go index 54ec9c8d..3414c935 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -53,8 +53,7 @@ func InitTokens() { // Set Blocked Endpoints on Config to User Layer Value // => effectively ignoring Default Layer - // TODO: check this, `endpoints` might be wrong and instead `access.endpoints` - config.Set("endpoints", userLayer.Strings("endpoints")) + config.Set("settings.access.endpoints", userLayer.Strings("settings.access.endpoints")) } if len(apiTokens) > 0 { From ae367f46ef8ac8be78c344a325895556349b81d8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 18:55:21 +0200 Subject: [PATCH 10/12] changed warn message --- utils/config/tokens.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/config/tokens.go b/utils/config/tokens.go index 3414c935..fcc852c5 100644 --- a/utils/config/tokens.go +++ b/utils/config/tokens.go @@ -45,7 +45,7 @@ func InitTokens() { } if len(apiTokens) <= 0 { - log.Warn("No API TOKEN provided this is NOT recommended") + log.Warn("No API Tokens provided this is NOT recommended") log.Info("Disabling Security Features due to incomplete Congfiguration") From 91a5f111de641712b85154a6fe3ce96e65fe4caf Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 19:08:03 +0200 Subject: [PATCH 11/12] moved logerror --- utils/config/loader.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/config/loader.go b/utils/config/loader.go index a3b5e9bd..9c484dd9 100644 --- a/utils/config/loader.go +++ b/utils/config/loader.go @@ -83,9 +83,9 @@ func LoadConfig() { if errors.Is(fsErr, fs.ErrNotExist) { return } - } - log.Error("Could not Load Config ", ENV.CONFIG_PATH, ": ", err.Error()) + log.Error("Could not Load Config ", ENV.CONFIG_PATH, ": ", err.Error()) + } } func transformVariables(key string, value any) (string, any) { From c465abb6d9e29b4a666e680bf1413a7470e4cc42 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 19:14:09 +0200 Subject: [PATCH 12/12] append to array instead of indexing null --- internals/proxy/middlewares/endpoints.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index 2e34c97f..f3e0419a 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -40,13 +40,13 @@ func getEndpoints(endpoints []string) ([]string, []string) { blockedEndpoints := []string{} allowedEndpoints := []string{} - for i, endpoint := range endpoints { + for _, endpoint := range endpoints { endpoint, block := strings.CutPrefix(endpoint, "!") if block { - blockedEndpoints[i] = endpoint + blockedEndpoints = append(blockedEndpoints, endpoint) } else { - allowedEndpoints[i] = endpoint + allowedEndpoints = append(allowedEndpoints, endpoint) } }