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[:]) }