You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

config.go 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "crypto/tls"
  8. "errors"
  9. "fmt"
  10. "io/ioutil"
  11. "log"
  12. "strings"
  13. "gopkg.in/yaml.v2"
  14. )
  15. type PassConfig struct {
  16. Password string
  17. }
  18. // TLSListenConfig defines configuration options for listening on TLS
  19. type TLSListenConfig struct {
  20. Cert string
  21. Key string
  22. }
  23. // Certificate returns the TLS certificate assicated with this TLSListenConfig
  24. func (conf *TLSListenConfig) Config() (*tls.Config, error) {
  25. cert, err := tls.LoadX509KeyPair(conf.Cert, conf.Key)
  26. if err != nil {
  27. return nil, errors.New("tls cert+key: invalid pair")
  28. }
  29. return &tls.Config{
  30. Certificates: []tls.Certificate{cert},
  31. }, err
  32. }
  33. func (conf *PassConfig) PasswordBytes() []byte {
  34. bytes, err := DecodePasswordHash(conf.Password)
  35. if err != nil {
  36. log.Fatal("decode password error: ", err)
  37. }
  38. return bytes
  39. }
  40. type AccountRegistrationConfig struct {
  41. Enabled bool
  42. EnabledCallbacks []string `yaml:"enabled-callbacks"`
  43. Callbacks struct {
  44. Mailto struct {
  45. Server string
  46. Port int
  47. TLS struct {
  48. Enabled bool
  49. InsecureSkipVerify bool `yaml:"insecure_skip_verify"`
  50. ServerName string `yaml:"servername"`
  51. }
  52. Username string
  53. Password string
  54. Sender string
  55. VerifyMessageSubject string `yaml:"verify-message-subject"`
  56. VerifyMessage string `yaml:"verify-message"`
  57. }
  58. }
  59. }
  60. type OperClassConfig struct {
  61. Title string
  62. WhoisLine string
  63. Extends string
  64. Capabilities []string
  65. }
  66. type OperConfig struct {
  67. Class string
  68. Vhost string
  69. WhoisLine string `yaml:"whois-line"`
  70. Password string
  71. }
  72. func (conf *OperConfig) PasswordBytes() []byte {
  73. bytes, err := DecodePasswordHash(conf.Password)
  74. if err != nil {
  75. log.Fatal("decode password error: ", err)
  76. }
  77. return bytes
  78. }
  79. type ConnectionLimitsConfig struct {
  80. CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
  81. CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
  82. IPsPerCidr int `yaml:"ips-per-subnet"`
  83. Exempted []string
  84. }
  85. type Config struct {
  86. Network struct {
  87. Name string
  88. }
  89. Server struct {
  90. PassConfig
  91. Password string
  92. Name string
  93. Listen []string
  94. Wslisten string `yaml:"ws-listen"`
  95. TLSListeners map[string]*TLSListenConfig `yaml:"tls-listeners"`
  96. CheckIdent bool `yaml:"check-ident"`
  97. Log string
  98. MOTD string
  99. ConnectionLimits ConnectionLimitsConfig `yaml:"connection-limits"`
  100. }
  101. Datastore struct {
  102. Path string
  103. }
  104. AuthenticationEnabled bool `yaml:"authentication-enabled"`
  105. Registration struct {
  106. Accounts AccountRegistrationConfig
  107. }
  108. OperClasses map[string]*OperClassConfig `yaml:"oper-classes"`
  109. Opers map[string]*OperConfig
  110. Limits struct {
  111. NickLen uint `yaml:"nicklen"`
  112. ChannelLen uint `yaml:"channellen"`
  113. AwayLen uint `yaml:"awaylen"`
  114. KickLen uint `yaml:"kicklen"`
  115. TopicLen uint `yaml:"topiclen"`
  116. WhowasEntries uint `yaml:"whowas-entries"`
  117. MonitorEntries uint `yaml:"monitor-entries"`
  118. ChanListModes uint `yaml:"chan-list-modes"`
  119. }
  120. }
  121. type OperClass struct {
  122. Title string
  123. WhoisLine string `yaml:"whois-line"`
  124. Capabilities map[string]bool // map to make lookups much easier
  125. }
  126. func (conf *Config) OperatorClasses() (*map[string]OperClass, error) {
  127. ocs := make(map[string]OperClass)
  128. // loop from no extends to most extended, breaking if we can't add any more
  129. lenOfLastOcs := -1
  130. for {
  131. if lenOfLastOcs == len(ocs) {
  132. return nil, errors.New("OperClasses contains a looping dependency, or a class extends from a class that doesn't exist")
  133. }
  134. lenOfLastOcs = len(ocs)
  135. var anyMissing bool
  136. for name, info := range conf.OperClasses {
  137. _, exists := ocs[name]
  138. _, extendsExists := ocs[info.Extends]
  139. if exists {
  140. // class already exists
  141. continue
  142. } else if len(info.Extends) > 0 && !extendsExists {
  143. // class we extend on doesn't exist
  144. _, exists := conf.OperClasses[info.Extends]
  145. if !exists {
  146. return nil, fmt.Errorf("Operclass [%s] extends [%s], which doesn't exist", name, info.Extends)
  147. }
  148. anyMissing = true
  149. continue
  150. }
  151. // create new operclass
  152. var oc OperClass
  153. oc.Capabilities = make(map[string]bool)
  154. // get inhereted info from other operclasses
  155. if len(info.Extends) > 0 {
  156. einfo, _ := ocs[info.Extends]
  157. for capab := range einfo.Capabilities {
  158. oc.Capabilities[capab] = true
  159. }
  160. }
  161. // add our own info
  162. oc.Title = info.Title
  163. for _, capab := range info.Capabilities {
  164. oc.Capabilities[capab] = true
  165. }
  166. if len(info.WhoisLine) > 0 {
  167. oc.WhoisLine = info.WhoisLine
  168. } else {
  169. oc.WhoisLine = "is a"
  170. if strings.Contains(strings.ToLower(string(oc.Title[0])), "aeiou") {
  171. oc.WhoisLine += "n"
  172. }
  173. oc.WhoisLine += " "
  174. oc.WhoisLine += oc.Title
  175. }
  176. ocs[name] = oc
  177. }
  178. if !anyMissing {
  179. // we've got every operclass!
  180. break
  181. }
  182. }
  183. return &ocs, nil
  184. }
  185. type Oper struct {
  186. Class *OperClass
  187. WhoisLine string
  188. Vhost string
  189. Pass []byte
  190. }
  191. func (conf *Config) Operators(oc *map[string]OperClass) (map[string]Oper, error) {
  192. operators := make(map[string]Oper)
  193. for name, opConf := range conf.Opers {
  194. var oper Oper
  195. // oper name
  196. name, err := CasefoldName(name)
  197. if err != nil {
  198. return nil, fmt.Errorf("Could not casefold oper name: %s", err.Error())
  199. }
  200. oper.Pass = opConf.PasswordBytes()
  201. oper.Vhost = opConf.Vhost
  202. class, exists := (*oc)[opConf.Class]
  203. if !exists {
  204. return nil, fmt.Errorf("Could not load operator [%s] - they use operclass [%s] which does not exist", name, opConf.Class)
  205. }
  206. oper.Class = &class
  207. if len(opConf.WhoisLine) > 0 {
  208. oper.WhoisLine = opConf.WhoisLine
  209. } else {
  210. oper.WhoisLine = class.WhoisLine
  211. }
  212. // successful, attach to list of opers
  213. operators[name] = oper
  214. }
  215. return operators, nil
  216. }
  217. func (conf *Config) TLSListeners() map[string]*tls.Config {
  218. tlsListeners := make(map[string]*tls.Config)
  219. for s, tlsListenersConf := range conf.Server.TLSListeners {
  220. config, err := tlsListenersConf.Config()
  221. if err != nil {
  222. log.Fatal(err)
  223. }
  224. name, err := CasefoldName(s)
  225. if err == nil {
  226. tlsListeners[name] = config
  227. } else {
  228. log.Println("Could not casefold TLS listener:", err.Error())
  229. }
  230. }
  231. return tlsListeners
  232. }
  233. func LoadConfig(filename string) (config *Config, err error) {
  234. data, err := ioutil.ReadFile(filename)
  235. if err != nil {
  236. return nil, err
  237. }
  238. err = yaml.Unmarshal(data, &config)
  239. if err != nil {
  240. return nil, err
  241. }
  242. // we need this so PasswordBytes returns the correct info
  243. if config.Server.Password != "" {
  244. config.Server.PassConfig.Password = config.Server.Password
  245. }
  246. if config.Network.Name == "" {
  247. return nil, errors.New("Network name missing")
  248. }
  249. if config.Server.Name == "" {
  250. return nil, errors.New("Server name missing")
  251. }
  252. if !IsHostname(config.Server.Name) {
  253. return nil, errors.New("Server name must match the format of a hostname")
  254. }
  255. if config.Datastore.Path == "" {
  256. return nil, errors.New("Datastore path missing")
  257. }
  258. if len(config.Server.Listen) == 0 {
  259. return nil, errors.New("Server listening addresses missing")
  260. }
  261. if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.KickLen < 1 || config.Limits.TopicLen < 1 {
  262. return nil, errors.New("Limits aren't setup properly, check them and make them sane")
  263. }
  264. return config, nil
  265. }