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

Add image and video thumbnail fingerprint checking on post attempt

This commit is contained in:
Eggbertx 2024-02-27 20:47:12 -08:00
parent a102fe355e
commit 8404e3834e
3 changed files with 82 additions and 9 deletions

View file

@ -65,6 +65,39 @@ type FileBan struct {
BanIPMessage *string // sql: `ban_ip_message`
}
// ApplyIPBan bans the given IP if it posted a banned image
// If BanIP is false, it returns with no error
func (fb *FileBan) ApplyIPBan(postIP string) error {
if !fb.BanIP {
return nil
}
now := time.Now()
ipBan := &IPBan{
RangeStart: postIP,
RangeEnd: postIP,
IssuedAt: now,
}
ipBan.IsActive = true
ipBan.CanAppeal = true
ipBan.AppealAt = now
ipBan.StaffID = fb.StaffID
ipBan.Permanent = true
if fb.BoardID != nil {
ipBan.BoardID = new(int)
*ipBan.BoardID = *fb.BoardID
}
if fb.BanIPMessage == nil {
ipBan.Message = "posting disallowed image, resulting in ban"
} else {
ipBan.Message = *fb.BanIPMessage
}
if fb.StaffNote == "" {
ipBan.StaffNote = "fingerprint"
}
return NewIPBan(ipBan)
}
type filenameOrUsernameBanBase struct {
ID int // sql: id
BoardID *int // sql: board_id

View file

@ -1,6 +1,7 @@
package uploads
import (
"bytes"
"crypto/md5"
"errors"
"fmt"
@ -15,6 +16,7 @@ import (
"strings"
"time"
"github.com/disintegration/imaging"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/events"
"github.com/gochan-org/gochan/pkg/gcsql"
@ -138,8 +140,29 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
errEv.Str("catalogThumbPath", catalogThumbPath)
}
if IsImage(filePath) {
img, err := imaging.Decode(bytes.NewReader(data))
if err != nil {
errEv.Err(err).Caller().Msg("unable to decode file")
return nil, errors.New("unable to decode image")
}
fileBan, err := checkImageFingerprintBan(img, postBoard.Dir)
if err != nil {
errEv.Err(err).Caller().Msg("unable to fingerprint image")
return nil, err
}
if fileBan != nil {
// image is fingerprint-banned
if err = fileBan.ApplyIPBan(post.IP); err != nil {
errEv.Err(err).Caller().Msg("unable to apply IP ban")
}
return nil, ErrFileNotAllowed
}
}
if err = os.WriteFile(filePath, data, config.GC_FILE_MODE); err != nil {
errEv.Err(err).Caller().Send()
writer.WriteHeader(http.StatusInternalServerError)
return nil, fmt.Errorf("couldn't write file %q", upload.OriginalFilename)
}
@ -170,6 +193,22 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
if err = uploadHandler(upload, post, postBoard.Dir, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv); err != nil {
return nil, errors.New("error processing upload: " + err.Error())
}
if IsVideo(filePath) && config.GetSiteConfig().FingerprintVideoThumbnails {
fileBan, err := checkFileFingerprintBan(thumbPath, postBoard.Dir)
if err != nil {
errEv.Err(err).Caller().Msg("unable to check video thumbnail ban")
return nil, err
}
if fileBan != nil {
// video thumbnail is fingerprint-banned
if err = fileBan.ApplyIPBan(post.IP); err != nil {
errEv.Err(err).Caller().Msg("unable to apply IP ban")
}
return nil, ErrFileNotAllowed
}
}
accessEv.Send()
return upload, nil
}

View file

@ -1,6 +1,7 @@
package uploads
import (
"database/sql"
"errors"
"fmt"
"image"
@ -18,7 +19,7 @@ var (
)
const (
defaultFingerprintHashLength = 8
defaultFingerprintHashLength = 16
)
type FingerprintSource struct {
@ -41,21 +42,21 @@ func checkImageFingerprintBan(img image.Image, board string) (*gcsql.FileBan, er
if err != nil {
return nil, err
}
const query = `SELECT id,board_id,staff_id,staff_note,issued_at,checksum,fingerprinter,ban_ip,ban_message
fmt.Printf("fingerprint: %x\n", ba)
const query = `SELECT id,board_id,staff_id,staff_note,issued_at,checksum,fingerprinter,
ban_ip,ban_ip_message
FROM DBPREFIXfile_ban WHERE fingerprinter = 'ahash' AND checksum = ? LIMIT 1`
var fileBan gcsql.FileBan
if err = gcsql.QueryRowSQL(query, []any{fmt.Sprintf("%x", ba)}, []any{
err = gcsql.QueryRowSQL(query, []any{fmt.Sprintf("%x", ba)}, []any{
&fileBan.ID, &fileBan.BoardID, &fileBan.StaffID, &fileBan.StaffNote,
&fileBan.IssuedAt, &fileBan.Checksum, &fileBan.Fingerprinter,
&fileBan.BanIP, &fileBan.BanIPMessage,
}); err != nil {
return nil, err
}
if fileBan.ID == 0 {
// no matches
})
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
} else if err != nil {
return nil, err
}
return &fileBan, err
}