gotel

simple terminal chat program
git clone git://git.mdnr.space/gotel
Log | Files | Refs | README | LICENSE

commit 3f6dad0a1b619add3b9c9dbb01aba538135b9d04
parent c1af6554271669412463ed574cc8ddabc17b3b33
Author: mdnrz <mehdeenoroozi@gmail.com>
Date:   Mon, 21 Apr 2025 13:45:39 +0330

add bcrypt to hash passwords

Diffstat:
Mclient.go | 7+++----
Mgo.mod | 1+
Mserver.go | 81+++++++++++++++++++++----------------------------------------------------------
3 files changed, 25 insertions(+), 64 deletions(-)

diff --git a/client.go b/client.go @@ -2,11 +2,10 @@ package main import ( "fmt" + "github.com/jroimartin/gocui" "log" "net" "strings" - - "github.com/jroimartin/gocui" ) type Command struct { @@ -205,7 +204,7 @@ func sendSignup(v *gocui.View, input []string) error { _, err := serverConn.Write([]byte(input[0] + " " + input[1] + " " + input[2])) if err != nil { - fmt.Fprintf(v, "Could not send signup request to the server: %s\n", err) + fmt.Fprintf(v, "Could not send signup request to the server: %s\nTry join command first.", err) } return nil } @@ -220,7 +219,7 @@ func sendLogin(v *gocui.View, input []string) error { _, err := serverConn.Write([]byte(input[0] + " " + input[1] + " " + input[2])) if err != nil { - fmt.Fprintf(v, "Could not send login request to the server: %s\n", err) + fmt.Fprintf(v, "Could not send login request to the server: %s\nTry /join command first.", err) } return nil } diff --git a/go.mod b/go.mod @@ -7,4 +7,5 @@ require ( github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect github.com/nsf/termbox-go v1.1.1 // indirect + golang.org/x/crypto v0.37.0 // indirect ) diff --git a/server.go b/server.go @@ -2,15 +2,16 @@ package main import ( "crypto/rand" + "database/sql" "fmt" + _ "github.com/mattn/go-sqlite3" + "golang.org/x/crypto/bcrypt" "log" "math/big" "net" "os" "strings" "time" - "database/sql" - _"github.com/mattn/go-sqlite3" ) type msgType int @@ -44,7 +45,6 @@ const ( type Client struct { Stage loginStage UserName string - Password string LastMsgTime time.Time Strike int Banned bool @@ -68,7 +68,7 @@ func initReqMap() { func clientRoutine(conn net.Conn, Msg_q chan Msg) { Msg_q <- Msg{ - Type: msgConnect, + Type: msgConnect, Author: Client{ Conn: conn, Stage: verification, @@ -174,45 +174,7 @@ func trimNewline(input rune) bool { return false } -func login(client *Client, msg string) bool { - if client.Stage == verification { - if !verifyToken(strings.TrimRightFunc(msg, trimNewline)) { - _, err := client.Conn.Write([]byte("Invalid token.\n")) - if err != nil { - log.Printf("Could not send invalid token message to client %s\n", client.Conn.RemoteAddr().String()) - } - client.LastMsgTime = time.Now() - return false - } - _, err := client.Conn.Write([]byte("Token verified successfully!\nEnter your user name")) - if err != nil { - log.Printf("Could not send verification message to %s\n", client.Conn.RemoteAddr().String()) - } - client.Stage = username - client.LastMsgTime = time.Now() - return false - } - if client.Stage == username { - client.UserName = strings.TrimRight(msg, "\r\n") - client.LastMsgTime = time.Now() - _, err := client.Conn.Write([]byte("Enter your password:\n")) - if err != nil { - log.Printf("Could not send passowrd message to %s\n", client.Conn.RemoteAddr().String()) - } - client.Stage = password - return false - } - client.Password = strings.TrimRight(msg, "\r\n") - client.LastMsgTime = time.Now() - _, err := client.Conn.Write([]byte("Welcome " + client.UserName + "\n")) - if err != nil { - log.Printf("Could not send welcome message to %s\n", client.Conn.RemoteAddr().String()) - } - client.LastMsgTime = time.Now() - return true -} - -func isUserInDB (username string) (bool, error) { +func isUserInDB(username string) (bool, error) { var count int check := "SELECT COUNT(*) FROM users WHERE username = ?" err := userDB.QueryRow(check, username).Scan(&count) @@ -222,20 +184,21 @@ func isUserInDB (username string) (bool, error) { return count > 0, nil } -func addUserToDB (client Client) error { +func addUserToDB(client Client, rawPass string) error { insert := "INSERT INTO users (username, password, banned, banEnd) VALUES ($1, $2, $3, $4)" - _, err := userDB.Exec(insert, client.UserName, client.Password, client.Banned, client.BanEnd) + passHashed, err := bcrypt.GenerateFromPassword([]byte(rawPass), bcrypt.DefaultCost) + if err != nil { + return err + } + _, err = userDB.Exec(insert, client.UserName, passHashed, client.Banned, client.BanEnd) return err } -func checkPassword(username string, inputPass string) (bool, error) { - var dbPass string +func getPassHash(username string) (string, error) { + var passHash string query := "SELECT password FROM users WHERE username = ?" - err := userDB.QueryRow(query, username).Scan(&dbPass) - if err != nil { - return false, nil - } - return dbPass == inputPass, nil + err := userDB.QueryRow(query, username).Scan(&passHash) + return passHash, err } func server(Msg_q chan Msg) { @@ -271,7 +234,7 @@ func server(Msg_q chan Msg) { delete(offlineList, keyString) msg.Author.Conn.Write([]byte("Authentication successfull.")) break - } + } msg.Author.Conn.Write([]byte("Provided token is not valid.")) break } @@ -291,7 +254,7 @@ func server(Msg_q chan Msg) { break } if joined { - yes, err := isUserInDB(msg.Args[0]) + yes, err := isUserInDB(msg.Args[0]) if err != nil { msg.Author.Conn.Write([]byte("Database error: " + err.Error())) break @@ -301,9 +264,8 @@ func server(Msg_q chan Msg) { break } msg.Author.UserName = msg.Args[0] - msg.Author.Password = msg.Args[1] msg.Author.LastMsgTime = time.Now() - if err := addUserToDB(msg.Author); err != nil { + if err := addUserToDB(msg.Author, msg.Args[1]); err != nil { msg.Author.Conn.Write([]byte("Could not signup user. Database error: " + err.Error())) break } @@ -329,7 +291,7 @@ func server(Msg_q chan Msg) { break } if joined { - yes, err := isUserInDB(msg.Args[0]) + yes, err := isUserInDB(msg.Args[0]) if err != nil { msg.Author.Conn.Write([]byte("Database error: " + err.Error())) break @@ -338,18 +300,17 @@ func server(Msg_q chan Msg) { msg.Author.Conn.Write([]byte("Username does not exist. You can create new user using /signup command.")) break } - passOK, err := checkPassword(msg.Args[0], msg.Args[1]) + passHash, err := getPassHash(msg.Args[0]) if err != nil { msg.Author.Conn.Write([]byte("Database error: " + err.Error())) break } - if !passOK { + if err = bcrypt.CompareHashAndPassword([]byte(passHash), []byte(msg.Args[1])); err != nil { // TODO: limited retry msg.Author.Conn.Write([]byte("Incorrect password.")) break } msg.Author.UserName = msg.Args[0] - msg.Author.Password = msg.Args[1] msg.Author.LastMsgTime = time.Now() onlineList[keyString] = msg.Author delete(joinedList, keyString)