From c9c9b2eb02a9d21856624e4aca0c5e8cc0d90ed7 Mon Sep 17 00:00:00 2001 From: rxdn <29165304+rxdn@users.noreply.github.com> Date: Sat, 16 Jul 2022 21:06:30 +0100 Subject: [PATCH] Custom URL parser --- .../api/integrations/createintegration.go | 4 +-- .../api/integrations/getintegration.go | 3 +- .../api/integrations/listintegrations.go | 3 +- .../api/integrations/ownedintegrations.go | 3 +- .../api/integrations/updateintegration.go | 2 +- .../endpoints/api/integrations/validators.go | 36 +++++++++++++++++++ go.mod | 2 +- go.sum | 2 -- utils/netutils.go | 4 ++- utils/utils.go | 6 ++++ 10 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 app/http/endpoints/api/integrations/validators.go diff --git a/app/http/endpoints/api/integrations/createintegration.go b/app/http/endpoints/api/integrations/createintegration.go index 4449fac..21b6254 100644 --- a/app/http/endpoints/api/integrations/createintegration.go +++ b/app/http/endpoints/api/integrations/createintegration.go @@ -17,7 +17,7 @@ type integrationCreateBody struct { PrivacyPolicyUrl *string `json:"privacy_policy_url" validate:"omitempty,url,max=255,startswith=https://"` Method string `json:"http_method" validate:"required,oneof=GET POST"` - WebhookUrl string `json:"webhook_url" validate:"required,url,max=255,startswith=http"` + WebhookUrl string `json:"webhook_url" validate:"required,webhook,max=255"` Secrets []struct { Name string `json:"name" validate:"required,min=1,max=32,excludesall=% "` @@ -34,7 +34,7 @@ type integrationCreateBody struct { } `json:"placeholders" validate:"dive,omitempty,min=0,max=15"` } -var validate = validator.New() +var validate = newIntegrationValidator() func CreateIntegrationHandler(ctx *gin.Context) { userId := ctx.Keys["userid"].(uint64) diff --git a/app/http/endpoints/api/integrations/getintegration.go b/app/http/endpoints/api/integrations/getintegration.go index ce0258c..837dce4 100644 --- a/app/http/endpoints/api/integrations/getintegration.go +++ b/app/http/endpoints/api/integrations/getintegration.go @@ -6,6 +6,7 @@ import ( "github.com/TicketsBot/database" "github.com/gin-gonic/gin" "strconv" + "strings" ) type integrationResponse struct { @@ -87,7 +88,7 @@ func GetIntegrationHandler(ctx *gin.Context) { ctx.JSON(200, integrationResponse{ Id: integration.Id, OwnerId: integration.OwnerId, - WebhookHost: utils.GetUrlHost(integration.WebhookUrl), + WebhookHost: utils.GetUrlHost(strings.ReplaceAll(integration.WebhookUrl, "%", "")), Name: integration.Name, Description: integration.Description, ImageUrl: integration.ImageUrl, diff --git a/app/http/endpoints/api/integrations/listintegrations.go b/app/http/endpoints/api/integrations/listintegrations.go index ab05808..360f135 100644 --- a/app/http/endpoints/api/integrations/listintegrations.go +++ b/app/http/endpoints/api/integrations/listintegrations.go @@ -5,6 +5,7 @@ import ( "github.com/TicketsBot/GoPanel/utils" "github.com/gin-gonic/gin" "strconv" + "strings" ) const pageLimit = 20 @@ -55,7 +56,7 @@ func ListIntegrationsHandler(ctx *gin.Context) { integrationResponse: integrationResponse{ Id: integration.Id, OwnerId: integration.OwnerId, - WebhookHost: utils.GetUrlHost(integration.WebhookUrl), + WebhookHost: utils.GetUrlHost(strings.ReplaceAll(integration.WebhookUrl, "%", "")), Name: integration.Name, Description: integration.Description, ImageUrl: integration.ImageUrl, diff --git a/app/http/endpoints/api/integrations/ownedintegrations.go b/app/http/endpoints/api/integrations/ownedintegrations.go index e413416..9216558 100644 --- a/app/http/endpoints/api/integrations/ownedintegrations.go +++ b/app/http/endpoints/api/integrations/ownedintegrations.go @@ -7,6 +7,7 @@ import ( "github.com/TicketsBot/database" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" + "strings" ) type integrationWithCount struct { @@ -56,7 +57,7 @@ func GetOwnedIntegrationsHandler(ctx *gin.Context) { integrationResponse: integrationResponse{ Id: integration.Id, OwnerId: integration.OwnerId, - WebhookHost: utils.GetUrlHost(integration.WebhookUrl), + WebhookHost: utils.GetUrlHost(strings.ReplaceAll(integration.WebhookUrl, "%", "")), Name: integration.Name, Description: integration.Description, ImageUrl: integration.ImageUrl, diff --git a/app/http/endpoints/api/integrations/updateintegration.go b/app/http/endpoints/api/integrations/updateintegration.go index ffa47eb..aacbae5 100644 --- a/app/http/endpoints/api/integrations/updateintegration.go +++ b/app/http/endpoints/api/integrations/updateintegration.go @@ -18,7 +18,7 @@ type integrationUpdateBody struct { PrivacyPolicyUrl *string `json:"privacy_policy_url" validate:"omitempty,url,max=255,startswith=https://"` Method string `json:"http_method" validate:"required,oneof=GET POST"` - WebhookUrl string `json:"webhook_url" validate:"required,url,max=255,startswith=http"` + WebhookUrl string `json:"webhook_url" validate:"required,webhook,max=255"` Secrets []struct { Id int `json:"id" validate:"omitempty,min=1"` diff --git a/app/http/endpoints/api/integrations/validators.go b/app/http/endpoints/api/integrations/validators.go new file mode 100644 index 0000000..4e797bc --- /dev/null +++ b/app/http/endpoints/api/integrations/validators.go @@ -0,0 +1,36 @@ +package api + +import ( + "github.com/TicketsBot/GoPanel/utils" + "github.com/go-playground/validator/v10" + "net/url" + "regexp" +) + +var placeholderRegex = regexp.MustCompile(`%[\w|-]+%`) + +func newIntegrationValidator() *validator.Validate { + v := validator.New() + utils.Must(v.RegisterValidation("webhook", WebhookValidator)) + return v +} + +func WebhookValidator(fl validator.FieldLevel) bool { + value := fl.Field().String() + stripped := placeholderRegex.ReplaceAllString(value, "") + + parsed, err := url.Parse(stripped) + if err != nil { + return false + } + + if parsed.Scheme != "http" && parsed.Scheme != "https" { + return false + } + + if parsed.Host == "" { + return false + } + + return true +} diff --git a/go.mod b/go.mod index 8635662..30129e9 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.1.1 github.com/gorilla/websocket v1.5.0 + github.com/jackc/pgconn v1.6.1 github.com/jackc/pgtype v1.4.0 github.com/jackc/pgx/v4 v4.7.1 github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c @@ -51,7 +52,6 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.6.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.0.2 // indirect diff --git a/go.sum b/go.sum index e23fdc5..c4ae1d7 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc h1:n15W8 github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc/go.mod h1:2KcfHS0JnSsgcxZBs3NyWMXNQzEo67mBSGOyzHPWOCc= github.com/TicketsBot/common v0.0.0-20220703211704-f792aa9f0c42 h1:3/qnbrEfL8gqSbjJ4o7WKkdoPngmhjAGEXFwteEjpqs= github.com/TicketsBot/common v0.0.0-20220703211704-f792aa9f0c42/go.mod h1:WxHh6bY7KhIqdayeOp5f0Zj2NNi/7QqCQfMEqHnpdAM= -github.com/TicketsBot/database v0.0.0-20220710122820-0fdcde6692f0 h1:1lrgdlmyf0KFkl4Y3Cu1L6BQzKOzowoLUp/Kq/jwfvc= -github.com/TicketsBot/database v0.0.0-20220710122820-0fdcde6692f0/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw= github.com/TicketsBot/database v0.0.0-20220712212403-61804b8beb18 h1:p3rr325yK5CqWQMBML1SzkC+mXx+SSaBq4PnyxeBYXA= github.com/TicketsBot/database v0.0.0-20220712212403-61804b8beb18/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw= github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c h1:OqGjFH6mbE6gd+NqI2ARJdtH3UUvhiAkD0r0fhGJK2s= diff --git a/utils/netutils.go b/utils/netutils.go index 1f13e55..b0aa6ca 100644 --- a/utils/netutils.go +++ b/utils/netutils.go @@ -1,6 +1,8 @@ package utils -import "net/url" +import ( + "net/url" +) func GetUrlHost(rawUrl string) string { parsed, err := url.Parse(rawUrl) diff --git a/utils/utils.go b/utils/utils.go index ffac9ba..bf3731e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -15,3 +15,9 @@ func ValueOrZero[T any](v *T) T { func Slice[T any](v ...T) []T { return v } + +func Must(err error) { + if err != nil { + panic(err) + } +}