Goit

Simple and lightweight Git web server
Mirror of https://github.com/Jamozed/Goit
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-11-03 09:19:52
Commit7974d70ab064a04f872f70f1bc94555ca333517b
Parent988a70896b863d3c930c5d6cd78b6f2df4c63d35

Implement filtering repository index by owner

Diffstat

M go.mod | 2 +-
M res/admin/repos.html | 2 +-
M src/admin.go | 6 +++---
M src/auth.go | 35 +++++++++++++++++++++++++++++++++++
M src/goit.go | 2 ++
M src/index.go | 20 +++++++++++++-------
M src/repo/create.go | 4 +---
M src/repo/edit.go | 2 +-
M src/user.go | 3 ---
M src/user/edit.go | 2 +-
M src/user/user.go | 2 --

11 files changed, 58 insertions, 22 deletions

diff --git a/go.mod b/go.mod
index 92f44fc..2baa3d1 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.21.0
 
 require (
 	github.com/adrg/xdg v0.4.0
+	github.com/buildkite/terminal-to-html/v3 v3.9.1
 	github.com/dustin/go-humanize v1.0.1
 	github.com/go-git/go-git/v5 v5.9.0
 	github.com/gorilla/mux v1.8.0
@@ -16,7 +17,6 @@ require (
 	github.com/Microsoft/go-winio v0.6.1 // indirect
 	github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
 	github.com/acomagu/bufpipe v1.0.4 // indirect
-	github.com/buildkite/terminal-to-html/v3 v3.9.1
 	github.com/cloudflare/circl v1.3.5 // indirect
 	github.com/cyphar/filepath-securejoin v0.2.4 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
diff --git a/res/admin/repos.html b/res/admin/repos.html
index a0e2997..f9be559 100644
--- a/res/admin/repos.html
+++ b/res/admin/repos.html
@@ -31,7 +31,7 @@
 			{{range .Repos}}
 				<tr>
 					<td>{{.Id}}</td>
-					<td><a href="/?user={{.Owner}}">{{.Owner}}</a></td>
+					<td><a href="/?u={{.Owner}}">{{.Owner}}</a></td>
 					<td><a href="/{{.Name}}">{{.Name}}</a></td>
 					<td>{{.Visibility}}</td>
 					<td>{{.Size}}</td>
diff --git a/src/admin.go b/src/admin.go
index 085375c..1dd9f85 100644
--- a/src/admin.go
+++ b/src/admin.go
@@ -88,7 +88,7 @@ func HandleAdminUserCreate(w http.ResponseWriter, r *http.Request) {
 
 		if username == "" {
 			data.Message = "Username cannot be empty"
-		} else if slices.Contains(reserved, username) {
+		} else if slices.Contains(Reserved, username) {
 			data.Message = "Username \"" + username + "\" is reserved"
 		} else if exists, err := UserExists(username); err != nil {
 			log.Println("[/admin/user/create]", err.Error())
@@ -155,7 +155,7 @@ func HandleAdminUserEdit(w http.ResponseWriter, r *http.Request) {
 
 		if data.Name == "" {
 			data.Message = "Username cannot be empty"
-		} else if slices.Contains(reserved, data.Name) {
+		} else if slices.Contains(Reserved, data.Name) {
 			data.Message = "Username \"" + data.Name + "\" is reserved"
 		} else if exists, err := UserExists(data.Name); err != nil {
 			log.Println("[/admin/user/edit]", err.Error())
@@ -295,7 +295,7 @@ func HandleAdminRepoEdit(w http.ResponseWriter, r *http.Request) {
 
 		if data.Name == "" {
 			data.Message = "Name cannot be empty"
-		} else if slices.Contains(reserved, data.Name) {
+		} else if slices.Contains(Reserved, data.Name) {
 			data.Message = "Name \"" + data.Name + "\" is reserved"
 		} else if exists, err := RepoExists(data.Name); err != nil {
 			log.Println("[/admin/repo/edit]", err.Error())
diff --git a/src/auth.go b/src/auth.go
index bdd0710..108f1f2 100644
--- a/src/auth.go
+++ b/src/auth.go
@@ -159,6 +159,40 @@ func EndSessionCookie(w http.ResponseWriter) {
 	http.SetCookie(w, &http.Cookie{Name: "session", Path: "/", MaxAge: -1})
 }
 
+/* Authenticate a user session, returns auth, user, error. */
+func Auth(w http.ResponseWriter, r *http.Request, renew bool) (bool, *User, error) {
+	uid, s := GetSessionCookie(r)
+	if s == (Session{}) {
+		return false, nil, nil
+	}
+
+	/* Attempt to get the user associated with the session UID */
+	user, err := GetUser(uid)
+	if err != nil {
+		return false, nil, fmt.Errorf("[auth] %w", err)
+	}
+
+	/* End invalid and expired sessions */
+	if user == nil || s.Expiry.Before(time.Now()) {
+		EndSession(uid, s.Token)
+		return false, nil, nil
+	}
+
+	/* Renew the session if appropriate */
+	if renew && time.Until(s.Expiry) < 24*time.Hour {
+		ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+		s1, err := NewSession(uid, ip, time.Now().Add(2*24*time.Hour))
+		if err != nil {
+			log.Println("[auth/renew]", err.Error())
+		} else {
+			SetSessionCookie(w, uid, s1)
+			EndSession(uid, s.Token)
+		}
+	}
+
+	return true, user, nil
+}
+
 /* Authenticate a user session cookie. */
 func AuthCookie(w http.ResponseWriter, r *http.Request, renew bool) (bool, int64) {
 	if uid, s := GetSessionCookie(r); s != (Session{}) {
diff --git a/src/goit.go b/src/goit.go
index b150df5..1ea91b3 100644
--- a/src/goit.go
+++ b/src/goit.go
@@ -38,6 +38,8 @@ var Conf = Config{
 var db *sql.DB
 var Favicon []byte
 
+var Reserved []string = []string{"admin", "repo", "static", "user"}
+
 func Goit(conf string) (err error) {
 	if dat, err := os.ReadFile(conf); err != nil {
 		if !errors.Is(err, os.ErrNotExist) {
diff --git a/src/index.go b/src/index.go
index 4ac76d5..e487e27 100644
--- a/src/index.go
+++ b/src/index.go
@@ -12,24 +12,25 @@ import (
 )
 
 func HandleIndex(w http.ResponseWriter, r *http.Request) {
-	auth, admin, uid := AuthCookieAdmin(w, r, true)
-
-	user, err := GetUser(uid)
+	auth, user, err := Auth(w, r, true)
 	if err != nil {
-		log.Println("[/]", err.Error())
+		log.Println("[index]", err.Error())
 		HttpError(w, http.StatusInternalServerError)
 		return
 	}
 
+	userQuery := r.FormValue("u")
+
 	type row struct{ Name, Description, Owner, Visibility, LastCommit string }
 	data := struct {
 		Title, Username string
 		Admin, Auth     bool
 		Repos           []row
-	}{Title: "Repositories", Admin: admin, Auth: auth}
+	}{Title: "Repositories", Auth: auth}
 
 	if user != nil {
 		data.Username = user.Name
+		data.Admin = user.IsAdmin
 	}
 
 	rows, err := db.Query("SELECT id, owner_id, name, description, is_private FROM repos")
@@ -45,12 +46,17 @@ func HandleIndex(w http.ResponseWriter, r *http.Request) {
 
 		if err := rows.Scan(&repo.Id, &repo.OwnerId, &repo.Name, &repo.Description, &repo.IsPrivate); err != nil {
 			log.Println("[/]", err.Error())
-		} else if !repo.IsPrivate || (auth && uid == repo.OwnerId) {
+		} else if !repo.IsPrivate || (auth && user.Id == repo.OwnerId) {
 			owner, err := GetUser(repo.OwnerId)
 			if err != nil {
 				log.Println("[/]", err.Error())
 			}
 
+			/* Only display repositories matching user query if present */
+			if userQuery != "" && owner.Name != userQuery {
+				continue
+			}
+
 			var lastCommit string
 			if gr, err := git.PlainOpen(RepoPath(repo.Name)); err != nil {
 				log.Println("[/]", err.Error())
diff --git a/src/repo/create.go b/src/repo/create.go
index c0b9444..25da57d 100644
--- a/src/repo/create.go
+++ b/src/repo/create.go
@@ -8,8 +8,6 @@ import (
 	goit "github.com/Jamozed/Goit/src"
 )
 
-var reserved []string = []string{"admin", "repo", "static", "user"}
-
 func HandleCreate(w http.ResponseWriter, r *http.Request) {
 	ok, uid := goit.AuthCookie(w, r, true)
 	if !ok {
@@ -30,7 +28,7 @@ func HandleCreate(w http.ResponseWriter, r *http.Request) {
 
 		if data.Name == "" {
 			data.Message = "Name cannot be empty"
-		} else if slices.Contains(reserved, data.Name) {
+		} else if slices.Contains(goit.Reserved, data.Name) {
 			data.Message = "Name \"" + data.Name + "\" is reserved"
 		} else if exists, err := goit.RepoExists(data.Name); err != nil {
 			log.Println("[/repo/create]", err.Error())
diff --git a/src/repo/edit.go b/src/repo/edit.go
index 6a2e4e7..0233f99 100644
--- a/src/repo/edit.go
+++ b/src/repo/edit.go
@@ -98,7 +98,7 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) {
 
 			if data.Edit.Name == "" {
 				data.Edit.Message = "Name cannot be empty"
-			} else if slices.Contains(reserved, data.Edit.Name) {
+			} else if slices.Contains(goit.Reserved, data.Edit.Name) {
 				data.Edit.Message = "Name \"" + data.Edit.Name + "\" is reserved"
 			} else if exists, err := goit.RepoExists(data.Edit.Name); err != nil {
 				log.Println("[/repo/edit]", err.Error())
diff --git a/src/user.go b/src/user.go
index 3b523ef..9c280b4 100644
--- a/src/user.go
+++ b/src/user.go
@@ -22,8 +22,6 @@ type User struct {
 	IsAdmin  bool
 }
 
-var reserved []string = []string{"admin", "repo", "static", "user"}
-
 func HandleUserLogout(w http.ResponseWriter, r *http.Request) {
 	id, s := GetSessionCookie(r)
 	EndSession(id, s.Token)
diff --git a/src/user/edit.go b/src/user/edit.go
index 909957c..bdd6f97 100644
--- a/src/user/edit.go
+++ b/src/user/edit.go
@@ -47,7 +47,7 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) {
 
 			if data.Form.Name == "" {
 				data.MessageA = "Username cannot be empty"
-			} else if slices.Contains(reserved, data.Form.Name) && uid != 0 {
+			} else if slices.Contains(goit.Reserved, data.Form.Name) && uid != 0 {
 				data.MessageA = "Username \"" + data.Form.Name + "\" is reserved"
 			} else if exists, err := goit.UserExists(data.Form.Name); err != nil {
 				log.Println("[/user/edit]", err.Error())
diff --git a/src/user/user.go b/src/user/user.go
index b41a851..a00006b 100644
--- a/src/user/user.go
+++ b/src/user/user.go
@@ -1,3 +1 @@
 package user
-
-var reserved []string = []string{"admin", "repo", "static", "user"}