From 61b77a3ff958c555bc3eb317af48b8f62c435175 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Wed, 27 Sep 2023 14:56:31 +0200 Subject: [PATCH] api: return 400 in case of non-existent config fields (#2425) --- internal/conf/conf.go | 4 +++- internal/conf/path.go | 4 +++- internal/core/api.go | 8 +++++-- internal/core/api_test.go | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 829647c7..6691df62 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -335,7 +335,9 @@ func (conf *Conf) Check() error { return nil } -// UnmarshalJSON implements json.Unmarshaler. It is used to set default values. +// UnmarshalJSON implements json.Unmarshaler. It is used to: +// - force DisallowUnknownFields +// - set default values func (conf *Conf) UnmarshalJSON(b []byte) error { // general conf.LogLevel = LogLevel(logger.Info) diff --git a/internal/conf/path.go b/internal/conf/path.go index f0533c7c..b258ea0f 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -447,7 +447,9 @@ func (pconf PathConf) HasOnDemandPublisher() bool { return pconf.RunOnDemand != "" } -// UnmarshalJSON implements json.Unmarshaler. It is used to set default values. +// UnmarshalJSON implements json.Unmarshaler. It is used to: +// - force DisallowUnknownFields +// - set default values func (pconf *PathConf) UnmarshalJSON(b []byte) error { // General pconf.Source = "publisher" diff --git a/internal/core/api.go b/internal/core/api.go index 393d797a..3fdbedfc 100644 --- a/internal/core/api.go +++ b/internal/core/api.go @@ -63,7 +63,9 @@ func generateStructWithOptionalFields(model interface{}) interface{} { func loadConfData(ctx *gin.Context) (interface{}, error) { in := generateStructWithOptionalFields(conf.Conf{}) - err := json.NewDecoder(ctx.Request.Body).Decode(in) + d := json.NewDecoder(ctx.Request.Body) + d.DisallowUnknownFields() + err := d.Decode(in) if err != nil { return nil, err } @@ -73,7 +75,9 @@ func loadConfData(ctx *gin.Context) (interface{}, error) { func loadConfPathData(ctx *gin.Context) (interface{}, error) { in := generateStructWithOptionalFields(conf.PathConf{}) - err := json.NewDecoder(ctx.Request.Body).Decode(in) + d := json.NewDecoder(ctx.Request.Body) + d.DisallowUnknownFields() + err := d.Decode(in) if err != nil { return nil, err } diff --git a/internal/core/api_test.go b/internal/core/api_test.go index 086849e4..d297c849 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -155,6 +155,29 @@ func TestAPIConfigSet(t *testing.T) { require.Equal(t, []interface{}{"tcp"}, out["protocols"]) } +func TestAPIConfigSetUnknownField(t *testing.T) { + p, ok := newInstance("api: yes\n") + require.Equal(t, true, ok) + defer p.Close() + + b := map[string]interface{}{ + "test": "asd", + } + + byts, err := json.Marshal(b) + require.NoError(t, err) + + hc := &http.Client{Transport: &http.Transport{}} + + req, err := http.NewRequest("POST", "http://localhost:9997/v2/config/set", bytes.NewReader(byts)) + require.NoError(t, err) + + res, err := hc.Do(req) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) +} + func TestAPIConfigPathsAdd(t *testing.T) { p, ok := newInstance("api: yes\n") require.Equal(t, true, ok) @@ -179,6 +202,29 @@ func TestAPIConfigPathsAdd(t *testing.T) { require.Equal(t, "10s", out.Paths["my/path"].SourceOnDemandStartTimeout) } +func TestAPIConfigPathsAddUnknownField(t *testing.T) { + p, ok := newInstance("api: yes\n") + require.Equal(t, true, ok) + defer p.Close() + + b := map[string]interface{}{ + "test": "asd", + } + + byts, err := json.Marshal(b) + require.NoError(t, err) + + hc := &http.Client{Transport: &http.Transport{}} + + req, err := http.NewRequest("POST", "http://localhost:9997/v2/config/paths/add/my/path", bytes.NewReader(byts)) + require.NoError(t, err) + + res, err := hc.Do(req) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) +} + func TestAPIConfigPathsEdit(t *testing.T) { p, ok := newInstance("api: yes\n") require.Equal(t, true, ok)