customizable max comment size

This commit is contained in:
Umputun
2018-05-06 19:15:36 -05:00
parent e8a59ed238
commit 639f89064b
9 changed files with 75 additions and 64 deletions
+11 -4
View File
@@ -33,9 +33,10 @@ var opts struct {
BackupLocation string `long:"backup" env:"BACKUP_PATH" default:"./var/backup" description:"backups location"`
MaxBackupFiles int `long:"max-back" env:"MAX_BACKUP_FILES" default:"10" description:"max backups to keep"`
SessionStore string `long:"session" env:"SESSION_STORE" default:"./var/session" description:"session store location"`
AvatarStore string `long:"avatars" env:"AVATAR_STORE" default:"./var/avatars" description:"avatars location"`
StoreKey string `long:"store-key" env:"STORE_KEY" default:"secure-store-key" description:"store key"`
SessionStore string `long:"session" env:"SESSION_STORE" default:"./var/session" description:"session store location"`
AvatarStore string `long:"avatars" env:"AVATAR_STORE" default:"./var/avatars" description:"avatars location"`
StoreKey string `long:"store-key" env:"STORE_KEY" default:"secure-store-key" description:"store key"`
MaxCommentSize int `long:"max-comment" env:"MAX_COMMENT_SIZE" default:"2048" description:"max comment size"`
GoogleCID string `long:"google-cid" env:"REMARK_GOOGLE_CID" description:"Google OAuth client ID"`
GoogleCSEC string `long:"google-csec" env:"REMARK_GOOGLE_CSEC" description:"Google OAuth client secret"`
@@ -72,7 +73,13 @@ func main() {
log.Printf("[WARN] running in dev mode")
}
dataService := store.Service{Interface: dataStore, EditDuration: 5 * time.Minute, Secret: opts.StoreKey}
dataService := store.Service{
Interface: dataStore,
EditDuration: 5 * time.Minute,
Secret: opts.StoreKey,
MaxCommentSize: opts.MaxCommentSize,
}
sessionStore := func() sessions.Store {
sess := sessions.NewFilesystemStore(opts.SessionStore, []byte(opts.StoreKey))
sess.Options.HttpOnly = true
+2 -2
View File
@@ -19,9 +19,9 @@ func TestAdmin_Delete(t *testing.T) {
assert.NotNil(t, srv)
defer cleanup(srv)
c1 := store.Comment{Text: "test test #1",
c1 := store.Comment{Text: "test test #1", User: store.User{ID: "id", Name: "name"},
Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}}
c2 := store.Comment{Text: "test test #2", ParentID: "p1",
c2 := store.Comment{Text: "test test #2", User: store.User{ID: "id", Name: "name"}, ParentID: "p1",
Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}}
id1 := addComment(t, c1, port)
+2 -2
View File
@@ -139,7 +139,7 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
comment.User = user
comment.User.IP = strings.Split(r.RemoteAddr, ":")[0]
if comment.Validate() != nil {
if err := s.DataService.ValidateComment(&comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
return
}
@@ -177,7 +177,7 @@ func (s *Rest) previewCommentCtrl(w http.ResponseWriter, r *http.Request) {
return
}
comment.User = user
if err := comment.Validate(); err != nil {
if err := s.DataService.ValidateComment(&comment); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "invalid comment")
return
}
+1 -1
View File
@@ -439,7 +439,7 @@ func prep(t *testing.T) (srv *Rest, port int) {
dataStore, err := store.NewBoltDB(bolt.Options{}, store.BoltSite{FileName: testDb, SiteID: "radio-t"})
require.Nil(t, err)
srv = &Rest{
DataService: store.Service{Interface: dataStore, EditDuration: 5 * time.Minute},
DataService: store.Service{Interface: dataStore, EditDuration: 5 * time.Minute, MaxCommentSize: 4000},
Authenticator: auth.Authenticator{
SessionStore: sessions.NewFilesystemStore("/tmp", []byte("blah")),
DevPasswd: "password",
+10 -9
View File
@@ -2,6 +2,7 @@ package rest
import (
"net/http"
"sync/atomic"
"testing"
"time"
@@ -10,32 +11,32 @@ import (
)
func TestLoadingCache_Get(t *testing.T) {
var postFnCall, coldCalls int
var postFnCall, coldCalls int32
lc := NewLoadingCache(1*time.Minute, 200*time.Millisecond, func() {
postFnCall++
atomic.AddInt32(&postFnCall, 1)
})
res, err := lc.Get("key", time.Minute, func() ([]byte, error) {
coldCalls++
atomic.AddInt32(&coldCalls, 1)
return []byte("result"), nil
})
assert.Nil(t, err)
assert.Equal(t, "result", string(res))
assert.Equal(t, 1, coldCalls)
assert.Equal(t, 0, postFnCall)
assert.Equal(t, int32(1), atomic.LoadInt32(&coldCalls))
assert.Equal(t, int32(0), atomic.LoadInt32(&postFnCall))
res, err = lc.Get("key", time.Minute, func() ([]byte, error) {
coldCalls++
atomic.AddInt32(&coldCalls, 1)
return []byte("result"), nil
})
assert.Nil(t, err)
assert.Equal(t, "result", string(res))
assert.Equal(t, 1, coldCalls)
assert.Equal(t, 0, postFnCall)
assert.Equal(t, int32(1), atomic.LoadInt32(&coldCalls))
assert.Equal(t, int32(0), atomic.LoadInt32(&postFnCall))
lc.Flush()
time.Sleep(100 * time.Millisecond) // let postFn to do its thing
assert.Equal(t, 1, postFnCall)
assert.Equal(t, int32(1), atomic.LoadInt32(&postFnCall))
}
func TestLoadingCache_URLKey(t *testing.T) {
-18
View File
@@ -3,7 +3,6 @@ package store
import (
"crypto/hmac"
"crypto/sha1"
"errors"
"fmt"
"html/template"
"log"
@@ -63,9 +62,6 @@ 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() {
@@ -99,20 +95,6 @@ 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) {
-26
View File
@@ -4,7 +4,6 @@ import (
"testing"
"time"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
@@ -33,31 +32,6 @@ 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`,
+21 -2
View File
@@ -10,8 +10,9 @@ import (
// Service wraps store.Interface with additional methods
type Service struct {
Interface
EditDuration time.Duration
Secret string
EditDuration time.Duration
Secret string
MaxCommentSize int
}
// Create prepares comment and forward to Interface.Create
@@ -115,3 +116,21 @@ func (s *Service) Counts(siteID string, postIDs []string) ([]PostInfo, error) {
}
return res, nil
}
// ValidateComment checks if comment size below max and user fields set
func (s *Service) ValidateComment(c *Comment) error {
maxSize := s.MaxCommentSize
if s.MaxCommentSize <= 0 {
maxSize = 2000
}
if c.Text == "" {
return errors.New("empty comment text")
}
if len(c.Text) > maxSize {
return errors.New("comment text exceeded max allowed size")
}
if c.User.ID == "" || c.User.Name == "" {
return errors.New("empty user info")
}
return nil
}
+28
View File
@@ -6,6 +6,7 @@ import (
"time"
"github.com/coreos/bbolt"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
@@ -166,6 +167,33 @@ func TestService_EditCommentDurationFailed(t *testing.T) {
assert.NotNil(t, err)
}
func TestService_ValidateComment(t *testing.T) {
b := Service{MaxCommentSize: 2000}
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 := b.ValidateComment(&tt.inp)
if tt.err == nil {
assert.Nil(t, e, "check #%d", n)
continue
}
assert.EqualError(t, tt.err, e.Error(), "check #%d", n)
}
}
func TestService_Counts(t *testing.T) {
defer os.Remove(testDb)
b := prep(t) // two comments for https://radio-t.com