1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-18 07:36:24 -07:00

Move router initialization to a new, server package, make serverutil a subpackage

This allows for more flexibility
This commit is contained in:
Eggbertx 2023-01-06 14:38:35 -08:00
parent 64a0f947a7
commit 91783c5837
22 changed files with 305 additions and 267 deletions

View file

@ -15,7 +15,8 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/manage"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
)
@ -47,13 +48,13 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
Str("boardid", request.FormValue("boardid")).
Msg("Invalid form data (boardid)")
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeError(writer, err.Error(), wantsJSON, nil)
server.ServeError(writer, err.Error(), wantsJSON, nil)
return
}
errEv.Int("boardid", boardid)
board, err := gcsql.GetBoardFromID(boardid)
if err != nil {
serverutil.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
"boardid": boardid,
})
errEv.Err(err).Caller().
@ -62,14 +63,14 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
}
if password == "" && rank == 0 {
serverutil.ServeError(writer, "Password required for post deletion", wantsJSON, nil)
server.ServeError(writer, "Password required for post deletion", wantsJSON, nil)
return
}
for _, checkedPostID := range checkedPosts {
post, err := gcsql.GetPostFromID(checkedPostID, true)
if err == sql.ErrNoRows {
serverutil.ServeError(writer, "Post does not exist", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Post does not exist", wantsJSON, map[string]interface{}{
"postid": post.ID,
"boardid": board.ID,
})
@ -78,7 +79,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
errEv.Err(err).Caller().
Int("postid", checkedPostID).
Msg("Error deleting post")
serverutil.ServeError(writer, "Error deleting post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error deleting post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": checkedPostID,
"boardid": board.ID,
})
@ -86,7 +87,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
}
if passwordMD5 != post.Password && rank == 0 {
serverutil.ServeError(writer, fmt.Sprintf("Incorrect password for #%d", post.ID), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Incorrect password for #%d", post.ID), wantsJSON, map[string]interface{}{
"postid": post.ID,
"boardid": board.ID,
})
@ -99,7 +100,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
}
if err = building.BuildBoardPages(board); err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeError(writer, "Unable to build board pages for /"+board.Dir+"/: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to build board pages for /"+board.Dir+"/: "+err.Error(), wantsJSON, map[string]interface{}{
"boardDir": board.Dir,
})
return
@ -113,7 +114,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
errEv.Err(err).Caller().
Int("postid", post.ID).
Msg("Unable to get thread information from post")
serverutil.ServeError(writer, "Unable to get thread info from post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get thread info from post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -123,7 +124,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
errEv.Err(err).Caller().
Int("postid", post.ID).
Msg("Unable to build thread pages")
serverutil.ServeError(writer, "Unable to get board info from post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get board info from post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -144,7 +145,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
Int("postid", post.ID).
Int("threadID", post.ThreadID).
Msg("Unable to get list of filenames in thread")
serverutil.ServeError(writer, "Unable to get list of filenames in thread", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get list of filenames in thread", wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -159,7 +160,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
Int("postid", post.ID).
Int("threadID", post.ThreadID).
Msg("Unable to get list of filenames in thread")
serverutil.ServeError(writer, "Unable to get list of filenames in thread", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get list of filenames in thread", wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -182,7 +183,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
Str("requestType", "deletePost").
Int("postid", post.ID).
Msg("Error deleting post")
serverutil.ServeError(writer, "Error deleting post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error deleting post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -203,7 +204,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
Bool("fileOnly", fileOnly).
Msg("Post deleted")
if wantsJSON {
serverutil.ServeJSON(writer, map[string]interface{}{
server.ServeJSON(writer, map[string]interface{}{
"success": "post deleted",
"postid": post.ID,
"boardid": boardid,
@ -255,7 +256,7 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
errEv.Err(err).Caller().
Int("postid", post.ID).
Msg("Unable to get file upload info")
serverutil.ServeError(writer, "Error getting file uplaod info: "+err.Error(),
server.ServeError(writer, "Error getting file uplaod info: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
return true
}
@ -266,7 +267,7 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
Int("postid", post.ID).
Str("filename", upload.Filename).
Msg("Unable to delete file")
serverutil.ServeError(writer, "Unable to delete file: "+err.Error(),
server.ServeError(writer, "Unable to delete file: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
return true
}
@ -277,7 +278,7 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
Int("postid", post.ID).
Str("thumbnail", upload.ThumbnailPath("thumb")).
Msg("Unable to delete thumbnail")
serverutil.ServeError(writer, "Unable to delete thumbnail: "+err.Error(),
server.ServeError(writer, "Unable to delete thumbnail: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
return true
}
@ -289,7 +290,7 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
Int("postid", post.ID).
Str("catalogThumb", upload.ThumbnailPath("catalog")).
Msg("Unable to delete catalog thumbnail")
serverutil.ServeError(writer, "Unable to delete catalog thumbnail: "+err.Error(),
server.ServeError(writer, "Unable to delete catalog thumbnail: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
return true
}
@ -300,7 +301,7 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
Str("requestType", "deleteFile").
Int("postid", post.ID).
Msg("Error unlinking post uploads")
serverutil.ServeError(writer, "Unable to unlink post uploads"+err.Error(),
server.ServeError(writer, "Unable to unlink post uploads"+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
return true
}

View file

@ -14,7 +14,8 @@ import (
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/manage"
"github.com/gochan-org/gochan/pkg/posting"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.ResponseWriter, request *http.Request) {
@ -27,16 +28,16 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
if editBtn == "Edit post" {
var err error
if len(checkedPosts) == 0 {
serverutil.ServeErrorPage(writer, "You need to select one post to edit.")
server.ServeErrorPage(writer, "You need to select one post to edit.")
return
} else if len(checkedPosts) > 1 {
serverutil.ServeErrorPage(writer, "You can only edit one post at a time.")
server.ServeErrorPage(writer, "You can only edit one post at a time.")
return
}
rank := manage.GetStaffRank(request)
if password == "" && rank == 0 {
serverutil.ServeErrorPage(writer, "Password required for post editing")
server.ServeErrorPage(writer, "Password required for post editing")
return
}
passwordMD5 := gcutil.Md5Sum(password)
@ -50,21 +51,21 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
errEv.Int("postID", post.ID)
if post.Password != passwordMD5 && rank == 0 {
serverutil.ServeErrorPage(writer, "Wrong password")
server.ServeErrorPage(writer, "Wrong password")
return
}
board, err := post.GetBoard()
if err != nil {
errEv.Err(err).Caller().Msg("Unable to get board ID from post")
serverutil.ServeErrorPage(writer, "Unable to get board ID from post: "+err.Error())
server.ServeErrorPage(writer, "Unable to get board ID from post: "+err.Error())
return
}
errEv.Str("board", board.Dir)
upload, err := post.GetUpload()
if err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeErrorPage(writer, "Error getting post upload info: "+err.Error())
server.ServeErrorPage(writer, "Error getting post upload info: "+err.Error())
return
}
@ -85,7 +86,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
if err != nil {
errEv.Err(err).Caller().
Msg("Error executing edit post template")
serverutil.ServeError(writer, "Error executing edit post template: "+err.Error(), wantsJSON, nil)
server.ServeError(writer, "Error executing edit post template: "+err.Error(), wantsJSON, nil)
return
}
writer.Write(buf.Bytes())
@ -97,7 +98,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
errEv.Err(err).Caller().
Str("postid", request.FormValue("postid")).
Msg("Invalid form data")
serverutil.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": postid,
})
return
@ -107,7 +108,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
errEv.Err(err).
Int("postid", postid).
Msg("Unable to find post")
serverutil.ServeError(writer, "Unable to find post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to find post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": postid,
})
return
@ -116,19 +117,19 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
if err != nil {
errEv.Err(err).Caller().
Msg("Invalid form data")
serverutil.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, nil)
server.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, nil)
return
}
rank := manage.GetStaffRank(request)
if request.FormValue("password") != password && rank == 0 {
serverutil.ServeError(writer, "Wrong password", wantsJSON, nil)
server.ServeError(writer, "Wrong password", wantsJSON, nil)
return
}
board, err := gcsql.GetBoardFromID(boardid)
if err != nil {
serverutil.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Invalid form data: "+err.Error(), wantsJSON, map[string]interface{}{
"boardid": boardid,
})
errEv.Err(err).Caller().Msg("Invalid form data")
@ -139,7 +140,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
oldUpload, err := post.GetUpload()
if err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeError(writer, err.Error(), wantsJSON, nil)
server.ServeError(writer, err.Error(), wantsJSON, nil)
return
}
@ -149,7 +150,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
return
}
if upload == nil {
serverutil.ServeError(writer, "Missing upload replacement", wantsJSON, nil)
server.ServeError(writer, "Missing upload replacement", wantsJSON, nil)
return
}
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
@ -160,7 +161,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
catalogThumbPath = path.Join(documentRoot, board.Dir, "thumb", oldUpload.ThumbnailPath("catalog"))
if err = post.UnlinkUploads(false); err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeError(writer, "Error unlinking old upload from post: "+err.Error(), wantsJSON, nil)
server.ServeError(writer, "Error unlinking old upload from post: "+err.Error(), wantsJSON, nil)
return
}
if oldUpload.Filename != "deleted" {
@ -177,7 +178,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
Str("newFilename", upload.Filename).
Str("newOriginalFilename", upload.OriginalFilename).
Send()
serverutil.ServeError(writer, "Error attaching new upload: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error attaching new upload: "+err.Error(), wantsJSON, map[string]interface{}{
"filename": upload.OriginalFilename,
})
filePath = path.Join(documentRoot, board.Dir, "src", upload.Filename)
@ -199,7 +200,7 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
errEv.Err(err).Caller().
Int("postid", post.ID).
Msg("Unable to edit post")
serverutil.ServeError(writer, "Unable to edit post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to edit post: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
@ -207,10 +208,10 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
}
if err = building.BuildBoards(false, boardid); err != nil {
serverutil.ServeErrorPage(writer, "Error rebuilding boards: "+err.Error())
server.ServeErrorPage(writer, "Error rebuilding boards: "+err.Error())
}
if err = building.BuildFrontPage(); err != nil {
serverutil.ServeErrorPage(writer, "Error rebuilding front page: "+err.Error())
server.ServeErrorPage(writer, "Error rebuilding front page: "+err.Error())
}
http.Redirect(writer, request, post.WebPath(), http.StatusFound)
return

View file

@ -16,7 +16,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/posting"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"

View file

@ -14,7 +14,8 @@ import (
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/manage"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.ResponseWriter, request *http.Request) {
@ -24,16 +25,16 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
// user clicked on move thread button on board or thread page
if len(checkedPosts) == 0 {
serverutil.ServeError(writer, "You need to select one thread to move.", wantsJSON, nil)
server.ServeError(writer, "You need to select one thread to move.", wantsJSON, nil)
return
} else if len(checkedPosts) > 1 {
serverutil.ServeError(writer, "You can only move one thread at a time.", wantsJSON, nil)
server.ServeError(writer, "You can only move one thread at a time.", wantsJSON, nil)
return
}
post, err := gcsql.GetPostFromID(checkedPosts[0], true)
if err != nil {
serverutil.ServeError(writer, err.Error(), wantsJSON, nil)
server.ServeError(writer, err.Error(), wantsJSON, nil)
gcutil.LogError(err).
Str("IP", gcutil.GetRealIP(request)).
Int("postid", checkedPosts[0]).
@ -43,7 +44,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if !post.IsTopPost {
topPostID, err := post.TopPostID()
if err != nil {
serverutil.ServeError(writer, "Unable to get top post ID: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get top post ID: "+err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
gcutil.LogError(err).
@ -52,7 +53,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
Msg("Unable to get top post ID")
return
}
serverutil.ServeError(writer, "You appear to be trying to move a post that is not the top post in the thread", wantsJSON, map[string]interface{}{
server.ServeError(writer, "You appear to be trying to move a post that is not the top post in the thread", wantsJSON, map[string]interface{}{
"postid": checkedPosts[0],
"toppost": topPostID,
})
@ -61,7 +62,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
srcBoardID, err := strconv.Atoi(request.PostForm.Get("boardid"))
if err != nil {
serverutil.ServeError(writer, fmt.Sprintf("Invalid or missing boarid: %q", request.PostForm.Get("boardid")), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Invalid or missing boarid: %q", request.PostForm.Get("boardid")), wantsJSON, map[string]interface{}{
"boardid": srcBoardID,
})
}
@ -75,15 +76,16 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
}
}
if err = serverutil.MinifyTemplate(gctemplates.MoveThreadPage, map[string]interface{}{
"postid": post.ID,
"destBoards": destBoards,
"pageTitle": fmt.Sprintf("Move thread #%d", post.ID),
"srcBoard": srcBoard,
"boardConfig": config.GetBoardConfig(srcBoard.Dir),
"postid": post.ID,
"destBoards": destBoards,
"pageTitle": fmt.Sprintf("Move thread #%d", post.ID),
"srcBoard": srcBoard,
}, writer, "text/html"); err != nil {
gcutil.LogError(err).
Str("IP", gcutil.GetRealIP(request)).
Int("postid", post.ID).Send()
serverutil.ServeError(writer, err.Error(), wantsJSON, nil)
server.ServeError(writer, err.Error(), wantsJSON, nil)
return
}
} else if doMove == "1" {
@ -91,14 +93,14 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
rank := manage.GetStaffRank(request)
if password == "" && rank == 0 {
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeError(writer, "Password required for post moving", wantsJSON, nil)
server.ServeError(writer, "Password required for post moving", wantsJSON, nil)
return
}
postIDstr := request.PostForm.Get("postid")
postID, err := strconv.Atoi(postIDstr)
if err != nil {
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeError(writer, fmt.Sprintf("Error parsing postid value: %q: %s", postIDstr, err.Error()), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Error parsing postid value: %q: %s", postIDstr, err.Error()), wantsJSON, map[string]interface{}{
"postid": postIDstr,
})
return
@ -107,7 +109,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
srcBoardID, err := strconv.Atoi(srcBoardIDstr)
if err != nil {
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeError(writer, fmt.Sprintf("Error parsing srcboardid value: %q: %s", srcBoardIDstr, err.Error()), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Error parsing srcboardid value: %q: %s", srcBoardIDstr, err.Error()), wantsJSON, map[string]interface{}{
"srcboardid": srcBoardIDstr,
})
return
@ -117,7 +119,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
gcutil.LogError(err).
Int("srcboardid", srcBoardID).Send()
writer.WriteHeader(http.StatusInternalServerError)
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"srcboardid": srcBoardID,
})
return
@ -127,7 +129,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
destBoardID, err := strconv.Atoi(destBoardIDstr)
if err != nil {
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeError(writer, fmt.Sprintf("Error parsing destboardid value: %q: %s", destBoardIDstr, err.Error()), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Error parsing destboardid value: %q: %s", destBoardIDstr, err.Error()), wantsJSON, map[string]interface{}{
"destboardid": destBoardIDstr,
})
return
@ -137,7 +139,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
gcutil.LogError(err).
Int("destboardid", destBoardID).Send()
writer.WriteHeader(http.StatusInternalServerError)
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"destboardid": destBoardID,
})
return
@ -147,7 +149,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if err != nil {
gcutil.LogError(err).Int("postid", postID).Send()
writer.WriteHeader(http.StatusInternalServerError)
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"postid": postID,
})
return
@ -155,7 +157,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
passwordMD5 := gcutil.Md5Sum(password)
if passwordMD5 != post.Password && rank == 0 {
serverutil.ServeError(writer, "Wrong password", wantsJSON, nil)
server.ServeError(writer, "Wrong password", wantsJSON, nil)
return
}
@ -164,7 +166,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
Int("postID", postID).
Int("destBoardID", destBoardID).
Msg("Failed changing thread board ID")
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"postID": postID,
"destBoardID": destBoardID,
})
@ -174,7 +176,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if err != nil {
gcutil.LogError(err).Int("postid", post.ID).Send()
writer.WriteHeader(http.StatusInternalServerError)
serverutil.ServeError(writer, "Error getting list of files in thread", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error getting list of files in thread", wantsJSON, map[string]interface{}{
"postid": post.ID,
})
}
@ -237,7 +239,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
}
if err != nil {
// got at least one error while trying to move files (if there were any)
serverutil.ServeError(writer, "Error while moving post upload: "+err.Error(), wantsJSON,
server.ServeError(writer, "Error while moving post upload: "+err.Error(), wantsJSON,
map[string]interface{}{
"postID": postID,
"srcBoard": srcBoard.Dir,
@ -253,7 +255,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
Str("srcBoard", srcBoard.Dir).
Msg("Failed deleting thread page")
writer.WriteHeader(500)
serverutil.ServeError(writer, "Failed deleting thread page: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Failed deleting thread page: "+err.Error(), wantsJSON, map[string]interface{}{
"postID": postID,
"srcBoard": srcBoard.Dir,
})
@ -266,7 +268,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
Str("srcBoard", srcBoard.Dir).
Msg("Failed deleting thread JSON file")
writer.WriteHeader(500)
serverutil.ServeError(writer, "Failed deleting thread JSON file: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Failed deleting thread JSON file: "+err.Error(), wantsJSON, map[string]interface{}{
"postID": postID,
"srcBoard": srcBoard.Dir,
})
@ -280,7 +282,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if err = building.BuildThreadPages(post); err != nil {
gcutil.LogError(err).Int("postID", postID).Msg("Failed moved thread page")
writer.WriteHeader(500)
serverutil.ServeError(writer, "Failed building thread page: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Failed building thread page: "+err.Error(), wantsJSON, map[string]interface{}{
"postID": postID,
})
return
@ -289,7 +291,7 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if err = building.BuildBoardPages(srcBoard); err != nil {
gcutil.LogError(err).Int("srcBoardID", srcBoardID).Send()
writer.WriteHeader(500)
serverutil.ServeError(writer, "Failed building board page: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Failed building board page: "+err.Error(), wantsJSON, map[string]interface{}{
"srcBoardID": srcBoardID,
})
return
@ -297,13 +299,13 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if err = building.BuildBoardPages(destBoard); err != nil {
gcutil.LogError(err).Int("destBoardID", destBoardID).Send()
writer.WriteHeader(500)
serverutil.ServeError(writer, "Failed building destination board page: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Failed building destination board page: "+err.Error(), wantsJSON, map[string]interface{}{
"destBoardID": destBoardID,
})
return
}
if wantsJSON {
serverutil.ServeJSON(writer, map[string]interface{}{
server.ServeJSON(writer, map[string]interface{}{
"status": "success",
"postID": postID,
"srcBoard": srcBoard.Dir,

View file

@ -5,10 +5,8 @@ import (
"net"
"net/http"
"net/http/fcgi"
"os"
"path"
"strconv"
"strings"
"github.com/uptrace/bunrouter"
@ -16,94 +14,10 @@ import (
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/manage"
"github.com/gochan-org/gochan/pkg/posting"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
var (
router *bunrouter.Router
)
func serveFile(writer http.ResponseWriter, request *http.Request) {
systemCritical := config.GetSystemCriticalConfig()
siteConfig := config.GetSiteConfig()
requestPath := request.URL.Path
if len(systemCritical.WebRoot) > 0 && systemCritical.WebRoot != "/" {
requestPath = requestPath[len(systemCritical.WebRoot):]
}
filePath := path.Join(systemCritical.DocumentRoot, requestPath)
var fileBytes []byte
results, err := os.Stat(filePath)
if err != nil {
// the requested path isn't a file or directory, 404
serverutil.ServeNotFound(writer, request)
return
}
//the file exists, or there is a folder here
if results.IsDir() {
//check to see if one of the specified index pages exists
var found bool
for _, value := range siteConfig.FirstPage {
newPath := path.Join(filePath, value)
_, err := os.Stat(newPath)
if err == nil {
filePath = newPath
found = true
break
}
}
if !found {
serverutil.ServeNotFound(writer, request)
return
}
}
setFileHeaders(filePath, writer)
// serve the requested file
fileBytes, _ = os.ReadFile(filePath)
gcutil.LogAccess(request).Int("status", 200).Send()
writer.Write(fileBytes)
}
// set mime type/cache headers according to the file's extension
func setFileHeaders(filename string, writer http.ResponseWriter) {
extension := strings.ToLower(path.Ext(filename))
switch extension {
case ".png":
writer.Header().Set("Content-Type", "image/png")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".gif":
writer.Header().Set("Content-Type", "image/gif")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".jpg":
fallthrough
case ".jpeg":
writer.Header().Set("Content-Type", "image/jpeg")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".css":
writer.Header().Set("Content-Type", "text/css")
writer.Header().Set("Cache-Control", "max-age=43200")
case ".js":
writer.Header().Set("Content-Type", "text/javascript")
writer.Header().Set("Cache-Control", "max-age=43200")
case ".json":
writer.Header().Set("Content-Type", "application/json")
writer.Header().Set("Cache-Control", "max-age=5, must-revalidate")
case ".webm":
writer.Header().Set("Content-Type", "video/webm")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".htm":
fallthrough
case ".html":
writer.Header().Set("Content-Type", "text/html")
writer.Header().Set("Cache-Control", "max-age=5, must-revalidate")
default:
writer.Header().Set("Content-Type", "application/octet-stream")
writer.Header().Set("Cache-Control", "max-age=86400")
}
}
func initServer() {
systemCritical := config.GetSystemCriticalConfig()
siteConfig := config.GetSiteConfig()
@ -118,9 +32,6 @@ func initServer() {
Str("ListenIP", systemCritical.ListenIP).
Int("Port", systemCritical.Port).Send()
}
router = bunrouter.New(
bunrouter.WithNotFoundHandler(bunrouter.HTTPHandlerFunc(serveFile)),
)
// Check if Akismet API key is usable at startup.
err = serverutil.CheckAkismetAPIKey(siteConfig.AkismetAPIKey)
@ -132,6 +43,7 @@ func initServer() {
Err(err).
Msg("Akismet spam protection will be disabled")
}
router := server.GetRouter()
router.GET(config.WebPath("/captcha"), bunrouter.HTTPHandlerFunc(posting.ServeCaptcha))
router.POST(config.WebPath("/captcha"), bunrouter.HTTPHandlerFunc(posting.ServeCaptcha))
router.GET(config.WebPath("/manage"), bunrouter.HTTPHandlerFunc(manage.CallManageFunction))
@ -175,10 +87,12 @@ func utilHandler(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
}
if action == "" && deleteBtn != "Delete" && reportBtn != "Report" && editBtn != "Edit post" && doEdit != "post" && doEdit != "upload" && moveBtn != "Move thread" && doMove != "1" {
gcutil.LogAccess(request).Int("status", 400).Msg("received invalid /util request")
gcutil.LogAccess(request).
Int("status", http.StatusBadRequest).
Msg("received invalid /util request")
if wantsJSON {
writer.WriteHeader(http.StatusBadRequest)
serverutil.ServeJSON(writer, map[string]interface{}{"error": "Invalid /util request"})
server.ServeJSON(writer, map[string]interface{}{"error": "Invalid /util request"})
} else {
http.Redirect(writer, request, path.Join(systemCritical.WebRoot, "/"), http.StatusBadRequest)
}
@ -205,7 +119,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request) {
Ints("posts", checkedPosts).
Str("board", board).
Msg("Error submitting report")
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"posts": checkedPosts,
"board": board,
})
@ -219,7 +133,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request) {
redirectTo := request.Referer()
if redirectTo == "" {
// request doesn't have a referer for some reason, redirect to board
redirectTo = path.Join(systemCritical.WebRoot, board)
redirectTo = config.WebPath(board)
}
http.Redirect(writer, request, redirectTo, http.StatusFound)
return

View file

@ -8,7 +8,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
const (

View file

@ -12,7 +12,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
const (

View file

@ -13,7 +13,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
var (

View file

@ -9,7 +9,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
type catalogThreadData struct {

View file

@ -12,7 +12,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
// BuildThreads builds thread(s) given a boardid, or if all = false, also given a threadid.

View file

@ -18,7 +18,7 @@ import (
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/posting"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
)

View file

@ -9,7 +9,8 @@ import (
"github.com/gochan-org/gochan/pkg/building"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/uptrace/bunrouter"
)
@ -25,7 +26,7 @@ func (esa *ErrStaffAction) Error() string {
}
func serveError(writer http.ResponseWriter, field string, action string, message string, isJSON bool) {
serverutil.ServeError(writer, message, isJSON, map[string]interface{}{
server.ServeError(writer, message, isJSON, map[string]interface{}{
"error": field,
"action": action,
"message": message,
@ -45,7 +46,7 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
errEv.Str("IP", gcutil.GetRealIP(request))
if err = request.ParseForm(); err != nil {
errEv.Err(err).Caller().Msg("Error parsing form data")
serverutil.ServeError(writer, "Error parsing form data: "+err.Error(), wantsJSON, nil)
server.ServeError(writer, "Error parsing form data: "+err.Error(), wantsJSON, nil)
return
}
params := bunrouter.ParamsFromContext(request.Context())
@ -61,7 +62,7 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
errEv.Err(err).
Str("request", "getCurrentFullStaff").
Caller().Send()
serverutil.ServeError(writer, "Error getting staff info from request: "+err.Error(), wantsJSON, nil)
server.ServeError(writer, "Error getting staff info from request: "+err.Error(), wantsJSON, nil)
return
}
if actionID == "" {
@ -79,7 +80,7 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
if wantsJSON {
serveError(writer, "notfound", actionID, "action not found", wantsJSON || (action.JSONoutput == AlwaysJSON))
} else {
serverutil.ServeNotFound(writer, request)
server.ServeNotFound(writer, request)
}
return
}

View file

@ -12,7 +12,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
"golang.org/x/crypto/bcrypt"
)

View file

@ -11,7 +11,8 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
)
@ -31,7 +32,7 @@ func showBanpage(ban *gcsql.IPBan, post *gcsql.Post, postBoard *gcsql.Board, wri
Str("IP", post.IP).
Str("building", "minifier").
Str("template", "banpage.html").Send()
serverutil.ServeErrorPage(writer, "Error minifying page: "+err.Error())
server.ServeErrorPage(writer, "Error minifying page: "+err.Error())
return
}
writer.Write(banPageBuffer.Bytes())
@ -49,7 +50,7 @@ func checkIpBan(post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWr
Str("IP", post.IP).
Str("boardDir", postBoard.Dir).
Msg("Error getting IP banned status")
serverutil.ServeErrorPage(writer, "Error getting ban info"+err.Error())
server.ServeErrorPage(writer, "Error getting ban info"+err.Error())
return true
}
if ipBan == nil {
@ -76,13 +77,13 @@ func checkUsernameBan(post *gcsql.Post, postBoard *gcsql.Board, writer http.Resp
Str("nameTrip", nameTrip).
Str("boardDir", postBoard.Dir).
Msg("Error getting name banned status")
serverutil.ServeErrorPage(writer, "Error getting name ban info")
server.ServeErrorPage(writer, "Error getting name ban info")
return true
}
if nameBan == nil {
return false // name is not banned
}
serverutil.ServeError(writer, "Name or tripcode not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
server.ServeError(writer, "Name or tripcode not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
gcutil.LogWarning().
Str("IP", post.IP).
Str("boardDir", postBoard.Dir).
@ -101,13 +102,13 @@ func checkFilenameBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
Str("filename", upload.OriginalFilename).
Str("boardDir", postBoard.Dir).
Msg("Error getting name banned status")
serverutil.ServeErrorPage(writer, "Error getting filename ban info")
server.ServeErrorPage(writer, "Error getting filename ban info")
return true
}
if filenameBan == nil {
return false
}
serverutil.ServeError(writer, "Filename not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
server.ServeError(writer, "Filename not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
gcutil.LogWarning().
Str("originalFilename", upload.OriginalFilename).
Msg("File rejected for having a banned filename")
@ -122,13 +123,13 @@ func checkChecksumBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
Str("boardDir", postBoard.Dir).
Str("checksum", upload.Checksum).
Msg("Error getting file checksum ban status")
serverutil.ServeErrorPage(writer, "Error processing file: "+err.Error())
server.ServeErrorPage(writer, "Error processing file: "+err.Error())
return true
}
if fileBan == nil {
return false
}
serverutil.ServeError(writer, "File not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
server.ServeError(writer, "File not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
gcutil.LogWarning().
Str("originalFilename", upload.OriginalFilename).
Str("checksum", upload.Checksum).
@ -140,20 +141,20 @@ func handleAppeal(writer http.ResponseWriter, request *http.Request, errEv *zero
banIDstr := request.FormValue("banid")
if banIDstr == "" {
errEv.Caller().Msg("Appeal sent without banid field")
serverutil.ServeErrorPage(writer, "Missing banid value")
server.ServeErrorPage(writer, "Missing banid value")
return
}
appealMsg := request.FormValue("appealmsg")
if appealMsg == "" {
errEv.Caller().Msg("Missing appealmsg value")
serverutil.ServeErrorPage(writer, "Missing or empty appeal")
server.ServeErrorPage(writer, "Missing or empty appeal")
return
}
banID, err := strconv.Atoi(banIDstr)
if err != nil {
errEv.Err(err).
Str("banIDstr", banIDstr).Caller().Send()
serverutil.ServeErrorPage(writer, fmt.Sprintf("Invalid banid value %q", banIDstr))
server.ServeErrorPage(writer, fmt.Sprintf("Invalid banid value %q", banIDstr))
return
}
errEv.Int("banID", banID)
@ -161,41 +162,41 @@ func handleAppeal(writer http.ResponseWriter, request *http.Request, errEv *zero
if err != nil {
errEv.Err(err).
Caller().Send()
serverutil.ServeErrorPage(writer, "Error getting ban info: "+err.Error())
server.ServeErrorPage(writer, "Error getting ban info: "+err.Error())
return
}
if ban == nil {
errEv.Caller().Msg("GetIPBanByID returned a nil ban (presumably not banned)")
serverutil.ServeErrorPage(writer, fmt.Sprintf("Invalid banid %d", banID))
server.ServeErrorPage(writer, fmt.Sprintf("Invalid banid %d", banID))
return
}
if ban.IP != gcutil.GetRealIP(request) {
errEv.Caller().
Str("banIP", ban.IP).
Msg("User tried to appeal a ban from a different IP")
serverutil.ServeErrorPage(writer, fmt.Sprintf("Invalid banid %d", banID))
server.ServeErrorPage(writer, fmt.Sprintf("Invalid banid %d", banID))
return
}
if !ban.IsActive {
errEv.Caller().Msg("Requested ban is not active")
serverutil.ServeErrorPage(writer, "Requested ban is not active")
server.ServeErrorPage(writer, "Requested ban is not active")
return
}
if !ban.CanAppeal {
errEv.Caller().Msg("Rejected appeal submission, appeals denied for this ban")
serverutil.ServeErrorPage(writer, "You can not appeal this ban")
server.ServeErrorPage(writer, "You can not appeal this ban")
}
if ban.AppealAt.After(time.Now()) {
errEv.Caller().
Time("appealAt", ban.AppealAt).
Msg("Rejected appeal submission, can't appeal yet")
serverutil.ServeErrorPage(writer, "You are not able to appeal this ban until "+ban.AppealAt.Format(config.GetBoardConfig("").DateTimeFormat))
server.ServeErrorPage(writer, "You are not able to appeal this ban until "+ban.AppealAt.Format(config.GetBoardConfig("").DateTimeFormat))
}
if err = ban.Appeal(appealMsg); err != nil {
errEv.Err(err).
Str("appealMsg", appealMsg).
Caller().Msg("Unable to submit appeal")
serverutil.ServeErrorPage(writer, "Unable to submit appeal")
server.ServeErrorPage(writer, "Unable to submit appeal")
return
}
board := request.FormValue("board")

View file

@ -13,7 +13,8 @@ import (
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
var (
@ -94,13 +95,13 @@ func ServeCaptcha(writer http.ResponseWriter, request *http.Request) {
return
}
if !captchaCfg.UseCaptcha() {
serverutil.ServeErrorPage(writer, "This site is not set up to require a CAPTCHA test")
server.ServeErrorPage(writer, "This site is not set up to require a CAPTCHA test")
return
}
if request.Method == "POST" {
result, err := SubmitCaptchaResponse(request)
if err != nil {
serverutil.ServeErrorPage(writer, "Error checking results: "+err.Error())
server.ServeErrorPage(writer, "Error checking results: "+err.Error())
}
fmt.Println("Success:", result)
}
@ -110,6 +111,6 @@ func ServeCaptcha(writer http.ResponseWriter, request *http.Request) {
"siteKey": captchaCfg.SiteKey,
}, writer, "text/html")
if err != nil {
serverutil.ServeErrorPage(writer, "Error serving CAPTCHA: "+err.Error())
server.ServeErrorPage(writer, "Error serving CAPTCHA: "+err.Error())
}
}

View file

@ -14,7 +14,8 @@ import (
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
const (
@ -68,7 +69,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
errEv.Err(err).
Str("opIDstr", threadidStr).
Caller().Msg("Invalid threadid value")
serverutil.ServeError(writer, "Invalid form data (invalid threadid)", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Invalid form data (invalid threadid)", wantsJSON, map[string]interface{}{
"threadid": threadidStr,
})
return
@ -78,7 +79,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
errEv.Err(err).
Int("opID", opID).
Caller().Send()
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"opID": opID,
})
}
@ -89,7 +90,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
boardID, err := strconv.Atoi(boardidStr)
if err != nil {
errEv.Str("boardid", boardidStr).Caller().Msg("Invalid boardid value")
serverutil.ServeError(writer, "Invalid form data (invalid boardid)", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Invalid form data (invalid boardid)", wantsJSON, map[string]interface{}{
"boardid": boardidStr,
})
return
@ -99,7 +100,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
errEv.Err(err).Caller().
Int("boardid", boardID).
Msg("Unable to get board info")
serverutil.ServeError(writer, "Unable to get board info", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Unable to get board info", wantsJSON, map[string]interface{}{
"boardid": boardID,
})
return
@ -137,7 +138,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
errEv.
Int("messageLength", len(post.MessageRaw)).
Int("maxMessageLength", postBoard.MaxMessageLength).Send()
serverutil.ServeError(writer, "Message is too long", wantsJSON, map[string]interface{}{
server.ServeError(writer, "Message is too long", wantsJSON, map[string]interface{}{
"messageLength": len(post.MessageRaw),
"boardid": boardID,
})
@ -146,7 +147,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
if post.MessageRaw, err = ApplyWordFilters(post.MessageRaw, postBoard.Dir); err != nil {
errEv.Err(err).Caller().Msg("Error formatting post")
serverutil.ServeError(writer, "Error formatting post: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error formatting post: "+err.Error(), wantsJSON, map[string]interface{}{
"boardDir": postBoard.Dir,
})
return
@ -182,7 +183,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
Str("IP", post.IP).
Int("threadID", post.ThreadID).
Msg("Rejected post from possible spambot")
serverutil.ServeError(writer, "Your post looks like spam", wantsJSON, nil)
server.ServeError(writer, "Your post looks like spam", wantsJSON, nil)
return
}
@ -196,11 +197,11 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
switch akismetResult {
case "discard":
logEvent.Str("akismet", "discard").Send()
serverutil.ServeError(writer, "Your post looks like spam.", wantsJSON, nil)
server.ServeError(writer, "Your post looks like spam.", wantsJSON, nil)
return
case "spam":
logEvent.Str("akismet", "spam").Send()
serverutil.ServeError(writer, "Your post looks like spam.", wantsJSON, nil)
server.ServeError(writer, "Your post looks like spam.", wantsJSON, nil)
return
default:
logEvent.Discard()
@ -219,14 +220,14 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
}
if err != nil {
errEv.Err(err).Caller().Str("boardDir", postBoard.Dir).Msg("Unable to check post cooldown")
serverutil.ServeError(writer, "Error checking post cooldown: "+err.Error(), wantsJSON, map[string]interface{}{
server.ServeError(writer, "Error checking post cooldown: "+err.Error(), wantsJSON, map[string]interface{}{
"boardDir": postBoard.Dir,
})
return
}
if tooSoon {
errEv.Int("delay", delay).Msg("Rejecting post (user must wait before making another post)")
serverutil.ServeError(writer, "Please wait before making a new post", wantsJSON, nil)
server.ServeError(writer, "Please wait before making a new post", wantsJSON, nil)
return
}
@ -239,13 +240,13 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
captchaSuccess, err := SubmitCaptchaResponse(request)
if err != nil {
serverutil.ServeErrorPage(writer, "Error submitting captcha response:"+err.Error())
server.ServeErrorPage(writer, "Error submitting captcha response:"+err.Error())
errEv.Err(err).
Caller().Send()
return
}
if !captchaSuccess {
serverutil.ServeErrorPage(writer, "Missing or invalid captcha response")
server.ServeErrorPage(writer, "Missing or invalid captcha response")
errEv.Msg("Missing or invalid captcha response")
return
}
@ -253,12 +254,12 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
noFile := err == http.ErrMissingFile
if noFile && post.ThreadID == 0 && boardConfig.NewThreadsRequireUpload {
errEv.Caller().Msg("New thread rejected (NewThreadsRequireUpload set in config)")
serverutil.ServeError(writer, "Upload required for new threads", wantsJSON, nil)
server.ServeError(writer, "Upload required for new threads", wantsJSON, nil)
return
}
if post.MessageRaw == "" && noFile {
errEv.Caller().Msg("New post rejected (no file and message is blank)")
serverutil.ServeError(writer, "Your post must have an upload or a comment", wantsJSON, nil)
server.ServeError(writer, "Your post must have an upload or a comment", wantsJSON, nil)
return
}
@ -284,7 +285,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
os.Remove(thumbPath)
os.Remove(catalogThumbPath)
}
serverutil.ServeErrorPage(writer, "Unable to insert post: "+err.Error())
server.ServeErrorPage(writer, "Unable to insert post: "+err.Error())
return
}
@ -295,7 +296,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
os.Remove(filePath)
os.Remove(thumbPath)
os.Remove(catalogThumbPath)
serverutil.ServeErrorPage(writer, "Unable to attach upload: "+err.Error())
server.ServeErrorPage(writer, "Unable to attach upload: "+err.Error())
return
}
if upload != nil {
@ -315,12 +316,12 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
// rebuild the board page
if err = building.BuildBoards(false, postBoard.ID); err != nil {
serverutil.ServeErrorPage(writer, "Error building boards: "+err.Error())
server.ServeErrorPage(writer, "Error building boards: "+err.Error())
return
}
if err = building.BuildFrontPage(); err != nil {
serverutil.ServeErrorPage(writer, "Error building front page: "+err.Error())
server.ServeErrorPage(writer, "Error building front page: "+err.Error())
return
}

View file

@ -23,7 +23,8 @@ import (
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
// AttachUploadFromRequest reads an incoming HTTP request and processes any incoming files.
@ -46,7 +47,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
wantsJSON := serverutil.IsRequestingJSON(request)
if err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeError(writer, err.Error(), wantsJSON, nil)
server.ServeError(writer, err.Error(), wantsJSON, nil)
return nil, true
}
upload := &gcsql.Upload{
@ -60,7 +61,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
data, err := io.ReadAll(file)
if err != nil {
errEv.Err(err).Caller().Send()
serverutil.ServeErrorPage(writer, "Error while trying to read file: "+err.Error())
server.ServeErrorPage(writer, "Error while trying to read file: "+err.Error())
return nil, true
}
defer file.Close()
@ -86,7 +87,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
Str("filename", upload.Filename).
Str("originalFilename", upload.OriginalFilename).
Send()
serverutil.ServeError(writer, fmt.Sprintf("Couldn't write file %q", upload.OriginalFilename), wantsJSON, map[string]interface{}{
server.ServeError(writer, fmt.Sprintf("Couldn't write file %q", upload.OriginalFilename), wantsJSON, map[string]interface{}{
"filename": upload.Filename,
"originalFilename": upload.OriginalFilename,
})
@ -109,7 +110,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
Str("thumbPath", thumbPath).
Int("thumbWidth", boardConfig.ThumbWidth).
Msg("Error creating video thumbnail")
serverutil.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
return nil, true
}
} else {
@ -119,7 +120,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
Str("thumbPath", thumbPath).
Int("thumbWidth", boardConfig.ThumbWidthReply).
Msg("Error creating video thumbnail for reply")
serverutil.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
return nil, true
}
}
@ -130,14 +131,14 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
Str("thumbPath", thumbPath).
Int("thumbWidth", boardConfig.ThumbWidthCatalog).
Msg("Error creating video thumbnail for catalog")
serverutil.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Error creating video thumbnail: "+err.Error())
return nil, true
}
outputBytes, err := exec.Command("ffprobe", "-v", "quiet", "-show_format", "-show_streams", filePath).CombinedOutput()
if err != nil {
gcutil.LogError(err).Msg("Error getting video info")
serverutil.ServeErrorPage(writer, "Error getting video info: "+err.Error())
server.ServeErrorPage(writer, "Error getting video info: "+err.Error())
return nil, true
}
if outputBytes != nil {
@ -171,7 +172,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
os.Remove(filePath)
errEv.Err(err).Caller().
Str("filePath", filePath).Send()
serverutil.ServeErrorPage(writer, "Upload filetype not supported")
server.ServeErrorPage(writer, "Upload filetype not supported")
return nil, true
}
// Get image filesize
@ -179,7 +180,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
if err != nil {
errEv.Err(err).Caller().
Str("filePath", filePath).Send()
serverutil.ServeErrorPage(writer, "Couldn't get image filesize: "+err.Error())
server.ServeErrorPage(writer, "Couldn't get image filesize: "+err.Error())
return nil, true
}
upload.FileSize = int(stat.Size())
@ -202,14 +203,14 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
if request.FormValue("spoiler") == "on" {
// If spoiler is enabled, symlink thumbnail to spoiler image
if _, err := os.Stat(path.Join(documentRoot, "spoiler.png")); err != nil {
serverutil.ServeErrorPage(writer, "missing spoiler.png")
server.ServeErrorPage(writer, "missing spoiler.png")
return nil, true
}
if err = syscall.Symlink(path.Join(documentRoot, "spoiler.png"), thumbPath); err != nil {
gcutil.LogError(err).
Str("thumbPath", thumbPath).
Msg("Error creating symbolic link to thumbnail path")
serverutil.ServeErrorPage(writer, err.Error())
server.ServeErrorPage(writer, err.Error())
return nil, true
}
}
@ -227,7 +228,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
errEv.Err(err).Caller().
Str("thumbPath", catalogThumbPath).
Msg("Couldn't generate catalog thumbnail")
serverutil.ServeErrorPage(writer, "Couldn't generate catalog thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Couldn't generate catalog thumbnail: "+err.Error())
return nil, true
}
} else {
@ -237,7 +238,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
errEv.Err(err).Caller().
Str("thumbPath", thumbPath).
Msg("Couldn't generate catalog thumbnail")
serverutil.ServeErrorPage(writer, "Couldn't save thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Couldn't save thumbnail: "+err.Error())
return nil, true
}
} else {
@ -248,7 +249,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
errEv.Err(err).Caller().
Str("thumbPath", thumbPath).
Msg("Couldn't generate catalog thumbnail")
serverutil.ServeErrorPage(writer, "Couldn't create thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Couldn't create thumbnail: "+err.Error())
return nil, true
}
if post.ThreadID == 0 {
@ -258,7 +259,7 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
errEv.Err(err).Caller().
Str("thumbPath", catalogThumbPath).
Msg("Couldn't generate catalog thumbnail")
serverutil.ServeErrorPage(writer, "Couldn't generate catalog thumbnail: "+err.Error())
server.ServeErrorPage(writer, "Couldn't generate catalog thumbnail: "+err.Error())
return nil, true
}
}

View file

@ -1,20 +1,38 @@
package serverutil
package server
import (
"net/http"
"os"
"time"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/uptrace/bunrouter"
)
var (
router *bunrouter.Router
)
// ServeJSON serves data as a JSON string
func ServeJSON(writer http.ResponseWriter, data map[string]interface{}) {
jsonStr, _ := gcutil.MarshalJSON(data, false)
writer.Header().Set("Content-Type", "application/json")
MinifyWriter(writer, []byte(jsonStr), "application/json")
serverutil.MinifyWriter(writer, []byte(jsonStr), "application/json")
}
// ServeErrorPage shows a general error page if something goes wrong
func ServeErrorPage(writer http.ResponseWriter, err string) {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
serverutil.MinifyTemplate(gctemplates.ErrorPage, map[string]interface{}{
"systemCritical": config.GetSystemCriticalConfig(),
"siteConfig": config.GetSiteConfig(),
"boardConfig": config.GetBoardConfig(""),
"errorTitle": "Error :c",
"errorHeader": "Error",
"errorText": err,
}, writer, "text/html")
}
// ServeError serves the given map as a JSON file (with the error string included) if wantsJSON is true,
@ -34,19 +52,6 @@ func ServeError(writer http.ResponseWriter, err string, wantsJSON bool, data map
}
}
// ServeErrorPage shows a general error page if something goes wrong
func ServeErrorPage(writer http.ResponseWriter, err string) {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
MinifyTemplate(gctemplates.ErrorPage, map[string]interface{}{
"systemCritical": config.GetSystemCriticalConfig(),
"siteConfig": config.GetSiteConfig(),
"boardConfig": config.GetBoardConfig(""),
"errorTitle": "Error :c",
"errorHeader": "Error",
"errorText": err,
}, writer, "text/html")
}
// ServeNotFound shows an error page if a requested file is not found
func ServeNotFound(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
@ -56,26 +61,20 @@ func ServeNotFound(writer http.ResponseWriter, request *http.Request) {
if err != nil {
writer.Write([]byte("Requested page not found, and /error/404.html not found"))
} else {
MinifyWriter(writer, errorPage, "text/html")
serverutil.MinifyWriter(writer, errorPage, "text/html")
}
gcutil.LogAccess(request).Int("status", 404).Msg("requested page or resource not found")
}
// DeleteCookie deletes the given cookie if it exists. It returns true if it exists and false
// with no errors if it doesn't
func DeleteCookie(writer http.ResponseWriter, request *http.Request, cookieName string) bool {
cookie, err := request.Cookie(cookieName)
if err != nil {
return false
}
cookie.MaxAge = 0
cookie.Expires = time.Now().Add(-7 * 24 * time.Hour)
http.SetCookie(writer, cookie)
return true
func InitRouter() {
router = bunrouter.New(
bunrouter.WithNotFoundHandler(bunrouter.HTTPHandlerFunc(serveFile)),
)
}
func IsRequestingJSON(request *http.Request) bool {
request.ParseForm()
field := request.Form["json"]
return len(field) == 1 && (field[0] == "1" || field[0] == "true")
func GetRouter() *bunrouter.Router {
if router == nil {
InitRouter()
}
return router
}

View file

@ -0,0 +1,24 @@
package serverutil
import (
"net/http"
"time"
)
// DeleteCookie deletes the given cookie if it exists. It returns true if it exists and false
// with no errors if it doesn't
func DeleteCookie(writer http.ResponseWriter, request *http.Request, cookieName string) bool {
cookie, err := request.Cookie(cookieName)
if err != nil {
return false
}
cookie.MaxAge = 0
cookie.Expires = time.Now().Add(-7 * 24 * time.Hour)
http.SetCookie(writer, cookie)
return true
}
func IsRequestingJSON(request *http.Request) bool {
jsonField := request.FormValue("json")
return jsonField == "1" || jsonField == "true"
}

92
pkg/server/servestatic.go Normal file
View file

@ -0,0 +1,92 @@
package server
import (
"net/http"
"os"
"path"
"strings"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcutil"
)
func serveFile(writer http.ResponseWriter, request *http.Request) {
systemCritical := config.GetSystemCriticalConfig()
siteConfig := config.GetSiteConfig()
requestPath := request.URL.Path
if len(systemCritical.WebRoot) > 0 && systemCritical.WebRoot != "/" {
requestPath = requestPath[len(systemCritical.WebRoot):]
}
filePath := path.Join(systemCritical.DocumentRoot, requestPath)
var fileBytes []byte
results, err := os.Stat(filePath)
if err != nil {
// the requested path isn't a file or directory, 404
ServeNotFound(writer, request)
return
}
//the file exists, or there is a folder here
if results.IsDir() {
//check to see if one of the specified index pages exists
var found bool
for _, value := range siteConfig.FirstPage {
newPath := path.Join(filePath, value)
_, err := os.Stat(newPath)
if err == nil {
filePath = newPath
found = true
break
}
}
if !found {
ServeNotFound(writer, request)
return
}
}
setFileHeaders(filePath, writer)
// serve the requested file
fileBytes, _ = os.ReadFile(filePath)
gcutil.LogAccess(request).Int("status", 200).Send()
writer.Write(fileBytes)
}
// set mime type/cache headers according to the file's extension
func setFileHeaders(filename string, writer http.ResponseWriter) {
extension := strings.ToLower(path.Ext(filename))
switch extension {
case ".png":
writer.Header().Set("Content-Type", "image/png")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".gif":
writer.Header().Set("Content-Type", "image/gif")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".jpg":
fallthrough
case ".jpeg":
writer.Header().Set("Content-Type", "image/jpeg")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".css":
writer.Header().Set("Content-Type", "text/css")
writer.Header().Set("Cache-Control", "max-age=43200")
case ".js":
writer.Header().Set("Content-Type", "text/javascript")
writer.Header().Set("Cache-Control", "max-age=43200")
case ".json":
writer.Header().Set("Content-Type", "application/json")
writer.Header().Set("Cache-Control", "max-age=5, must-revalidate")
case ".webm":
writer.Header().Set("Content-Type", "video/webm")
writer.Header().Set("Cache-Control", "max-age=86400")
case ".htm":
fallthrough
case ".html":
writer.Header().Set("Content-Type", "text/html")
writer.Header().Set("Cache-Control", "max-age=5, must-revalidate")
default:
writer.Header().Set("Content-Type", "application/octet-stream")
writer.Header().Set("Cache-Control", "max-age=86400")
}
}