customizable max comment size
This commit is contained in:
+11
-4
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user