diff --git a/app/migrator/disqus.go b/app/migrator/disqus.go index 301616f3..74295f30 100644 --- a/app/migrator/disqus.go +++ b/app/migrator/disqus.go @@ -129,7 +129,7 @@ func (d *Disqus) convert(r io.Reader, siteID string) (ch chan store.Comment) { ID: comment.UID, Locator: store.Locator{URL: postsMap[comment.Tid.Val], SiteID: siteID}, User: store.User{ - ID: "disqus_" + comment.AuthorUserName, + ID: "disqus_" + store.EncodeID(comment.AuthorUserName), Name: comment.AuthorName, IP: comment.IP, }, diff --git a/app/migrator/disqus_test.go b/app/migrator/disqus_test.go index 8177963d..bce46a57 100644 --- a/app/migrator/disqus_test.go +++ b/app/migrator/disqus_test.go @@ -32,7 +32,7 @@ func TestDisqus_Import(t *testing.T) { assert.Equal(t, "", c.ParentID) assert.Equal(t, store.Locator{SiteID: "test", URL: "http://radio-t.umputun.com/2011/03/229_8880.html"}, c.Locator) assert.Equal(t, "Dmitry Noname", c.User.Name) - assert.Equal(t, "disqus_google-74b9e7568ef6860e93862c5d77590123", c.User.ID) + assert.Equal(t, "disqus_8799342cdf328253e03313958ffc6a433659d7ff", c.User.ID) assert.Equal(t, "89.89.89.139", c.User.IP) posts, err := dataStore.List("test", 0, 0) @@ -63,7 +63,7 @@ func TestDisqus_Convert(t *testing.T) { Text: `
The quick brown fox jumps over the lazy dog.
`, User: store.User{ Name: "Alexander Blah", - ID: "disqus_facebook-1787732238", + ID: "disqus_328c8b68974aef73785f6b38c3d3fedfdf941434", IP: "178.178.178.178", }, } diff --git a/app/rest/api/rest.go b/app/rest/api/rest.go index 2a9ec992..60a38ed6 100644 --- a/app/rest/api/rest.go +++ b/app/rest/api/rest.go @@ -41,6 +41,8 @@ type Rest struct { amdminService admin } +const hardBodyLimit = 1024 * 64 // limit size of body + var mdExt = blackfriday.NoIntraEmphasis | blackfriday.Tables | blackfriday.FencedCode | blackfriday.Strikethrough | blackfriday.SpaceHeadings | blackfriday.HardLineBreak | blackfriday.BackslashLineBreak @@ -124,7 +126,7 @@ func (s *Rest) Run(port int) { func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) { comment := store.Comment{} - if err := render.DecodeJSON(r.Body, &comment); err != nil { + if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &comment); err != nil { rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment") return } @@ -166,7 +168,7 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) { func (s *Rest) previewCommentCtrl(w http.ResponseWriter, r *http.Request) { comment := store.Comment{} - if err := render.DecodeJSON(r.Body, &comment); err != nil { + if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &comment); err != nil { rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment") return } @@ -195,7 +197,7 @@ func (s *Rest) updateCommentCtrl(w http.ResponseWriter, r *http.Request) { Summary string }{} - if err := render.DecodeJSON(r.Body, &edit); err != nil { + if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &edit); err != nil { rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't bind comment") return } @@ -397,7 +399,7 @@ func (s *Rest) countCtrl(w http.ResponseWriter, r *http.Request) { func (s *Rest) countMultiCtrl(w http.ResponseWriter, r *http.Request) { siteID := r.URL.Query().Get("site") posts := []string{} - if err := render.DecodeJSON(r.Body, &posts); err != nil { + if err := render.DecodeJSON(http.MaxBytesReader(w, r.Body, hardBodyLimit), &posts); err != nil { rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get list of posts from request") return } diff --git a/app/rest/auth/avatar.go b/app/rest/auth/avatar.go index e4a70c77..8f2928ac 100644 --- a/app/rest/auth/avatar.go +++ b/app/rest/auth/avatar.go @@ -53,7 +53,7 @@ func (p *AvatarProxy) Put(u store.User) (avatarURL string, err error) { }() // get ID and location of locally cached avatar - encID := rest.EncodeID(u.ID) + encID := store.EncodeID(u.ID) location := p.location(encID) // location adds partion to path if _, err = os.Stat(location); os.IsNotExist(err) { diff --git a/app/rest/auth/providers.go b/app/rest/auth/providers.go index c6698e42..5e0d2c6e 100644 --- a/app/rest/auth/providers.go +++ b/app/rest/auth/providers.go @@ -9,7 +9,6 @@ import ( "golang.org/x/oauth2/github" "golang.org/x/oauth2/google" - "github.com/umputun/remark/app/rest" "github.com/umputun/remark/app/store" ) @@ -25,7 +24,7 @@ func NewGoogle(p Params) Provider { MapUser: func(data userData, _ []byte) store.User { userInfo := store.User{ // encode email with provider name to avoid collision if same id returned by other provider - ID: "google_" + rest.EncodeID(data.value("email")), + ID: "google_" + store.EncodeID(data.value("email")), Name: data.value("name"), Picture: data.value("picture"), } @@ -48,7 +47,7 @@ func NewGithub(p Params) Provider { Store: p.SessionStore, MapUser: func(data userData, _ []byte) store.User { userInfo := store.User{ - ID: "github_" + rest.EncodeID(data.value("login")), + ID: "github_" + store.EncodeID(data.value("login")), Name: data.value("name"), Picture: data.value("avatar_url"), } @@ -83,7 +82,7 @@ func NewFacebook(p Params) Provider { Store: p.SessionStore, MapUser: func(data userData, bdata []byte) store.User { userInfo := store.User{ - ID: "facebook_" + rest.EncodeID(data.value("id")), + ID: "facebook_" + store.EncodeID(data.value("id")), Name: data.value("name"), } if userInfo.Name == "" { @@ -113,7 +112,7 @@ func NewDisqus(p Params) Provider { Store: p.SessionStore, MapUser: func(data userData, _ []byte) store.User { userInfo := store.User{ - ID: "disqus_" + rest.EncodeID(data.value("login")), + ID: "disqus_" + store.EncodeID(data.value("login")), Name: data.value("name"), Picture: data.value("avatar_url"), } diff --git a/app/rest/user.go b/app/rest/user.go index 7264faf3..a48a748f 100644 --- a/app/rest/user.go +++ b/app/rest/user.go @@ -2,11 +2,7 @@ package rest import ( "context" - "crypto/sha1" "errors" - "fmt" - "hash/crc64" - "log" "net/http" "github.com/umputun/remark/app/store" @@ -35,14 +31,3 @@ func SetUserInfo(r *http.Request, user store.User) *http.Request { ctx = context.WithValue(ctx, contextKey("user"), user) return r.WithContext(ctx) } - -// EncodeID hashes user id to sha1 -func EncodeID(id string) string { - h := sha1.New() - if _, err := h.Write([]byte(id)); err != nil { - // fail back to crc64 - log.Printf("[WARN] can't hash id %s, %s", id, err) - return fmt.Sprintf("%x", crc64.Checksum([]byte(id), crc64.MakeTable(crc64.ECMA))) - } - return fmt.Sprintf("%x", h.Sum(nil)) -} diff --git a/app/rest/user_test.go b/app/rest/user_test.go index 7c65330b..4edf4c2c 100644 --- a/app/rest/user_test.go +++ b/app/rest/user_test.go @@ -8,21 +8,6 @@ import ( "github.com/umputun/remark/app/store" ) -func TestEncodeID(t *testing.T) { - tbl := []struct { - id string - hash string - }{ - {"myid", "6e34471f84557e1713012d64a7477c71bfdac631"}, - {"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, - {"blah blah", "135a1e01bae742c4a576b20fd41a683f6483ca43"}, - } - - for i, tt := range tbl { - assert.Equal(t, tt.hash, EncodeID(tt.id), "case #%d", i) - } -} - func TestGetUserInfo(t *testing.T) { r, err := http.NewRequest("GET", "http://blah.com", nil) assert.Nil(t, err) diff --git a/app/store/comment.go b/app/store/comment.go index de1b551d..28390096 100644 --- a/app/store/comment.go +++ b/app/store/comment.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/sha1" "fmt" + "hash/crc64" "html/template" "log" "strconv" @@ -95,7 +96,7 @@ func (c *Comment) Sanitize() { // c.Text = strings.Replace(c.Text, "\t", "", -1) } -// hashIP replace sensitive fields with hashes +// hashIP replace sensitive fields with hmac func (u *User) hashIP(secret string) { hashVal := func(val string) string { @@ -112,3 +113,15 @@ func (u *User) hashIP(secret string) { u.IP = hashVal(u.IP) } + +// EncodeID hashes id to sha1. The function intentionally left outside of User struct because in some cases +// we need hashing for parts of id, in some others hasing for non-User values. +func EncodeID(id string) string { + h := sha1.New() + if _, err := h.Write([]byte(id)); err != nil { + // fail back to crc64 + log.Printf("[WARN] can't hash id %s, %s", id, err) + return fmt.Sprintf("%x", crc64.Checksum([]byte(id), crc64.MakeTable(crc64.ECMA))) + } + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/app/store/comment_test.go b/app/store/comment_test.go index 33713083..e37989e6 100644 --- a/app/store/comment_test.go +++ b/app/store/comment_test.go @@ -58,3 +58,18 @@ func TestComment_PrepareUntrusted(t *testing.T) { assert.Equal(t, User{ID: "username"}, comment.User) } + +func TestComment_EncodeID(t *testing.T) { + tbl := []struct { + id string + hash string + }{ + {"myid", "6e34471f84557e1713012d64a7477c71bfdac631"}, + {"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, + {"blah blah", "135a1e01bae742c4a576b20fd41a683f6483ca43"}, + } + + for i, tt := range tbl { + assert.Equal(t, tt.hash, EncodeID(tt.id), "case #%d", i) + } +}