validate image existence before post or preview
This commit is contained in:
committed by
Umputun
parent
992b843cf5
commit
fe716b0a71
@@ -88,6 +88,20 @@ func (s *private) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
comment = s.commentFormatter.Format(comment)
|
||||
|
||||
// check if images are valid
|
||||
imgIds, err := s.imageService.ExtractPictures(comment.Text)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't extract pictures from comment text", rest.ErrCommentValidation)
|
||||
return
|
||||
}
|
||||
for _, id := range imgIds {
|
||||
_, err = s.imageService.Load(id)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't load picture from the comment", rest.ErrImgNotFound)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// check if user blocked
|
||||
if s.dataService.IsBlocked(comment.Locator.SiteID, comment.User.ID) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked", rest.ErrUserBlocked)
|
||||
|
||||
@@ -165,6 +165,28 @@ func TestRest_CreateRejected(t *testing.T) {
|
||||
require.Equal(t, http.StatusForbidden, resp.StatusCode, "reject wrong aud")
|
||||
}
|
||||
|
||||
func TestRest_CreateWithWrongImage(t *testing.T) {
|
||||
ts, srv, teardown := startupT(t)
|
||||
defer teardown()
|
||||
|
||||
// create comment
|
||||
resp, err := post(t, ts.URL+"/api/v1/comment", fmt.Sprintf(`{"text": "", "locator":{"url": "https://radio-t.com/blah1", "site": "radio-t"}}`, srv.RemarkURL))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, resp.Body.Close())
|
||||
assert.Contains(t,
|
||||
string(b),
|
||||
"{\"code\":20,\"details\":\"can't load picture from the comment\","+
|
||||
"\"error\":\"can't get image file for dev_user/bad_picture: can't get image stats for dev_user/bad_picture: stat ",
|
||||
)
|
||||
assert.Contains(t,
|
||||
string(b),
|
||||
"/pics-remark42/staging/dev_user/62/bad_picture: no such file or directory\"}\n",
|
||||
)
|
||||
}
|
||||
|
||||
func TestRest_CreateWithLazyImage(t *testing.T) {
|
||||
ts, _, teardown := startupT(t)
|
||||
defer teardown()
|
||||
@@ -979,6 +1001,8 @@ func TestRest_CreateWithPictures(t *testing.T) {
|
||||
}, image.ServiceParams{
|
||||
EditDuration: 100 * time.Millisecond,
|
||||
MaxSize: 2000,
|
||||
ImageAPI: svc.RemarkURL + "/api/v1/picture/",
|
||||
ProxyAPI: svc.RemarkURL + "/api/v1/img",
|
||||
})
|
||||
defer imageService.Close(context.Background())
|
||||
|
||||
@@ -1022,7 +1046,7 @@ func TestRest_CreateWithPictures(t *testing.T) {
|
||||
ids[i] = uploadPicture(fmt.Sprintf("pic%d.png", i))
|
||||
}
|
||||
|
||||
text := fmt.Sprintf(`text 123  *xxx*  `, ids[0], ids[1], ids[2])
|
||||
text := fmt.Sprintf(`text 123  *xxx*  `, svc.RemarkURL, ids[0], svc.RemarkURL, ids[1], svc.RemarkURL, ids[2])
|
||||
body := fmt.Sprintf(`{"text": "%s", "locator":{"url": "https://radio-t.com/blah1", "site": "remark42"}}`, text)
|
||||
|
||||
resp, err := post(t, ts.URL+"/api/v1/comment", body)
|
||||
|
||||
@@ -132,6 +132,21 @@ func (s *public) previewCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
comment = s.commentFormatter.Format(comment)
|
||||
comment.Sanitize()
|
||||
|
||||
// check if images are valid
|
||||
imgIds, err := s.imageService.ExtractPictures(comment.Text)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't extract pictures from comment text", rest.ErrCommentValidation)
|
||||
return
|
||||
}
|
||||
for _, id := range imgIds {
|
||||
_, err = s.imageService.Load(id)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't load picture from the comment", rest.ErrImgNotFound)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
render.HTML(w, r, comment.Text)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,27 @@ func TestRest_Preview(t *testing.T) {
|
||||
assert.Equal(t, 400, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestRest_PreviewWithWrongImage(t *testing.T) {
|
||||
ts, srv, teardown := startupT(t)
|
||||
defer teardown()
|
||||
|
||||
resp, err := post(t, ts.URL+"/api/v1/preview", fmt.Sprintf(`{"text": "", "locator":{"url": "https://radio-t.com/blah1", "site": "radio-t"}}`, srv.RemarkURL))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, resp.Body.Close())
|
||||
assert.Contains(t,
|
||||
string(b),
|
||||
"{\"code\":20,\"details\":\"can't load picture from the comment\","+
|
||||
"\"error\":\"can't get image file for dev_user/bad_picture: can't get image stats for dev_user/bad_picture: stat ",
|
||||
)
|
||||
assert.Contains(t,
|
||||
string(b),
|
||||
"/pics-remark42/staging/dev_user/62/bad_picture: no such file or directory\"}\n",
|
||||
)
|
||||
}
|
||||
|
||||
func TestRest_PreviewWithMD(t *testing.T) {
|
||||
ts, _, teardown := startupT(t)
|
||||
defer teardown()
|
||||
|
||||
@@ -402,6 +402,8 @@ func startupT(t *testing.T) (ts *httptest.Server, srv *Rest, teardown func()) {
|
||||
RestrictedWordsMatcher: restrictedWordsMatcher,
|
||||
}
|
||||
|
||||
remarkURL := "https://demo.remark42.com"
|
||||
|
||||
srv = &Rest{
|
||||
DataService: dataStore,
|
||||
Authenticator: auth.NewService(auth.Opts{
|
||||
@@ -411,13 +413,15 @@ func startupT(t *testing.T) (ts *httptest.Server, srv *Rest, teardown func()) {
|
||||
}),
|
||||
Cache: memCache,
|
||||
WebRoot: tmp,
|
||||
RemarkURL: "https://demo.remark42.com",
|
||||
RemarkURL: remarkURL,
|
||||
ImageService: image.NewService(&image.FileSystem{
|
||||
Location: tmp + "/pics-remark42",
|
||||
Partitions: 100,
|
||||
Staging: tmp + "/pics-remark42/staging",
|
||||
}, image.ServiceParams{
|
||||
EditDuration: 100 * time.Millisecond,
|
||||
ImageAPI: remarkURL + "/api/v1/picture/",
|
||||
ProxyAPI: remarkURL + "/api/v1/img",
|
||||
MaxSize: 10000,
|
||||
}),
|
||||
ImageProxy: &proxy.Image{},
|
||||
|
||||
@@ -39,6 +39,7 @@ const (
|
||||
ErrActionRejected = 17 // general error for rejected actions
|
||||
ErrAssetNotFound = 18 // requested file not found
|
||||
ErrCommentRestrictWords = 19 // restricted words in a comment
|
||||
ErrImgNotFound = 20 // posted image not found in the storage
|
||||
)
|
||||
|
||||
// errTmplData store data for error message
|
||||
|
||||
@@ -148,6 +148,8 @@ func (s *Service) Submit(idsFn func() []string) {
|
||||
}
|
||||
|
||||
// ExtractPictures gets list of images from the doc html and convert from urls to ids, i.e. user/pic.png
|
||||
// It doesn't return possible errors parsing the cached images, and will try to return as many parsed ids
|
||||
// as possible instead.
|
||||
func (s *Service) ExtractPictures(commentHTML string) (ids []string, err error) {
|
||||
|
||||
doc, err := goquery.NewDocumentFromReader(strings.NewReader(commentHTML))
|
||||
|
||||
Reference in New Issue
Block a user