diff --git a/app/rest/api/rest.go b/app/rest/api/rest.go index cf871921..40abed6d 100644 --- a/app/rest/api/rest.go +++ b/app/rest/api/rest.go @@ -138,6 +138,12 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) { comment.PrepareUntrusted() // clean all fields user not suppoed to set comment.User = user comment.User.IP = strings.Split(r.RemoteAddr, ":")[0] + + if comment.Validate() != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment") + return + } + comment.Text = string(blackfriday.Run([]byte(comment.Text), blackfriday.WithExtensions(mdExt))) log.Printf("[DEBUG] create comment %+v", comment) @@ -165,6 +171,17 @@ func (s *Rest) previewCommentCtrl(w http.ResponseWriter, r *http.Request) { return } + user, err := rest.GetUserInfo(r) + if err != nil { // this not suppose to happen (handled by Auth), just dbl-check + rest.SendErrorJSON(w, r, http.StatusUnauthorized, err, "can't get user info") + return + } + comment.User = user + if err := comment.Validate(); err != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment") + return + } + comment.Text = string(blackfriday.Run([]byte(comment.Text), blackfriday.WithExtensions(mdExt))) comment.Sanitize() render.HTML(w, r, comment.Text) diff --git a/app/rest/api/rest_test.go b/app/rest/api/rest_test.go index 62cdee3d..831f0c88 100644 --- a/app/rest/api/rest_test.go +++ b/app/rest/api/rest_test.go @@ -63,7 +63,7 @@ func TestServer_Preview(t *testing.T) { defer cleanup(srv) r := strings.NewReader(`{"text": "test 123", "locator":{"url": "https://radio-t.com/blah1", "site": "radio-t"}}`) - resp, err := http.Post(fmt.Sprintf("http://127.0.0.1:%d/api/v1/preview", port), "application/json", r) + resp, err := http.Post(fmt.Sprintf("http://dev:password@127.0.0.1:%d/api/v1/preview", port), "application/json", r) assert.Equal(t, http.StatusOK, resp.StatusCode) b, err := ioutil.ReadAll(resp.Body) assert.Nil(t, err) @@ -90,7 +90,7 @@ BKT j = strings.Replace(j, "\n", "\\n", -1) t.Log(j) r := strings.NewReader(j) - resp, err := http.Post(fmt.Sprintf("http://127.0.0.1:%d/api/v1/preview", port), "application/json", r) + resp, err := http.Post(fmt.Sprintf("http://dev:password@127.0.0.1:%d/api/v1/preview", port), "application/json", r) assert.Equal(t, http.StatusOK, resp.StatusCode) b, err := ioutil.ReadAll(resp.Body) assert.Nil(t, err) diff --git a/app/store/comment.go b/app/store/comment.go index de1b551d..28c461aa 100644 --- a/app/store/comment.go +++ b/app/store/comment.go @@ -3,6 +3,7 @@ package store import ( "crypto/hmac" "crypto/sha1" + "errors" "fmt" "html/template" "log" @@ -62,6 +63,9 @@ type BlockedUser struct { Timestamp time.Time `json:"time"` } +// MaxCommentSize defines max size of comment's text +const MaxCommentSize = 2048 + // PrepareUntrusted preprocess comment received from untrusted source by clearing all // autogen fields and reset everything users not supposed to provide func (c *Comment) PrepareUntrusted() { @@ -95,6 +99,20 @@ func (c *Comment) Sanitize() { // c.Text = strings.Replace(c.Text, "\t", "", -1) } +// Validate comment +func (c *Comment) Validate() error { + if c.Text == "" { + return errors.New("empty comment text") + } + if len(c.Text) > MaxCommentSize { + return errors.New("comment text exceeded max allowed size") + } + if c.User.ID == "" || c.User.Name == "" { + return errors.New("empty user info") + } + return nil +} + // hashIP replace sensitive fields with hashes func (u *User) hashIP(secret string) { diff --git a/app/store/comment_test.go b/app/store/comment_test.go index 33713083..0180c80f 100644 --- a/app/store/comment_test.go +++ b/app/store/comment_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -32,6 +33,31 @@ func TestComment_Sanitize(t *testing.T) { } } +func TestComment_Validate(t *testing.T) { + longText := "" + for i := 0; i < 4000; i++ { + longText += "X" + } + tbl := []struct { + inp Comment + err error + }{ + {inp: Comment{}, err: errors.New("empty comment text")}, + {inp: Comment{Text: "something blah", User: User{ID: "myid", Name: "name"}}, err: nil}, + {inp: Comment{Text: "something blah", User: User{ID: "myid"}}, err: errors.New("empty user info")}, + {inp: Comment{Text: longText, User: User{ID: "myid", Name: "name"}}, err: errors.New("comment text exceeded max allowed size")}, + } + + for n, tt := range tbl { + e := tt.inp.Validate() + if tt.err == nil { + assert.Nil(t, e, "check #%d", n) + continue + } + assert.EqualError(t, tt.err, e.Error(), "check #%d", n) + } +} + func TestComment_PrepareUntrusted(t *testing.T) { comment := Comment{ Text: `blah`,