package main import ( "errors" "io/ioutil" "os/user" "path" "strings" "time" "gopkg.in/yaml.v2" ) const defKeySize = 2048 type Config struct { Gracetime time.Duration Listen string ListenTLS string BaseDir string KeySize int Provider map[string]string Account map[string]account Desire map[string]desire Hook map[string]string } type account struct { Mail string Phone string KeySize int Key string } type desire struct { Provider string Account string Altnames []string KeySize int Key string Cert string Webroot string Hook []string } var ( errNoProvider = errors.New("no provider specified") errNoAccount = errors.New("no account specified") errNoKey = errors.New("no key specified") errNoCert = errors.New("no cert specified") errNoAltNames = errors.New("no altnames specified") errNoMail = errors.New("no mail specified") ) func LoadConfig(fname string) (*Config, error) { conf, err := ioutil.ReadFile(fname) if err != nil { return nil, err } c := &Config{} err = yaml.Unmarshal(conf, c) if err != nil { return nil, err } if strings.HasPrefix(c.BaseDir, "~") { usr, err := user.Current() if err != nil { return nil, err } c.BaseDir = path.Join(usr.HomeDir, c.BaseDir[1:]) } // apply defaults if c.KeySize == 0 { c.KeySize = defKeySize } for k, v := range c.Account { if v.KeySize == 0 { v.KeySize = c.KeySize } if v.Mail == "" { return nil, errNoMail } if v.Key == "" { return nil, errNoKey } if c.BaseDir != "" { v.Key = path.Join(c.BaseDir, v.Key) } c.Account[k] = v } for k, v := range c.Desire { if v.Provider == "" { return nil, errNoProvider } if v.Account == "" { return nil, errNoAccount } if v.KeySize == 0 { v.KeySize = c.KeySize } if v.Key == "" { return nil, errNoKey } if v.Cert == "" { return nil, errNoCert } if c.BaseDir != "" { v.Key = path.Join(c.BaseDir, v.Key) v.Cert = path.Join(c.BaseDir, v.Cert) } v.Altnames = checkWWW(v.Altnames) c.Desire[k] = v } return c, nil } func checkWWW(altnames []string) []string { ch := make(chan string) go func(ch chan string, s []string) { for _, an := range s { if strings.HasPrefix(an, "www.") { ch <- an[4:] } } close(ch) }(ch, altnames) has := func(s string) bool { for _, an := range altnames { if an == s { return true } } return false } for d := range ch { if !has(d) { altnames = append(altnames, d) } } return altnames }