Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-08-08 10:43:43
Commitff9ec25a03d343b2b4ea7c538faa27264dd0233c
Parent0dadb00e59a08480835e2e6b9de8510d42857b64

Update the user login page

Diffstat

M main.go | 3 ++-
M res/repo/create.html | 4 +---
M res/style.css | 1 +
M res/user/login.html | 44 ++++++++++++++++++++++++++++++++++----------
M src/repo/log.go | 4 ++--
M src/user.go | 50 --------------------------------------------------
A src/user/login.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

7 files changed, 104 insertions, 66 deletions

diff --git a/main.go b/main.go
index 90df6ef..6daa6f0 100644
--- a/main.go
+++ b/main.go
@@ -13,6 +13,7 @@ import (
 	"github.com/Jamozed/Goit/res"
 	goit "github.com/Jamozed/Goit/src"
 	"github.com/Jamozed/Goit/src/repo"
+	"github.com/Jamozed/Goit/src/user"
 	"github.com/gorilla/mux"
 )
 
@@ -25,7 +26,7 @@ func main() {
 	h.StrictSlash(true)
 
 	h.Path("/").HandlerFunc(goit.HandleIndex)
-	h.Path("/user/login").Methods("GET", "POST").HandlerFunc(goit.HandleUserLogin)
+	h.Path("/user/login").Methods("GET", "POST").HandlerFunc(user.HandleLogin)
 	h.Path("/user/logout").Methods("GET", "POST").HandlerFunc(goit.HandleUserLogout)
 	h.Path("/user/sessions").Methods("GET", "POST").HandlerFunc(goit.HandleUserSessions)
 	h.Path("/repo/create").Methods("GET", "POST").HandlerFunc(repo.HandleCreate)
diff --git a/res/repo/create.html b/res/repo/create.html
index 7f5f495..753e578 100644
--- a/res/repo/create.html
+++ b/res/repo/create.html
@@ -4,9 +4,7 @@
 	<header>
 		<table>
 			<tr>
-				<td rowspan="2">
-					<a href="/"><img src="/static/favicon.png" style="max-height: 24px"></a>
-				</td>
+				<td rowspan="2"><a href="/"><img src="/static/favicon.png" style="max-height: 24px"></a></td>
 				<td><h1>{{.Title}}</h1></td>
 			</tr>
 			<tr><td></td></tr>
diff --git a/res/style.css b/res/style.css
index 8b0443f..2c00a7f 100644
--- a/res/style.css
+++ b/res/style.css
@@ -18,6 +18,7 @@ table td.line { tab-size: 4; white-space: pre; }
 
 form table input { border: 2px solid #333333; border-radius: 3px; background-color: #111111; padding: 2px; }
 form table input[type="text"] { color: #888888; width: 24em; }
+form table input[type="password"] { color: #888888; width: 24em; }
 form table input[type="submit"] { color: #FF7E00; width: 6em; }
 
 form table select {
diff --git a/res/user/login.html b/res/user/login.html
index f7890de..4d235cf 100644
--- a/res/user/login.html
+++ b/res/user/login.html
@@ -1,14 +1,38 @@
 <!DOCTYPE html>
 <head lang="en-GB">{{template "base/head" .}}</head>
 <body>
-<body>
-	<h1>Login</h1>
-	<form action="/user/login" method="post">
-		<label for="username">Username:</label>
-		<input type="text" name="username"><br>
-		<label for="password">Password:</label>
-		<input type="password" name="password"><br>
-		<input type="submit" value="Login">
-	</form>
-	<p>{{.Message}}</p>
+	<header>
+		<table>
+			<tr>
+				<td rowspan="2"><a href="/"><img src="/static/favicon.png" style="max-height: 24px"></a></td>
+				<td><h1>{{.Title}}</h1></td>
+			</tr>
+			<tr><td></td></tr>
+		</table>
+	</header>
+	<main>
+		<form action="/user/login" method="post">
+			<table>
+				<tr>
+					<td style="text-align: right;"><label for="username">Username</label></td>
+					<td><input type="text" name="username" value="{{.Name}}" {{if not .FocusPw}}autofocus{{end}}></td>
+				</tr>
+				<tr>
+					<td style="text-align: right;"><label for="password">Password</label></td>
+					<td><input type="password" name="password" {{if .FocusPw}}autofocus{{end}}></td>
+				</tr>
+				<tr>
+					<td></td>
+					<td>
+						<input type="submit" value="Login">
+						<a href="/" style="color: inherit;">Cancel</a>
+					</td>
+				</tr>
+				<tr>
+					<td></td>
+					<td style="color: #AA0000">{{.Message}}</td>
+				</tr>
+			</table>
+		</form>
+	</main>
 </body>
diff --git a/src/repo/log.go b/src/repo/log.go
index ab408d6..7c0f08a 100644
--- a/src/repo/log.go
+++ b/src/repo/log.go
@@ -18,13 +18,13 @@ import (
 )
 
 func HandleLog(w http.ResponseWriter, r *http.Request) {
-	_, uid := goit.AuthCookie(w, r, true)
+	auth, uid := goit.AuthCookie(w, r, true)
 
 	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
-	} else if repo == nil || (repo.IsPrivate && repo.OwnerId != uid) {
+	} else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != uid)) {
 		goit.HttpError(w, http.StatusNotFound)
 		return
 	}
diff --git a/src/user.go b/src/user.go
index 4d0ee24..9e74553 100644
--- a/src/user.go
+++ b/src/user.go
@@ -5,12 +5,10 @@
 package goit
 
 import (
-	"bytes"
 	"database/sql"
 	"errors"
 	"fmt"
 	"log"
-	"net"
 	"net/http"
 	"strings"
 	"time"
@@ -30,54 +28,6 @@ type User struct {
 
 var reserved []string = []string{"admin", "repo", "static", "user"}
 
-func HandleUserLogin(w http.ResponseWriter, r *http.Request) {
-	if ok, _ := AuthCookie(w, r, true); ok {
-		http.Redirect(w, r, "/", http.StatusFound)
-		return
-	}
-
-	data := struct{ Title, Message string }{"Login", ""}
-
-	if r.Method == http.MethodPost {
-		u := User{}
-		username := strings.ToLower(r.FormValue("username"))
-		password := r.FormValue("password")
-
-		if username == "" {
-			data.Message = "Username cannot be empty"
-		} else if exists, err := UserExists(username); err != nil {
-			log.Println("[User:Login:Exists]", err.Error())
-			HttpError(w, http.StatusInternalServerError)
-			return
-		} else if !exists {
-			data.Message = "Invalid credentials"
-		} else if err := db.QueryRow(
-			"SELECT id, name, pass, pass_algo, salt FROM users WHERE name = ?", username,
-		).Scan(&u.Id, &u.Name, &u.Pass, &u.PassAlgo, &u.Salt); err != nil {
-			log.Println("[User:Login:SELECT]", err.Error())
-			HttpError(w, http.StatusInternalServerError)
-			return
-		} else if !bytes.Equal(Hash(password, u.Salt), u.Pass) {
-			data.Message = "Invalid credentials"
-		} else {
-			ip, _, _ := net.SplitHostPort(r.RemoteAddr)
-			if s, err := NewSession(u.Id, ip, time.Now().Add(2*24*time.Hour)); err != nil {
-				log.Println("[User:Login:Session]", err.Error())
-				HttpError(w, http.StatusInternalServerError)
-				return
-			} else {
-				SetSessionCookie(w, u.Id, s)
-				http.Redirect(w, r, "/", http.StatusFound)
-				return
-			}
-		}
-	}
-
-	if err := Tmpl.ExecuteTemplate(w, "user/login", data); err != nil {
-		log.Println("[/user/login]", err.Error())
-	}
-}
-
 func HandleUserLogout(w http.ResponseWriter, r *http.Request) {
 	id, s := GetSessionCookie(r)
 	EndSession(id, s.Token)
diff --git a/src/user/login.go b/src/user/login.go
new file mode 100644
index 0000000..f307e5d
--- /dev/null
+++ b/src/user/login.go
@@ -0,0 +1,64 @@
+// user/login.go
+// Copyright (C) 2023, Jakob Wakeling
+// All rights reserved.
+
+package user
+
+import (
+	"bytes"
+	"log"
+	"net"
+	"net/http"
+	"time"
+
+	goit "github.com/Jamozed/Goit/src"
+)
+
+func HandleLogin(w http.ResponseWriter, r *http.Request) {
+	if auth, _ := goit.AuthCookie(w, r, true); auth {
+		http.Redirect(w, r, "/", http.StatusFound)
+	}
+
+	data := struct {
+		Title, Message, Name string
+		FocusPw              bool
+	}{Title: "Login"}
+
+	if r.Method == http.MethodPost {
+		data.Name = r.FormValue("username")
+		password := r.FormValue("password")
+
+		if data.Name == "" {
+			data.Message = "Username cannot be empty"
+			goto execute
+		}
+
+		user, err := goit.GetUserByName(data.Name)
+		if err != nil {
+			log.Println("[/user/login]", err.Error())
+			goit.HttpError(w, http.StatusInternalServerError)
+			return
+		} else if user == nil || !bytes.Equal(goit.Hash(password, user.Salt), user.Pass) {
+			data.Message = "Invalid credentials"
+			data.FocusPw = true
+			goto execute
+		}
+
+		ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+		sess, err := goit.NewSession(user.Id, ip, time.Now().Add(2*24*time.Hour))
+		if err != nil {
+			log.Println("[/user/login]", err.Error())
+			goit.HttpError(w, http.StatusInternalServerError)
+			return
+		}
+
+		goit.SetSessionCookie(w, user.Id, sess)
+		http.Redirect(w, r, "/", http.StatusFound)
+		return
+	}
+
+execute:
+	if err := goit.Tmpl.ExecuteTemplate(w, "user/login", data); err != nil {
+		log.Println("[/user/login]", err.Error())
+	}
+}