Added proper verification for forum urls

Fixes issue #12
This commit is contained in:
Asaf Gartner 2022-06-14 22:52:50 +03:00
parent 86a7128f25
commit 870a073e22
4 changed files with 41 additions and 21 deletions

View File

@ -67,7 +67,7 @@ func GetFullSubforumTree(ctx context.Context, conn *pgxpool.Pool) SubforumTree {
} }
for _, cat := range subforums { for _, cat := range subforums {
// NOTE(asaf): Doing this in a separate loop over rowsSlice to ensure that Children are in db order. // NOTE(asaf): Doing this in a separate loop over subforums to ensure that Children are in db order.
node := sfTreeMap[cat.ID] node := sfTreeMap[cat.ID]
if node.Parent != nil { if node.Parent != nil {
node.Parent.Children = append(node.Parent.Children, node) node.Parent.Children = append(node.Parent.Children, node)

View File

@ -48,7 +48,7 @@ func BlogIndex(c *RequestContext) ResponseData {
numPages := utils.NumPages(numThreads, postsPerPage) numPages := utils.NumPages(numThreads, postsPerPage)
page, ok := ParsePageNumber(c, "page", numPages) page, ok := ParsePageNumber(c, "page", numPages)
if !ok { if !ok {
c.Redirect(c.UrlContext.BuildBlog(page), http.StatusSeeOther) return c.Redirect(c.UrlContext.BuildBlog(page), http.StatusSeeOther)
} }
threads, err := hmndata.FetchThreads(c.Context(), c.Conn, c.CurrentUser, hmndata.ThreadsQuery{ threads, err := hmndata.FetchThreads(c.Context(), c.Conn, c.CurrentUser, hmndata.ThreadsQuery{

View File

@ -103,7 +103,7 @@ func Forum(c *RequestContext) ResponseData {
numPages := utils.NumPages(numThreads, threadsPerPage) numPages := utils.NumPages(numThreads, threadsPerPage)
page, ok := ParsePageNumber(c, "page", numPages) page, ok := ParsePageNumber(c, "page", numPages)
if !ok { if !ok {
c.Redirect(c.UrlContext.BuildForum(currentSubforumSlugs, page), http.StatusSeeOther) return c.Redirect(c.UrlContext.BuildForum(currentSubforumSlugs, page), http.StatusSeeOther)
} }
howManyThreadsToSkip := (page - 1) * threadsPerPage howManyThreadsToSkip := (page - 1) * threadsPerPage
@ -332,8 +332,6 @@ func ForumThread(c *RequestContext) ResponseData {
return FourOhFour(c) return FourOhFour(c)
} }
currentSubforumSlugs := cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID)
threads, err := hmndata.FetchThreads(c.Context(), c.Conn, c.CurrentUser, hmndata.ThreadsQuery{ threads, err := hmndata.FetchThreads(c.Context(), c.Conn, c.CurrentUser, hmndata.ThreadsQuery{
ProjectIDs: []int{c.CurrentProject.ID}, ProjectIDs: []int{c.CurrentProject.ID},
ThreadIDs: []int{cd.ThreadID}, ThreadIDs: []int{cd.ThreadID},
@ -346,6 +344,12 @@ func ForumThread(c *RequestContext) ResponseData {
} }
threadResult := threads[0] threadResult := threads[0]
thread := threadResult.Thread thread := threadResult.Thread
currentSubforumSlugs := cd.LineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID)
if *thread.SubforumID != cd.SubforumID {
correctThreadUrl := c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, 1)
return c.Redirect(correctThreadUrl, http.StatusSeeOther)
}
numPosts, err := hmndata.CountPosts(c.Context(), c.Conn, c.CurrentUser, hmndata.PostsQuery{ numPosts, err := hmndata.CountPosts(c.Context(), c.Conn, c.CurrentUser, hmndata.PostsQuery{
ProjectIDs: []int{c.CurrentProject.ID}, ProjectIDs: []int{c.CurrentProject.ID},
@ -466,11 +470,11 @@ func ForumPostRedirect(c *RequestContext) ResponseData {
page := (postIdx / threadPostsPerPage) + 1 page := (postIdx / threadPostsPerPage) + 1
return c.Redirect(c.UrlContext.BuildForumThreadWithPostHash( return c.Redirect(c.UrlContext.BuildForumThreadWithPostHash(
cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID),
cd.ThreadID, post.Thread.ID,
post.Thread.Title, post.Thread.Title,
page, page,
cd.PostID, post.Post.ID,
), http.StatusSeeOther) ), http.StatusSeeOther)
} }
@ -567,9 +571,14 @@ func ForumPostReply(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for reply")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for reply"))
} }
if *post.Thread.SubforumID != cd.SubforumID {
correctUrl := c.UrlContext.BuildForumPostReply(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
return c.Redirect(correctUrl, http.StatusSeeOther)
}
baseData := getBaseData( baseData := getBaseData(
c, c,
fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name), fmt.Sprintf("Replying to post | %s", cd.SubforumTree[*post.Thread.SubforumID].Name),
ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread), ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread),
) )
@ -577,7 +586,7 @@ func ForumPostReply(c *RequestContext) ResponseData {
replyPost.AddContentVersion(post.CurrentVersion, post.Editor) replyPost.AddContentVersion(post.CurrentVersion, post.Editor)
editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, &replyPost) editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, &replyPost)
editData.SubmitUrl = c.UrlContext.BuildForumPostReply(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID) editData.SubmitUrl = c.UrlContext.BuildForumPostReply(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
editData.SubmitLabel = "Submit Reply" editData.SubmitLabel = "Submit Reply"
var res ResponseData var res ResponseData
@ -616,18 +625,18 @@ func ForumPostReplySubmit(c *RequestContext) ResponseData {
// Replies to the OP should not be considered replies // Replies to the OP should not be considered replies
var replyPostId *int var replyPostId *int
if cd.PostID != post.Thread.FirstID { if post.Post.ID != post.Thread.FirstID {
replyPostId = &cd.PostID replyPostId = &post.Post.ID
} }
newPostId, _ := hmndata.CreateNewPost(c.Context(), tx, c.CurrentProject.ID, cd.ThreadID, models.ThreadTypeForumPost, c.CurrentUser.ID, replyPostId, unparsed, c.Req.Host) newPostId, _ := hmndata.CreateNewPost(c.Context(), tx, c.CurrentProject.ID, post.Thread.ID, models.ThreadTypeForumPost, c.CurrentUser.ID, replyPostId, unparsed, c.Req.Host)
err = tx.Commit(c.Context()) err = tx.Commit(c.Context())
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post"))
} }
newPostUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, newPostId) newPostUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, newPostId)
return c.Redirect(newPostUrl, http.StatusSeeOther) return c.Redirect(newPostUrl, http.StatusSeeOther)
} }
@ -651,16 +660,21 @@ func ForumPostEdit(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for editing")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for editing"))
} }
if *post.Thread.SubforumID != cd.SubforumID {
correctUrl := c.UrlContext.BuildForumPostEdit(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
return c.Redirect(correctUrl, http.StatusSeeOther)
}
title := "" title := ""
if post.Thread.FirstID == post.Post.ID { if post.Thread.FirstID == post.Post.ID {
title = fmt.Sprintf("Editing \"%s\" | %s", post.Thread.Title, cd.SubforumTree[cd.SubforumID].Name) title = fmt.Sprintf("Editing \"%s\" | %s", post.Thread.Title, cd.SubforumTree[*post.Thread.SubforumID].Name)
} else { } else {
title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[cd.SubforumID].Name) title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[*post.Thread.SubforumID].Name)
} }
baseData := getBaseData(c, title, ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread)) baseData := getBaseData(c, title, ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread))
editData := getEditorDataForEdit(c.UrlContext, c.CurrentUser, baseData, post) editData := getEditorDataForEdit(c.UrlContext, c.CurrentUser, baseData, post)
editData.SubmitUrl = c.UrlContext.BuildForumPostEdit(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID) editData.SubmitUrl = c.UrlContext.BuildForumPostEdit(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
editData.SubmitLabel = "Submit Edited Post" editData.SubmitLabel = "Submit Edited Post"
var res ResponseData var res ResponseData
@ -705,7 +719,7 @@ func ForumPostEditSubmit(c *RequestContext) ResponseData {
return RejectRequest(c, "You must provide a body for your post.") return RejectRequest(c, "You must provide a body for your post.")
} }
hmndata.CreatePostVersion(c.Context(), tx, cd.PostID, unparsed, c.Req.Host, editReason, &c.CurrentUser.ID) hmndata.CreatePostVersion(c.Context(), tx, post.Post.ID, unparsed, c.Req.Host, editReason, &c.CurrentUser.ID)
if title != "" { if title != "" {
_, err := tx.Exec(c.Context(), _, err := tx.Exec(c.Context(),
@ -725,7 +739,7 @@ func ForumPostEditSubmit(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post"))
} }
postUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID) postUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
return c.Redirect(postUrl, http.StatusSeeOther) return c.Redirect(postUrl, http.StatusSeeOther)
} }
@ -749,9 +763,14 @@ func ForumPostDelete(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for delete")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post for delete"))
} }
if *post.Thread.SubforumID != cd.SubforumID {
correctUrl := c.UrlContext.BuildForumPostDelete(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID)
return c.Redirect(correctUrl, http.StatusSeeOther)
}
baseData := getBaseData( baseData := getBaseData(
c, c,
fmt.Sprintf("Deleting post in \"%s\" | %s", post.Thread.Title, cd.SubforumTree[cd.SubforumID].Name), fmt.Sprintf("Deleting post in \"%s\" | %s", post.Thread.Title, cd.SubforumTree[*post.Thread.SubforumID].Name),
ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread), ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread),
) )
@ -767,7 +786,7 @@ func ForumPostDelete(c *RequestContext) ResponseData {
var res ResponseData var res ResponseData
res.MustWriteTemplate("forum_post_delete.html", forumPostDeleteData{ res.MustWriteTemplate("forum_post_delete.html", forumPostDeleteData{
BaseData: baseData, BaseData: baseData,
SubmitUrl: c.UrlContext.BuildForumPostDelete(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID), SubmitUrl: c.UrlContext.BuildForumPostDelete(cd.LineageBuilder.GetSubforumLineageSlugs(*post.Thread.SubforumID), post.Thread.ID, post.Post.ID),
Post: templatePost, Post: templatePost,
}, c.Perf) }, c.Perf)
return res return res

View File

@ -19,6 +19,7 @@ func ParsePageNumber(
paramName string, paramName string,
numPages int, numPages int,
) (page int, ok bool) { ) (page int, ok bool) {
page = 1
if pageString, hasPage := c.PathParams[paramName]; hasPage && pageString != "" { if pageString, hasPage := c.PathParams[paramName]; hasPage && pageString != "" {
if pageParsed, err := strconv.Atoi(pageString); err == nil { if pageParsed, err := strconv.Atoi(pageString); err == nil {
page = pageParsed page = pageParsed