Add host check

This commit is contained in:
rxdn 2023-06-08 20:45:05 +01:00
parent dbb440eadf
commit 651073f69f
4 changed files with 65 additions and 2 deletions

View File

@ -2,11 +2,13 @@ package api
import (
"encoding/json"
"fmt"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
"strings"
)
type activateIntegrationBody struct {
@ -77,6 +79,7 @@ func ActivateIntegrationHandler(ctx *gin.Context) {
// Since we've checked the length, we can just iterate over the secrets and they're guaranteed to be correct
secretMap := make(map[int]string)
secretValues := make(map[string]string)
for secretName, value := range data.Secrets {
if len(value) == 0 || len(value) > 255 {
ctx.JSON(400, utils.ErrorStr("Secret values must be between 1 and 255 characters"))
@ -90,6 +93,7 @@ func ActivateIntegrationHandler(ctx *gin.Context) {
if secret.Name == secretName {
found = true
secretMap[secret.Id] = value
secretValues[secret.Name] = value
break inner
}
}
@ -102,7 +106,23 @@ func ActivateIntegrationHandler(ctx *gin.Context) {
// Validate secrets
if integration.Public && integration.Approved && integration.ValidationUrl != nil {
res, statusCode, err := utils.SecureProxyClient.DoRequest(http.MethodPost, *integration.ValidationUrl, nil, data.Secrets)
integrationHeaders, err := dbclient.Client.CustomIntegrationHeaders.GetByIntegration(integrationId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
headers := make(map[string]string)
for _, header := range integrationHeaders {
value := header.Value
for key, secret := range secretValues {
value = strings.ReplaceAll(value, fmt.Sprintf("%%%s%%", key), secret)
}
headers[header.Name] = value
}
res, statusCode, err := utils.SecureProxyClient.DoRequest(http.MethodPost, *integration.ValidationUrl, headers, secretValues)
if err != nil {
if statusCode == http.StatusRequestTimeout {
ctx.JSON(400, utils.ErrorStr("Secret validation server did not respond in time (contact the integration author)"))

View File

@ -1,11 +1,13 @@
package api
import (
"errors"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"strings"
)
type integrationCreateBody struct {
@ -68,6 +70,19 @@ func CreateIntegrationHandler(ctx *gin.Context) {
return
}
if data.ValidationUrl != nil {
sameHost, err := isSameValidationUrlHost(data.WebhookUrl, *data.ValidationUrl)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if !sameHost {
ctx.JSON(400, utils.ErrorStr("Validation URL must be on the same host as the webhook URL"))
return
}
}
integration, err := dbclient.Client.CustomIntegrations.Create(userId, data.WebhookUrl, data.ValidationUrl, data.Method, data.Name, data.Description, data.ImageUrl, data.PrivacyPolicyUrl)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
@ -124,3 +139,14 @@ func CreateIntegrationHandler(ctx *gin.Context) {
ctx.JSON(200, integration)
}
func isSameValidationUrlHost(webhookUrl, validationUrl string) (bool, error) {
webhookStripped := utils.GetUrlHost(strings.ReplaceAll(webhookUrl, "%", ""))
validationStripped := utils.GetUrlHost(strings.ReplaceAll(validationUrl, "%", ""))
if webhookStripped == "Invalid URL" || validationStripped == "Invalid URL" {
return false, errors.New("invalid webhook or validation URL")
}
return strings.ToLower(utils.SecondLevelDomain(webhookStripped)) == strings.ToLower(utils.SecondLevelDomain(validationStripped)), nil
}

View File

@ -88,6 +88,19 @@ func UpdateIntegrationHandler(ctx *gin.Context) {
return
}
if data.ValidationUrl != nil {
sameHost, err := isSameValidationUrlHost(data.WebhookUrl, *data.ValidationUrl)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if !sameHost {
ctx.JSON(400, utils.ErrorStr("Validation URL must be on the same host as the webhook URL"))
return
}
}
// Update integration metadata
err = dbclient.Client.CustomIntegrations.Update(database.CustomIntegration{
Id: integration.Id,

View File

@ -79,7 +79,11 @@
let res = await axios.post(`${API_URL}/api/${guildId}/integrations/${integrationId}`, data);
if (res.status !== 204) {
if (res.data.client_error) {
notifyError(`${res.data.error}: ${res.data.client_error}`);
} else {
notifyError(res.data.error);
}
return;
}