package main import ( "crypto/rsa" "errors" "path" "github.com/BurntSushi/toml" ) type Config struct { Defaults defaults Provider map[string]*provider Account map[string]*account Hook map[string]*hook Desire map[string]*desire } type defaults struct { Gracetime string Listen string Provider string Account string Basedir string KeySize int } type provider struct { Directory string } type account struct { Mail string Phone string Key string KeySize int key *rsa.PrivateKey } type hook struct { CMD string } type desire struct { Provider string Account string Altnames []string Key string KeySize int Cert string Webroot string Hooks []string key *rsa.PrivateKey `toml:"-"` account *account provider *provider } 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") ) func LoadConfig(fname string) (*Config, error) { c := &Config{} _, err := toml.DecodeFile(fname, c) if err != nil { return nil, err } // apply defaults if c.Defaults.KeySize == 0 { c.Defaults.KeySize = 2048 } for k, v := range c.Account { if v.KeySize == 0 { v.KeySize = c.Defaults.KeySize } if v.Key == "" { return nil, errNoKey } if c.Defaults.Basedir != "" { v.Key = path.Join(c.Defaults.Basedir, v.Key) } c.Account[k] = v } for k, v := range c.Desire { if v.Provider == "" { if c.Defaults.Provider != "" { v.Provider = c.Defaults.Provider } else { return nil, errNoProvider } } v.provider = c.Provider[v.Provider] if v.Account == "" { if c.Defaults.Account != "" { v.Account = c.Defaults.Account } else { return nil, errNoAccount } } v.account = c.Account[v.Account] if v.KeySize == 0 { v.KeySize = c.Defaults.KeySize } if v.Key == "" { return nil, errNoKey } if v.Cert == "" { return nil, errNoCert } if c.Defaults.Basedir != "" { v.Key = path.Join(c.Defaults.Basedir, v.Key) v.Cert = path.Join(c.Defaults.Basedir, v.Cert) } c.Desire[k] = v } return c, nil } type Keychain interface { Path() string Size() int } func (d desire) Path() string { return d.Key } func (d desire) Size() int { return d.KeySize } func (a account) Path() string { return a.Key } func (a account) Size() int { return a.KeySize }