drone/app/api/controller/webhook/common.go
Atefeh Mohseni Ejiyeh cef6708a1e Support Repo Migration APIs (create repo, import PRs, webhooks, and branch rules) (#2158)
* update migrator mdoule
* added formatted forbidden error helper
* delete work sum
* check branch rule identifier check
* match migrator data contract for webhooks
* self review
* self review
* self review, code cleaning
* resolve conflicts
* updated import api calls
* resolve conflicts
* lint
* bypass pre-receive block ref update on push if it's migrator push
* migrate controller and apis
* pull main
* add migrate routes to terminate path prefix apis
* move apis to migrate pkg
* Merge branch 'main' of https://git0.harness.io/l7B_kbSEQD2wjrM7PShm5w/PROD/Harness_Commons/gitness into atmsn/import_meta
* import branch rules API
* wip import webhooks
2024-08-07 23:40:09 +00:00

125 lines
3.7 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package webhook
import (
"net"
"net/url"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/types/check"
"github.com/harness/gitness/types/enum"
)
const (
// webhookMaxURLLength defines the max allowed length of a webhook URL.
webhookMaxURLLength = 2048
// webhookMaxSecretLength defines the max allowed length of a webhook secret.
webhookMaxSecretLength = 4096
)
var ErrInternalWebhookOperationNotAllowed = usererror.Forbidden("changes to internal webhooks are not allowed")
// CheckURL validates the url of a webhook.
func CheckURL(rawURL string, allowLoopback bool, allowPrivateNetwork bool) error {
// check URL
if len(rawURL) > webhookMaxURLLength {
return check.NewValidationErrorf("The URL of a webhook can be at most %d characters long.",
webhookMaxURLLength)
}
parsedURL, err := url.Parse(rawURL)
if err != nil {
return check.NewValidationErrorf("The provided webhook url is invalid: %s", err)
}
host := parsedURL.Hostname()
if host == "" {
return check.NewValidationError("The URL of a webhook has to have a non-empty host.")
}
// basic validation for loopback / private network addresses (only sanitary to give user an early error)
// IMPORTANT: during webook execution loopback / private network addresses are blocked (handles DNS resolution)
if host == "localhost" {
return check.NewValidationError("localhost is not allowed.")
}
if ip := net.ParseIP(host); ip != nil {
if !allowLoopback && ip.IsLoopback() {
return check.NewValidationError("Loopback IP addresses are not allowed.")
}
if !allowPrivateNetwork && ip.IsPrivate() {
return check.NewValidationError("Private IP addresses are not allowed.")
}
}
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
return check.NewValidationError("The scheme of a webhook must be either http or https.")
}
return nil
}
// checkSecret validates the secret of a webhook.
func checkSecret(secret string) error {
if len(secret) > webhookMaxSecretLength {
return check.NewValidationErrorf("The secret of a webhook can be at most %d characters long.",
webhookMaxSecretLength)
}
return nil
}
// CheckTriggers validates the triggers of a webhook.
func CheckTriggers(triggers []enum.WebhookTrigger) error {
// ignore duplicates here, should be deduplicated later
for _, trigger := range triggers {
if _, ok := trigger.Sanitize(); !ok {
return check.NewValidationErrorf("The provided webhook trigger '%s' is invalid.", trigger)
}
}
return nil
}
// DeduplicateTriggers de-duplicates the triggers provided by the user.
func DeduplicateTriggers(in []enum.WebhookTrigger) []enum.WebhookTrigger {
if len(in) == 0 {
return []enum.WebhookTrigger{}
}
triggerSet := make(map[enum.WebhookTrigger]bool, len(in))
out := make([]enum.WebhookTrigger, 0, len(in))
for _, trigger := range in {
if triggerSet[trigger] {
continue
}
triggerSet[trigger] = true
out = append(out, trigger)
}
return out
}
func ConvertTriggers(vals []string) []enum.WebhookTrigger {
res := make([]enum.WebhookTrigger, len(vals))
for i := range vals {
res[i] = enum.WebhookTrigger(vals[i])
}
return res
}