Files
yovision/Bell/server/app/bell/contact/redaction.go
T

63 lines
1.7 KiB
Go

package contact
import (
"bytes"
"errors"
"io"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
const maxChannelRequestBytes = 8 * 1024
const channelBodyKey = "bell.contact.channel-body"
const channelBodyErrorKey = "bell.contact.channel-body-error"
var redactedChannelBody = []byte(`{"redacted":true}`)
// RedactRequestBody must run before GoAdmin's LoggerToFile middleware. The
// handler restores the original body from Gin context, while sys_opera_log
// only sees a fixed marker and never the contact address.
func RedactRequestBody() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method != http.MethodPost || !isChannelCreatePath(c.Request.URL.Path) {
c.Next()
return
}
body, err := io.ReadAll(io.LimitReader(c.Request.Body, maxChannelRequestBytes+1))
if err != nil {
c.Set(channelBodyErrorKey, err)
} else if len(body) > maxChannelRequestBytes {
c.Set(channelBodyErrorKey, errors.New("request body too large"))
} else {
c.Set(channelBodyKey, body)
}
_ = c.Request.Body.Close()
c.Request.Body = io.NopCloser(bytes.NewReader(redactedChannelBody))
c.Next()
}
}
func restoreChannelBody(c *gin.Context) error {
if value, ok := c.Get(channelBodyErrorKey); ok {
return value.(error)
}
value, ok := c.Get(channelBodyKey)
if !ok {
return errors.New("channel request body was not captured")
}
c.Request.Body = io.NopCloser(bytes.NewReader(value.([]byte)))
return nil
}
func isChannelCreatePath(path string) bool {
const prefix = "/api/v1/bell/contacts/"
const suffix = "/channels"
if !strings.HasPrefix(path, prefix) || !strings.HasSuffix(path, suffix) {
return false
}
id := strings.TrimSuffix(strings.TrimPrefix(path, prefix), suffix)
return id != "" && !strings.Contains(id, "/")
}