| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | package middlewareimport (	"bytes"	"encoding/json"	"io"	"mime/multipart"	"net/http"	"net/url"	"strings"	"github.com/0xJacky/Nginx-UI/internal/crypto"	"github.com/gin-gonic/gin"	"github.com/uozi-tech/cosy")var (	e                       = cosy.NewErrorScope("middleware")	ErrInvalidRequestFormat = e.New(40000, "invalid request format")	ErrDecryptionFailed     = e.New(40001, "decryption failed")	ErrFormParseFailed      = e.New(40002, "form parse failed"))func EncryptedParams() gin.HandlerFunc {	return func(c *gin.Context) {		// read the encrypted payload		var encryptedReq struct {			EncryptedParams string `json:"encrypted_params"`		}		if err := c.ShouldBindJSON(&encryptedReq); err != nil {			c.AbortWithStatusJSON(http.StatusBadRequest, ErrInvalidRequestFormat)			return		}		// decrypt the parameters		decryptedData, err := crypto.Decrypt(encryptedReq.EncryptedParams)		if err != nil {			c.AbortWithStatusJSON(http.StatusBadRequest, ErrDecryptionFailed)			return		}		// replace request body with decrypted data		newBody, _ := json.Marshal(decryptedData)		c.Request.Body = io.NopCloser(bytes.NewReader(newBody))		c.Request.ContentLength = int64(len(newBody))		c.Next()	}}// EncryptedForm handles multipart/form-data with encrypted fields while preserving file uploadsfunc EncryptedForm() gin.HandlerFunc {	return func(c *gin.Context) {		// Only process if the content type is multipart/form-data		if !strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {			c.Next()			return		}		// Parse the multipart form		if err := c.Request.ParseMultipartForm(512 << 20); err != nil { // 512MB max memory			c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormParseFailed)			return		}		// Check if encrypted_params field exists		encryptedParams := c.Request.FormValue("encrypted_params")		if encryptedParams == "" {			// No encryption, continue normally			c.Next()			return		}		// Decrypt the parameters		params, err := crypto.Decrypt(encryptedParams)		if err != nil {			c.AbortWithStatusJSON(http.StatusBadRequest, ErrDecryptionFailed)			return		}		// Create a new multipart form with the decrypted data		newForm := &multipart.Form{			Value: make(map[string][]string),			File:  c.Request.MultipartForm.File, // Keep original file uploads		}		// Add decrypted values to the new form		for key, val := range params {			strVal, ok := val.(string)			if ok {				newForm.Value[key] = []string{strVal}			} else {				// Handle other types if necessary				jsonVal, _ := json.Marshal(val)				newForm.Value[key] = []string{string(jsonVal)}			}		}		// Also copy original non-encrypted form values (except encrypted_params)		for key, vals := range c.Request.MultipartForm.Value {			if key != "encrypted_params" && newForm.Value[key] == nil {				newForm.Value[key] = vals			}		}		// Replace the original form with our modified one		c.Request.MultipartForm = newForm		// Remove the encrypted_params field from the form		delete(c.Request.MultipartForm.Value, "encrypted_params")		// Reset ContentLength as form structure has changed		c.Request.ContentLength = -1		// Sync the form values to the request PostForm to ensure Gin can access them		if c.Request.PostForm == nil {			c.Request.PostForm = make(url.Values)		}		// Copy all values from MultipartForm to PostForm		for k, v := range newForm.Value {			c.Request.PostForm[k] = v		}		c.Next()	}}
 |