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:
parent
a102fe355e
commit
8404e3834e
3 changed files with 82 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue