package server import ( "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) { writeError(writer, http.StatusTooManyRequests, "too many failed attempts, try again later") return } var body loginRequest if err := decodeJSON(request, &body); err != nil { writeError(writer, http.StatusBadRequest, "invalid request body") return } if !auth.CredentialsMatch(server.settings.Username, server.settings.Password, body.Username, body.Password) { server.limiter.RecordFailure(client) writeError(writer, http.StatusUnauthorized, "invalid username or password") return } server.limiter.Reset(client) token, err := server.sessions.Create() if err != nil { writeError(writer, http.StatusInternalServerError, "could not create session") return } 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 }