1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-05 11:06:23 -07:00

Make thumbnail extension determining more dynamic, move to uploads pkg

This commit is contained in:
Eggbertx 2023-07-14 11:04:46 -07:00
parent b0e81aac99
commit a0c0466725
16 changed files with 173 additions and 172 deletions

View file

@ -15,6 +15,7 @@ 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/posting/uploads"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
@ -151,7 +152,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
return
}
defer rows.Close()
var uploads []upload
var postUploads []upload
for rows.Next() {
var filename string
if err = rows.Scan(&filename); err != nil {
@ -165,7 +166,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
})
return
}
uploads = append(uploads, upload{
postUploads = append(postUploads, upload{
filename: filename,
boardDir: board.Dir,
})
@ -173,7 +174,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
// done as a goroutine to avoid delays if the thread has a lot of files
// the downside is of course that if something goes wrong, deletion errors
// won't be seen in the browser
go deleteUploads(uploads)
go deleteUploads(postUploads)
} else if deletePostUpload(post, board, writer, request, errEv) {
return
}
@ -222,24 +223,24 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
}
}
func deleteUploads(uploads []upload) {
func deleteUploads(postUploads []upload) {
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
var filePath, thumbPath, catalogThumbPath string
var filePath string
var err error
for _, upload := range uploads {
for _, upload := range postUploads {
filePath = path.Join(documentRoot, upload.boardDir, "src", upload.filename)
if err = os.Remove(filePath); err != nil && !errors.Is(err, os.ErrNotExist) {
gcutil.LogError(err).Caller().
Str("filePath", filePath).
Int("postid", upload.postID).Send()
}
thumbPath = path.Join(documentRoot, upload.boardDir, "thumb", gcutil.GetThumbnailPath("reply", upload.filename))
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
path.Join(documentRoot, upload.boardDir, "thumb", upload.filename))
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, os.ErrNotExist) {
gcutil.LogError(err).Caller().
Str("thumbPath", thumbPath).
Int("postid", upload.postID).Send()
}
catalogThumbPath = path.Join(documentRoot, upload.boardDir, "thumb", gcutil.GetThumbnailPath("catalog", upload.filename))
if err = os.Remove(catalogThumbPath); err != nil && !errors.Is(err, os.ErrNotExist) {
gcutil.LogError(err).Caller().
Str("catalogThumbPath", catalogThumbPath).
@ -272,11 +273,11 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
return true
}
// delete the file's thumbnail
thumbPath := path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("thumb"))
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(path.Join(documentRoot, board.Dir, "thumb", upload.Filename))
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
errEv.Err(err).Caller().
Int("postid", post.ID).
Str("thumbnail", upload.ThumbnailPath("thumb")).
Str("thumbnail", thumbPath).
Msg("Unable to delete thumbnail")
server.ServeError(writer, "Unable to delete thumbnail: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})
@ -284,11 +285,10 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
}
// delete the catalog thumbnail
if post.IsTopPost {
thumbPath := path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("catalog"))
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
if err = os.Remove(catalogThumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
errEv.Err(err).Caller().
Int("postid", post.ID).
Str("catalogThumb", upload.ThumbnailPath("catalog")).
Str("catalogThumb", catalogThumbPath).
Msg("Unable to delete catalog thumbnail")
server.ServeError(writer, "Unable to delete catalog thumbnail: "+err.Error(),
wantsJSON, map[string]interface{}{"postid": post.ID})

View file

@ -148,9 +148,9 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
return
}
upload, gotErr := uploads.AttachUploadFromRequest(request, writer, post, board)
if gotErr {
// AttachUploadFromRequest handles error serving/logging
upload, err := uploads.AttachUploadFromRequest(request, writer, post, board)
if err != nil {
server.ServeError(writer, err.Error(), wantsJSON, nil)
return
}
if upload == nil {
@ -161,8 +161,8 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
var filePath, thumbPath, catalogThumbPath string
if oldUpload != nil {
filePath = path.Join(documentRoot, board.Dir, "src", oldUpload.Filename)
thumbPath = path.Join(documentRoot, board.Dir, "thumb", oldUpload.ThumbnailPath("thumb"))
catalogThumbPath = path.Join(documentRoot, board.Dir, "thumb", oldUpload.ThumbnailPath("catalog"))
thumbPath, catalogThumbPath = uploads.GetThumbnailFilenames(
path.Join(documentRoot, board.Dir, "thumb", oldUpload.Filename))
if err = post.UnlinkUploads(false); err != nil {
errEv.Err(err).Caller().Send()
server.ServeError(writer, "Error unlinking old upload from post: "+err.Error(), wantsJSON, nil)
@ -186,8 +186,8 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
"filename": upload.OriginalFilename,
})
filePath = path.Join(documentRoot, board.Dir, "src", upload.Filename)
thumbPath = path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("thumb"))
catalogThumbPath = path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("catalog"))
thumbPath, catalogThumbPath = uploads.GetThumbnailFilenames(
path.Join(documentRoot, board.Dir, "thumb", upload.Filename))
os.Remove(filePath)
os.Remove(thumbPath)
if post.IsTopPost {

View file

@ -14,6 +14,7 @@ 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/posting/uploads"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
@ -213,12 +214,13 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
}
// move the upload thumbnail
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(upload.Filename)
if tmpErr = moveFileIfExists(
path.Join(documentRoot, srcBoard.Dir, "thumb", upload.ThumbnailPath("upload")),
path.Join(documentRoot, destBoard.Dir, "thumb", upload.ThumbnailPath("upload")),
path.Join(documentRoot, srcBoard.Dir, "thumb", thumbnail),
path.Join(documentRoot, destBoard.Dir, "thumb", thumbnail),
); tmpErr != nil {
errEv.Err(err).Caller().
Str("thumbnail", upload.ThumbnailPath("upload")).
Str("thumbnail", thumbnail).
Msg("Unable to move thumbnail from source board to destination board")
if err == nil {
err = tmpErr
@ -227,11 +229,11 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
if upload.PostID == post.ID {
// move the upload catalog thumbnail
if tmpErr = moveFileIfExists(
path.Join(documentRoot, srcBoard.Dir, "thumb", upload.ThumbnailPath("catalog")),
path.Join(documentRoot, destBoard.Dir, "thumb", upload.ThumbnailPath("catalog")),
path.Join(documentRoot, srcBoard.Dir, "thumb", catalogThumbnail),
path.Join(documentRoot, destBoard.Dir, "thumb", catalogThumbnail),
); tmpErr != nil {
errEv.Err(err).Caller().
Str("catalogThumbnail", upload.ThumbnailPath("catalog")).
Str("catalogThumbnail", catalogThumbnail).
Msg("Unable to move catalog thumbnail from source board to destination board")
}
if err == nil {

View file

@ -12,6 +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/posting/uploads"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
@ -370,19 +371,19 @@ func buildBoard(board *gcsql.Board, force bool) error {
Str("upload", filePath).Send()
return err
}
filePath = path.Join(boardDir, "thumb", upload.ThumbnailPath("thumbnail"))
if err = os.Remove(filePath); err != nil {
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
path.Join(boardDir, "thumb", upload.Filename))
if err = os.Remove(thumbPath); err != nil {
errEv.Err(err).Caller().
Int("postID", postID).
Str("upload", filePath).Send()
Str("thumbnail", thumbPath).Send()
return err
}
if post.IsTopPost && board.EnableCatalog {
filePath = path.Join(boardDir, "thumb", upload.ThumbnailPath("catalog"))
if err = os.Remove(filePath); err != nil {
if err = os.Remove(catalogThumbPath); err != nil {
errEv.Err(err).Caller().
Int("postID", postID).
Str("upload", filePath).Send()
Str("catalogThumbPath", catalogThumbPath).Send()
return err
}
}

View file

@ -13,6 +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/posting/uploads"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
@ -63,10 +64,11 @@ func getRecentPosts() ([]recentPost, error) {
if len(message) > 40 {
message = message[:37] + "..."
}
thumbnail, _ := uploads.GetThumbnailFilenames(filename)
post = recentPost{
Board: boardDir,
URL: config.WebPath(boardDir, "res", topPostID+".html") + "#" + id,
ThumbURL: config.WebPath(boardDir, "thumb", gcutil.GetThumbnailPath("post", filename)),
ThumbURL: config.WebPath(boardDir, "thumb", thumbnail),
Filename: filename,
FileDeleted: filename == "deleted",
MessageSample: message,

View file

@ -8,7 +8,7 @@ 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/posting/uploads"
)
const (
@ -103,7 +103,11 @@ func (p Post) ThumbnailPath() string {
if p.Filename == "" {
return ""
}
return config.WebPath(p.BoardDir, "thumb", gcutil.GetThumbnailPath("reply", p.Filename))
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(p.Filename)
if p.IsTopPost {
return config.WebPath(p.BoardDir, "thumb", catalogThumbnail)
}
return config.WebPath(p.BoardDir, "thumb", thumbnail)
}
func (p Post) UploadPath() string {

View file

@ -17,6 +17,7 @@ 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/posting/uploads"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
@ -129,6 +130,34 @@ func registerLuaFunctions() {
lState.Register("warn_log", createLuaLogFunc("warn"))
lState.Register("error_log", createLuaLogFunc("error"))
lState.Register("register_upload_handler", func(l *lua.LState) int {
ext := l.CheckString(1)
handler := l.CheckFunction(2)
uploads.RegisterUploadHandler(ext, func(upload *gcsql.Upload, post *gcsql.Post, board, filePath, thumbPath, catalogThumbPath string, infoEv, accessEv, errEv *zerolog.Event) error {
l.CallByParam(lua.P{
Fn: handler,
NRet: 1,
// Protect: true,
}, luar.New(l, upload), luar.New(l, post), lua.LString(board), lua.LString(filePath), lua.LString(thumbPath), lua.LString(catalogThumbPath))
errRet := l.CheckAny(-1)
fmt.Println("Error:", errRet, errRet == nil)
return nil
})
return 0
})
lState.Register("get_thumbnail_ext", func(l *lua.LState) int {
fileExt := l.CheckString(1)
l.Push(luar.New(l, uploads.GetThumbnailExtension(fileExt)))
return 1
})
lState.Register("set_thumbnail_ext", func(l *lua.LState) int {
fileExt := l.CheckString(1)
thumbExt := l.CheckString(2)
uploads.SetThumbnailExtension(fileExt, thumbExt)
return 0
})
lState.Register("system_critical_config", func(l *lua.LState) int {
l.Push(luar.New(l, config.GetSystemCriticalConfig()))
return 1

View file

@ -2,8 +2,6 @@ package gcsql
import (
"errors"
"github.com/gochan-org/gochan/pkg/gcutil"
)
const (
@ -88,8 +86,3 @@ func (p *Post) AttachFile(upload *Upload) error {
}
return tx.Commit()
}
// ThumbnailPath returns the thumbnail path of the upload, given an thumbnail type ("thumbnail" or "catalog")
func (u *Upload) ThumbnailPath(thumbType string) string {
return gcutil.GetThumbnailPath(thumbType, u.Filename)
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"html"
"html/template"
"path"
"reflect"
"strconv"
"strings"
@ -13,6 +14,7 @@ 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/posting/uploads"
)
var (
@ -197,32 +199,19 @@ var funcMap = template.FuncMap{
return ban.IP
},
"getCatalogThumbnail": func(img string) string {
return gcutil.GetThumbnailPath("catalog", img)
_, catalogThumb := uploads.GetThumbnailFilenames(img)
return catalogThumb
},
"getTopPostID": func(post *gcsql.Post) int {
id, _ := post.TopPostID()
return id
},
"getThreadThumbnail": func(img string) string {
return gcutil.GetThumbnailPath("thread", img)
thumb, _ := uploads.GetThumbnailFilenames(img)
return thumb
},
"getUploadType": func(name string) string {
return gcutil.GetThumbnailExt(name)
},
"imageToThumbnailPath": func(thumbType string, img string) string {
filetype := strings.ToLower(img[strings.LastIndex(img, ".")+1:])
if filetype == "gif" || filetype == "webm" || filetype == "mp4" {
filetype = "jpg"
}
index := strings.LastIndex(img, ".")
if index < 0 || index > len(img) {
return ""
}
thumbSuffix := "t." + filetype
if thumbType == "catalog" {
thumbSuffix = "c." + filetype
}
return img[0:index] + thumbSuffix
return uploads.GetThumbnailExtension(path.Ext(name))
},
"numReplies": func(boardid, opID int) int {
num, err := gcsql.GetThreadReplyCountFromOP(opID)

View file

@ -138,47 +138,6 @@ func GetRealIP(request *http.Request) string {
return remoteHost
}
// GetThumbnailExt returns the extension to be used when creating a thumbnail of img. For non-image files,
// it returns an empty string, in which case a generic icon will be (eventually) used
func GetThumbnailExt(filename string) string {
ext := filepath.Ext(strings.ToLower(filename))
switch ext {
case ".gif":
fallthrough
case ".mp4":
fallthrough
case ".png":
fallthrough
case ".webm":
fallthrough
case ".webp":
return "png"
case ".jfif":
fallthrough
case ".jpg":
fallthrough
case ".jpeg":
return "jpg"
default:
// invalid file format
return ""
}
}
// GetThumbnailPath returns the thumbnail path of the given filename
func GetThumbnailPath(thumbType string, img string) string {
ext := GetThumbnailExt(img)
index := strings.LastIndex(img, ".")
if index < 0 || index > len(img) {
return ""
}
thumbSuffix := "t." + ext
if thumbType == "catalog" {
thumbSuffix = "c." + ext
}
return img[0:index] + thumbSuffix
}
// HackyStringToInt parses a string to an int, or 0 if error
func HackyStringToInt(text string) int {
value, _ := strconv.Atoi(text)

View file

@ -291,18 +291,18 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
return
}
upload, gotErr := uploads.AttachUploadFromRequest(request, writer, post, postBoard)
if gotErr {
// got an error receiving the upload, stop here (assuming an error page was actually shown)
upload, err := uploads.AttachUploadFromRequest(request, writer, post, postBoard)
if err != nil {
// got an error receiving the upload or the upload was rejected
server.ServeError(writer, err.Error(), wantsJSON, nil)
return
}
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
var filePath, thumbPath, catalogThumbPath string
if upload != nil {
filePath = path.Join(documentRoot, postBoard.Dir, "src", upload.Filename)
thumbPath = path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("thumb"))
catalogThumbPath = path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("catalog"))
_, err, recovered = events.TriggerEvent("incoming-upload", upload)
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
path.Join(documentRoot, postBoard.Dir, "thumb", upload.Filename))
if recovered {
os.Remove(filePath)
os.Remove(thumbPath)

View file

@ -8,6 +8,7 @@ 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/posting/uploads"
)
func tempCleaner() {
@ -41,19 +42,19 @@ func tempCleaner() {
Str("filePath", fileSrc).Send()
}
thumbSrc := upload.ThumbnailPath("thread")
if err = os.Remove(thumbSrc); err != nil {
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(
path.Join(systemCritical.DocumentRoot, board.Dir, "thumb", upload.Filename))
if err = os.Remove(thumbnail); err != nil {
gcutil.LogError(err).
Str("subject", "tempUpload").
Str("filePath", thumbSrc).Send()
Str("filePath", thumbnail).Send()
}
if post.IsTopPost {
catalogSrc := upload.ThumbnailPath("catalog")
if err = os.Remove(catalogSrc); err != nil {
if err = os.Remove(catalogThumbnail); err != nil {
gcutil.LogError(err).
Str("subject", "tempUpload").
Str("filePath", catalogSrc).Send()
Str("filePath", catalogThumbnail).Send()
}
}
}

View file

@ -19,8 +19,6 @@ import (
"github.com/gochan-org/gochan/pkg/events"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
"github.com/rs/zerolog"
)
@ -49,7 +47,7 @@ func init() {
// AttachUploadFromRequest reads an incoming HTTP request and processes any incoming files.
// It returns the upload (if there was one) and whether or not any errors were served (meaning
// that it should stop processing the post
func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter, post *gcsql.Post, postBoard *gcsql.Board) (*gcsql.Upload, bool) {
func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter, post *gcsql.Post, postBoard *gcsql.Board) (*gcsql.Upload, error) {
errEv := gcutil.LogError(nil).
Str("IP", post.IP)
infoEv := gcutil.LogInfo().
@ -58,16 +56,14 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
infoEv.Discard()
errEv.Discard()
}()
wantsJSON := serverutil.IsRequestingJSON(request)
file, handler, err := request.FormFile("imagefile")
if errors.Is(err, http.ErrMissingFile) {
// no file was submitted with the form
return nil, false
return nil, nil
}
if err != nil {
errEv.Err(err).Caller().Send()
server.ServeError(writer, err.Error(), wantsJSON, nil)
return nil, true
return nil, err
}
upload := &gcsql.Upload{
OriginalFilename: html.EscapeString(handler.Filename),
@ -78,47 +74,37 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
boardConfig := config.GetBoardConfig(postBoard.Dir)
if !boardConfig.AcceptedExtension(upload.OriginalFilename) {
errEv.Caller().Msg("Upload filetype not supported")
server.ServeError(writer, "Upload filetype not supported", wantsJSON, map[string]interface{}{
"filename": upload.OriginalFilename,
})
return nil, true
return nil, ErrUnsupportedFileExt
}
if IsFilenameBanned(upload, post, postBoard, writer, request) {
if err = CheckFilenameBan(upload, post, postBoard, writer, request); err != nil {
// If checkFilenameBan returns true, an error occured or the file was
// rejected for having a banned filename, and the incident was logged either way
return nil, true
return nil, err
}
data, err := io.ReadAll(file)
if err != nil {
errEv.Err(err).Caller().Send()
server.ServeError(writer, "Error while trying to read file: "+err.Error(), wantsJSON, map[string]interface{}{
"filename": upload.OriginalFilename,
})
return nil, true
return nil, errors.New("Error while trying to read file: " + err.Error())
}
defer file.Close()
// Calculate image checksum
upload.Checksum = fmt.Sprintf("%x", md5.Sum(data)) // skipcq: GSC-G401
if IsChecksumBanned(upload, post, postBoard, writer, request) {
// If checkChecksumBan returns true, an error occured or the file was
if err = CheckFileChecksumBan(upload, post, postBoard, writer, request); err != nil {
// If CheckFileChecksumBan returns a non-nil error, an error occured or the file was
// rejected for having a banned checksum, and the incident was logged either way
return nil, true
return nil, err
}
ext := strings.ToLower(filepath.Ext(upload.OriginalFilename))
upload.Filename = getNewFilename() + ext
errorMap := map[string]any{
"filename": upload.Filename,
"originalFilename": upload.OriginalFilename,
}
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
filePath := path.Join(documentRoot, postBoard.Dir, "src", upload.Filename)
thumbPath := path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("thumb"))
catalogThumbPath := path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("catalog"))
thumbPath, catalogThumbPath := GetThumbnailFilenames(
path.Join(documentRoot, postBoard.Dir, "thumb", upload.Filename))
errEv.
Str("originalFilename", upload.OriginalFilename).
@ -129,28 +115,17 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
if err = os.WriteFile(filePath, data, config.GC_FILE_MODE); err != nil {
errEv.Err(err).Caller().Send()
server.ServeError(writer, fmt.Sprintf("Couldn't write file %q", upload.OriginalFilename), wantsJSON, errorMap)
return nil, true
}
gcutil.LogStr("stripImageMetadata", boardConfig.StripImageMetadata, errEv, infoEv)
if err = stripImageMetadata(filePath, boardConfig); err != nil {
errEv.Err(err).Caller().Msg("Unable to strip metadata")
server.ServeError(writer, "Unable to strip metadata from image", wantsJSON, errorMap)
return nil, true
return nil, fmt.Errorf("couldn't write file %q", upload.OriginalFilename)
}
// event triggered after the file is successfully written but be
_, err, recovered := events.TriggerEvent("upload-saved", filePath)
if recovered {
writer.WriteHeader(http.StatusInternalServerError)
server.ServeError(writer, "Unable to save upload (recovered from a panic in event handler)", wantsJSON,
map[string]interface{}{"event": "upload-saved"})
return nil, true
return nil, errors.New("unable to save upload (recovered from a panic in event handler)")
}
if err != nil {
server.ServeError(writer, err.Error(), wantsJSON, errorMap)
return nil, true
return nil, err
}
infoEv.Str("referer", request.Referer()).Str("filename", handler.Filename).Send()
@ -168,13 +143,10 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
}
if err = uploadHandler(upload, post, postBoard.Dir, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv); err != nil {
server.ServeError(writer, "Error processing upload: "+err.Error(), wantsJSON, map[string]interface{}{
"filename": upload.OriginalFilename,
})
return nil, true
return nil, errors.New("error processing upload:" + err.Error())
}
accessEv.Send()
return upload, false
return upload, nil
}
func getNewFilename() string {

View file

@ -1,15 +1,20 @@
package uploads
import (
"errors"
"net/http"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
func IsFilenameBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) bool {
var (
ErrFilenameNotAllowed = errors.New("filename not allowed")
ErrCheckingFileBan = errors.New("unable to check file ban info")
ErrFileNotAllowed = errors.New("uploaded file not allowed")
)
func CheckFilenameBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) error {
filenameBan, err := gcsql.CheckFilenameBan(upload.OriginalFilename, postBoard.ID)
if err != nil {
gcutil.LogError(err).
@ -17,20 +22,18 @@ func IsFilenameBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
Str("filename", upload.OriginalFilename).
Str("boardDir", postBoard.Dir).
Msg("Error getting name banned status")
server.ServeErrorPage(writer, "Error getting filename ban info")
return true
return ErrCheckingFileBan
}
if filenameBan == nil {
return false
return nil
}
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")
return true
return ErrFilenameNotAllowed
}
func IsChecksumBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) bool {
func CheckFileChecksumBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) error {
fileBan, err := gcsql.CheckFileChecksumBan(upload.Checksum, postBoard.ID)
if err != nil {
gcutil.LogError(err).
@ -38,16 +41,14 @@ func IsChecksumBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
Str("boardDir", postBoard.Dir).
Str("checksum", upload.Checksum).
Msg("Error getting file checksum ban status")
server.ServeErrorPage(writer, "Error processing file: "+err.Error())
return true
return ErrCheckingFileBan
}
if fileBan == nil {
return false
return nil
}
server.ServeError(writer, "File not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
gcutil.LogWarning().
Str("originalFilename", upload.OriginalFilename).
Str("checksum", upload.Checksum).
Msg("File rejected for having a banned checksum")
return true
return ErrFileNotAllowed
}

View file

@ -1,6 +1,7 @@
package uploads
import (
"errors"
"image"
"image/gif"
"os"
@ -11,9 +12,14 @@ import (
"github.com/disintegration/imaging"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/rs/zerolog"
)
var (
ErrStripMetadata = errors.New("unable to strip image metadata")
)
func stripImageMetadata(filePath string, boardConfig *config.BoardConfig) (err error) {
var stripFlag string
switch boardConfig.StripImageMetadata {
@ -47,6 +53,14 @@ func numImageFrames(imgPath string) (int, error) {
}
func processImage(upload *gcsql.Upload, post *gcsql.Post, board string, filePath string, thumbPath string, catalogThumbPath string, infoEv *zerolog.Event, accessEv *zerolog.Event, errEv *zerolog.Event) error {
boardConfig := config.GetBoardConfig(board)
gcutil.LogStr("stripImageMetadata", boardConfig.StripImageMetadata, errEv, infoEv)
err := stripImageMetadata(filePath, boardConfig)
if err != nil {
errEv.Err(err).Caller().Msg("Unable to strip metadata")
return ErrStripMetadata
}
img, err := imaging.Open(filePath)
if err != nil {
os.Remove(filePath)

View file

@ -23,6 +23,40 @@ const (
ThumbnailCatalog
)
var (
thumbnailExtensions = map[string]string{
".gif": ".png",
".mp4": ".png",
".webm": ".png",
".webp": ".png",
".jfif": ".jpg",
".jpeg": ".jpg",
}
)
func GetThumbnailExtension(fileExt string) string {
thumbExt, ok := thumbnailExtensions[fileExt]
if !ok {
return fileExt
}
return thumbExt
}
func SetThumbnailExtension(fileExt, thumbExt string) {
thumbnailExtensions[fileExt] = thumbExt
}
// GetThumbnailFilenames returns the regular thumbnail and the catalog thumbnail filenames of the given upload
// filename. It does not check if the catalog actually exists (for example, if it's a reply)
func GetThumbnailFilenames(img string) (string, string) {
ext := GetThumbnailExtension(path.Ext(img))
index := strings.LastIndex(img, ".")
if index < 0 || index > len(img) {
return "", ""
}
return img[:index] + "t" + ext, img[:index] + "c" + ext
}
func createImageThumbnail(imageObj image.Image, boardDir string, thumbType ThumbnailCategory) image.Image {
thumbWidth, thumbHeight := getBoardThumbnailSize(boardDir, thumbType)