| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package webhooks
- import (
- "net/http"
- "regexp"
- "strings"
- "github.com/OliveTin/OliveTin/internal/config"
- log "github.com/sirupsen/logrus"
- )
- type WebhookMatcher struct {
- config config.WebhookConfig
- req *http.Request
- bodyBytes []byte
- }
- func NewWebhookMatcher(cfg config.WebhookConfig, r *http.Request, bodyBytes []byte) *WebhookMatcher {
- return &WebhookMatcher{
- config: cfg,
- req: r,
- bodyBytes: bodyBytes,
- }
- }
- func (m *WebhookMatcher) Matches() bool {
- if !m.matchHeaders() {
- return false
- }
- if !m.matchQuery() {
- return false
- }
- if !m.matchPath() {
- return false
- }
- return true
- }
- func (m *WebhookMatcher) matchHeaders() bool {
- if len(m.config.MatchHeaders) == 0 {
- return true
- }
- for key, expectedValue := range m.config.MatchHeaders {
- actualValue := m.req.Header.Get(key)
- if !m.compareValues(actualValue, expectedValue) {
- log.WithFields(log.Fields{
- "header": key,
- "expected": expectedValue,
- "actual": actualValue,
- }).Debugf("Header mismatch")
- return false
- }
- }
- return true
- }
- func (m *WebhookMatcher) matchQuery() bool {
- if len(m.config.MatchQuery) == 0 {
- return true
- }
- query := m.req.URL.Query()
- for key, expectedValue := range m.config.MatchQuery {
- actualValue := query.Get(key)
- if !m.compareValues(actualValue, expectedValue) {
- log.WithFields(log.Fields{
- "query": key,
- "expected": expectedValue,
- "actual": actualValue,
- }).Debugf("Query parameter mismatch")
- return false
- }
- }
- return true
- }
- func (m *WebhookMatcher) matchPath() bool {
- if m.config.MatchPath == "" {
- return true
- }
- jsonPath, expectedValue := m.parseMatchPath()
- matcher, err := NewJSONMatcher(m.bodyBytes)
- if err != nil {
- log.WithFields(log.Fields{
- "error": err,
- }).Debugf("Failed to create JSON matcher")
- return false
- }
- return m.matchPathValue(matcher, jsonPath, expectedValue)
- }
- func (m *WebhookMatcher) parseMatchPath() (string, string) {
- parts := strings.SplitN(m.config.MatchPath, "=", 2)
- jsonPath := parts[0]
- expectedValue := ""
- if len(parts) == 2 {
- expectedValue = parts[1]
- }
- return jsonPath, expectedValue
- }
- func (m *WebhookMatcher) matchPathValue(matcher *JSONMatcher, jsonPath, expectedValue string) bool {
- if expectedValue == "" {
- _, err := matcher.ExtractValue(jsonPath)
- return err == nil
- }
- matches, err := matcher.MatchPath(jsonPath, expectedValue)
- if err != nil {
- log.WithFields(log.Fields{
- "jsonPath": jsonPath,
- "error": err,
- }).Debugf("Failed to match JSONPath")
- return false
- }
- return matches
- }
- func (m *WebhookMatcher) compareValues(actual, expected string) bool {
- if strings.HasPrefix(expected, "regex:") {
- pattern := strings.TrimPrefix(expected, "regex:")
- matched, err := regexp.MatchString(pattern, actual)
- if err != nil {
- log.WithFields(log.Fields{
- "pattern": pattern,
- "error": err,
- }).Warnf("Invalid regex pattern")
- return false
- }
- return matched
- }
- return actual == expected
- }
- func (m *WebhookMatcher) ExtractArguments() (map[string]string, error) {
- matcher, err := NewJSONMatcher(m.bodyBytes)
- if err != nil {
- return nil, err
- }
- args := m.extractJSONPathValues(matcher)
- m.addWebhookMetadata(args)
- m.addWebhookHeaders(args)
- return args, nil
- }
- func (m *WebhookMatcher) extractJSONPathValues(matcher *JSONMatcher) map[string]string {
- args := make(map[string]string)
- for argName, jsonPath := range m.config.Extract {
- value, err := matcher.ExtractValue(jsonPath)
- if err != nil {
- log.WithFields(log.Fields{
- "argName": argName,
- "jsonPath": jsonPath,
- "error": err,
- }).Debugf("Failed to extract value")
- continue
- }
- args[argName] = value
- }
- return args
- }
- func (m *WebhookMatcher) addWebhookMetadata(args map[string]string) {
- args["webhook_method"] = m.req.Method
- args["webhook_path"] = m.req.URL.Path
- args["webhook_query"] = m.req.URL.RawQuery
- }
- func (m *WebhookMatcher) addWebhookHeaders(args map[string]string) {
- for key, values := range m.req.Header {
- if len(values) > 0 {
- args["webhook_header_"+strings.ToLower(key)] = values[0]
- }
- }
- }
|