index.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package controller
  2. import (
  3. "net/http"
  4. "text/template"
  5. "time"
  6. "fmt"
  7. "github.com/mhsanaei/3x-ui/v2/logger"
  8. "github.com/mhsanaei/3x-ui/v2/web/service"
  9. "github.com/mhsanaei/3x-ui/v2/web/session"
  10. "github.com/gin-contrib/sessions"
  11. "github.com/gin-gonic/gin"
  12. )
  13. // LoginForm represents the login request structure.
  14. type LoginForm struct {
  15. Username string `json:"username" form:"username"`
  16. Password string `json:"password" form:"password"`
  17. TwoFactorCode string `json:"twoFactorCode" form:"twoFactorCode"`
  18. }
  19. // IndexController handles the main index and login-related routes.
  20. type IndexController struct {
  21. BaseController
  22. settingService service.SettingService
  23. userService service.UserService
  24. tgbot service.Tgbot
  25. }
  26. // NewIndexController creates a new IndexController and initializes its routes.
  27. func NewIndexController(g *gin.RouterGroup) *IndexController {
  28. a := &IndexController{}
  29. a.initRouter(g)
  30. return a
  31. }
  32. // initRouter sets up the routes for index, login, logout, and two-factor authentication.
  33. func (a *IndexController) initRouter(g *gin.RouterGroup) {
  34. g.GET("/", a.index)
  35. g.GET("/logout", a.logout)
  36. g.POST("/login", a.login)
  37. g.POST("/getTwoFactorEnable", a.getTwoFactorEnable)
  38. }
  39. // index handles the root route, redirecting logged-in users to the panel or showing the login page.
  40. func (a *IndexController) index(c *gin.Context) {
  41. if session.IsLogin(c) {
  42. c.Redirect(http.StatusTemporaryRedirect, "panel/")
  43. return
  44. }
  45. html(c, "login.html", "pages.login.title", nil)
  46. }
  47. // login handles user authentication and session creation.
  48. func (a *IndexController) login(c *gin.Context) {
  49. var form LoginForm
  50. if err := c.ShouldBind(&form); err != nil {
  51. pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
  52. return
  53. }
  54. if form.Username == "" {
  55. pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyUsername"))
  56. return
  57. }
  58. if form.Password == "" {
  59. pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyPassword"))
  60. return
  61. }
  62. user, checkErr := a.userService.CheckUser(form.Username, form.Password, form.TwoFactorCode)
  63. timeStr := time.Now().Format("2006-01-02 15:04:05")
  64. safeUser := template.HTMLEscapeString(form.Username)
  65. safePass := template.HTMLEscapeString(form.Password)
  66. if user == nil {
  67. logger.Warningf("wrong username: \"%s\", password: \"%s\", IP: \"%s\"", safeUser, safePass, getRemoteIp(c))
  68. notifyPass := safePass
  69. if checkErr != nil && checkErr.Error() == "invalid 2fa code" {
  70. translatedError := a.tgbot.I18nBot("tgbot.messages.2faFailed")
  71. notifyPass = fmt.Sprintf("*** (%s)", translatedError)
  72. }
  73. a.tgbot.UserLoginNotify(safeUser, notifyPass, getRemoteIp(c), timeStr, 0)
  74. pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
  75. return
  76. }
  77. logger.Infof("%s logged in successfully, Ip Address: %s\n", safeUser, getRemoteIp(c))
  78. a.tgbot.UserLoginNotify(safeUser, ``, getRemoteIp(c), timeStr, 1)
  79. sessionMaxAge, err := a.settingService.GetSessionMaxAge()
  80. if err != nil {
  81. logger.Warning("Unable to get session's max age from DB")
  82. }
  83. session.SetMaxAge(c, sessionMaxAge*60)
  84. session.SetLoginUser(c, user)
  85. if err := sessions.Default(c).Save(); err != nil {
  86. logger.Warning("Unable to save session: ", err)
  87. return
  88. }
  89. logger.Infof("%s logged in successfully", safeUser)
  90. jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), nil)
  91. }
  92. // logout handles user logout by clearing the session and redirecting to the login page.
  93. func (a *IndexController) logout(c *gin.Context) {
  94. user := session.GetLoginUser(c)
  95. if user != nil {
  96. logger.Infof("%s logged out successfully", user.Username)
  97. }
  98. session.ClearSession(c)
  99. if err := sessions.Default(c).Save(); err != nil {
  100. logger.Warning("Unable to save session after clearing:", err)
  101. }
  102. c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
  103. }
  104. // getTwoFactorEnable retrieves the current status of two-factor authentication.
  105. func (a *IndexController) getTwoFactorEnable(c *gin.Context) {
  106. status, err := a.settingService.GetTwoFactorEnable()
  107. if err == nil {
  108. jsonObj(c, status, nil)
  109. }
  110. }