All checks were successful
continuous-integration/drone/push Build is passing
Iterating over a slice returns a copy of the respective member instead of a reference to the original slice member. Thus, any modification are discarded and the pointers saved inside cfg.users and cfg.rrconfigs are incorrect, too.
117 lines
3 KiB
Go
117 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/pelletier/go-toml"
|
|
"os"
|
|
)
|
|
|
|
type Config struct {
|
|
ServerPort uint16 `toml:"port"`
|
|
Users []User `toml:"user"`
|
|
RRConfigs []RRConfig `toml:"rrconfig"`
|
|
|
|
users map[string]*User
|
|
rrconfigs map[string]*RRConfig
|
|
}
|
|
|
|
type User struct {
|
|
Username string `toml:"username"`
|
|
Password string `toml:"password"`
|
|
Records []string `toml:"records"`
|
|
|
|
records map[string]bool
|
|
}
|
|
|
|
type RRConfig struct {
|
|
Recordname string `toml:"recordname"`
|
|
Zonename string `toml:"zonename"`
|
|
Nameserver string `toml:"nameserver"`
|
|
Tsigalgo string `toml:"tsig_algo"`
|
|
Tsigid string `toml:"tsig_id"`
|
|
Tsigkey string `toml:"tsig_key"`
|
|
Ttl int `toml:"ttl" default:"60"`
|
|
}
|
|
|
|
func LoadConfig(path string) (*Config, error) {
|
|
var cfg Config
|
|
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
decoder := toml.NewDecoder(f).Strict(true)
|
|
err = decoder.Decode(&cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return prepareConfig(&cfg)
|
|
}
|
|
|
|
func prepareConfig(cfg *Config) (*Config, error) {
|
|
if len(cfg.Users) <= 0 || len(cfg.RRConfigs) <= 0 {
|
|
return nil, fmt.Errorf("No users or resource record configs present.")
|
|
}
|
|
|
|
// temporary map for detecting duplicated or orphaned entries between
|
|
// records and users
|
|
globRecords := map[string]bool{}
|
|
|
|
// populate user map
|
|
cfg.users = map[string]*User{}
|
|
for u := range cfg.Users {
|
|
user := &cfg.Users[u]
|
|
if _, ok := cfg.users[user.Username]; ok {
|
|
return nil, fmt.Errorf("Duplicate username detected: %s", user.Username)
|
|
}
|
|
|
|
// initialize and populate user.records map
|
|
user.records = make(map[string]bool)
|
|
if len(user.Records) <= 0 {
|
|
return nil, fmt.Errorf("User without records detected: %s", user.Username)
|
|
}
|
|
for _, record := range user.Records {
|
|
// check for duplicate records
|
|
if globRecords[record] {
|
|
return nil, fmt.Errorf("Record associated with multiple users detected: %s", record)
|
|
}
|
|
// memorize record both in the user as well as in the temporary map
|
|
user.records[record] = true
|
|
globRecords[record] = true
|
|
}
|
|
cfg.users[user.Username] = user
|
|
}
|
|
|
|
// populate record map
|
|
cfg.rrconfigs = map[string]*RRConfig{}
|
|
for r := range cfg.RRConfigs {
|
|
record := &cfg.RRConfigs[r]
|
|
|
|
// check for duplicate record before verifying association to users
|
|
if _, ok := cfg.rrconfigs[record.Recordname]; ok {
|
|
return nil, fmt.Errorf("Duplicate record detected: %s", record.Recordname)
|
|
}
|
|
|
|
if !globRecords[record.Recordname] {
|
|
return nil, fmt.Errorf("Record without associated user detected: %s", record.Recordname)
|
|
}
|
|
// need to remove record from globRecords for detecting orphaned records
|
|
delete(globRecords, record.Recordname)
|
|
|
|
cfg.rrconfigs[record.Recordname] = record
|
|
}
|
|
|
|
// check whether all records have been processed
|
|
if len(globRecords) > 0 {
|
|
missing := make([]string, len(globRecords))
|
|
i := 0
|
|
for k := range globRecords {
|
|
missing[i] = k
|
|
i++
|
|
}
|
|
return nil, fmt.Errorf("Records associated to user missing: %v", missing)
|
|
}
|
|
return cfg, nil
|
|
}
|