From 7b95d6b80dd2d1efb26f7c515383abd4f0dc9d42 Mon Sep 17 00:00:00 2001 From: Andinus Date: Sat, 28 Mar 2020 19:25:53 +0530 Subject: Prepare for rewrite on several functions User struct now exports everything, encapsulation is not necessary over here. Instead of introducing a new variable uInfo we'll use user.User and pass that. Handlers & related functions will be rewritten to work with this change. This will make it easier to work on later as the program grows. I'm also rethinking error handling. --- auth/login.go | 46 --------------------------- auth/register.go | 42 ------------------------- auth/token/add.go | 58 ---------------------------------- auth/token/generate.go | 14 --------- auth/token/validate.go | 51 ------------------------------ handler/web/login.go | 83 ------------------------------------------------- handler/web/page.go | 7 +++-- handler/web/register.go | 74 ------------------------------------------- user/adduser.go | 4 +-- user/getid.go | 4 +-- user/user.go | 37 +++------------------- 11 files changed, 13 insertions(+), 407 deletions(-) delete mode 100644 auth/login.go delete mode 100644 auth/register.go delete mode 100644 auth/token/add.go delete mode 100644 auth/token/generate.go delete mode 100644 auth/token/validate.go delete mode 100644 handler/web/login.go delete mode 100644 handler/web/register.go diff --git a/auth/login.go b/auth/login.go deleted file mode 100644 index 99e74ba..0000000 --- a/auth/login.go +++ /dev/null @@ -1,46 +0,0 @@ -package auth - -import ( - "log" - - "tildegit.org/andinus/perseus/storage/sqlite3" - "tildegit.org/andinus/perseus/user" -) - -// Login takes in login details and returns an error. If error doesn't -// equal nil then consider login failed. -func Login(db *sqlite3.DB, uInfo map[string]string) error { - // Acquire read lock on the database. - db.Mu.RLock() - defer db.Mu.RUnlock() - - u := user.User{} - u.SetUsername(uInfo["username"]) - - // Get password for this user from the database. - stmt, err := db.Conn.Prepare("SELECT password FROM users WHERE username = ?") - if err != nil { - log.Printf("auth/login.go: %s\n", - "failed to prepare statement") - return err - } - defer stmt.Close() - - var pass string - err = stmt.QueryRow(u.Username()).Scan(&pass) - if err != nil { - log.Printf("auth/login.go: %s\n", - "query failed") - return err - } - u.SetPassword(pass) - - // Check user's password. - err = checkPass(uInfo["password"], u.Password()) - if err != nil { - log.Printf("auth/login.go: %s%s\n", - "user login failed, username: ", u.Username()) - } - - return err -} diff --git a/auth/register.go b/auth/register.go deleted file mode 100644 index f946072..0000000 --- a/auth/register.go +++ /dev/null @@ -1,42 +0,0 @@ -package auth - -import ( - "errors" - "log" - "regexp" - "strings" - - "tildegit.org/andinus/perseus/storage/sqlite3" - "tildegit.org/andinus/perseus/user" -) - -// Register takes in registration details and returns an error. If -// error doesn't equal nil then the registration was unsuccessful. -// uInfo should have username & password. -func Register(db *sqlite3.DB, uInfo map[string]string) error { - u := user.User{} - u.SetID(genID(64)) - u.SetUsername(strings.ToLower(uInfo["username"])) - - // Validate username - re := regexp.MustCompile("^[a-z0-9]*$") - if !re.MatchString(u.Username()) { - return errors.New("auth/register.go: invalid username") - } - - // Validate password - if len(uInfo["password"]) < 8 { - return errors.New("auth/register.go: password too short") - } - - pass, err := hashPass(uInfo["password"]) - if err != nil { - log.Printf("auth/register.go: %s\n", - "hashPass func failed") - return err - } - u.SetPassword(pass) - - err = u.AddUser(db) - return err -} diff --git a/auth/token/add.go b/auth/token/add.go deleted file mode 100644 index eadc6dc..0000000 --- a/auth/token/add.go +++ /dev/null @@ -1,58 +0,0 @@ -package token - -import ( - "log" - "time" - - "tildegit.org/andinus/perseus/storage/sqlite3" - "tildegit.org/andinus/perseus/user" -) - -// AddToken will generate a random token, add it to database and -// return the token. -func AddToken(db *sqlite3.DB, uInfo map[string]string) (token string, err error) { - // Acquire write lock on the database. - db.Mu.Lock() - defer db.Mu.Unlock() - - token = genToken(64) - - u := user.User{} - u.SetUsername(uInfo["username"]) - - // Set user id from username. - err = u.GetID(db) - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to get id from username") - return - } - - // Start the transaction - tx, err := db.Conn.Begin() - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to begin transaction") - return - } - - stmt, err := db.Conn.Prepare(` -INSERT INTO access(id, token, genTime) values(?, ?, ?)`) - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to prepare statement") - return - } - defer stmt.Close() - - _, err = stmt.Exec(u.ID(), u.Username(), time.Now().UTC()) - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to execute statement") - return - } - - tx.Commit() - return - -} diff --git a/auth/token/generate.go b/auth/token/generate.go deleted file mode 100644 index 0c717d9..0000000 --- a/auth/token/generate.go +++ /dev/null @@ -1,14 +0,0 @@ -package token - -import ( - "crypto/rand" - "encoding/base64" -) - -// genToken generates a random token string of length n. Don't forget to -// seed the random number generator otherwise it won't be random. -func genToken(n int) string { - b := make([]byte, n/2) - rand.Read(b) - return base64.StdEncoding.EncodeToString(b) -} diff --git a/auth/token/validate.go b/auth/token/validate.go deleted file mode 100644 index f1ee149..0000000 --- a/auth/token/validate.go +++ /dev/null @@ -1,51 +0,0 @@ -package token - -import ( - "errors" - "log" - - "tildegit.org/andinus/perseus/storage/sqlite3" - "tildegit.org/andinus/perseus/user" -) - -// ValToken will validate the token and returns an error. If error -// doesn't equal nil then consider token invalid. -func ValToken(db *sqlite3.DB, uInfo map[string]string) error { - // Acquire read lock on the database. - db.Mu.RLock() - defer db.Mu.RUnlock() - - u := user.User{} - u.SetUsername(uInfo["username"]) - - // Set user id from username. - err := u.GetID(db) - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to get id from username") - return err - } - - // Check if user's token is valid. - stmt, err := db.Conn.Prepare("SELECT token FROM access WHERE id = ?") - if err != nil { - log.Printf("auth/token.go: %s\n", - "failed to prepare statement") - return err - } - defer stmt.Close() - - var token string - err = stmt.QueryRow(u.ID()).Scan(&token) - if err != nil { - log.Printf("auth/token.go: %s\n", - "query failed") - return err - } - - if token != uInfo["token"] { - err = errors.New("token mismatch") - } - - return err -} diff --git a/handler/web/login.go b/handler/web/login.go deleted file mode 100644 index 0c70b56..0000000 --- a/handler/web/login.go +++ /dev/null @@ -1,83 +0,0 @@ -package web - -import ( - "fmt" - "html/template" - "log" - "net/http" - "time" - - "tildegit.org/andinus/perseus/auth" - "tildegit.org/andinus/perseus/auth/token" - "tildegit.org/andinus/perseus/core" - "tildegit.org/andinus/perseus/storage/sqlite3" -) - -// HandleLogin handles /login pages. -func HandleLogin(w http.ResponseWriter, r *http.Request, db *sqlite3.DB) { - p := Page{Version: core.Version()} - error := []string{} - success := []string{} - - switch r.Method { - case http.MethodGet: - t, _ := template.ParseFiles("web/login.html") - t.Execute(w, p) - - case http.MethodPost: - if err := r.ParseForm(); err != nil { - log.Printf("web/login.go: 400 Bad Request :: %s", err.Error()) - http.Error(w, "400 Bad Request", http.StatusBadRequest) - return - } - - // Get form values - uInfo := make(map[string]string) - uInfo["username"] = r.FormValue("username") - uInfo["password"] = r.FormValue("password") - - // Perform authentication - err := auth.Login(db, uInfo) - - if err != nil { - log.Printf("web/login.go: %s :: %s :: %s", - "login failed", - uInfo["username"], - err.Error()) - - error = append(error, - fmt.Sprintf("Login failed")) - - p.Error = error - } else { - success = append(success, - fmt.Sprintf("Login successful")) - p.Success = success - - // Set token if login was successful. - token, err := token.AddToken(db, uInfo) - if err != nil { - log.Printf("web/login.go: %s :: %s :: %s", - "token generation failed", - uInfo["username"], - err.Error()) - - error = append(error, - fmt.Sprintf("Token generation failed")) - } - // If token was generated then ask browser to - // set it as cookie. - expiration := time.Now().Add(1 * 24 * time.Hour) - cookie := http.Cookie{Name: "token", Value: token, Expires: expiration} - http.SetCookie(w, &cookie) - } - - t, _ := template.ParseFiles("web/login.html") - t.Execute(w, p) - - default: - w.WriteHeader(http.StatusMethodNotAllowed) - log.Printf("web/login.go: %v not allowed on %v", r.Method, r.URL) - } - -} diff --git a/handler/web/page.go b/handler/web/page.go index 647984d..1f457de 100644 --- a/handler/web/page.go +++ b/handler/web/page.go @@ -1,8 +1,11 @@ package web -import "html/template" +import ( + "html/template" +) -// Page holds page information +// Page holds page information that is sent to all webpages rendered +// by perseus. type Page struct { SafeList []template.HTML List []string diff --git a/handler/web/register.go b/handler/web/register.go deleted file mode 100644 index 1e76af2..0000000 --- a/handler/web/register.go +++ /dev/null @@ -1,74 +0,0 @@ -package web - -import ( - "fmt" - "html/template" - "log" - "net/http" - "strings" - - "tildegit.org/andinus/perseus/auth" - "tildegit.org/andinus/perseus/core" - "tildegit.org/andinus/perseus/storage/sqlite3" -) - -// HandleRegister handles /register pages. -func HandleRegister(w http.ResponseWriter, r *http.Request, db *sqlite3.DB) { - p := Page{Version: core.Version()} - p.Notice = []string{ - "Only [a-z] & [0-9] allowed for username", - "Password length must be greater than 8 characters", - } - switch r.Method { - case http.MethodGet: - t, _ := template.ParseFiles("web/register.html") - t.Execute(w, p) - - case http.MethodPost: - if err := r.ParseForm(); err != nil { - log.Printf("web/register.go: 400 Bad Request :: %s", err.Error()) - http.Error(w, "400 Bad Request", http.StatusBadRequest) - return - } - - // Get form values - uInfo := make(map[string]string) - uInfo["username"] = r.FormValue("username") - uInfo["password"] = r.FormValue("password") - - // Perform registration - err := auth.Register(db, uInfo) - - if err != nil { - log.Printf("web/register.go: %s :: %s :: %s", - "registration failed", - uInfo["username"], - err.Error()) - - error := []string{} - error = append(error, - fmt.Sprintf("Registration failed")) - - // Check if the error was because of username - // not being unique. - if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") { - error = append(error, - fmt.Sprintf("Username not unique")) - } - p.Error = error - } else { - success := []string{} - success = append(success, - fmt.Sprintf("Registration successful")) - p.Success = success - } - - t, _ := template.ParseFiles("web/register.html") - t.Execute(w, p) - - default: - w.WriteHeader(http.StatusMethodNotAllowed) - log.Printf("web/register.go: %v not allowed on %v", r.Method, r.URL) - } - -} diff --git a/user/adduser.go b/user/adduser.go index 873454b..d1dbcde 100644 --- a/user/adduser.go +++ b/user/adduser.go @@ -8,7 +8,7 @@ import ( ) // AddUser adds the user to record. -func (u *User) AddUser(db *sqlite3.DB) error { +func (u User) AddUser(db *sqlite3.DB) error { // Acquire write lock on the database. db.Mu.Lock() defer db.Mu.Unlock() @@ -30,7 +30,7 @@ INSERT INTO users(id, username, password, regTime) values(?, ?, ?, ?)`) } defer usrStmt.Close() - _, err = usrStmt.Exec(u.id, u.username, u.password, time.Now().UTC()) + _, err = usrStmt.Exec(u.ID, u.Username, u.Password, time.Now().UTC()) if err != nil { log.Printf("user/adduser.go: %s\n", "failed to execute statement") diff --git a/user/getid.go b/user/getid.go index b8edfc7..9cf8870 100644 --- a/user/getid.go +++ b/user/getid.go @@ -18,12 +18,12 @@ func (u *User) GetID(db *sqlite3.DB) error { defer stmt.Close() var id string - err = stmt.QueryRow(u.username).Scan(&id) + err = stmt.QueryRow(u.Username).Scan(&id) if err != nil { log.Printf("user/getid.go: %s\n", "query failed") } - u.id = id + u.ID = id return err } diff --git a/user/user.go b/user/user.go index a15d625..078215e 100644 --- a/user/user.go +++ b/user/user.go @@ -2,37 +2,8 @@ package user // User holds information about the user. type User struct { - id string - username string - password string -} - -// SetUsername will set the username. -func (u *User) SetUsername(username string) { - u.username = username -} - -// Username returns the username. -func (u *User) Username() string { - return u.username -} - -// SetPassword will set the password. -func (u *User) SetPassword(password string) { - u.password = password -} - -// Password returns the password. -func (u *User) Password() string { - return u.password -} - -// SetID will set the id. -func (u *User) SetID(id string) { - u.id = id -} - -// ID returns the id. -func (u *User) ID() string { - return u.id + ID string + Username string + Password string + Hash string } -- cgit 1.4.1-2-gfad0