encrypted_params.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package middleware
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io"
  6. "mime/multipart"
  7. "net/http"
  8. "net/url"
  9. "strings"
  10. "github.com/0xJacky/Nginx-UI/internal/crypto"
  11. "github.com/gin-gonic/gin"
  12. "github.com/uozi-tech/cosy"
  13. "github.com/uozi-tech/cosy/logger"
  14. )
  15. var (
  16. e = cosy.NewErrorScope("middleware")
  17. ErrInvalidRequestFormat = e.New(40000, "invalid request format")
  18. ErrDecryptionFailed = e.New(40001, "decryption failed")
  19. ErrFormParseFailed = e.New(40002, "form parse failed")
  20. )
  21. func EncryptedParams() gin.HandlerFunc {
  22. return func(c *gin.Context) {
  23. // read the encrypted payload
  24. var encryptedReq struct {
  25. EncryptedParams string `json:"encrypted_params"`
  26. }
  27. if err := c.ShouldBindJSON(&encryptedReq); err != nil {
  28. c.AbortWithStatusJSON(http.StatusBadRequest, ErrInvalidRequestFormat)
  29. return
  30. }
  31. // decrypt the parameters
  32. decryptedData, err := crypto.Decrypt(encryptedReq.EncryptedParams)
  33. if err != nil {
  34. logger.Error(err)
  35. c.AbortWithStatusJSON(http.StatusBadRequest, ErrDecryptionFailed)
  36. return
  37. }
  38. // replace request body with decrypted data
  39. newBody, _ := json.Marshal(decryptedData)
  40. c.Request.Body = io.NopCloser(bytes.NewReader(newBody))
  41. c.Request.ContentLength = int64(len(newBody))
  42. c.Next()
  43. }
  44. }
  45. // EncryptedForm handles multipart/form-data with encrypted fields while preserving file uploads
  46. func EncryptedForm() gin.HandlerFunc {
  47. return func(c *gin.Context) {
  48. // Only process if the content type is multipart/form-data
  49. if !strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
  50. c.Next()
  51. return
  52. }
  53. // Parse the multipart form
  54. if err := c.Request.ParseMultipartForm(512 << 20); err != nil { // 512MB max memory
  55. c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormParseFailed)
  56. return
  57. }
  58. // Check if encrypted_params field exists
  59. encryptedParams := c.Request.FormValue("encrypted_params")
  60. if encryptedParams == "" {
  61. // No encryption, continue normally
  62. c.Next()
  63. return
  64. }
  65. // Decrypt the parameters
  66. params, err := crypto.Decrypt(encryptedParams)
  67. if err != nil {
  68. logger.Error(err)
  69. c.AbortWithStatusJSON(http.StatusBadRequest, ErrDecryptionFailed)
  70. return
  71. }
  72. // Create a new multipart form with the decrypted data
  73. newForm := &multipart.Form{
  74. Value: make(map[string][]string),
  75. File: c.Request.MultipartForm.File, // Keep original file uploads
  76. }
  77. // Add decrypted values to the new form
  78. for key, val := range params {
  79. strVal, ok := val.(string)
  80. if ok {
  81. newForm.Value[key] = []string{strVal}
  82. } else {
  83. // Handle other types if necessary
  84. jsonVal, _ := json.Marshal(val)
  85. newForm.Value[key] = []string{string(jsonVal)}
  86. }
  87. }
  88. // Also copy original non-encrypted form values (except encrypted_params)
  89. for key, vals := range c.Request.MultipartForm.Value {
  90. if key != "encrypted_params" && newForm.Value[key] == nil {
  91. newForm.Value[key] = vals
  92. }
  93. }
  94. // Replace the original form with our modified one
  95. c.Request.MultipartForm = newForm
  96. // Remove the encrypted_params field from the form
  97. delete(c.Request.MultipartForm.Value, "encrypted_params")
  98. // Reset ContentLength as form structure has changed
  99. c.Request.ContentLength = -1
  100. // Sync the form values to the request PostForm to ensure Gin can access them
  101. if c.Request.PostForm == nil {
  102. c.Request.PostForm = make(url.Values)
  103. }
  104. // Copy all values from MultipartForm to PostForm
  105. for k, v := range newForm.Value {
  106. c.Request.PostForm[k] = v
  107. }
  108. c.Next()
  109. }
  110. }