mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-08 18:56:37 +08:00
chore: remove obsolete root-level legacy Go files
This commit is contained in:
-42
@@ -1,42 +0,0 @@
|
|||||||
// Package controller provides HTTP request handlers and controllers for the 3x-ui web management panel.
|
|
||||||
// It handles routing, authentication, and API endpoints for managing Xray inbounds, settings, and more.
|
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/logger"
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/web/locale"
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/web/session"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BaseController provides common functionality for all controllers, including authentication checks.
|
|
||||||
type BaseController struct{}
|
|
||||||
|
|
||||||
// checkLogin is a middleware that verifies user authentication and handles unauthorized access.
|
|
||||||
func (a *BaseController) checkLogin(c *gin.Context) {
|
|
||||||
if !session.IsLogin(c) {
|
|
||||||
if isAjax(c) {
|
|
||||||
pureJsonMsg(c, http.StatusUnauthorized, false, I18nWeb(c, "pages.login.loginAgain"))
|
|
||||||
} else {
|
|
||||||
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
|
|
||||||
}
|
|
||||||
c.Abort()
|
|
||||||
} else {
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// I18nWeb retrieves an internationalized message for the web interface based on the current locale.
|
|
||||||
func I18nWeb(c *gin.Context, name string, params ...string) string {
|
|
||||||
anyfunc, funcExists := c.Get("I18n")
|
|
||||||
if !funcExists {
|
|
||||||
logger.Warning("I18n function not exists in gin context!")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
i18nFunc, _ := anyfunc.(func(i18nType locale.I18nType, key string, keyParams ...string) string)
|
|
||||||
msg := i18nFunc(locale.Web, name, params...)
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
-424
@@ -1,424 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/database/model"
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/web/service"
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/web/session"
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/web/websocket"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InboundController handles HTTP requests related to Xray inbounds management.
|
|
||||||
type InboundController struct {
|
|
||||||
inboundService service.InboundService
|
|
||||||
xrayService service.XrayService
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInboundController creates a new InboundController and sets up its routes.
|
|
||||||
func NewInboundController(g *gin.RouterGroup) *InboundController {
|
|
||||||
a := &InboundController{}
|
|
||||||
a.initRouter(g)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// initRouter initializes the routes for inbound-related operations.
|
|
||||||
func (a *InboundController) initRouter(g *gin.RouterGroup) {
|
|
||||||
|
|
||||||
g.GET("/list", a.getInbounds)
|
|
||||||
g.GET("/get/:id", a.getInbound)
|
|
||||||
g.GET("/getClientTraffics/:email", a.getClientTraffics)
|
|
||||||
g.GET("/getClientTrafficsById/:id", a.getClientTrafficsById)
|
|
||||||
|
|
||||||
g.POST("/add", a.addInbound)
|
|
||||||
g.POST("/del/:id", a.delInbound)
|
|
||||||
g.POST("/update/:id", a.updateInbound)
|
|
||||||
g.POST("/clientIps/:email", a.getClientIps)
|
|
||||||
g.POST("/clearClientIps/:email", a.clearClientIps)
|
|
||||||
g.POST("/addClient", a.addInboundClient)
|
|
||||||
g.POST("/:id/delClient/:clientId", a.delInboundClient)
|
|
||||||
g.POST("/updateClient/:clientId", a.updateInboundClient)
|
|
||||||
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
|
|
||||||
g.POST("/resetAllTraffics", a.resetAllTraffics)
|
|
||||||
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
|
|
||||||
g.POST("/delDepletedClients/:id", a.delDepletedClients)
|
|
||||||
g.POST("/import", a.importInbound)
|
|
||||||
g.POST("/onlines", a.onlines)
|
|
||||||
g.POST("/lastOnline", a.lastOnline)
|
|
||||||
g.POST("/updateClientTraffic/:email", a.updateClientTraffic)
|
|
||||||
g.POST("/:id/delClientByEmail/:email", a.delInboundClientByEmail)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getInbounds retrieves the list of inbounds for the logged-in user.
|
|
||||||
func (a *InboundController) getInbounds(c *gin.Context) {
|
|
||||||
user := session.GetLoginUser(c)
|
|
||||||
inbounds, err := a.inboundService.GetInbounds(user.Id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.obtain"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonObj(c, inbounds, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getInbound retrieves a specific inbound by its ID.
|
|
||||||
func (a *InboundController) getInbound(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "get"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inbound, err := a.inboundService.GetInbound(id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.obtain"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonObj(c, inbound, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClientTraffics retrieves client traffic information by email.
|
|
||||||
func (a *InboundController) getClientTraffics(c *gin.Context) {
|
|
||||||
email := c.Param("email")
|
|
||||||
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.trafficGetError"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonObj(c, clientTraffics, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClientTrafficsById retrieves client traffic information by inbound ID.
|
|
||||||
func (a *InboundController) getClientTrafficsById(c *gin.Context) {
|
|
||||||
id := c.Param("id")
|
|
||||||
clientTraffics, err := a.inboundService.GetClientTrafficByID(id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.trafficGetError"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonObj(c, clientTraffics, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addInbound creates a new inbound configuration.
|
|
||||||
func (a *InboundController) addInbound(c *gin.Context) {
|
|
||||||
inbound := &model.Inbound{}
|
|
||||||
err := c.ShouldBind(inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundCreateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
user := session.GetLoginUser(c)
|
|
||||||
inbound.UserId = user.Id
|
|
||||||
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
|
||||||
} else {
|
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
inbound, needRestart, err := a.inboundService.AddInbound(inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsgObj(c, I18nWeb(c, "pages.inbounds.toasts.inboundCreateSuccess"), inbound, nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
// Broadcast inbounds update via WebSocket
|
|
||||||
inbounds, _ := a.inboundService.GetInbounds(user.Id)
|
|
||||||
websocket.BroadcastInbounds(inbounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delInbound deletes an inbound configuration by its ID.
|
|
||||||
func (a *InboundController) delInbound(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundDeleteSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
needRestart, err := a.inboundService.DelInbound(id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsgObj(c, I18nWeb(c, "pages.inbounds.toasts.inboundDeleteSuccess"), id, nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
// Broadcast inbounds update via WebSocket
|
|
||||||
user := session.GetLoginUser(c)
|
|
||||||
inbounds, _ := a.inboundService.GetInbounds(user.Id)
|
|
||||||
websocket.BroadcastInbounds(inbounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateInbound updates an existing inbound configuration.
|
|
||||||
func (a *InboundController) updateInbound(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inbound := &model.Inbound{
|
|
||||||
Id: id,
|
|
||||||
}
|
|
||||||
err = c.ShouldBind(inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inbound, needRestart, err := a.inboundService.UpdateInbound(inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsgObj(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), inbound, nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
// Broadcast inbounds update via WebSocket
|
|
||||||
user := session.GetLoginUser(c)
|
|
||||||
inbounds, _ := a.inboundService.GetInbounds(user.Id)
|
|
||||||
websocket.BroadcastInbounds(inbounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClientIps retrieves the IP addresses associated with a client by email.
|
|
||||||
func (a *InboundController) getClientIps(c *gin.Context) {
|
|
||||||
email := c.Param("email")
|
|
||||||
|
|
||||||
ips, err := a.inboundService.GetInboundClientIps(email)
|
|
||||||
if err != nil || ips == "" {
|
|
||||||
jsonObj(c, "No IP Record", nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonObj(c, ips, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearClientIps clears the IP addresses for a client by email.
|
|
||||||
func (a *InboundController) clearClientIps(c *gin.Context) {
|
|
||||||
email := c.Param("email")
|
|
||||||
|
|
||||||
err := a.inboundService.ClearClientIps(email)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.updateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.logCleanSuccess"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addInboundClient adds a new client to an existing inbound.
|
|
||||||
func (a *InboundController) addInboundClient(c *gin.Context) {
|
|
||||||
data := &model.Inbound{}
|
|
||||||
err := c.ShouldBind(data)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart, err := a.inboundService.AddInboundClient(data)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientAddSuccess"), nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delInboundClient deletes a client from an inbound by inbound ID and client ID.
|
|
||||||
func (a *InboundController) delInboundClient(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientId := c.Param("clientId")
|
|
||||||
|
|
||||||
needRestart, err := a.inboundService.DelInboundClient(id, clientId)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientDeleteSuccess"), nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateInboundClient updates a client's configuration in an inbound.
|
|
||||||
func (a *InboundController) updateInboundClient(c *gin.Context) {
|
|
||||||
clientId := c.Param("clientId")
|
|
||||||
|
|
||||||
inbound := &model.Inbound{}
|
|
||||||
err := c.ShouldBind(inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart, err := a.inboundService.UpdateInboundClient(inbound, clientId)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientUpdateSuccess"), nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resetClientTraffic resets the traffic counter for a specific client in an inbound.
|
|
||||||
func (a *InboundController) resetClientTraffic(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
email := c.Param("email")
|
|
||||||
|
|
||||||
needRestart, err := a.inboundService.ResetClientTraffic(id, email)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetInboundClientTrafficSuccess"), nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resetAllTraffics resets all traffic counters across all inbounds.
|
|
||||||
func (a *InboundController) resetAllTraffics(c *gin.Context) {
|
|
||||||
err := a.inboundService.ResetAllTraffics()
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllTrafficSuccess"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resetAllClientTraffics resets traffic counters for all clients in a specific inbound.
|
|
||||||
func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.inboundService.ResetAllClientTraffics(id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllClientTrafficSuccess"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// importInbound imports an inbound configuration from provided data.
|
|
||||||
func (a *InboundController) importInbound(c *gin.Context) {
|
|
||||||
inbound := &model.Inbound{}
|
|
||||||
err := json.Unmarshal([]byte(c.PostForm("data")), inbound)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
user := session.GetLoginUser(c)
|
|
||||||
inbound.Id = 0
|
|
||||||
inbound.UserId = user.Id
|
|
||||||
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
|
||||||
} else {
|
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
for index := range inbound.ClientStats {
|
|
||||||
inbound.ClientStats[index].Id = 0
|
|
||||||
inbound.ClientStats[index].Enable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart := false
|
|
||||||
inbound, needRestart, err = a.inboundService.AddInbound(inbound)
|
|
||||||
jsonMsgObj(c, I18nWeb(c, "pages.inbounds.toasts.inboundCreateSuccess"), inbound, err)
|
|
||||||
if err == nil && needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delDepletedClients deletes clients in an inbound who have exhausted their traffic limits.
|
|
||||||
func (a *InboundController) delDepletedClients(c *gin.Context) {
|
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = a.inboundService.DelDepletedClients(id)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.delDepletedClientsSuccess"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// onlines retrieves the list of currently online clients.
|
|
||||||
func (a *InboundController) onlines(c *gin.Context) {
|
|
||||||
jsonObj(c, a.inboundService.GetOnlineClients(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lastOnline retrieves the last online timestamps for clients.
|
|
||||||
func (a *InboundController) lastOnline(c *gin.Context) {
|
|
||||||
data, err := a.inboundService.GetClientsLastOnline()
|
|
||||||
jsonObj(c, data, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateClientTraffic updates the traffic statistics for a client by email.
|
|
||||||
func (a *InboundController) updateClientTraffic(c *gin.Context) {
|
|
||||||
email := c.Param("email")
|
|
||||||
|
|
||||||
// Define the request structure for traffic update
|
|
||||||
type TrafficUpdateRequest struct {
|
|
||||||
Upload int64 `json:"upload"`
|
|
||||||
Download int64 `json:"download"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var request TrafficUpdateRequest
|
|
||||||
err := c.ShouldBindJSON(&request)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.inboundService.UpdateClientTrafficByEmail(email, request.Upload, request.Download)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientUpdateSuccess"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delInboundClientByEmail deletes a client from an inbound by email address.
|
|
||||||
func (a *InboundController) delInboundClientByEmail(c *gin.Context) {
|
|
||||||
inboundId, err := strconv.Atoi(c.Param("id"))
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Invalid inbound ID", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
email := c.Param("email")
|
|
||||||
needRestart, err := a.inboundService.DelInboundClientByEmail(inboundId, email)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Failed to delete client by email", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonMsg(c, "Client deleted successfully", nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// XUIController is the main controller for the X-UI panel, managing sub-controllers.
|
|
||||||
type XUIController struct {
|
|
||||||
BaseController
|
|
||||||
|
|
||||||
settingController *SettingController
|
|
||||||
xraySettingController *XraySettingController
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewXUIController creates a new XUIController and initializes its routes.
|
|
||||||
func NewXUIController(g *gin.RouterGroup) *XUIController {
|
|
||||||
a := &XUIController{}
|
|
||||||
a.initRouter(g)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// initRouter sets up the main panel routes and initializes sub-controllers.
|
|
||||||
func (a *XUIController) initRouter(g *gin.RouterGroup) {
|
|
||||||
g = g.Group("/panel")
|
|
||||||
g.Use(a.checkLogin)
|
|
||||||
|
|
||||||
g.GET("/", a.index)
|
|
||||||
g.GET("/inbounds", a.inbounds)
|
|
||||||
g.GET("/settings", a.settings)
|
|
||||||
g.GET("/xray", a.xraySettings)
|
|
||||||
|
|
||||||
a.settingController = NewSettingController(g)
|
|
||||||
a.xraySettingController = NewXraySettingController(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
// index renders the main panel index page.
|
|
||||||
func (a *XUIController) index(c *gin.Context) {
|
|
||||||
html(c, "index.html", "pages.index.title", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// inbounds renders the inbounds management page.
|
|
||||||
func (a *XUIController) inbounds(c *gin.Context) {
|
|
||||||
html(c, "inbounds.html", "pages.inbounds.title", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// settings renders the settings management page.
|
|
||||||
func (a *XUIController) settings(c *gin.Context) {
|
|
||||||
html(c, "settings.html", "pages.settings.title", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// xraySettings renders the Xray settings page.
|
|
||||||
func (a *XUIController) xraySettings(c *gin.Context) {
|
|
||||||
html(c, "xray.html", "pages.xray.title", nil)
|
|
||||||
}
|
|
||||||
-89
@@ -1,89 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func JWTAuth() gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
|
|
||||||
token := utils.GetToken(c)
|
|
||||||
if token == "" {
|
|
||||||
response.NoAuth("未登录或非法访问,请登录", c)
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isBlacklist(token) {
|
|
||||||
response.NoAuth("您的帐户异地登陆或令牌失效", c)
|
|
||||||
utils.ClearToken(c)
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
j := utils.NewJWT()
|
|
||||||
// parseToken 解析token包含的信息
|
|
||||||
claims, err := j.ParseToken(token)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, utils.TokenExpired) {
|
|
||||||
response.NoAuth("登录已过期,请重新登录", c)
|
|
||||||
utils.ClearToken(c)
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
response.NoAuth(err.Error(), c)
|
|
||||||
utils.ClearToken(c)
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 已登录用户被管理员禁用 需要使该用户的jwt失效 此处比较消耗性能 如果需要 请自行打开
|
|
||||||
// 用户被删除的逻辑 需要优化 此处比较消耗性能 如果需要 请自行打开
|
|
||||||
|
|
||||||
//if user, err := userService.FindUserByUuid(claims.UUID.String()); err != nil || user.Enable == 2 {
|
|
||||||
// _ = jwtService.JsonInBlacklist(system.JwtBlacklist{Jwt: token})
|
|
||||||
// response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c)
|
|
||||||
// c.Abort()
|
|
||||||
//}
|
|
||||||
c.Set("claims", claims)
|
|
||||||
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
|
||||||
dr, _ := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
|
||||||
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(dr))
|
|
||||||
newToken, _ := j.CreateTokenByOldToken(token, *claims)
|
|
||||||
newClaims, _ := j.ParseToken(newToken)
|
|
||||||
c.Header("new-token", newToken)
|
|
||||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10))
|
|
||||||
utils.SetToken(c, newToken, int(dr.Seconds()/60))
|
|
||||||
if global.GVA_CONFIG.System.UseMultipoint {
|
|
||||||
// 记录新的活跃jwt
|
|
||||||
_ = utils.SetRedisJWT(newToken, newClaims.Username)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.Next()
|
|
||||||
|
|
||||||
if newToken, exists := c.Get("new-token"); exists {
|
|
||||||
c.Header("new-token", newToken.(string))
|
|
||||||
}
|
|
||||||
if newExpiresAt, exists := c.Get("new-expires-at"); exists {
|
|
||||||
c.Header("new-expires-at", newExpiresAt.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@author: [piexlmax](https://github.com/piexlmax)
|
|
||||||
//@function: IsBlacklist
|
|
||||||
//@description: 判断JWT是否在黑名单内部
|
|
||||||
//@param: jwt string
|
|
||||||
//@return: bool
|
|
||||||
|
|
||||||
func isBlacklist(jwt string) bool {
|
|
||||||
_, ok := global.BlackCache.Get(jwt)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package response
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Response struct {
|
|
||||||
Code int `json:"code"`
|
|
||||||
Data interface{} `json:"data"`
|
|
||||||
Msg string `json:"msg"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
ERROR = 7
|
|
||||||
SUCCESS = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
func Result(code int, data interface{}, msg string, c *gin.Context) {
|
|
||||||
c.JSON(http.StatusOK, Response{
|
|
||||||
code,
|
|
||||||
data,
|
|
||||||
msg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Ok(c *gin.Context) {
|
|
||||||
Result(SUCCESS, map[string]interface{}{}, "操作成功", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OkWithMessage(message string, c *gin.Context) {
|
|
||||||
Result(SUCCESS, map[string]interface{}{}, message, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OkWithData(data interface{}, c *gin.Context) {
|
|
||||||
Result(SUCCESS, data, "成功", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OkWithDetailed(data interface{}, message string, c *gin.Context) {
|
|
||||||
Result(SUCCESS, data, message, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Fail(c *gin.Context) {
|
|
||||||
Result(ERROR, map[string]interface{}{}, "操作失败", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FailWithMessage(message string, c *gin.Context) {
|
|
||||||
Result(ERROR, map[string]interface{}{}, message, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NoAuth(message string, c *gin.Context) {
|
|
||||||
c.JSON(http.StatusUnauthorized, Response{
|
|
||||||
7,
|
|
||||||
nil,
|
|
||||||
message,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func FailWithDetailed(data interface{}, message string, c *gin.Context) {
|
|
||||||
Result(ERROR, data, message, c)
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UserRouter struct{}
|
|
||||||
|
|
||||||
func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
|
|
||||||
userRouter := Router.Group("user").Use(middleware.OperationRecord())
|
|
||||||
userRouterWithoutRecord := Router.Group("user")
|
|
||||||
{
|
|
||||||
userRouter.POST("admin_register", baseApi.Register) // 管理员注册账号
|
|
||||||
userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码
|
|
||||||
userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限
|
|
||||||
userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户
|
|
||||||
userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息
|
|
||||||
userRouter.PUT("setSelfInfo", baseApi.SetSelfInfo) // 设置自身信息
|
|
||||||
userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组
|
|
||||||
userRouter.POST("resetPassword", baseApi.ResetPassword) // 重置用户密码
|
|
||||||
userRouter.PUT("setSelfSetting", baseApi.SetSelfSetting) // 用户界面配置
|
|
||||||
}
|
|
||||||
{
|
|
||||||
userRouterWithoutRecord.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表
|
|
||||||
userRouterWithoutRecord.GET("getUserInfo", baseApi.GetUserInfo) // 获取自身信息
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user