mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
128 lines
3.4 KiB
Go
128 lines
3.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"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 uploads
|
|
func 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()
|
|
}
|
|
}
|