From 9b71bdcbdd0fe8d9aac4e20ae662758e43c47989 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 23 Aug 2013 23:59:33 +0100 Subject: [PATCH] Added OPER and auth file parsing. --- main.go | 30 ++++++++++++++++++++++++++++++ rosella.go | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index 0ad4b61..733bd17 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,8 @@ import ( "crypto/tls" "flag" "log" + "os" + "strings" ) func main() { @@ -15,6 +17,8 @@ func main() { serverName := flag.String("irc-servername", "rosella", "Server name displayed to clients") + authFile := flag.String("irc-authfile", "", "File containing usernames and passwords of operators.\nPasswords hashed with SHA1, one username and password per line, space separated. Lines starting with a # are ignored.") + flag.Parse() log.Printf("Rosella Initialising.") @@ -22,6 +26,32 @@ func main() { //Init rosella itself server := NewServer() server.name = *serverName + + if *authFile != "" { + log.Printf("Loading auth file: %q", *authFile) + + f, err := os.Open(*authFile) + if err != nil { + log.Fatal(err) + } + data := make([]byte, 1024) + size, err := f.Read(data) + if err != nil { + log.Fatal(err) + } + + lines := strings.Split(string(data[:size]), "\n") + for _, line := range lines { + if strings.HasPrefix(line, "#") { + continue + } + fields := strings.Fields(line) + + if len(fields) == 2 { + server.operatorMap[fields[0]] = fields[1] + } + } + } server.Run() tlsConfig := new(tls.Config) diff --git a/rosella.go b/rosella.go index b8d4c3f..6c9931f 100644 --- a/rosella.go +++ b/rosella.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "crypto/sha1" "fmt" "io" "log" @@ -13,11 +14,12 @@ import ( ) type Server struct { - eventChan chan Event - running bool - name string - clientMap map[string]*Client //Map of nicks → clients - channelMap map[string]*Channel //Map of channel names → channels + eventChan chan Event + running bool + name string + clientMap map[string]*Client //Map of nicks → clients + channelMap map[string]*Channel //Map of channel names → channels + operatorMap map[string]string //Map of usernames → SHA1 hashed passwords } type Client struct { @@ -28,6 +30,7 @@ type Client struct { nick string registered bool connected bool + operator bool channelMap map[string]*Channel } @@ -57,6 +60,7 @@ const ( rplKill rplMsg rplList + rplOper errMoreArgs errNoNick errInvalidNick @@ -65,6 +69,7 @@ const ( errNoSuchNick errUnknownCommand errNotReg + errPassword ) var ( @@ -74,9 +79,10 @@ var ( func NewServer() *Server { return &Server{eventChan: make(chan Event), - name: "rosella", - clientMap: make(map[string]*Client), - channelMap: make(map[string]*Channel)} + name: "rosella", + clientMap: make(map[string]*Client), + channelMap: make(map[string]*Channel), + operatorMap: make(map[string]string)} } func (s *Server) Run() { @@ -300,6 +306,31 @@ func (s *Server) handleEvent(e Event) { e.client.reply(rplList, chanList...) } + case command == "OPER": + if e.client.registered == false { + e.client.reply(errNotReg) + return + } + + if len(args) < 2 { + e.client.reply(errMoreArgs) + return + } + + username := args[0] + password := args[1] + + if hashedPassword, exists := s.operatorMap[username]; exists { + h := sha1.New() + io.WriteString(h, password) + pass := fmt.Sprintf("%x", h.Sum(nil)) + if hashedPassword == pass { + e.client.operator = true + e.client.reply(rplOper) + return + } + } + e.client.reply(errPassword) default: e.client.reply(errUnknownCommand, command) @@ -477,8 +508,10 @@ func (c *Client) reply(code int, args ...string) { c.outputChan <- fmt.Sprintf(":%s 322 %s %s", c.server.name, c.nick, listItem) } c.outputChan <- fmt.Sprintf(":%s 323 %s", c.server.name, c.nick) + case rplOper: + c.outputChan <- fmt.Sprintf(":%s 381 %s :You are now an operator", c.server.name, c.nick) case errMoreArgs: - c.outputChan <- fmt.Sprintf(":%s 461 %s %s :Not enough params", c.server.name, c.nick, args[0]) + c.outputChan <- fmt.Sprintf(":%s 461 %s :Not enough params", c.server.name, c.nick) case errNoNick: c.outputChan <- fmt.Sprintf(":%s 431 %s :No nickname given", c.server.name, c.nick) case errInvalidNick: @@ -493,6 +526,8 @@ func (c *Client) reply(code int, args ...string) { c.outputChan <- fmt.Sprintf(":%s 421 %s %s :Unknown command", c.server.name, c.nick, args[0]) case errNotReg: c.outputChan <- fmt.Sprintf(":%s 451 :You have not registered", c.server.name) + case errPassword: + c.outputChan <- fmt.Sprintf(":%s 464 %s :Error, password incorrect", c.server.name, c.nick) } }