mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 09:36:05 +00:00
- Vite dev server reads webBasePath from x-ui.db via node:sqlite and injects __X_UI_BASE_PATH__ on every HTML serve, mirroring dist.go. Single broad proxy regex catches backend routes whether the URL is prefixed or not, and the bypass serves login.html for the bare basePath URL so post-logout navigation lands on Vite's own page instead of the production dist HTML's hashed asset URLs. - axios.defaults.baseURL is set from __X_UI_BASE_PATH__ at startup so HttpUtil calls reach the backend's basePath group instead of 404ing on every prefixed install. fetch() for the public CSRF endpoint prepends the prefix manually since it doesn't honor axios defaults. - Logout/redirect responses set Cache-Control: no-store and the index handler's logged-in redirect uses an absolute base_path+panel/ URL, preventing browsers from replaying a stale cached 307 that bounced the user back to /panel/ after logout. - ClearSession also issues a Path=/ deletion cookie when basePath is not "/", so a legacy cookie from an earlier basePath setting can't keep IsLogin returning true after logout. - getPanelUpdateInfo no longer returns a translated error message on GitHub fetch failures, so HttpUtil's auto-popup stays quiet on offline / blocked environments. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
98 lines
1.8 KiB
Go
98 lines
1.8 KiB
Go
package session
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
|
"github.com/mhsanaei/3x-ui/v2/logger"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
const (
|
|
loginUserKey = "LOGIN_USER"
|
|
apiAuthUserKey = "api_auth_user"
|
|
sessionCookieName = "3x-ui"
|
|
)
|
|
|
|
func init() {
|
|
gob.Register(model.User{})
|
|
}
|
|
|
|
func SetLoginUser(c *gin.Context, user *model.User) error {
|
|
if user == nil {
|
|
return nil
|
|
}
|
|
s := sessions.Default(c)
|
|
s.Set(loginUserKey, *user)
|
|
return s.Save()
|
|
}
|
|
|
|
func SetAPIAuthUser(c *gin.Context, user *model.User) {
|
|
if user == nil {
|
|
return
|
|
}
|
|
c.Set(apiAuthUserKey, user)
|
|
}
|
|
|
|
func GetLoginUser(c *gin.Context) *model.User {
|
|
if v, ok := c.Get(apiAuthUserKey); ok {
|
|
if u, ok2 := v.(*model.User); ok2 {
|
|
return u
|
|
}
|
|
}
|
|
s := sessions.Default(c)
|
|
obj := s.Get(loginUserKey)
|
|
if obj == nil {
|
|
return nil
|
|
}
|
|
user, ok := obj.(model.User)
|
|
if !ok {
|
|
s.Delete(loginUserKey)
|
|
if err := s.Save(); err != nil {
|
|
logger.Warning("session: failed to drop stale user payload:", err)
|
|
}
|
|
return nil
|
|
}
|
|
return &user
|
|
}
|
|
|
|
func IsLogin(c *gin.Context) bool {
|
|
return GetLoginUser(c) != nil
|
|
}
|
|
|
|
func ClearSession(c *gin.Context) error {
|
|
s := sessions.Default(c)
|
|
s.Clear()
|
|
cookiePath := c.GetString("base_path")
|
|
if cookiePath == "" {
|
|
cookiePath = "/"
|
|
}
|
|
secure := c.Request.TLS != nil
|
|
s.Options(sessions.Options{
|
|
Path: cookiePath,
|
|
MaxAge: -1,
|
|
HttpOnly: true,
|
|
Secure: secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
if err := s.Save(); err != nil {
|
|
return err
|
|
}
|
|
if cookiePath != "/" {
|
|
http.SetCookie(c.Writer, &http.Cookie{
|
|
Name: sessionCookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
MaxAge: -1,
|
|
Expires: time.Unix(0, 0),
|
|
HttpOnly: true,
|
|
Secure: secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
}
|
|
return nil
|
|
}
|