Files
ddc/internal/server/auth_handlers.go
T

88 lines
2.6 KiB
Go
Executable File

package server
import (
"fmt"
"log/slog"
"net"
"net/http"
"strings"
"ddc/internal/auth"
)
type loginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type sessionResponse struct {
Authenticated bool `json:"authenticated"`
}
func (server *Server) handleLogin(writer http.ResponseWriter, request *http.Request) {
client := server.clientAddress(request)
if !server.limiter.Allowed(client) {
slog.Warn("login blocked after too many failures", "client", client, "request_id", requestIDFrom(request))
writeError(writer, http.StatusTooManyRequests, "too many failed attempts, try again later")
return
}
var body loginRequest
if !decodeBody(writer, request, &body) {
return
}
if !auth.CredentialsMatch(server.settings.Username, server.settings.Password, body.Username, body.Password) {
server.limiter.RecordFailure(client)
slog.Warn("login failed", "client", client, "username", body.Username, "request_id", requestIDFrom(request))
writeError(writer, http.StatusUnauthorized, "invalid username or password")
return
}
server.limiter.Reset(client)
token, err := server.sessions.Create()
if err != nil {
writeFailure(writer, request, fmt.Errorf("could not create session: %w", err))
return
}
slog.Info("login succeeded", "client", client, "request_id", requestIDFrom(request))
http.SetCookie(writer, server.sessionCookie(token, int(server.settings.SessionTTL.Seconds())))
writeJSON(writer, http.StatusOK, sessionResponse{Authenticated: true})
}
func (server *Server) handleLogout(writer http.ResponseWriter, request *http.Request) {
if cookie, err := request.Cookie(sessionCookieName); err == nil {
server.sessions.Delete(cookie.Value)
}
http.SetCookie(writer, server.sessionCookie("", -1))
writeJSON(writer, http.StatusOK, sessionResponse{Authenticated: false})
}
func (server *Server) handleSession(writer http.ResponseWriter, request *http.Request) {
writeJSON(writer, http.StatusOK, sessionResponse{Authenticated: server.authenticated(request)})
}
func (server *Server) sessionCookie(value string, maxAge int) *http.Cookie {
return &http.Cookie{
Name: sessionCookieName,
Value: value,
Path: "/",
MaxAge: maxAge,
HttpOnly: true,
Secure: server.settings.CookieSecure,
SameSite: http.SameSiteStrictMode,
}
}
func (server *Server) clientAddress(request *http.Request) string {
if server.settings.TrustProxyHeaders {
if realIP := strings.TrimSpace(request.Header.Get("X-Real-IP")); realIP != "" {
return realIP
}
}
host, _, err := net.SplitHostPort(request.RemoteAddr)
if err != nil {
return request.RemoteAddr
}
return host
}