fix: correct webhook Content-Type validation

This commit is contained in:
Fu Diwei
2026-06-23 22:24:47 +08:00
committed by RHQYZ
parent 1d02567daf
commit 0b57ae723e
2 changed files with 58 additions and 34 deletions
+29 -17
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"log/slog"
"mime"
"net/http"
"net/url"
"strings"
@@ -48,6 +49,26 @@ type Deployer struct {
var _ Provider = (*Deployer)(nil)
const (
contentTypeJson = "application/json"
contentTypeForm = "application/x-www-form-urlencoded"
contentTypeMultipart = "multipart/form-data"
)
var allowedContentTypes = map[string]bool{
contentTypeJson: true,
contentTypeForm: true,
contentTypeMultipart: true,
}
var allowedMethods = map[string]bool{
http.MethodGet: true,
http.MethodPost: true,
http.MethodPut: true,
http.MethodPatch: true,
http.MethodDelete: true,
}
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
@@ -104,11 +125,7 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
webhookMethod := strings.ToUpper(d.config.Method)
if webhookMethod == "" {
webhookMethod = http.MethodPost
} else if webhookMethod != http.MethodGet &&
webhookMethod != http.MethodPost &&
webhookMethod != http.MethodPut &&
webhookMethod != http.MethodPatch &&
webhookMethod != http.MethodDelete {
} else if !allowedMethods[webhookMethod] {
return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod)
}
@@ -119,16 +136,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
}
// 处理 Webhook 请求内容类型
const CONTENT_TYPE_JSON = "application/json"
const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"
const CONTENT_TYPE_MULTIPART = "multipart/form-data"
webhookContentType := webhookHeaders.Get("Content-Type")
if webhookContentType == "" {
webhookContentType = CONTENT_TYPE_JSON
webhookHeaders.Set("Content-Type", CONTENT_TYPE_JSON)
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
webhookContentType = contentTypeJson
webhookHeaders.Set("Content-Type", contentTypeJson)
} else if mediaType, _, err := mime.ParseMediaType(webhookContentType); err != nil || !allowedContentTypes[mediaType] {
return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType)
}
@@ -146,7 +158,7 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err)
}
if webhookMethod == http.MethodGet || webhookContentType == CONTENT_TYPE_FORM || webhookContentType == CONTENT_TYPE_MULTIPART {
if webhookMethod == http.MethodGet || webhookContentType == contentTypeForm || webhookContentType == contentTypeMultipart {
temp := make(map[string]string)
jsonb, err := json.Marshal(webhookData)
if err != nil {
@@ -186,11 +198,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
req.SetQueryParams(webhookData.(map[string]string))
} else {
switch webhookContentType {
case CONTENT_TYPE_JSON:
case contentTypeJson:
req.SetBody(webhookData)
case CONTENT_TYPE_FORM:
case contentTypeForm:
req.SetFormData(webhookData.(map[string]string))
case CONTENT_TYPE_MULTIPART:
case contentTypeMultipart:
req.SetMultipartFormData(webhookData.(map[string]string))
}
}
+29 -17
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"log/slog"
"mime"
"net/http"
"net/url"
"strings"
@@ -46,6 +47,26 @@ type Notifier struct {
var _ Provider = (*Notifier)(nil)
const (
contentTypeJson = "application/json"
contentTypeForm = "application/x-www-form-urlencoded"
contentTypeMultipart = "multipart/form-data"
)
var allowedContentTypes = map[string]bool{
contentTypeJson: true,
contentTypeForm: true,
contentTypeMultipart: true,
}
var allowedMethods = map[string]bool{
http.MethodGet: true,
http.MethodPost: true,
http.MethodPut: true,
http.MethodPatch: true,
http.MethodDelete: true,
}
func NewNotifier(config *NotifierConfig) (*Notifier, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the notifier provider is nil")
@@ -90,11 +111,7 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) (
webhookMethod := strings.ToUpper(n.config.Method)
if webhookMethod == "" {
webhookMethod = http.MethodPost
} else if webhookMethod != http.MethodGet &&
webhookMethod != http.MethodPost &&
webhookMethod != http.MethodPut &&
webhookMethod != http.MethodPatch &&
webhookMethod != http.MethodDelete {
} else if !allowedMethods[webhookMethod] {
return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod)
}
@@ -105,16 +122,11 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) (
}
// 处理 Webhook 请求内容类型
const CONTENT_TYPE_JSON = "application/json"
const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"
const CONTENT_TYPE_MULTIPART = "multipart/form-data"
webhookContentType := webhookHeaders.Get("Content-Type")
if webhookContentType == "" {
webhookContentType = CONTENT_TYPE_JSON
webhookHeaders.Set("Content-Type", CONTENT_TYPE_JSON)
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
webhookContentType = contentTypeJson
webhookHeaders.Set("Content-Type", contentTypeJson)
} else if mediaType, _, err := mime.ParseMediaType(webhookContentType); err != nil || !allowedContentTypes[mediaType] {
return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType)
}
@@ -131,7 +143,7 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) (
return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err)
}
if webhookMethod == http.MethodGet || webhookContentType == CONTENT_TYPE_FORM || webhookContentType == CONTENT_TYPE_MULTIPART {
if webhookMethod == http.MethodGet || webhookContentType == contentTypeForm || webhookContentType == contentTypeMultipart {
temp := make(map[string]string)
jsonb, err := json.Marshal(webhookData)
if err != nil {
@@ -161,11 +173,11 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) (
req.SetQueryParams(webhookData.(map[string]string))
} else {
switch webhookContentType {
case CONTENT_TYPE_JSON:
case contentTypeJson:
req.SetBody(webhookData)
case CONTENT_TYPE_FORM:
case contentTypeForm:
req.SetFormData(webhookData.(map[string]string))
case CONTENT_TYPE_MULTIPART:
case contentTypeMultipart:
req.SetMultipartFormData(webhookData.(map[string]string))
}
}