middleware.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package middleware
  2. import (
  3. "encoding/base64"
  4. "net/http"
  5. "path"
  6. "strings"
  7. "github.com/0xJacky/Nginx-UI/internal/user"
  8. "github.com/0xJacky/Nginx-UI/model"
  9. "github.com/0xJacky/Nginx-UI/settings"
  10. "github.com/gin-gonic/gin"
  11. "github.com/uozi-tech/cosy/logger"
  12. )
  13. // getToken from header, cookie or query
  14. func getToken(c *gin.Context) (token string) {
  15. if token = c.GetHeader("Authorization"); token != "" {
  16. return
  17. }
  18. if token = c.Query("token"); token != "" {
  19. if len(token) > 16 {
  20. // Long token (base64 encoded JWT)
  21. tokenBytes, _ := base64.StdEncoding.DecodeString(token)
  22. return string(tokenBytes)
  23. }
  24. // Short token (16 characters)
  25. return token
  26. }
  27. if token, _ = c.Cookie("token"); token != "" {
  28. return token
  29. }
  30. return ""
  31. }
  32. // getXNodeID from header or query
  33. func getXNodeID(c *gin.Context) (xNodeID string) {
  34. if xNodeID = c.GetHeader("X-Node-ID"); xNodeID != "" {
  35. return xNodeID
  36. }
  37. return c.Query("x_node_id")
  38. }
  39. // getNodeSecret from header or query
  40. func getNodeSecret(c *gin.Context) (secret string) {
  41. if secret = c.GetHeader("X-Node-Secret"); secret != "" {
  42. return secret
  43. }
  44. return c.Query("node_secret")
  45. }
  46. // AuthRequired is a middleware that checks if the user is authenticated
  47. func AuthRequired() gin.HandlerFunc {
  48. return func(c *gin.Context) {
  49. abortWithAuthFailure := func() {
  50. c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
  51. "message": "Authorization failed",
  52. })
  53. }
  54. xNodeID := getXNodeID(c)
  55. if xNodeID != "" {
  56. c.Set("ProxyNodeID", xNodeID)
  57. }
  58. // Check node secret authentication
  59. if nodeSecret := getNodeSecret(c); nodeSecret != "" && nodeSecret == settings.NodeSettings.Secret {
  60. initUser := user.GetInitUser(c)
  61. c.Set("Secret", nodeSecret)
  62. c.Set("user", initUser)
  63. c.Next()
  64. return
  65. }
  66. token := getToken(c)
  67. if token == "" {
  68. abortWithAuthFailure()
  69. return
  70. }
  71. var (
  72. u *model.User
  73. ok bool
  74. )
  75. if len(token) <= 16 {
  76. // Short token (16 characters)
  77. u, ok = user.GetTokenUserByShortToken(token)
  78. if !ok {
  79. abortWithAuthFailure()
  80. return
  81. }
  82. } else {
  83. // Long JWT token
  84. u, ok = user.GetTokenUser(token)
  85. if !ok {
  86. abortWithAuthFailure()
  87. return
  88. }
  89. }
  90. c.Set("user", u)
  91. c.Next()
  92. }
  93. }
  94. type ServerFileSystemType struct {
  95. http.FileSystem
  96. }
  97. func (f ServerFileSystemType) Exists(prefix string, _path string) bool {
  98. file, err := f.Open(path.Join(prefix, _path))
  99. if file != nil {
  100. defer func(file http.File) {
  101. err = file.Close()
  102. if err != nil {
  103. logger.Error("file not found", err)
  104. }
  105. }(file)
  106. }
  107. return err == nil
  108. }
  109. // CacheJs is a middleware that send header to client to cache js file
  110. func CacheJs() gin.HandlerFunc {
  111. return func(c *gin.Context) {
  112. if strings.Contains(c.Request.URL.String(), "js") {
  113. c.Header("Cache-Control", "max-age: 1296000")
  114. if c.Request.Header.Get("If-Modified-Since") == settings.LastModified {
  115. c.AbortWithStatus(http.StatusNotModified)
  116. }
  117. c.Header("Last-Modified", settings.LastModified)
  118. }
  119. }
  120. }