cerrado @ fa7b51a709413a214fbd5157fe0f32138a889f0d

feat: Filter private repository from the UI

Now the whole application takes public into account.
  1diff --git a/pkg/ext/auth.go b/pkg/ext/auth.go
  2index 304f4ad3fe1d2e9f97f9f930ac1e527c74787c6c..5c3070e869de09ec7b6c8239603cf037330085c1 100644
  3--- a/pkg/ext/auth.go
  4+++ b/pkg/ext/auth.go
  5@@ -6,6 +6,8 @@ 	"encoding/base64"
  6 	"errors"
  7 	"log/slog"
  8 	"net/http"
  9+
 10+	serverconfig "git.gabrielgio.me/cerrado/pkg/config"
 11 )
 12 
 13 type authService interface {
 14@@ -20,6 +22,25 @@ 		next(w, r.WithContext(ctx))
 15 	}
 16 }
 17 
 18+func VerifyRespository(
 19+	config *serverconfig.ConfigurationRepository,
 20+) func(next http.HandlerFunc) http.HandlerFunc {
 21+	return func(next http.HandlerFunc) http.HandlerFunc {
 22+		return func(w http.ResponseWriter, r *http.Request) {
 23+			name := r.PathValue("name")
 24+			if name != "" {
 25+				repo := config.GetByName(name)
 26+				if repo != nil && !repo.Public && !IsLoggedIn(r.Context()) {
 27+					NotFound(w, r)
 28+					return
 29+				}
 30+			}
 31+
 32+			next(w, r)
 33+		}
 34+	}
 35+}
 36+
 37 func Authenticate(auth authService) func(next http.HandlerFunc) http.HandlerFunc {
 38 	return func(next http.HandlerFunc) http.HandlerFunc {
 39 		return func(w http.ResponseWriter, r *http.Request) {
 40@@ -28,6 +49,7 @@ 			if err != nil {
 41 				if !errors.Is(err, http.ErrNoCookie) {
 42 					slog.Error("Error loading cookie", "error", err)
 43 				}
 44+
 45 				next(w, r)
 46 				return
 47 			}
 48@@ -47,10 +69,15 @@ 				return
 49 			}
 50 
 51 			ctx := r.Context()
 52-			ctx = context.WithValue(ctx, "logged", true)
 53+			ctx = context.WithValue(ctx, "logged", valid)
 54 
 55 			slog.Info("Validated token", "valid?", valid)
 56 			next(w, r.WithContext(ctx))
 57 		}
 58 	}
 59 }
 60+
 61+func IsLoggedIn(ctx context.Context) bool {
 62+	t, ok := ctx.Value("logged").(bool)
 63+	return ok && t
 64+}
 65diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
 66index 42761595323c97d0ea49dc3fe69d618446284bcc..6225b1a444f98701f9049c856c2b63e5c248adc6 100644
 67--- a/pkg/handler/git/handler.go
 68+++ b/pkg/handler/git/handler.go
 69@@ -13,6 +13,7 @@ 	"strings"
 70 
 71 	"git.gabrielgio.me/cerrado/pkg/ext"
 72 	"git.gabrielgio.me/cerrado/pkg/service"
 73+	"git.gabrielgio.me/cerrado/pkg/u"
 74 	"git.gabrielgio.me/cerrado/templates"
 75 	"github.com/alecthomas/chroma/v2"
 76 	"github.com/alecthomas/chroma/v2/formatters/html"
 77@@ -44,9 +45,17 @@ 	}
 78 }
 79 
 80 func (g *GitHandler) List(w http.ResponseWriter, r *http.Request) error {
 81+	// this is the only handler that needs to handle authentication itself.
 82+	// everything else relay on name path parameter
 83+	logged := ext.IsLoggedIn(r.Context())
 84+
 85 	repos, err := g.gitService.ListRepositories()
 86 	if err != nil {
 87 		return err
 88+	}
 89+
 90+	if !logged {
 91+		repos = u.Filter(repos, isPublic)
 92 	}
 93 
 94 	f, err := os.Open(g.config.GetRootReadme())
 95@@ -375,3 +384,7 @@ 		lexer = lexers.Get("txt")
 96 	}
 97 	return lexer
 98 }
 99+
100+func isPublic(r *service.Repository) bool {
101+	return r.Public
102+}
103diff --git a/pkg/handler/router.go b/pkg/handler/router.go
104index 82ee8fdc32a068b111399bd610fddc7496dd90d2..8d27b743bf46ad25bd31a4a984ceffdd2626bc0c 100644
105--- a/pkg/handler/router.go
106+++ b/pkg/handler/router.go
107@@ -34,6 +34,7 @@
108 	mux := ext.NewRouter()
109 	mux.AddMiddleware(ext.Compress)
110 	mux.AddMiddleware(ext.Log)
111+	mux.AddMiddleware(ext.VerifyRespository(configRepo))
112 
113 	if configRepo.IsAuthEnabled() {
114 		mux.AddMiddleware(ext.Authenticate(authService))
115diff --git a/pkg/u/list.go b/pkg/u/list.go
116index 39d7b117fa7b9a509be2fa3f7946dc11945ce812..835ecd289214a9c5a4f30d249c39ee70e957e4ab 100644
117--- a/pkg/u/list.go
118+++ b/pkg/u/list.go
119@@ -1,5 +1,17 @@
120 package u
121 
122+func Filter[T any](v []T, f func(T) bool) []T {
123+	var result []T
124+
125+	for _, s := range v {
126+		if f(s) {
127+			result = append(result, s)
128+		}
129+	}
130+
131+	return result
132+}
133+
134 func First[T any](v []T) (T, bool) {
135 	if len(v) == 0 {
136 		var zero T
137@@ -25,7 +37,7 @@ 	return v[len(v)-1]
138 }
139 
140 func ChunkBy[T any](items []T, chunkSize int) [][]T {
141-	var chunks = make([][]T, 0, (len(items)/chunkSize)+1)
142+	chunks := make([][]T, 0, (len(items)/chunkSize)+1)
143 	for chunkSize < len(items) {
144 		items, chunks = items[chunkSize:], append(chunks, items[0:chunkSize:chunkSize])
145 	}