Beispiel #1
0
func GetStorage(config *conf.ConfigFile) (Storage, error) {
	storageMethod, err := config.GetString("storage", "method")
	if err != nil {
		return nil, errors.New("Error: storage method not specified in config file.")
	}

	var storage Storage

	switch storageMethod {
	case "local":
		storage, err = NewLocalStorage(config)
	case "ftp":
		storage, err = NewFTPStorage(config)
	case "gdrive":
		storage, err = NewGDriveStorage(config)
	default:
		return nil, errors.New("Error: storage method '" + storageMethod + "' not found.")
	}

	if err != nil {
		return nil, err
	}

	return storage, nil
}
Beispiel #2
0
func getPasswords(c *conf.ConfigFile) ([]string, error) {
	passwords, err := c.GetString("default", "passwords")
	if err != nil {
		return nil, err
	}
	return strings.Split(passwords, " "), nil
}
Beispiel #3
0
func getString(c *conf.ConfigFile, section, option string) (value string) {
	value, err := c.GetString(section, option)
	if err != nil {
		log.Fatal("missing config value: ", option)
	}
	return
}
Beispiel #4
0
func sendMail(c *conf.ConfigFile, e Envelope) error {
	var addr string
	var err error
	var conn *smtp.Client

	addr, _ = c.GetString("main", "smtp")

	conn, err = smtp.Dial(addr)
	if err != nil {
		return err
	}

	if err = conn.Mail(e.Sender); err != nil {
		return err
	}

	for _, addr := range e.Recipients {
		if err = conn.Rcpt(addr); err != nil {
			return err
		}
	}

	w, err := conn.Data()
	if err != nil {
		return err
	}

	io.Copy(w, serializeMail(e))
	conn.Quit()
	return nil
}
Beispiel #5
0
func getIdsByEmails(c *conf.ConfigFile, k openpgp.EntityList, emails []string) (ids []string) {
	var emailsLeft []string

	for _, email := range emails {
		if c.HasOption("keys", email) {
			line, _ := c.GetString("keys", email)
			parts := strings.Fields(line)
			ids = append(ids, parts...)
		} else {
			emailsLeft = append(emailsLeft, email)
		}
	}

	for _, entity := range k {
		for _, identity := range entity.Identities {
			for _, email := range emailsLeft {
				if identity.UserId.Email == email {
					ids = append(ids, getKeyId(entity))
					continue // enough if one addr per key matches
				}
			}
		}
	}

	return ids
}
func LoadRestAddr(c *conf.ConfigFile) (string, error) {
	addr, err := c.GetString("WebFrontend", "addr")
	if err != nil || addr == "" {
		addr = "localhost:9898"
		err = nil
	}
	return addr, err
}
func LoadLoggers(c *conf.ConfigFile) (loggers []Logger, err error) {
	var logfile io.Writer

	logfilename, err := c.GetString("default", "logfile")
	if err == nil && logfilename != "" {
		logfile, err = os.OpenFile(logfilename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
		if err != nil {
			logfile = os.Stderr
		}
	} else {
		logfile = os.Stderr
	}

	loggers = make([]Logger, LOGGER_NR_LOGGERS)
	loggers[LOGGER_WEB], err = loadLogger(logfile, c, "WebFrontend", "[WebFrontend]")
	if err != nil {
		loggers = nil
		return
	}

	loggers[LOGGER_ADDPSP], err = loadLogger(logfile, c, "AddPushServiceProvider", "[AddPushServiceProvider]")
	if err != nil {
		loggers = nil
		return
	}

	loggers[LOGGER_RMPSP], err = loadLogger(logfile, c, "RemovePushServiceProvider", "[RemovePushServiceProvider]")
	if err != nil {
		loggers = nil
		return
	}

	loggers[LOGGER_SUB], err = loadLogger(logfile, c, "Subscribe", "[Subscribe]")
	if err != nil {
		loggers = nil
		return
	}

	loggers[LOGGER_UNSUB], err = loadLogger(logfile, c, "Unsubscribe", "[Unsubscribe]")
	if err != nil {
		loggers = nil
		return
	}

	loggers[LOGGER_PUSH], err = loadLogger(logfile, c, "Push", "[Push]")
	if err != nil {
		loggers = nil
		return
	}
	return
}
Beispiel #8
0
func NewFTPStorage(config *conf.ConfigFile) (*FTPStorage, error) {
	server, err := config.GetString("storage", "server")
	if err != nil {
		return nil, errors.New("Error: FTPStorage indicated in config file, but 'server' not specified.")
	}
	port, err := config.GetInt("storage", "port")
	if err != nil {
		return nil, errors.New("Error: FTPStorage indicated in config file, but 'port' not specified.")
	}
	directory, err := config.GetString("storage", "directory")
	if err != nil {
		return nil, errors.New("Error: FTPStorage indicated in config file, but 'directory' not specified.")
	}
	username, err := config.GetString("storage", "username")
	if err != nil {
		return nil, errors.New("Error: FTPStorage indicated in config file, but 'username' not specified.")
	}
	password, err := config.GetString("storage", "password")
	if err != nil {
		return nil, errors.New("Error: FTPStorage indicated in config file, but 'password' not specified.")
	}

	fs := new(FTPStorage)
	fs.server = server
	fs.port = port
	fs.directory = directory
	fs.username = username
	fs.password = password

	fs.connectionsChan = make(chan int, FTP_MAX_CONNECTIONS)

	return fs, nil
}
Beispiel #9
0
func configureSandboxes(config *conf.ConfigFile) ([]SandboxPair, error) {
	basePath, err := config.GetString("default", "path")
	if err != nil {
		return nil, err
	}
	passwords, err := getPasswords(config)
	if err != nil {
		return nil, err
	}
	result := make([]SandboxPair, len(passwords))
	for index, password := range passwords {
		localBase := filepath.Join(basePath, strconv.Itoa(index))
		result[index].Compile.Path = filepath.Join(localBase, "C")
		result[index].Run.Path = filepath.Join(localBase, "R")

		e := checkSandbox(result[index].Compile.Path)
		if e != nil {
			return nil, e
		}
		e = checkSandbox(result[index].Run.Path)
		if e != nil {
			return nil, e
		}

		if PLATFORM_ID == "linux" {
			e = setAcl(result[index].Compile.Path, "compiler")
			if e != nil {
				return nil, e
			}
			result[index].Compile.Login, e = subprocess.NewLoginInfo("compiler", "compiler")
			if e != nil {
				return nil, e
			}
		}

		restrictedUser := "******" + strconv.Itoa(index)

		e = setAcl(result[index].Run.Path, restrictedUser)
		if e != nil {
			return nil, e
		}
		// HACK HACK: on linux, passwords are ignored.
		result[index].Run.Login, e = subprocess.NewLoginInfo(restrictedUser, password)
		if e != nil {
			return nil, e
		}
	}
	return result, nil
}
Beispiel #10
0
func initTemplates(conf *conf.ConfigFile) {
	tmplDir, err := conf.GetString("default", "tmpl_dir")
	if err != nil {
		log.Panicf("not specified tmpl_dir: %s", err)
	}

	registerTmpl = getTemplate(tmplDir, "register")
	loginTmpl = getTemplate(tmplDir, "login")
}
Beispiel #11
0
func startServer(conf *conf.ConfigFile) {
	http.Handle("/", http.HandlerFunc(rootHandler))
	http.Handle("/login/", http.HandlerFunc(loginHandler))
	http.Handle("/register/", http.HandlerFunc(registerHandler))
	host, err := conf.GetString("default", "host")
	if err != nil {
		log.Panic("not specified host")
	}
	port, _ := conf.GetString("default", "port")
	if err != nil {
		log.Panic("not specified port")
	}
	err = http.ListenAndServe(host+":"+port, nil)
	if err != nil {
		log.Fatal("ListernAndServe:", err)
	}

}
Beispiel #12
0
func getKeys(c *conf.ConfigFile, e Envelope) openpgp.EntityList {
	var ids []string
	var path string
	var fh *os.File
	var err error
	var k openpgp.EntityList

	path, _ = c.GetString("main", "keyring")

	fh, err = os.Open(path)
	if err != nil {
		panic(err)
	}

	k, err = openpgp.ReadKeyRing(fh)
	if err != nil {
		panic(err)
	}

	ids = getIdsByEmails(c, k, e.Recipients)
	return getKeysByIds(k, ids)
}
Beispiel #13
0
func NewLocalStorage(config *conf.ConfigFile) (*LocalStorage, error) {
	storageDir, err := config.GetString("storage", "dir")
	if err != nil {
		return nil, errors.New("Error: LocalStorage indicated in config file, but lacking local storage directory ('dir = some/dir').")
	}

	ls := new(LocalStorage)
	ls.storageDir = storageDir
	ls.tmpSubdir = path.Join(storageDir, ".asink-tmpdir")

	//make sure the base directory and tmp subdir exist
	err = util.EnsureDirExists(ls.storageDir)
	if err != nil {
		return nil, err
	}
	err = util.EnsureDirExists(ls.tmpSubdir)
	if err != nil {
		return nil, err
	}

	return ls, nil
}
func loadLogger(writer io.Writer, c *conf.ConfigFile, field string, prefix string) (Logger, error) {
	var loglevel string
	var logswitch bool
	var err error

	logswitch, err = c.GetBool(field, "log")
	if err != nil {
		logswitch = true
	}

	if writer == nil {
		writer = os.Stderr
	}

	loglevel, err = c.GetString(field, "loglevel")
	if err != nil {
		loglevel = "standard"
	}
	var level int

	if logswitch {
		switch strings.ToLower(loglevel) {
		case "standard":
			level = LOGLEVEL_INFO
		case "verbose":
			level = LOGLEVEL_INFO
		case "debug":
			level = LOGLEVEL_DEBUG
		default:
			level = LOGLEVEL_INFO
		}
	} else {
		level = LOGLEVEL_SILENT
	}

	logger := NewLogger(writer, prefix, level)
	return logger, nil
}
Beispiel #15
0
func GetAndInitDB(config *conf.ConfigFile) (*AsinkDB, error) {
	dbLocation, err := config.GetString("local", "dblocation")
	if err != nil {
		return nil, errors.New("Error: database location not specified in config file.")
	}

	db, err := sql.Open("sqlite3", "file:"+dbLocation+"?cache=shared&mode=rwc")
	if err != nil {
		return nil, err
	}

	//make sure the events table is created
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	rows, err := tx.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='events';")
	if err != nil {
		return nil, err
	}
	if !rows.Next() {
		//if this is false, it means no rows were returned
		tx.Exec("CREATE TABLE events (id INTEGER, localid INTEGER PRIMARY KEY ASC, type INTEGER, localstatus INTEGER, path TEXT, hash TEXT, predecessor TEXT, timestamp INTEGER, permissions INTEGER);")
		//		tx.Exec("CREATE INDEX IF NOT EXISTS localididx on events (localid)")
		tx.Exec("CREATE INDEX IF NOT EXISTS ididx on events (id);")
		tx.Exec("CREATE INDEX IF NOT EXISTS pathidx on events (path);")
	}
	err = tx.Commit()
	if err != nil {
		return nil, err
	}

	ret := new(AsinkDB)
	ret.db = db
	return ret, nil
}
func LoadDatabaseConfig(cf *conf.ConfigFile) (*DatabaseConfig, error) {
	var err error
	c := new(DatabaseConfig)
	c.PushServiceManager = GetPushServiceManager()
	c.Engine, err = cf.GetString("Database", "engine")
	if err != nil || c.Engine == "" {
		c.Engine = "redis"
	}
	c.Name, err = cf.GetString("Database", "name")
	if err != nil || c.Name == "" {
		c.Name = "0"
	}
	c.Port, err = cf.GetInt("Database", "port")
	if err != nil || c.Port <= 0 {
		c.Port = -1
	}
	c.Host, err = cf.GetString("Database", "host")
	if err != nil || c.Host == "" {
		c.Host = "localhost"
	}
	c.Password, err = cf.GetString("Database", "password")
	if err != nil {
		c.Password = ""
	}
	i, e := cf.GetInt("Database", "everysec")
	c.EverySec = int64(i)
	if e != nil || c.EverySec <= 60 {
		c.EverySec = 600
	}
	c.LeastDirty, err = cf.GetInt("Database", "leastdirty")
	if err != nil || c.LeastDirty < 0 {
		c.LeastDirty = 10
	}
	c.CacheSize, err = cf.GetInt("Database", "cachesize")
	if err != nil || c.CacheSize < 0 {
		c.CacheSize = 1024
	}

	return c, nil
}
Beispiel #17
0
func NewGDriveStorage(config *conf.ConfigFile) (*GDriveStorage, error) {
	cachefile, err := config.GetString("storage", "cachefile")
	if err != nil {
		return nil, errors.New("Error: GDriveStorage indicated in config file, but 'cachefile' not specified.")
	}

	code, err := config.GetString("storage", "oauth_code")
	if err != nil {
		code = ""
	}

	directory, err := config.GetString("storage", "directory")
	if err != nil {
		return nil, errors.New("Error: GDriveStorage indicated in config file, but 'directory' not specified.")
	}

	oauth_config := &oauth.Config{
		ClientId:     GDRIVE_CLIENT_ID,
		ClientSecret: GDRIVE_CLIENT_SECRET,
		RedirectURL:  "urn:ietf:wg:oauth:2.0:oob",
		Scope:        "https://www.googleapis.com/auth/drive",
		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
		TokenURL:     "https://accounts.google.com/o/oauth2/token",
		TokenCache:   oauth.CacheFile(cachefile),
	}

	transport := &oauth.Transport{Config: oauth_config}
	token, err := oauth_config.TokenCache.Token()
	if err != nil {
		//if a code wasn't specified in the config file, ask the user to do that
		if code == "" {
			url := oauth_config.AuthCodeURL("")
			return nil, errors.New(fmt.Sprintf("Visit the following URL and sign in using your Google account to get an authorization code allowing Asink to access your GDrive files. Be sure to add this code to your Asink config file as 'oauth_code = your_code_here' before re-starting Asink:\n%s\n", url))
		}

		//attempt to fetch a token using the user-supplied code (this
		//has the effect of caching the token in the specified cache
		//file)
		token, err = transport.Exchange(code)
		if err != nil {
			url := oauth_config.AuthCodeURL("")
			return nil, errors.New(fmt.Sprintf("Error exchanging user-supplied GDrive code for an authentication token. Please check your auth code supplied in the Asink config file, or consider obtaining another by visiting %s\n(%s)", url, err.Error()))
		}
	}

	//Now, actually initialize the GDrive part of the API
	transport.Token = token
	s, err := drive.New(transport.Client())
	if err != nil {
		return nil, err
	}

	folderlist, err := s.Files.List().Q("mimeType = 'application/vnd.google-apps.folder' and title = '" + directory + "'").Do()

	if len(folderlist.Items) < 1 {
		//try to create a folder named 'directory'
		f := &drive.File{Title: directory, Description: "Asink client folder", MimeType: "application/vnd.google-apps.folder"}
		f, err := s.Files.Insert(f).Do()

		folderlist, err = s.Files.List().Q("mimeType = 'application/vnd.google-apps.folder' and title = '" + directory + "'").Do()
		if err != nil {
			return nil, err
		} else if len(folderlist.Items) < 1 {
			return nil, errors.New("I was unable to create a new folder in your GDrive, but I'm not sure why")
		}
	} else if len(folderlist.Items) > 1 {
		return nil, errors.New(fmt.Sprintf("Error: Your GDrive has more than one directory named '%s'. You are a barbarian. Fix that and we'll talk. (check your trash if you can't find it)\n", directory))
	}

	folderid := folderlist.Items[0].Id

	gs := new(GDriveStorage)
	gs.cachefile = cachefile
	gs.directory = directory
	gs.auth_code = code
	gs.service = s
	gs.transport = transport
	gs.folderid = folderid
	return gs, nil
}
Beispiel #18
0
// Parse the configuration file for CDRStatConfigs
func ParseCfgDefaultCDRStatsConfig(c *conf.ConfigFile) (*CdrStatsConfig, error) {
	var err error
	csCfg := NewCdrStatsConfigWithDefaults()
	if hasOpt := c.HasOption("cdrstats", "queue_length"); hasOpt {
		csCfg.QueueLength, _ = c.GetInt("cdrstats", "queue_length")
	}
	if hasOpt := c.HasOption("cdrstats", "time_window"); hasOpt {
		durStr, _ := c.GetString("cdrstats", "time_window")
		if csCfg.TimeWindow, err = utils.ParseDurationWithSecs(durStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "metrics"); hasOpt {
		metricsStr, _ := c.GetString("cdrstats", "metrics")
		if csCfg.Metrics, err = ConfigSlice(metricsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "setup_interval"); hasOpt {
		setupIntervalStr, _ := c.GetString("cdrstats", "setup_interval")
		if len(setupIntervalStr) != 0 { // If we parse empty, will get empty time, we prefer nil
			if setupIntervalSlc, err := ConfigSlice(setupIntervalStr); err != nil {
				return nil, err
			} else {
				for _, setupTimeStr := range setupIntervalSlc {
					if setupTime, err := utils.ParseTimeDetectLayout(setupTimeStr); err != nil {
						return nil, err
					} else {
						csCfg.SetupInterval = append(csCfg.SetupInterval, setupTime)
					}
				}
			}
		}
	}
	if hasOpt := c.HasOption("cdrstats", "tors"); hasOpt {
		torsStr, _ := c.GetString("cdrstats", "tors")
		if csCfg.TORs, err = ConfigSlice(torsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "cdr_hosts"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "cdr_hosts")
		if csCfg.CdrHosts, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "cdr_sources"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "cdr_sources")
		if csCfg.CdrSources, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "req_types"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "req_types")
		if csCfg.ReqTypes, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "directions"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "directions")
		if csCfg.Directions, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "tenants"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "tenants")
		if csCfg.Tenants, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "categories"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "categories")
		if csCfg.Categories, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "accounts"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "accounts")
		if csCfg.Accounts, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "subjects"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "subjects")
		if csCfg.Subjects, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "destination_prefixes"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "destination_prefixes")
		if csCfg.DestinationPrefixes, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "usage_interval"); hasOpt {
		usageIntervalStr, _ := c.GetString("cdrstats", "usage_interval")
		if usageIntervalSlc, err := ConfigSlice(usageIntervalStr); err != nil {
			return nil, err
		} else {
			for _, usageDurStr := range usageIntervalSlc {
				if usageDur, err := utils.ParseDurationWithSecs(usageDurStr); err != nil {
					return nil, err
				} else {
					csCfg.UsageInterval = append(csCfg.UsageInterval, usageDur)
				}
			}
		}
	}
	if hasOpt := c.HasOption("cdrstats", "mediation_run_ids"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "mediation_run_ids")
		if csCfg.MediationRunIds, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "rated_accounts"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "rated_accounts")
		if csCfg.RatedAccounts, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "rated_subjects"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "rated_subjects")
		if csCfg.RatedSubjects, err = ConfigSlice(valsStr); err != nil {
			return nil, err
		}
	}
	if hasOpt := c.HasOption("cdrstats", "cost_intervals"); hasOpt {
		valsStr, _ := c.GetString("cdrstats", "cost_intervals")
		if costSlc, err := ConfigSlice(valsStr); err != nil {
			return nil, err
		} else {
			for _, costStr := range costSlc {
				if cost, err := strconv.ParseFloat(costStr, 64); err != nil {
					return nil, err
				} else {
					csCfg.CostInterval = append(csCfg.CostInterval, cost)
				}
			}
		}
	}

	return csCfg, nil
}
Beispiel #19
0
// Parse the configuration file and returns utils.DerivedChargers instance if no errors
func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err error) {
	var runIds, runFilters, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
	cfgVal, _ := c.GetString("derived_charging", "run_ids")
	if runIds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "run_filters")
	if runFilters, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "reqtype_fields")
	if reqTypeFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "direction_fields")
	if directionFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "tenant_fields")
	if tenantFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "category_fields")
	if torFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "account_fields")
	if acntFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "subject_fields")
	if subjFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "destination_fields")
	if dstFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "setup_time_fields")
	if sTimeFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "answer_time_fields")
	if aTimeFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	cfgVal, _ = c.GetString("derived_charging", "usage_fields")
	if durFlds, err = ConfigSlice(cfgVal); err != nil {
		return nil, err
	}
	// We need all to be the same length
	if len(runFilters) != len(runIds) ||
		len(reqTypeFlds) != len(runIds) ||
		len(directionFlds) != len(runIds) ||
		len(tenantFlds) != len(runIds) ||
		len(torFlds) != len(runIds) ||
		len(acntFlds) != len(runIds) ||
		len(subjFlds) != len(runIds) ||
		len(dstFlds) != len(runIds) ||
		len(sTimeFlds) != len(runIds) ||
		len(aTimeFlds) != len(runIds) ||
		len(durFlds) != len(runIds) {
		return nil, errors.New("<ConfigSanity> Inconsistent fields length in derivated_charging section")
	}
	// Create the individual chargers and append them to the final instance
	dcs = make(utils.DerivedChargers, 0)
	if len(runIds) == 1 && len(runIds[0]) == 0 { // Avoid iterating on empty runid
		return dcs, nil
	}
	for runIdx, runId := range runIds {
		dc, err := utils.NewDerivedCharger(runId, runFilters[runIdx], reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
			acntFlds[runIdx], subjFlds[runIdx], dstFlds[runIdx], sTimeFlds[runIdx], aTimeFlds[runIdx], durFlds[runIdx])
		if err != nil {
			return nil, err
		}
		if dcs, err = dcs.Append(dc); err != nil {
			return nil, err
		}
	}
	return dcs, nil
}