diff --git a/ergonomadic.go b/ergonomadic.go index 41fe26b3..525e38ac 100644 --- a/ergonomadic.go +++ b/ergonomadic.go @@ -1,48 +1,14 @@ package main import ( - "code.google.com/p/go.crypto/bcrypt" - "database/sql" - "encoding/base64" "flag" "fmt" "github.com/jlatt/ergonomadic/irc" - _ "github.com/mattn/go-sqlite3" "log" "os" "path/filepath" ) -func genPasswd(passwd string) { - crypted, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.MinCost) - if err != nil { - log.Fatal(err) - } - encoded := base64.StdEncoding.EncodeToString(crypted) - fmt.Println(encoded) -} - -func initDB(config *irc.Config) { - os.Remove(config.Server.Database) - - db, err := sql.Open("sqlite3", config.Server.Database) - if err != nil { - log.Fatal(err) - } - defer db.Close() - - _, err = db.Exec(` - CREATE TABLE channel ( - name TEXT NOT NULL UNIQUE, - flags TEXT NOT NULL, - key TEXT NOT NULL, - topic TEXT NOT NULL, - user_limit INTEGER DEFAULT 0)`) - if err != nil { - log.Fatal(err) - } -} - func main() { conf := flag.String("conf", "ergonomadic.json", "ergonomadic config file") initdb := flag.Bool("initdb", false, "initialize database") @@ -50,7 +16,11 @@ func main() { flag.Parse() if *passwd != "" { - genPasswd(*passwd) + encoded, err := irc.GenerateEncodedPassword(*passwd) + if err != nil { + log.Fatal(err) + } + fmt.Println(encoded) return } @@ -64,7 +34,8 @@ func main() { } if *initdb { - initDB(config) + irc.InitDB(config.Server.Database) + log.Println("database initialized: " + config.Server.Database) return } diff --git a/irc/commands.go b/irc/commands.go index 8229d217..7f7a14bb 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -1,7 +1,6 @@ package irc import ( - "code.google.com/p/go.crypto/bcrypt" "code.google.com/p/go.text/unicode/norm" "errors" "fmt" @@ -214,7 +213,7 @@ func (cmd *PassCommand) CheckPassword() { if cmd.hash == nil { return } - cmd.err = bcrypt.CompareHashAndPassword(cmd.hash, cmd.password) + cmd.err = ComparePassword(cmd.hash, cmd.password) } func NewPassCommand(args []string) (editableCommand, error) { diff --git a/irc/config.go b/irc/config.go index ba065722..34181acd 100644 --- a/irc/config.go +++ b/irc/config.go @@ -2,7 +2,6 @@ package irc import ( "code.google.com/p/gcfg" - "encoding/base64" "errors" "log" ) @@ -12,10 +11,7 @@ type PassConfig struct { } func (conf *PassConfig) PasswordBytes() []byte { - if conf.Password == "" { - return nil - } - bytes, err := base64.StdEncoding.DecodeString(conf.Password) + bytes, err := DecodePassword(conf.Password) if err != nil { log.Fatal(err) } diff --git a/irc/constants.go b/irc/constants.go index 83e73efb..f68c0c9e 100644 --- a/irc/constants.go +++ b/irc/constants.go @@ -19,11 +19,11 @@ var ( // regexps ChannelNameExpr = regexp.MustCompile(`^[&!#+][\pL\pN]{1,63}$`) NicknameExpr = regexp.MustCompile( - "^[\\pL\\[\\]{}^`][\\pL\\pN\\[\\]{}^`]{1,31}$") + "^[\\pL\\[\\]{}^`_][\\pL\\pN\\[\\]{}^`_]{1,31}$") ) const ( - SEM_VER = "ergonomadic-1.2.11" + SEM_VER = "ergonomadic-1.2.12" CRLF = "\r\n" MAX_REPLY_LEN = 512 - len(CRLF) diff --git a/irc/database.go b/irc/database.go new file mode 100644 index 00000000..1ff3bd67 --- /dev/null +++ b/irc/database.go @@ -0,0 +1,32 @@ +package irc + +import ( + "database/sql" + _ "github.com/mattn/go-sqlite3" + "log" + "os" +) + +func InitDB(path string) { + os.Remove(path) + db := OpenDB(path) + defer db.Close() + _, err := db.Exec(` + CREATE TABLE channel ( + name TEXT NOT NULL UNIQUE, + flags TEXT NOT NULL, + key TEXT NOT NULL, + topic TEXT NOT NULL, + user_limit INTEGER DEFAULT 0)`) + if err != nil { + log.Fatal(err) + } +} + +func OpenDB(path string) *sql.DB { + db, err := sql.Open("sqlite3", path) + if err != nil { + log.Fatal(err) + } + return db +} diff --git a/irc/password.go b/irc/password.go new file mode 100644 index 00000000..1426c402 --- /dev/null +++ b/irc/password.go @@ -0,0 +1,37 @@ +package irc + +import ( + "code.google.com/p/go.crypto/bcrypt" + "encoding/base64" + "errors" +) + +var ( + EmptyPasswordError = errors.New("empty password") +) + +func GenerateEncodedPassword(passwd string) (encoded string, err error) { + if passwd == "" { + err = EmptyPasswordError + return + } + bcrypted, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.MinCost) + if err != nil { + return + } + encoded = base64.StdEncoding.EncodeToString(bcrypted) + return +} + +func DecodePassword(encoded string) (decoded []byte, err error) { + if encoded == "" { + err = EmptyPasswordError + return + } + decoded, err = base64.StdEncoding.DecodeString(encoded) + return +} + +func ComparePassword(hash, password []byte) error { + return bcrypt.CompareHashAndPassword(hash, password) +} diff --git a/irc/server.go b/irc/server.go index 8c9d9ebe..898e56aa 100644 --- a/irc/server.go +++ b/irc/server.go @@ -4,7 +4,6 @@ import ( "bufio" "database/sql" "fmt" - _ "github.com/mattn/go-sqlite3" "log" "net" "os" @@ -13,6 +12,7 @@ import ( "runtime/debug" "runtime/pprof" "strings" + "syscall" "time" ) @@ -33,17 +33,12 @@ type Server struct { } func NewServer(config *Config) *Server { - db, err := sql.Open("sqlite3", config.Server.Database) - if err != nil { - log.Fatal(err) - } - server := &Server{ channels: make(ChannelNameMap), clients: make(ClientNameMap), commands: make(chan Command, 16), ctime: time.Now(), - db: db, + db: OpenDB(config.Server.Database), idle: make(chan *Client, 16), motdFile: config.Server.MOTD, name: config.Server.Name, @@ -54,7 +49,7 @@ func NewServer(config *Config) *Server { timeout: make(chan *Client, 16), } - signal.Notify(server.signals, os.Interrupt, os.Kill) + signal.Notify(server.signals, syscall.SIGINT, syscall.SIGHUP) server.loadChannels() @@ -135,14 +130,20 @@ func (server *Server) processCommand(cmd Command) { } } +func (server *Server) Shutdown() { + server.db.Close() + for _, client := range server.clients { + client.Reply(RplNotice(server, client, "shutting down")) + } +} + func (server *Server) Run() { done := false for !done { select { case <-server.signals: - server.db.Close() + server.Shutdown() done = true - continue case conn := <-server.newConns: NewClient(server, conn)