diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index 34cf8a62d..a14ad949f 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -6,6 +6,7 @@ package setting import ( "net/url" + "strings" "code.gitea.io/gitea/modules/log" ) @@ -13,14 +14,18 @@ import ( var ( // Webhook settings Webhook = struct { - QueueLength int - DeliverTimeout int - SkipTLSVerify bool - Types []string - PagingNum int - ProxyURL string - ProxyURLFixed *url.URL - ProxyHosts []string + QueueLength int + DeliverTimeout int + SkipTLSVerify bool + Types []string + PagingNum int + ProxyURL string + ProxyURLFixed *url.URL + ProxyHosts []string + Socks5Proxy string + Socks5UserName string + Socks5Password string + Socks5ProxyHosts []string }{ QueueLength: 1000, DeliverTimeout: 5, @@ -39,6 +44,10 @@ func newWebhookService() { Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix"} Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("") + Webhook.Socks5Proxy = sec.Key("SOCKS5_PROXY_URL").MustString("") + Webhook.Socks5UserName = sec.Key("SOCKS5_USER_NAME").MustString("") + Webhook.Socks5Password = sec.Key("SOCKS5_PASSWORD").MustString("") + Webhook.Socks5ProxyHosts = strings.Split(sec.Key("SOCKS5_PROXY_HOST").MustString(""), ";") if Webhook.ProxyURL != "" { var err error Webhook.ProxyURLFixed, err = url.Parse(Webhook.ProxyURL) diff --git a/modules/webhook/deliver.go b/modules/webhook/deliver.go index 7b0c65173..8348e8641 100644 --- a/modules/webhook/deliver.go +++ b/modules/webhook/deliver.go @@ -16,6 +16,8 @@ import ( "sync" "time" + "golang.org/x/net/proxy" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" @@ -137,8 +139,10 @@ func Deliver(t *models.HookTask) error { return } }() + match := isSocks5ProxyUrlMatch(req) + + resp, err := makeReq(req, match) - resp, err := webhookHTTPClient.Do(req) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err) return err @@ -161,6 +165,23 @@ func Deliver(t *models.HookTask) error { return nil } +func makeReq(req *http.Request, proxyMatch bool) (*http.Response, error) { + if proxyMatch { + return webhookSocks5PoxyHTTPClient.Do(req) + } + return webhookHTTPClient.Do(req) +} + +func isSocks5ProxyUrlMatch(req *http.Request) bool { + + for _, v := range socks5HostMatchers { + if v.Match(req.URL.Host) { + return true + } + } + return false +} + // DeliverHooks checks and delivers undelivered hooks. // FIXME: graceful: This would likely benefit from either a worker pool with dummy queue // or a full queue. Then more hooks could be sent at same time. @@ -225,9 +246,11 @@ func DeliverHooks(ctx context.Context) { } var ( - webhookHTTPClient *http.Client - once sync.Once - hostMatchers []glob.Glob + webhookHTTPClient *http.Client + once sync.Once + hostMatchers []glob.Glob + webhookSocks5PoxyHTTPClient *http.Client + socks5HostMatchers []glob.Glob ) func webhookProxy() func(req *http.Request) (*url.URL, error) { @@ -274,5 +297,31 @@ func InitDeliverHooks() { }, } + if setting.Webhook.Socks5Proxy != "" { + auth := proxy.Auth{ + User: setting.Webhook.Socks5UserName, + Password: setting.Webhook.Socks5Password, + } + + dialSocksProxy, err := proxy.SOCKS5("tcp", setting.Webhook.Socks5Proxy, &auth, proxy.Direct) + if err != nil { + fmt.Println("Error connecting to proxy:", err) + } + tr := &http.Transport{Dial: dialSocksProxy.Dial} + + webhookSocks5PoxyHTTPClient = &http.Client{ + Transport: tr, + } + + for _, h := range setting.Webhook.Socks5ProxyHosts { + if g, err := glob.Compile(h); err == nil { + socks5HostMatchers = append(socks5HostMatchers, g) + } else { + log.Error("glob.Compile %s failed: %v", h, err) + } + } + + } + go graceful.GetManager().RunWithShutdownContext(DeliverHooks) }