api.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package controller
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/mhsanaei/3x-ui/v3/internal/web/middleware"
  6. "github.com/mhsanaei/3x-ui/v3/internal/web/service/panel"
  7. "github.com/mhsanaei/3x-ui/v3/internal/web/service/tgbot"
  8. "github.com/mhsanaei/3x-ui/v3/internal/web/session"
  9. "github.com/gin-gonic/gin"
  10. )
  11. // APIController handles the main API routes for the 3x-ui panel, including inbounds and server management.
  12. type APIController struct {
  13. BaseController
  14. inboundController *InboundController
  15. serverController *ServerController
  16. nodeController *NodeController
  17. hostController *HostController
  18. settingController *SettingController
  19. xraySettingController *XraySettingController
  20. userService panel.UserService
  21. apiTokenService panel.ApiTokenService
  22. Tgbot tgbot.Tgbot
  23. }
  24. // NewAPIController creates a new APIController instance and initializes its routes.
  25. func NewAPIController(g *gin.RouterGroup) *APIController {
  26. a := &APIController{}
  27. a.initRouter(g)
  28. return a
  29. }
  30. func (a *APIController) checkAPIAuth(c *gin.Context) {
  31. // A verified client certificate (a completed mTLS handshake) authenticates
  32. // the caller, equivalent to a valid bearer token. api_authed must be set so
  33. // the CSRF middleware lets cert-authed mutations through.
  34. if c.Request.TLS != nil && len(c.Request.TLS.VerifiedChains) > 0 {
  35. if u, err := a.userService.GetFirstUser(); err == nil {
  36. session.SetAPIAuthUser(c, u)
  37. }
  38. c.Set("api_authed", true)
  39. c.Next()
  40. return
  41. }
  42. auth := c.GetHeader("Authorization")
  43. if after, ok := strings.CutPrefix(auth, "Bearer "); ok {
  44. tok := after
  45. if a.apiTokenService.Match(tok) {
  46. if u, err := a.userService.GetFirstUser(); err == nil {
  47. session.SetAPIAuthUser(c, u)
  48. }
  49. c.Set("api_authed", true)
  50. c.Next()
  51. return
  52. }
  53. }
  54. if !session.IsLogin(c) {
  55. if c.GetHeader("X-Requested-With") == "XMLHttpRequest" {
  56. c.AbortWithStatus(http.StatusUnauthorized)
  57. } else {
  58. c.AbortWithStatus(http.StatusNotFound)
  59. }
  60. return
  61. }
  62. c.Next()
  63. }
  64. // initRouter sets up the API routes for inbounds, server, and other endpoints.
  65. func (a *APIController) initRouter(g *gin.RouterGroup) {
  66. // Main API group
  67. api := g.Group("/panel/api")
  68. api.Use(a.checkAPIAuth)
  69. // Decode + verify the node config envelope (zstd + X-Config-Sha256) and
  70. // advertise support, before CSRF/handlers read the body.
  71. api.Use(middleware.ConfigEnvelopeMiddleware())
  72. api.Use(middleware.CSRFMiddleware())
  73. // Inbounds API
  74. inbounds := api.Group("/inbounds")
  75. a.inboundController = NewInboundController(inbounds)
  76. clients := api.Group("/clients")
  77. NewClientController(clients)
  78. NewGroupController(clients)
  79. // Server API
  80. server := api.Group("/server")
  81. a.serverController = NewServerController(server)
  82. // Nodes API — multi-panel management
  83. nodes := api.Group("/nodes")
  84. a.nodeController = NewNodeController(nodes)
  85. // Hosts API — per-inbound override endpoints for subscription links
  86. hosts := api.Group("/hosts")
  87. a.hostController = NewHostController(hosts)
  88. // Settings + Xray config management live under the API surface too, so the
  89. // same API token drives them. Paths are /panel/api/setting/* and
  90. // /panel/api/xray/*.
  91. a.settingController = NewSettingController(api)
  92. a.xraySettingController = NewXraySettingController(api)
  93. // Extra routes
  94. api.POST("/backuptotgbot", a.BackuptoTgbot)
  95. }
  96. // BackuptoTgbot sends a backup of the panel data to Telegram bot admins.
  97. func (a *APIController) BackuptoTgbot(c *gin.Context) {
  98. a.Tgbot.SendBackupToAdmins()
  99. }