From 83d021fcb7b4f6d7daf8459383b97607016d1a84 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Sat, 1 Mar 2014 14:34:51 -0800 Subject: [PATCH] switch to gcfg for conf file - add some validation for config file - add comments explaining config - remove TLS listener since most clients can't use it anyway - remove unused nick generation function --- config.json | 39 ------------------ ergonomadic.conf | 16 ++++++++ ergonomadic.go | 12 +++--- irc/config.go | 100 +++++++++++++++++++++-------------------------- irc/server.go | 56 +++++--------------------- 5 files changed, 76 insertions(+), 147 deletions(-) delete mode 100644 config.json create mode 100644 ergonomadic.conf diff --git a/config.json b/config.json deleted file mode 100644 index b607611a..00000000 --- a/config.json +++ /dev/null @@ -1,39 +0,0 @@ -// Ergonomadic IRC Server Config -// ----------------------------- -// Passwords are generated by `ergonomadic -genpasswd "$plaintext"`. -// Comments are not allowed in the actual config file. -{ - // `name` is usually a hostname. - "name": "irc.example.com", - - // The path to the MOTD is relative to this file's directory. - "motd": "motd.txt", - - // PASS command password - "password": "JDJhJDA0JHBBenUyV3Z5UU5iWUpiYmlNMlNLZC5VRDZDM21HUzFVbmxLUUI3NTVTLkZJOERLdUFaUWNt", - - // `listeners` are places to bind and listen for - // connections. http://golang.org/pkg/net/#Dial demonstrates valid - // values for `net` and `address`. `net` is optional and defaults - // to `tcp`. - "listeners": [ { - "address": "localhost:7777" - }, { - "net": "tcp6", - "address": "[::1]:7777" - } ], - - // Operators for the OPER command - "operators": [ { - "name": "root", - "password": "JDJhJDA0JHBBenUyV3Z5UU5iWUpiYmlNMlNLZC5VRDZDM21HUzFVbmxLUUI3NTVTLkZJOERLdUFaUWNt" - } ], - - // Global debug flags. `net` generates a lot of output. - "debug": { - "net": true, - "client": false, - "channel": false, - "server": false - } -} diff --git a/ergonomadic.conf b/ergonomadic.conf new file mode 100644 index 00000000..6181e9a7 --- /dev/null +++ b/ergonomadic.conf @@ -0,0 +1,16 @@ +[server] +name = "irc.example.com" ; required, usually a hostname +database = "ergonomadic.db" ; path relative to this file +listen = "localhost:6667" ; see `net.Listen` for examples +listen = "[::1]:6667" ; multiple `listen`s are allowed. +motd = "motd.txt" ; path relative to this file +password = "JDJhJDA0JHJzVFFlNXdOUXNhLmtkSGRUQVVEVHVYWXRKUmdNQ3FKVTRrczRSMTlSWGRPZHRSMVRzQmtt" + +[operator "root"] +password = "JDJhJDA0JEhkcm10UlNFRkRXb25iOHZuSDVLZXVBWlpyY0xyNkQ4dlBVc1VMWVk1LlFjWFpQbGxZNUtl" + +[debug] +net = true +client = false +channel = false +server = false diff --git a/ergonomadic.go b/ergonomadic.go index e04f9e8a..6537ff0b 100644 --- a/ergonomadic.go +++ b/ergonomadic.go @@ -22,9 +22,9 @@ func genPasswd(passwd string) { } func initDB(config *irc.Config) { - os.Remove(config.Database()) + os.Remove(config.Server.Database) - db, err := sql.Open("sqlite3", config.Database()) + db, err := sql.Open("sqlite3", config.Server.Database) if err != nil { log.Fatal(err) } @@ -64,10 +64,10 @@ func main() { } // TODO move to data structures - irc.DEBUG_NET = config.Debug["net"] - irc.DEBUG_CLIENT = config.Debug["client"] - irc.DEBUG_CHANNEL = config.Debug["channel"] - irc.DEBUG_SERVER = config.Debug["server"] + irc.DEBUG_NET = config.Debug.Net + irc.DEBUG_CLIENT = config.Debug.Client + irc.DEBUG_CHANNEL = config.Debug.Channel + irc.DEBUG_SERVER = config.Debug.Server irc.NewServer(config).Run() } diff --git a/irc/config.go b/irc/config.go index 07518f00..8fea2974 100644 --- a/irc/config.go +++ b/irc/config.go @@ -1,18 +1,22 @@ package irc import ( + "code.google.com/p/gcfg" "encoding/base64" - "encoding/json" + "errors" "log" - "os" "path/filepath" ) -func decodePassword(password string) []byte { - if password == "" { +type PassConfig struct { + Password string +} + +func (conf *PassConfig) PasswordBytes() []byte { + if conf.Password == "" { return nil } - bytes, err := base64.StdEncoding.DecodeString(password) + bytes, err := base64.StdEncoding.DecodeString(conf.Password) if err != nil { log.Fatal(err) } @@ -20,72 +24,56 @@ func decodePassword(password string) []byte { } type Config struct { - Debug map[string]bool - Listeners []ListenerConfig - MOTD string - Name string - Operators []OperatorConfig - Password string - directory string + Server struct { + PassConfig + Database string + Listen []string + MOTD string + Name string + } + + Operator map[string]*PassConfig + + Debug struct { + Net bool + Client bool + Channel bool + Server bool + } } -func (conf *Config) Database() string { - return filepath.Join(conf.directory, "ergonomadic.db") -} - -func (conf *Config) PasswordBytes() []byte { - return decodePassword(conf.Password) -} - -func (conf *Config) OperatorsMap() map[string][]byte { +func (conf *Config) Operators() map[string][]byte { operators := make(map[string][]byte) - for _, opConf := range conf.Operators { - operators[opConf.Name] = opConf.PasswordBytes() + for name, opConf := range conf.Operator { + operators[name] = opConf.PasswordBytes() } return operators } -type OperatorConfig struct { - Name string - Password string -} - -func (conf *OperatorConfig) PasswordBytes() []byte { - return decodePassword(conf.Password) -} - -type ListenerConfig struct { - Net string - Address string - Key string - Certificate string -} - -func (config *ListenerConfig) IsTLS() bool { - return (config.Key != "") && (config.Certificate != "") -} - func LoadConfig(filename string) (config *Config, err error) { config = &Config{} - - file, err := os.Open(filename) + err = gcfg.ReadFileInto(config, filename) if err != nil { return } - defer file.Close() - - decoder := json.NewDecoder(file) - err = decoder.Decode(config) - if err != nil { + if config.Server.Name == "" { + err = errors.New("server.name missing") + return + } + if config.Server.Database == "" { + err = errors.New("server.database missing") + return + } + if len(config.Server.Listen) == 0 { + err = errors.New("server.listen missing") return } - config.directory = filepath.Dir(filename) - config.MOTD = filepath.Join(config.directory, config.MOTD) - for _, lconf := range config.Listeners { - if lconf.Net == "" { - lconf.Net = "tcp" - } + // make + dir := filepath.Dir(filename) + if config.Server.MOTD != "" { + config.Server.MOTD = filepath.Join(dir, config.Server.MOTD) } + config.Server.Database = filepath.Join(dir, config.Server.Database) return } diff --git a/irc/server.go b/irc/server.go index 49c5f4ad..8c9d9ebe 100644 --- a/irc/server.go +++ b/irc/server.go @@ -2,10 +2,7 @@ package irc import ( "bufio" - "crypto/rand" - "crypto/tls" "database/sql" - "encoding/binary" "fmt" _ "github.com/mattn/go-sqlite3" "log" @@ -36,7 +33,7 @@ type Server struct { } func NewServer(config *Config) *Server { - db, err := sql.Open("sqlite3", config.Database()) + db, err := sql.Open("sqlite3", config.Server.Database) if err != nil { log.Fatal(err) } @@ -48,11 +45,11 @@ func NewServer(config *Config) *Server { ctime: time.Now(), db: db, idle: make(chan *Client, 16), - motdFile: config.MOTD, - name: config.Name, + motdFile: config.Server.MOTD, + name: config.Server.Name, newConns: make(chan net.Conn, 16), - operators: config.OperatorsMap(), - password: config.PasswordBytes(), + operators: config.Operators(), + password: config.Server.PasswordBytes(), signals: make(chan os.Signal, 1), timeout: make(chan *Client, 16), } @@ -61,8 +58,8 @@ func NewServer(config *Config) *Server { server.loadChannels() - for _, listenerConf := range config.Listeners { - go server.listen(listenerConf) + for _, addr := range config.Server.Listen { + go server.listen(addr) } return server @@ -169,33 +166,18 @@ func (server *Server) InitPhase() Phase { return Authorization } -func newListener(config ListenerConfig) (net.Listener, error) { - if config.IsTLS() { - certificate, err := tls.LoadX509KeyPair(config.Certificate, config.Key) - if err != nil { - return nil, err - } - return tls.Listen("tcp", config.Address, &tls.Config{ - Certificates: []tls.Certificate{certificate}, - PreferServerCipherSuites: true, - }) - } - - return net.Listen("tcp", config.Address) -} - // // listen goroutine // -func (s *Server) listen(config ListenerConfig) { - listener, err := newListener(config) +func (s *Server) listen(addr string) { + listener, err := net.Listen("tcp", addr) if err != nil { log.Fatal(s, "listen error: ", err) } if DEBUG_SERVER { - log.Printf("%s listening on %s", s, config.Address) + log.Printf("%s listening on %s", s, addr) } for { @@ -214,24 +196,6 @@ func (s *Server) listen(config ListenerConfig) { } } -func (s *Server) GenerateGuestNick() string { - bytes := make([]byte, 8) - for { - _, err := rand.Read(bytes) - if err != nil { - panic(err) - } - randInt, n := binary.Uvarint(bytes) - if n <= 0 { - continue // TODO handle error - } - nick := fmt.Sprintf("guest%d", randInt) - if s.clients.Get(nick) == nil { - return nick - } - } -} - // // server functionality //