aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/config/config.go16
-rw-r--r--pkg/ext/auth.go45
-rw-r--r--pkg/ext/router.go18
-rw-r--r--pkg/handler/about/handler.go4
-rw-r--r--pkg/handler/auth/login.go75
-rw-r--r--pkg/handler/git/handler.go24
-rw-r--r--pkg/handler/router.go5
-rw-r--r--pkg/service/auth.go8
-rw-r--r--pkg/service/git.go4
9 files changed, 166 insertions, 33 deletions
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 812a06e..da6e0e7 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -55,8 +55,8 @@ type (
ConfigurationRepository struct {
rootReadme string
listenAddr string
- passphrase string
- aesKey string
+ passphrase []byte
+ aesKey []byte
syntaxHighlight string
repositories []*GitRepositoryConfiguration
}
@@ -74,9 +74,9 @@ func LoadConfigurationRepository(configPath string) (*ConfigurationRepository, e
}
repo := &ConfigurationRepository{
- aesKey: config.AESKey,
+ aesKey: []byte(config.AESKey),
listenAddr: config.ListenAddr,
- passphrase: config.Passphrase,
+ passphrase: []byte(config.Passphrase),
repositories: config.Repositories,
rootReadme: config.RootReadme,
syntaxHighlight: config.SyntaxHighlight,
@@ -105,6 +105,14 @@ func (c *ConfigurationRepository) GetListenAddr() string {
return c.listenAddr
}
+func (c *ConfigurationRepository) GetPassphrase() []byte {
+ return c.passphrase
+}
+
+func (c *ConfigurationRepository) GetBase64AesKey() []byte {
+ return c.aesKey
+}
+
// GetByName returns configuration of repository for a given name.
// It returns nil if there is not match for it.
func (c *ConfigurationRepository) GetByName(name string) *GitRepositoryConfiguration {
diff --git a/pkg/ext/auth.go b/pkg/ext/auth.go
new file mode 100644
index 0000000..bb6c0a2
--- /dev/null
+++ b/pkg/ext/auth.go
@@ -0,0 +1,45 @@
+package ext
+
+import (
+ "context"
+ "encoding/base64"
+ "log/slog"
+ "net/http"
+)
+
+type authService interface {
+ ValidateToken(token []byte) (bool, error)
+}
+
+func Authenticate(auth authService) func(next http.HandlerFunc) http.HandlerFunc {
+ return func(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ cookie, err := r.Cookie("auth")
+ if err != nil {
+ slog.Error("Error loading cookie", "error", err)
+ next(w, r)
+ return
+ }
+
+ value, err := base64.StdEncoding.DecodeString(cookie.Value)
+ if err != nil {
+ slog.Error("Error decoding", "error", err)
+ next(w, r)
+ return
+ }
+
+ valid, err := auth.ValidateToken(value)
+ if err != nil {
+ slog.Error("Error validating token", "error", err, "cookie", cookie.Value)
+ next(w, r)
+ return
+ }
+
+ ctx := r.Context()
+ ctx = context.WithValue(ctx, "logged", true)
+
+ slog.Info("Validated token", "valid?", valid)
+ next(w, r.WithContext(ctx))
+ }
+ }
+}
diff --git a/pkg/ext/router.go b/pkg/ext/router.go
index 96da1c9..956254d 100644
--- a/pkg/ext/router.go
+++ b/pkg/ext/router.go
@@ -23,6 +23,7 @@ func NewRouter() *Router {
router: http.NewServeMux(),
}
}
+
func (r *Router) Handler() http.Handler {
return r.router
}
@@ -35,9 +36,9 @@ func wrapError(next ErrorRequestHandler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := next(w, r); err != nil {
if errors.Is(err, service.ErrRepositoryNotFound) {
- NotFound(w)
+ NotFound(w, r)
} else {
- InternalServerError(w, err)
+ InternalServerError(r, w, err)
}
}
}
@@ -57,16 +58,21 @@ func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) {
r.router.HandleFunc(path, r.run(handler))
}
-func NotFound(w http.ResponseWriter) {
+func NotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
templates.WritePageTemplate(w, &templates.ErrorPage{
Message: "Not Found",
- })
+ }, r.Context())
+}
+
+func Redirect(w http.ResponseWriter, location string) {
+ w.Header().Add("location", location)
+ w.WriteHeader(http.StatusTemporaryRedirect)
}
-func InternalServerError(w http.ResponseWriter, err error) {
+func InternalServerError(r *http.Request, w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusInternalServerError)
templates.WritePageTemplate(w, &templates.ErrorPage{
Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
- })
+ }, r.Context())
}
diff --git a/pkg/handler/about/handler.go b/pkg/handler/about/handler.go
index ac3d314..ee084cd 100644
--- a/pkg/handler/about/handler.go
+++ b/pkg/handler/about/handler.go
@@ -26,7 +26,7 @@ func NewAboutHandler(configRepo configurationRepository) *AboutHandler {
return &AboutHandler{configRepo.GetRootReadme()}
}
-func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) error {
+func (g *AboutHandler) About(w http.ResponseWriter, r *http.Request) error {
f, err := os.Open(g.readmePath)
if err != nil {
return err
@@ -50,6 +50,6 @@ func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) error {
gitList := &templates.AboutPage{
Body: bs,
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
diff --git a/pkg/handler/auth/login.go b/pkg/handler/auth/login.go
index 7e77a67..7014548 100644
--- a/pkg/handler/auth/login.go
+++ b/pkg/handler/auth/login.go
@@ -1,20 +1,87 @@
package auth
import (
+ "encoding/base64"
"net/http"
+ "time"
"git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/templates"
)
type (
- LoginHandler struct{}
+ LoginHandler struct {
+ auth authService
+ }
+
+ authService interface {
+ CheckAuth(username, password string) bool
+ IssueToken() ([]byte, error)
+ }
)
+func NewLoginHandler(auth authService) *LoginHandler {
+ return &LoginHandler{
+ auth: auth,
+ }
+}
+
+func (g *LoginHandler) Logout(w http.ResponseWriter, r *http.Request) error {
+ cookie := &http.Cookie{
+ Name: "auth",
+ Value: "",
+ Path: "/",
+ Expires: time.Unix(0, 0),
+ }
+
+ referer := r.Header.Get("Referer")
+ if referer == "" {
+ referer = "/"
+ }
+
+ http.SetCookie(w, cookie)
+ ext.Redirect(w, referer)
+ return nil
+}
+
func (g *LoginHandler) Login(w http.ResponseWriter, r *http.Request) error {
- ext.SetHTML(w)
+ if r.Method == "GET" {
+ ext.SetHTML(w)
+
+ login := &templates.LoginPage{}
+ templates.WritePageTemplate(w, login, r.Context())
+ } else if r.Method == "POST" {
+
+ username := r.FormValue("username")
+ password := r.FormValue("password")
+
+ if !g.auth.CheckAuth(username, password) {
+ login := &templates.LoginPage{
+ ErrorMessage: "Invalid login",
+ }
+ templates.WritePageTemplate(w, login, r.Context())
+ } else {
+
+ bytes, err := g.auth.IssueToken()
+ if err != nil {
+ return err
+ }
+
+ cookie := &http.Cookie{
+ Name: "auth",
+ Value: base64.StdEncoding.EncodeToString(bytes),
+ Path: "/",
+ MaxAge: 3600,
+ HttpOnly: true,
+ Secure: true,
+ SameSite: http.SameSiteStrictMode,
+ }
+
+ http.SetCookie(w, cookie)
+ ext.Redirect(w, "/")
+ }
+
+ }
- login := &templates.LoginPage{}
- templates.WritePageTemplate(w, login)
return nil
}
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
index 5739c8e..4276159 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -43,7 +43,7 @@ func NewGitHandler(gitService *service.GitService, confRepo configurationReposit
}
}
-func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
+func (g *GitHandler) List(w http.ResponseWriter, r *http.Request) error {
repos, err := g.gitService.ListRepositories()
if err != nil {
return err
@@ -73,7 +73,7 @@ func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
Respositories: repos,
About: bs,
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -85,7 +85,7 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
// TODO: remove it once we can support more than gzip
if !strings.HasSuffix(file, ".tar.gz") {
- ext.NotFound(w)
+ ext.NotFound(w, r)
return nil
}
@@ -135,7 +135,7 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
Commits: commits,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -155,7 +155,7 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
GitItemBase: &templates.GitItemAboutPage{
About: []byte("About file not configured properly"),
},
- })
+ }, r.Context())
return nil
}
if err != nil {
@@ -179,7 +179,7 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
About: bs,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -210,7 +210,7 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
Branches: branches,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -239,7 +239,7 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
Tree: tree,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -270,7 +270,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
Content: []byte("Binary file"),
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -307,7 +307,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
Content: code.Bytes(),
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -328,7 +328,7 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
Commits: commits,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -355,7 +355,7 @@ func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
Diff: diff,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index 32bd78a..ee4081b 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -17,12 +17,13 @@ import (
// its sub package don't leak in other places.
func MountHandler(
gitService *service.GitService,
+ authService *service.AuthService,
configRepo *serverconfig.ConfigurationRepository,
) (http.Handler, error) {
var (
gitHandler = git.NewGitHandler(gitService, configRepo)
aboutHandler = about.NewAboutHandler(configRepo)
- loginHandler = &auth.LoginHandler{}
+ loginHandler = auth.NewLoginHandler(authService)
)
staticHandler, err := static.ServeStaticHandler()
@@ -32,10 +33,12 @@ func MountHandler(
mux := ext.NewRouter()
mux.AddMiddleware(ext.Compress)
+ mux.AddMiddleware(ext.Authenticate(authService))
mux.AddMiddleware(ext.Log)
mux.HandleFunc("/static/{file}", staticHandler)
mux.HandleFunc("/login/{$}", loginHandler.Login)
+ mux.HandleFunc("/logout/{$}", loginHandler.Logout)
mux.HandleFunc("/{name}/about/{$}", gitHandler.About)
mux.HandleFunc("/{name}/", gitHandler.Summary)
mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
diff --git a/pkg/service/auth.go b/pkg/service/auth.go
index 1fbf4b6..0dbd960 100644
--- a/pkg/service/auth.go
+++ b/pkg/service/auth.go
@@ -23,7 +23,13 @@ type (
}
)
-var tokenSeed = []byte("cerrado")
+var tokenSeed = []byte("this is a token for cerrado")
+
+func NewAuthService(repostiory authRepository) *AuthService {
+ return &AuthService{
+ authRepository: repostiory,
+ }
+}
func (a *AuthService) CheckAuth(username, password string) bool {
passphrase := a.authRepository.GetPassphrase()
diff --git a/pkg/service/git.go b/pkg/service/git.go
index f03ba42..6c3912f 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -30,9 +30,7 @@ type (
}
)
-var (
- ErrRepositoryNotFound = errors.New("Repository not found")
-)
+var ErrRepositoryNotFound = errors.New("Repository not found")
// TODO: make it configurable
const timeFormat = "2006.01.02 15:04:05"