Update application UI and functionality
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
@@ -31,6 +32,8 @@ type router struct {
|
||||
publicSnapshots *publicSnapshotService
|
||||
}
|
||||
|
||||
const loginRequestTimeout = 5 * time.Second
|
||||
|
||||
func NewRouter(cfg *config.Config, store *db.Store, authService *auth.Service, feedbackService *feedback.Service, releaseService *releases.Service, sourceService *sources.Service, legacyService *legacy.Service, optional ...any) http.Handler {
|
||||
r := &router{
|
||||
cfg: cfg,
|
||||
@@ -55,7 +58,10 @@ func NewRouter(cfg *config.Config, store *db.Store, authService *auth.Service, f
|
||||
|
||||
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
path := cleanPath(req.URL.Path)
|
||||
if strings.HasPrefix(path, "/api/admin/") && req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
if strings.HasPrefix(path, "/api/admin/") &&
|
||||
path != "/api/admin/auth/login" &&
|
||||
path != "/api/admin/auth/logout" &&
|
||||
req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
captured := &mutationResponseWriter{ResponseWriter: w, status: http.StatusOK}
|
||||
w = captured
|
||||
defer func() {
|
||||
@@ -116,7 +122,7 @@ func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
case strings.HasPrefix(path, "/downloads/"):
|
||||
r.handleDownload(w, req)
|
||||
case strings.HasPrefix(path, "/admin/assets/"):
|
||||
serveStaticAsset(w, req, r.cfg.AdminWebDir, "admin/dist", strings.TrimPrefix(path, "/admin/"))
|
||||
r.serveAdminAsset(w, req, strings.TrimPrefix(path, "/admin/"))
|
||||
case strings.HasPrefix(path, "/assets/"):
|
||||
serveStaticAsset(w, req, r.cfg.PortalWebDir, "portal/dist", strings.TrimPrefix(path, "/"))
|
||||
case strings.HasPrefix(path, "/api/admin/feedbacks"):
|
||||
@@ -196,6 +202,8 @@ func (r *router) handleLogin(w http.ResponseWriter, req *http.Request) {
|
||||
writeError(w, http.StatusMethodNotAllowed, "METHOD_NOT_ALLOWED", errors.New("POST required"))
|
||||
return
|
||||
}
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
req.Body = http.MaxBytesReader(w, req.Body, 64<<10)
|
||||
var body struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
@@ -209,8 +217,14 @@ func (r *router) handleLogin(w http.ResponseWriter, req *http.Request) {
|
||||
if body.Username == "" {
|
||||
body.Username = "admin"
|
||||
}
|
||||
sessionID, csrf, ok, err := r.auth.Login(req.Context(), body.Username, body.Password, body.CaptchaID, body.Captcha, req.RemoteAddr)
|
||||
ctx, cancel := context.WithTimeout(req.Context(), loginRequestTimeout)
|
||||
defer cancel()
|
||||
sessionID, csrf, ok, err := r.auth.Login(ctx, body.Username, body.Password, body.CaptchaID, body.Captcha, req.RemoteAddr)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
|
||||
writeError(w, http.StatusGatewayTimeout, "LOGIN_TIMEOUT", errors.New("login verification timed out"))
|
||||
return
|
||||
}
|
||||
writeError(w, http.StatusInternalServerError, "LOGIN_FAILED", err)
|
||||
return
|
||||
}
|
||||
@@ -219,8 +233,16 @@ func (r *router) handleLogin(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
auth.SetSessionCookieForRequest(w, req, sessionID)
|
||||
_ = r.store.InsertAudit(db.AuditLog{Actor: body.Username, Type: "auth.login", Target: "admin", Message: "管理员登录", IP: req.RemoteAddr, UserAgent: req.UserAgent()})
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true, "csrfToken": csrf, "user": map[string]any{"username": body.Username}})
|
||||
go r.recordLoginAudit(body.Username, req.RemoteAddr, req.UserAgent())
|
||||
}
|
||||
|
||||
func (r *router) recordLoginAudit(username, remoteAddr, userAgent string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
_ = r.store.InsertAuditContext(ctx, db.AuditLog{
|
||||
Actor: username, Type: "auth.login", Target: "admin", Message: "管理员登录", IP: remoteAddr, UserAgent: userAgent,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *router) handleLogout(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user