diff --git a/api-backups.go b/api-backups.go index ca7e28b..3a4c6f3 100644 --- a/api-backups.go +++ b/api-backups.go @@ -1,6 +1,7 @@ package main import ( + "net/url" "os" "path/filepath" "sort" @@ -29,10 +30,15 @@ func (app *appContext) CreateBackup(gc *gin.Context) { // @Security Bearer // @tags Backups func (app *appContext) GetBackup(gc *gin.Context) { - fname := gc.Param("fname") + escapedFName := gc.Param("fname") + fname, err := url.QueryUnescape(escapedFName) + if err != nil { + respondBool(400, false, gc) + return + } // Hopefully this is enough to ensure the path isn't malicious. Hidden behind bearer auth anyway so shouldn't matter too much I guess. b := Backup{} - err := b.FromString(fname) + err = b.FromString(fname) if err != nil || b.Date.IsZero() { app.debug.Printf(lm.IgnoreInvalidFilename, fname, err) respondBool(400, false, gc) diff --git a/api-messages.go b/api-messages.go index 12049e9..8f8e41c 100644 --- a/api-messages.go +++ b/api-messages.go @@ -1,6 +1,7 @@ package main import ( + "net/url" "time" "github.com/gin-gonic/gin" @@ -584,8 +585,9 @@ func (app *appContext) MatrixConnect(gc *gin.Context) { // @Security Bearer // @tags Other func (app *appContext) DiscordGetUsers(gc *gin.Context) { - name := gc.Param("username") - if name == "" { + escapedName := gc.Param("username") + name, err := url.QueryUnescape(escapedName) + if err != nil || name == "" { respondBool(400, false, gc) return } diff --git a/api-profiles.go b/api-profiles.go index 44b88f7..907ec99 100644 --- a/api-profiles.go +++ b/api-profiles.go @@ -247,7 +247,13 @@ func (app *appContext) DeleteProfile(gc *gin.Context) { // @Security Bearer // @tags Profiles & Settings func (app *appContext) EnableReferralForProfile(gc *gin.Context) { - profileName := gc.Param("profile") + escapedProfileName := gc.Param("profile") + profileName, err := url.QueryUnescape(escapedProfileName) + if err != nil { + respond(400, "Invalid profile", gc) + app.err.Printf(lm.FailedGetProfile, profileName) + return + } invCode := gc.Param("invite") useExpiry := gc.Param("useExpiry") == "with-expiry" inv, ok := app.storage.GetInvitesKey(invCode) @@ -294,7 +300,13 @@ func (app *appContext) EnableReferralForProfile(gc *gin.Context) { // @Security Bearer // @tags Profiles & Settings func (app *appContext) DisableReferralForProfile(gc *gin.Context) { - profileName := gc.Param("profile") + escapedProfileName := gc.Param("profile") + profileName, err := url.QueryUnescape(escapedProfileName) + if err != nil { + respond(400, "Invalid profile", gc) + app.err.Printf(lm.FailedGetProfile, profileName) + return + } profile, ok := app.storage.GetProfileKey(profileName) if !ok { respondBool(200, true, gc) diff --git a/api-users.go b/api-users.go index 140a59e..cf77781 100644 --- a/api-users.go +++ b/api-users.go @@ -625,7 +625,12 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) { gc.BindJSON(&req) mode := gc.Param("mode") - source := gc.Param("source") + escapedSource := gc.Param("source") + source, err := url.QueryUnescape(escapedSource) + if err != nil { + respondBool(400, false, gc) + return + } useExpiry := gc.Param("useExpiry") == "with-expiry" baseInv := Invite{} if mode == "profile" { @@ -813,13 +818,19 @@ func (app *appContext) GetAnnounceTemplate(gc *gin.Context) { // @Summary Delete an announcement template. // @Produce json // @Success 200 {object} boolResponse +// @Failure 400 {object} boolResponse // @Failure 500 {object} boolResponse -// @Param name path string true "name of template" +// @Param name path string true "name of template (url encoded if necessary)" // @Router /users/announce/template/{name} [delete] // @Security Bearer // @tags Users func (app *appContext) DeleteAnnounceTemplate(gc *gin.Context) { - name := gc.Param("name") + escapedName := gc.Param("name") + name, err := url.QueryUnescape(escapedName) + if err != nil { + respondBool(400, false, gc) + return + } app.storage.DeleteAnnouncementsKey(name) respondBool(200, false, gc) }