Move UUID validation from multiple places into a middleware func
This commit is contained in:
parent
3fddd78ebf
commit
a060d94cb5
37
handlers.go
37
handlers.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -37,6 +38,8 @@ type pagination struct {
|
||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reUUID = regexp.MustCompile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
|
||||||
|
|
||||||
// registerHandlers registers HTTP handlers.
|
// registerHandlers registers HTTP handlers.
|
||||||
func registerHandlers(e *echo.Echo) {
|
func registerHandlers(e *echo.Echo) {
|
||||||
e.GET("/", handleIndexPage)
|
e.GET("/", handleIndexPage)
|
||||||
|
@ -97,12 +100,18 @@ func registerHandlers(e *echo.Echo) {
|
||||||
e.DELETE("/api/templates/:id", handleDeleteTemplate)
|
e.DELETE("/api/templates/:id", handleDeleteTemplate)
|
||||||
|
|
||||||
// Subscriber facing views.
|
// Subscriber facing views.
|
||||||
e.GET("/subscription/:campUUID/:subUUID", handleSubscriptionPage)
|
e.GET("/subscription/:campUUID/:subUUID", validateUUID(handleSubscriptionPage,
|
||||||
e.POST("/subscription/:campUUID/:subUUID", handleSubscriptionPage)
|
"campUUID", "subUUID"))
|
||||||
e.POST("/subscription/export/:subUUID", handleSelfExportSubscriberData)
|
e.POST("/subscription/:campUUID/:subUUID", validateUUID(handleSubscriptionPage,
|
||||||
e.POST("/subscription/wipe/:subUUID", handleWipeSubscriberData)
|
"campUUID", "subUUID"))
|
||||||
e.GET("/link/:linkUUID/:campUUID/:subUUID", handleLinkRedirect)
|
e.POST("/subscription/export/:subUUID", validateUUID(handleSelfExportSubscriberData,
|
||||||
e.GET("/campaign/:campUUID/:subUUID/px.png", handleRegisterCampaignView)
|
"subUUID"))
|
||||||
|
e.POST("/subscription/wipe/:subUUID", validateUUID(handleWipeSubscriberData,
|
||||||
|
"subUUID"))
|
||||||
|
e.GET("/link/:linkUUID/:campUUID/:subUUID", validateUUID(handleLinkRedirect,
|
||||||
|
"linkUUID", "campUUID", "subUUID"))
|
||||||
|
e.GET("/campaign/:campUUID/:subUUID/px.png", validateUUID(handleRegisterCampaignView,
|
||||||
|
"campUUID", "subUUID"))
|
||||||
|
|
||||||
// Static views.
|
// Static views.
|
||||||
e.GET("/lists", handleIndexPage)
|
e.GET("/lists", handleIndexPage)
|
||||||
|
@ -130,6 +139,20 @@ func handleIndexPage(c echo.Context) error {
|
||||||
return c.String(http.StatusOK, string(b))
|
return c.String(http.StatusOK, string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateUUID validates the UUID string format for a given set of params.
|
||||||
|
func validateUUID(next echo.HandlerFunc, params ...string) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
for _, p := range params {
|
||||||
|
if !reUUID.MatchString(c.Param(p)) {
|
||||||
|
return c.Render(http.StatusBadRequest, "message",
|
||||||
|
makeMsgTpl("Invalid request", "",
|
||||||
|
`One or more UUIDs in the request are invalid.`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// makeAttribsBlob takes a list of keys and values and creates
|
// makeAttribsBlob takes a list of keys and values and creates
|
||||||
// a JSON map out of them.
|
// a JSON map out of them.
|
||||||
func makeAttribsBlob(keys []string, vals []string) ([]byte, bool) {
|
func makeAttribsBlob(keys []string, vals []string) ([]byte, bool) {
|
||||||
|
@ -154,7 +177,6 @@ func makeAttribsBlob(keys []string, vals []string) ([]byte, bool) {
|
||||||
val = s
|
val = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attribs[key] = val
|
attribs[key] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +184,6 @@ func makeAttribsBlob(keys []string, vals []string) ([]byte, bool) {
|
||||||
j, _ := json.Marshal(attribs)
|
j, _ := json.Marshal(attribs)
|
||||||
return j, true
|
return j, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
public.go
31
public.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/knadh/listmonk/messenger"
|
"github.com/knadh/listmonk/messenger"
|
||||||
|
@ -52,7 +51,6 @@ type msgTpl struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
regexValidUUID = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
|
|
||||||
pixelPNG = drawTransparentImage(3, 14)
|
pixelPNG = drawTransparentImage(3, 14)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,14 +81,6 @@ func handleSubscriptionPage(c echo.Context) error {
|
||||||
out.AllowExport = app.Constants.Privacy.AllowExport
|
out.AllowExport = app.Constants.Privacy.AllowExport
|
||||||
out.AllowWipe = app.Constants.Privacy.AllowWipe
|
out.AllowWipe = app.Constants.Privacy.AllowWipe
|
||||||
|
|
||||||
if !regexValidUUID.MatchString(campUUID) ||
|
|
||||||
!regexValidUUID.MatchString(subUUID) {
|
|
||||||
return c.Render(http.StatusBadRequest, "message",
|
|
||||||
makeMsgTpl("Invalid request", "",
|
|
||||||
`The unsubscription request contains invalid IDs.
|
|
||||||
Please follow the correct link.`))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unsubscribe.
|
// Unsubscribe.
|
||||||
if unsub {
|
if unsub {
|
||||||
// Is blacklisting allowed?
|
// Is blacklisting allowed?
|
||||||
|
@ -119,12 +109,6 @@ func handleLinkRedirect(c echo.Context) error {
|
||||||
campUUID = c.Param("campUUID")
|
campUUID = c.Param("campUUID")
|
||||||
subUUID = c.Param("subUUID")
|
subUUID = c.Param("subUUID")
|
||||||
)
|
)
|
||||||
if !regexValidUUID.MatchString(linkUUID) ||
|
|
||||||
!regexValidUUID.MatchString(campUUID) ||
|
|
||||||
!regexValidUUID.MatchString(subUUID) {
|
|
||||||
return c.Render(http.StatusBadRequest, "message",
|
|
||||||
makeMsgTpl("Invalid link", "", "The link you clicked is invalid."))
|
|
||||||
}
|
|
||||||
|
|
||||||
var url string
|
var url string
|
||||||
if err := app.Queries.RegisterLinkClick.Get(&url, linkUUID, campUUID, subUUID); err != nil {
|
if err := app.Queries.RegisterLinkClick.Get(&url, linkUUID, campUUID, subUUID); err != nil {
|
||||||
|
@ -146,13 +130,9 @@ func handleRegisterCampaignView(c echo.Context) error {
|
||||||
campUUID = c.Param("campUUID")
|
campUUID = c.Param("campUUID")
|
||||||
subUUID = c.Param("subUUID")
|
subUUID = c.Param("subUUID")
|
||||||
)
|
)
|
||||||
if regexValidUUID.MatchString(campUUID) &&
|
|
||||||
regexValidUUID.MatchString(subUUID) {
|
|
||||||
if _, err := app.Queries.RegisterCampaignView.Exec(campUUID, subUUID); err != nil {
|
if _, err := app.Queries.RegisterCampaignView.Exec(campUUID, subUUID); err != nil {
|
||||||
app.Logger.Printf("error registering campaign view: %s", err)
|
app.Logger.Printf("error registering campaign view: %s", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
c.Response().Header().Set("Cache-Control", "no-cache")
|
c.Response().Header().Set("Cache-Control", "no-cache")
|
||||||
return c.Blob(http.StatusOK, "image/png", pixelPNG)
|
return c.Blob(http.StatusOK, "image/png", pixelPNG)
|
||||||
}
|
}
|
||||||
|
@ -166,12 +146,6 @@ func handleSelfExportSubscriberData(c echo.Context) error {
|
||||||
app = c.Get("app").(*App)
|
app = c.Get("app").(*App)
|
||||||
subUUID = c.Param("subUUID")
|
subUUID = c.Param("subUUID")
|
||||||
)
|
)
|
||||||
if !regexValidUUID.MatchString(subUUID) {
|
|
||||||
return c.Render(http.StatusInternalServerError, "message",
|
|
||||||
makeMsgTpl("Invalid request", "",
|
|
||||||
"The subscriber ID is invalid."))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is export allowed?
|
// Is export allowed?
|
||||||
if !app.Constants.Privacy.AllowExport {
|
if !app.Constants.Privacy.AllowExport {
|
||||||
return c.Render(http.StatusBadRequest, "message",
|
return c.Render(http.StatusBadRequest, "message",
|
||||||
|
@ -230,11 +204,6 @@ func handleWipeSubscriberData(c echo.Context) error {
|
||||||
app = c.Get("app").(*App)
|
app = c.Get("app").(*App)
|
||||||
subUUID = c.Param("subUUID")
|
subUUID = c.Param("subUUID")
|
||||||
)
|
)
|
||||||
if !regexValidUUID.MatchString(subUUID) {
|
|
||||||
return c.Render(http.StatusInternalServerError, "message",
|
|
||||||
makeMsgTpl("Invalid request", "",
|
|
||||||
"The subscriber ID is invalid."))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is wiping allowed?
|
// Is wiping allowed?
|
||||||
if !app.Constants.Privacy.AllowExport {
|
if !app.Constants.Privacy.AllowExport {
|
||||||
|
|
Loading…
Reference in New Issue