sabisan/internal/app/auth.go

82 lines
2.4 KiB
Go
Raw Permalink Normal View History

2026-05-16 23:03:50 +00:00
package app
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"net/http"
"time"
"golang.org/x/crypto/bcrypt"
)
func (s *Server) adminLogin(w http.ResponseWriter, r *http.Request) {
s.render(w, "admin_login.html", pageData{Title: "Admin login"})
}
func (s *Server) adminLoginPost(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
s.render(w, "admin_login.html", pageData{Title: "Admin login", Error: "Invalid login request."})
return
}
user, err := s.store.AdminByUsername(r.Context(), r.FormValue("username"))
if err != nil || bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(r.FormValue("password"))) != nil {
s.render(w, "admin_login.html", pageData{Title: "Admin login", Error: "Incorrect username or password."})
return
}
token, err := randomToken()
if err != nil {
s.error(w, err)
return
}
if err := s.store.CreateSession(r.Context(), s.hashToken(token), user.ID, time.Now().Add(24*time.Hour)); err != nil {
s.error(w, err)
return
}
http.SetCookie(w, &http.Cookie{
Name: "archi_session",
Value: token,
Path: "/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
MaxAge: 86400,
})
http.Redirect(w, r, "/admin/main", http.StatusSeeOther)
}
func (s *Server) adminLogout(w http.ResponseWriter, r *http.Request) {
if cookie, err := r.Cookie("archi_session"); err == nil {
_ = s.store.DeleteSession(r.Context(), s.hashToken(cookie.Value))
}
http.SetCookie(w, &http.Cookie{Name: "archi_session", Value: "", Path: "/", MaxAge: -1, HttpOnly: true, SameSite: http.SameSiteLaxMode})
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func (s *Server) requireAdmin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("archi_session")
if err != nil {
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
return
}
if _, err := s.store.SessionUser(r.Context(), s.hashToken(cookie.Value)); err != nil {
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
return
}
next.ServeHTTP(w, r)
})
}
func randomToken() (string, error) {
buf := make([]byte, 32)
if _, err := rand.Read(buf); err != nil {
return "", err
}
return hex.EncodeToString(buf), nil
}
func (s *Server) hashToken(token string) string {
sum := sha256.Sum256([]byte(s.cfg.SessionSecret + ":" + token))
return hex.EncodeToString(sum[:])
}