diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/config/config.go | 16 | ||||
| -rw-r--r-- | pkg/ext/auth.go | 45 | ||||
| -rw-r--r-- | pkg/ext/router.go | 18 | ||||
| -rw-r--r-- | pkg/handler/about/handler.go | 4 | ||||
| -rw-r--r-- | pkg/handler/auth/login.go | 75 | ||||
| -rw-r--r-- | pkg/handler/git/handler.go | 24 | ||||
| -rw-r--r-- | pkg/handler/router.go | 5 | ||||
| -rw-r--r-- | pkg/service/auth.go | 8 | ||||
| -rw-r--r-- | pkg/service/git.go | 4 | 
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" | 
