Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions server/torr/dbwrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,18 @@ func AddTorrentDB(torr *Torrent) {
t.Data = torr.Data
}

if torr.Poster != "" && utils.CheckImgUrl(torr.Poster) {
t.Poster = torr.Poster
t.Poster = torr.Poster
if t.Poster != "" {
var existing string
if db := GetTorrentDB(torr.Hash()); db != nil {
existing = db.Poster
}
if existing != t.Poster {
ok, verified := utils.CheckImgUrl(t.Poster)
if !ok || (existing != "" && !verified) {
t.Poster = existing
}
}
}
t.Size = torr.Size
if t.Size == 0 && torr.Torrent != nil {
Expand Down
30 changes: 19 additions & 11 deletions server/torr/utils/webImageChecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
_ "image/png"
"io"
"net/http"
"net/url"
"strings"
"time"

Expand All @@ -16,9 +17,17 @@ import (
"server/log"
)

func CheckImgUrl(link string) bool {
// CheckImgUrl reports whether link may be stored.
// verified is true only when a real image body was decoded; a timeout or
// transport error is ok but not verified, so a caller with an existing poster
// should keep it.
func CheckImgUrl(link string) (ok, verified bool) {
if link == "" {
return false
return false, false
}
u, err := url.Parse(link)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
return false, false
}

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
Expand All @@ -27,17 +36,13 @@ func CheckImgUrl(link string) bool {
req, err := http.NewRequestWithContext(ctx, "GET", link, nil)
if err != nil {
log.TLogln("Error create request for image:", err)
return false
}

client := &http.Client{
Timeout: 5 * time.Second,
return false, false
}

resp, err := client.Do(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.TLogln("Error check image:", err)
return false
return true, false
}
defer resp.Body.Close()

Expand All @@ -50,7 +55,10 @@ func CheckImgUrl(link string) bool {
}
if err != nil {
log.TLogln("Error decode image:", err)
return false
if ctx.Err() != nil {
return true, false
}
return false, false
}
return true
return true, true
}
67 changes: 67 additions & 0 deletions server/torr/utils/webImageChecker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package utils

import (
"bytes"
"image"
"image/jpeg"
"net/http"
"net/http/httptest"
"testing"
)

func TestCheckImgUrl(t *testing.T) {
for _, link := range []string{
"",
"javascript:alert(1)",
"data:text/html,<script>alert(1)</script>",
"file:///etc/passwd",
} {
if ok, _ := CheckImgUrl(link); ok {
t.Errorf("%q: want reject", link)
}
}

var jpegBuf bytes.Buffer
if err := jpeg.Encode(&jpegBuf, image.NewRGBA(image.Rect(0, 0, 1, 1)), nil); err != nil {
t.Fatal(err)
}

okSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "image/jpeg")
w.Write(jpegBuf.Bytes())
}))
defer okSrv.Close()
if ok, verified := CheckImgUrl(okSrv.URL + "/poster.jpg"); !ok || !verified {
t.Error("jpeg: want ok and verified")
}

htmlSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.Write([]byte("<html>not an image</html>"))
}))
defer htmlSrv.Close()
if ok, _ := CheckImgUrl(htmlSrv.URL + "/index.html"); ok {
t.Error("html: want reject")
}

hangSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-r.Context().Done()
}))
defer hangSrv.Close()
if ok, verified := CheckImgUrl(hangSrv.URL + "/poster.jpg"); !ok || verified {
t.Error("timeout: want ok, not verified")
}

slowSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/jpeg")
w.WriteHeader(http.StatusOK)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
<-r.Context().Done()
}))
defer slowSrv.Close()
if ok, verified := CheckImgUrl(slowSrv.URL + "/poster.jpg"); !ok || verified {
t.Error("decode after deadline: want ok, not verified")
}
}