89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
package app
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/yourorg/ntfywui/internal/security"
|
|
"github.com/yourorg/ntfywui/internal/store"
|
|
)
|
|
|
|
func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
next := r.URL.Query().Get("next")
|
|
if next == "" {
|
|
next = "/users"
|
|
}
|
|
csrf, _ := s.csrfEnsure(w, r)
|
|
flash := s.popFlash(w, r)
|
|
s.renderer.Render(w, "login.html", PageData{
|
|
Title: "Login",
|
|
CSRF: csrf,
|
|
Flash: flash,
|
|
Next: next,
|
|
})
|
|
case http.MethodPost:
|
|
_ = r.ParseForm()
|
|
user := cleanUser(r.Form.Get("username"))
|
|
pass := r.Form.Get("password")
|
|
totp := strings.TrimSpace(r.Form.Get("totp"))
|
|
next := r.Form.Get("next")
|
|
if next == "" {
|
|
next = "/users"
|
|
}
|
|
// CSRF checked by middleware in routes (we add it by calling s.csrf wrapper above in routes)
|
|
a, ok := s.admins.Authenticate(user, pass, totp)
|
|
if !ok {
|
|
s.audit.Append(store.AuditEvent{
|
|
Actor: user,
|
|
IP: security.RealIP(r, security.RealIPConfig{TrustedProxies: s.cfg.TrustedProxies}),
|
|
UA: r.UserAgent(),
|
|
Action: "login_failed",
|
|
})
|
|
s.setFlash(w, r, "Login fehlgeschlagen")
|
|
http.Redirect(w, r, s.abs("/login"), http.StatusFound)
|
|
return
|
|
}
|
|
|
|
sess, _ := s.sessions.Get(r)
|
|
if sess == nil {
|
|
sess = &security.Session{}
|
|
}
|
|
sess.User = a.Username
|
|
sess.Role = string(a.Role)
|
|
if sess.CSRF == "" {
|
|
tok, _ := security.NewCSRFToken()
|
|
sess.CSRF = tok
|
|
}
|
|
s.sessions.Save(w, sess)
|
|
|
|
s.auditEvent(r, "login_ok", a.Username, map[string]string{"role": string(a.Role)})
|
|
http.Redirect(w, r, s.abs(next), http.StatusFound)
|
|
default:
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
|
|
func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) {
|
|
s.auditEvent(r, "logout", "", nil)
|
|
s.sessions.Clear(w)
|
|
http.Redirect(w, r, s.abs("/login"), http.StatusFound)
|
|
}
|
|
|
|
func (s *Server) csrfEnsure(w http.ResponseWriter, r *http.Request) (string, error) {
|
|
sess, ok := s.sessions.Get(r)
|
|
if !ok {
|
|
sess = &security.Session{}
|
|
}
|
|
if sess.CSRF == "" {
|
|
tok, err := security.NewCSRFToken()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sess.CSRF = tok
|
|
_ = s.sessions.Save(w, sess)
|
|
}
|
|
return sess.CSRF, nil
|
|
}
|