diff --git a/config/diametercfg_test.go b/config/diametercfg_test.go index 5445d256d..53606a716 100644 --- a/config/diametercfg_test.go +++ b/config/diametercfg_test.go @@ -18,7 +18,6 @@ along with this program. If not, see package config import ( - "fmt" "reflect" "testing" @@ -194,8 +193,6 @@ func TestDiameterAgentCfgAsMapInterface(t *testing.T) { } rcv := cgrCfg.diameterAgentCfg.AsMapInterface(utils.InfieldSep) if !reflect.DeepEqual(rcv, eMap) { - fmt.Printf("%T \n", rcv[utils.RequestProcessorsCfg].([]map[string]interface{})[0][utils.FlagsCfg]) - fmt.Printf("%T \n", eMap[utils.RequestProcessorsCfg].([]map[string]interface{})[0][utils.FlagsCfg]) t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } diff --git a/engine/datamanager.go b/engine/datamanager.go index 4a84b0c4c..ac4b3b4b3 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -28,15 +28,15 @@ import ( var ( filterIndexesPrefixMap = utils.StringSet{ - utils.AttributeFilterIndexes: {}, - utils.ResourceFilterIndexes: {}, - utils.StatFilterIndexes: {}, - utils.ThresholdFilterIndexes: {}, - utils.RouteFilterIndexes: {}, - utils.ChargerFilterIndexes: {}, - utils.DispatcherFilterIndexes: {}, - utils.ActionPlanIndexes: {}, - utils.FilterIndexPrfx: {}, + utils.AttributeFilterIndexes: {}, + utils.ResourceFilterIndexes: {}, + utils.StatFilterIndexes: {}, + utils.ThresholdFilterIndexes: {}, + utils.RouteFilterIndexes: {}, + utils.ChargerFilterIndexes: {}, + utils.DispatcherFilterIndexes: {}, + utils.ActionPlanIndexes: {}, + utils.FilterIndexPrfx: {}, } cachePrefixMap = utils.StringSet{ utils.DestinationPrefix: {}, @@ -845,6 +845,9 @@ func (dm *DataManager) SetFilter(fltr *Filter, withIndex bool) (err error) { if dm == nil { return utils.ErrNoDatabaseConn } + if err = CheckFilter(fltr); err != nil { + return + } var oldFlt *Filter if oldFlt, err = dm.GetFilter(fltr.Tenant, fltr.ID, true, false, utils.NonTransactional); err != nil && err != utils.ErrNotFound { @@ -1075,10 +1078,10 @@ func (dm *DataManager) SetThresholdProfile(th *ThresholdProfile, withIndex bool) return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(th.Tenant, th.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(th.Tenant, th.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, th.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, th.TenantID()) } } oldTh, err := dm.GetThresholdProfile(th.Tenant, th.ID, true, false, utils.NonTransactional) @@ -1203,10 +1206,10 @@ func (dm *DataManager) SetStatQueueProfile(sqp *StatQueueProfile, withIndex bool return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(sqp.Tenant, sqp.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(sqp.Tenant, sqp.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, sqp.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, sqp.TenantID()) } } oldSts, err := dm.GetStatQueueProfile(sqp.Tenant, sqp.ID, true, false, utils.NonTransactional) @@ -1537,10 +1540,10 @@ func (dm *DataManager) SetResourceProfile(rp *ResourceProfile, withIndex bool) ( return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(rp.Tenant, rp.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(rp.Tenant, rp.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, rp.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, rp.TenantID()) } } oldRes, err := dm.GetResourceProfile(rp.Tenant, rp.ID, true, false, utils.NonTransactional) @@ -2358,10 +2361,10 @@ func (dm *DataManager) SetRouteProfile(rpp *RouteProfile, withIndex bool) (err e return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(rpp.Tenant, rpp.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(rpp.Tenant, rpp.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, rpp.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, rpp.TenantID()) } } oldRpp, err := dm.GetRouteProfile(rpp.Tenant, rpp.ID, true, false, utils.NonTransactional) @@ -2492,10 +2495,10 @@ func (dm *DataManager) SetAttributeProfile(ap *AttributeProfile, withIndex bool) return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(ap.Tenant, ap.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(ap.Tenant, ap.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, ap.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, ap.TenantID()) } } oldAP, err := dm.GetAttributeProfile(ap.Tenant, ap.ID, true, false, utils.NonTransactional) @@ -2623,10 +2626,10 @@ func (dm *DataManager) SetChargerProfile(cpp *ChargerProfile, withIndex bool) (e return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(cpp.Tenant, cpp.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(cpp.Tenant, cpp.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, cpp.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, cpp.TenantID()) } } oldCpp, err := dm.GetChargerProfile(cpp.Tenant, cpp.ID, true, false, utils.NonTransactional) @@ -2751,10 +2754,10 @@ func (dm *DataManager) SetDispatcherProfile(dpp *DispatcherProfile, withIndex bo return utils.ErrNoDatabaseConn } if withIndex { - if brokenReference := dm.checkFilters(dpp.Tenant, dpp.FilterIDs); len(brokenReference) != 0 { + if err = dm.checkFilters(dpp.Tenant, dpp.FilterIDs); err != nil { // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, dpp.TenantID()) + return fmt.Errorf("%+s for item with ID: %+v", + err, dpp.TenantID()) } } oldDpp, err := dm.GetDispatcherProfile(dpp.Tenant, dpp.ID, true, false, utils.NonTransactional) @@ -3157,17 +3160,19 @@ func (dm *DataManager) GetAPIBan(ip string, apiKeys []string, single, cacheRead, // checkFilters returns the id of the first Filter that is not valid // it should be called after the dm nil check -func (dm *DataManager) checkFilters(tenant string, ids []string) (brokenReference string) { +func (dm *DataManager) checkFilters(tenant string, ids []string) (err error) { for _, id := range ids { // in case of inline filter we try to build them // if they are not correct it should fail here not in indexes if strings.HasPrefix(id, utils.Meta) { - if _, err := NewFilterFromInline(tenant, id); err != nil { - return id + if fltr, err := NewFilterFromInline(tenant, id); err != nil { + return fmt.Errorf("broken reference to filter: <%s>", id) + } else if err := CheckFilter(fltr); err != nil { + return err } } else if x, has := Cache.Get(utils.CacheFilters, // because the method HasDataDrv doesn't use cache utils.ConcatenatedKey(tenant, id)); has && x == nil { // check to see if filter is already in cache - return id + return fmt.Errorf("broken reference to filter: <%s>", id) } else if has, err := dm.DataDB().HasDataDrv(utils.FilterPrefix, // check in local DB if we have the filter id, tenant); err != nil || !has { // in case we can not find it localy try to find it in the remote DB @@ -3184,7 +3189,7 @@ func (dm *DataManager) checkFilters(tenant string, ids []string) (brokenReferenc } // not in local DB and not in remote DB if err != nil || !has { - return id + return fmt.Errorf("broken reference to filter: <%s>", id) } } } diff --git a/engine/filters.go b/engine/filters.go index f4b30aced..156bfaf4a 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -688,3 +688,21 @@ func verifyInlineFilterS(fltrs []string) (err error) { } return } + +func CheckFilter(fltr *Filter) (err error) { + for _, rls := range fltr.Rules { + valFunc := utils.IsPathValid + if rls.Type == utils.MetaEmpty || rls.Type == utils.MetaExists { + valFunc = utils.IsPathValidForExporters + } + if err = valFunc(rls.Element); err != nil { + return fmt.Errorf("%s for filter <%v>", err, fltr) //encapsulated error + } + for _, val := range rls.Values { + if err = valFunc(val); err != nil { + return fmt.Errorf("%s for filter <%v>", err, fltr) //encapsulated error + } + } + } + return nil +} diff --git a/utils/datanode_test.go b/utils/datanode_test.go index 6a392ce9f..854151314 100644 --- a/utils/datanode_test.go +++ b/utils/datanode_test.go @@ -378,8 +378,10 @@ func TestAppend2(t *testing.T) { dn.Slice = nil dn.Map = map[string]*DataNode{} - if _, err := dn.Append(testPath, val1); err != nil { + if rcv, err := dn.Append(testPath, val1); err != nil { t.Error(err) + } else if rcv != 0 { + t.Errorf("Expected %+v, received %+v", 0, rcv) } /// diff --git a/utils/dataprovider.go b/utils/dataprovider.go index 82cbc9bd3..3ab0aff03 100644 --- a/utils/dataprovider.go +++ b/utils/dataprovider.go @@ -19,6 +19,8 @@ along with this program. If not, see package utils import ( + "errors" + "fmt" "net" "strings" ) @@ -73,3 +75,56 @@ func DPDynamicString(dnVal string, dP DataProvider) (string, error) { } return dnVal, nil } + +func IsPathValid(path string) (err error) { + if !strings.HasPrefix(path, DynamicDataPrefix) { + return nil + } + paths := strings.Split(path, NestingSep) + if len(paths) <= 1 { + return errors.New("Path is missing ") + } + for _, path := range paths { + if strings.TrimSpace(path) == EmptyString { + return errors.New("Empty field path ") + } + } + return nil +} + +func IsPathValidForExporters(path string) (err error) { + if !strings.HasPrefix(path, DynamicDataPrefix) { + return nil + } + paths := strings.Split(path, NestingSep) + for _, path := range paths { + if strings.TrimSpace(path) == EmptyString { + return errors.New("Empty field path ") + } + } + return nil +} + +func CheckInLineFilter(fltrs []string) (err error) { + for _, fltr := range fltrs { + if strings.HasPrefix(fltr, Meta) { + rules := strings.SplitN(fltr, InInFieldSep, 3) + if len(rules) < 3 { + return fmt.Errorf("inline parse error for string: <%s>", fltr) + } + valFunc := IsPathValid + if rules[0] == MetaEmpty || rules[0] == MetaExists { + valFunc = IsPathValidForExporters + } + if err = valFunc(rules[1]); err != nil { + return fmt.Errorf("%s for <%s>", err, fltr) //encapsulated error + } + for _, val := range strings.Split(rules[2], PipeSep) { + if err = valFunc(val); err != nil { + return fmt.Errorf("%s for <%s>", err, fltr) //encapsulated error + } + } + } + } + return nil +}