prep hashed ip and id

This commit is contained in:
Umputun
2018-03-22 02:38:49 -05:00
parent 1e395456da
commit ee4228c5d2
4 changed files with 67 additions and 26 deletions
+1 -6
View File
@@ -126,7 +126,7 @@ func (a *admin) checkBlocked(siteID string, user store.User) bool {
return a.dataService.IsBlocked(siteID, user.ID)
}
// processes comments and hides text of all comments for blocked users.
// post-processes comments, hides text of all comments for blocked users,
// resets score and votes too. Also hides sensitive info for non-admin users
func (a *admin) alterComments(comments []store.Comment, r *http.Request) (res []store.Comment) {
res = make([]store.Comment, len(comments))
@@ -145,11 +145,6 @@ func (a *admin) alterComments(comments []store.Comment, r *http.Request) (res []
c.Deleted = true
}
// set default avatar
if c.User.Picture == "" {
c.User.Picture = a.defAvatarURL
}
// hide info from non-admins
if !isAdmin {
c.User.IP = ""
+14 -15
View File
@@ -36,8 +36,8 @@ type Rest struct {
Cache rest.LoadingCache
WebRoot string
httpServer *http.Server
mod admin
httpServer *http.Server
amdminService admin
}
// Run the lister and request's router, activate rest server
@@ -48,6 +48,10 @@ func (s *Rest) Run(port int) {
log.Printf("[DEBUG] admins %+v", s.Authenticator.Admins)
}
s.amdminService = admin{dataService: s.DataService, exporter: s.Exporter, cache: s.Cache,
defAvatarURL: s.Authenticator.AvatarProxy.Default(),
}
router := chi.NewRouter()
router.Use(middleware.RealIP, Recoverer)
router.Use(middleware.Throttle(1000), middleware.Timeout(60*time.Second))
@@ -92,14 +96,9 @@ func (s *Rest) Run(port int) {
rauth.Put("/comment/{id}", s.updateCommentCtrl)
rauth.Get("/user", s.userInfoCtrl)
rauth.Put("/vote/{id}", s.voteCtrl)
// admin routes, admin users only
s.mod = admin{
dataService: s.DataService,
exporter: s.Exporter,
cache: s.Cache,
defAvatarURL: s.Authenticator.AvatarProxy.Default(),
}
rauth.Mount("/admin", s.mod.routes(s.Authenticator.AdminOnly))
rauth.Mount("/admin", s.amdminService.routes(s.Authenticator.AdminOnly))
})
})
@@ -129,14 +128,14 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
return
}
comment.Prepare() // clean all fields user not suppoed to set
comment.PrepareUntrusted() // clean all fields user not suppoed to set
comment.User = user
comment.User.IP = strings.Split(r.RemoteAddr, ":")[0]
comment.Text = string(blackfriday.Run([]byte(comment.Text), blackfriday.WithNoExtensions())) // render markdown
log.Printf("[DEBUG] create comment %+v", comment)
// check if user blocked
if s.mod.checkBlocked(comment.Locator.SiteID, comment.User) {
if s.amdminService.checkBlocked(comment.Locator.SiteID, comment.User) {
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked")
return
}
@@ -220,7 +219,7 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
if e != nil {
return nil, e
}
maskedComments := s.mod.alterComments(comments, r)
maskedComments := s.amdminService.alterComments(comments, r)
var b []byte
switch r.URL.Query().Get("format") {
case "tree":
@@ -253,7 +252,7 @@ func (s *Rest) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
if e != nil {
return nil, e
}
comments = s.mod.alterComments(comments, r)
comments = s.amdminService.alterComments(comments, r)
return encodeJSONWithHTML(comments)
})
@@ -278,7 +277,7 @@ func (s *Rest) commentByIDCtrl(w http.ResponseWriter, r *http.Request) {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by id")
return
}
comment = s.mod.alterComments([]store.Comment{comment}, r)[0]
comment = s.amdminService.alterComments([]store.Comment{comment}, r)[0]
render.Status(r, http.StatusOK)
renderJSONWithHTML(w, r, comment)
}
@@ -306,7 +305,7 @@ func (s *Rest) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
if e != nil {
return nil, e
}
comments = s.mod.alterComments(comments, r)
comments = s.amdminService.alterComments(comments, r)
resp.Comments, resp.Count = comments, count
return encodeJSONWithHTML(resp)
})
+26 -3
View File
@@ -1,7 +1,11 @@
package store
import (
"crypto/sha1"
"fmt"
"hash/crc64"
"html/template"
"strconv"
"strings"
"time"
@@ -59,9 +63,9 @@ type BlockedUser struct {
Timestamp time.Time `json:"time"`
}
// Prepare comment received from untrusted source by clearing all autogen fields and
// reset everyting users not supposed to provide
func (c *Comment) Prepare() {
// PrepareUntrusted preprocess comment received from untrusted source by clearing all
// autogen fields and reset everyting users not supposed to provide
func (c *Comment) PrepareUntrusted() {
c.ID = "" // don't allow user to define ID, force auto-gen
c.Timestamp = time.Time{} // reset time, force auto-gen
c.Votes = make(map[string]bool)
@@ -84,6 +88,25 @@ func (c *Comment) Sanitize() {
c.Text = strings.Replace(c.Text, "\t", "", -1)
}
// HashUserFields replace sensitive fields with hashes
func (c *Comment) HashUserFields() {
hashVal := func(val string) string {
if _, err := strconv.ParseUint(val, 16, 64); err == nil || val == "" {
return val // already hashed
}
h := sha1.New()
if _, err := h.Write([]byte(val)); err != nil {
// fail back to crc64
return fmt.Sprintf("%x", crc64.Checksum([]byte(val), crc64.MakeTable(crc64.ECMA)))
}
return fmt.Sprintf("%x", h.Sum(nil))
}
c.User.IP = hashVal(c.User.IP)
c.User.ID = hashVal(c.User.ID)
}
// SetDeleted clears comment info, reset to deleted state
func (c *Comment) SetDeleted() {
c.Text = ""
+26 -2
View File
@@ -32,7 +32,7 @@ func TestComment_Sanitize(t *testing.T) {
}
}
func TestComment_Prepare(t *testing.T) {
func TestComment_PrepareUntrusted(t *testing.T) {
comment := Comment{
Text: `blah`,
User: User{ID: "username"},
@@ -46,7 +46,7 @@ func TestComment_Prepare(t *testing.T) {
Votes: map[string]bool{"uu": true},
}
comment.Prepare()
comment.PrepareUntrusted()
assert.Equal(t, "", comment.ID)
assert.Equal(t, "p123", comment.ParentID)
assert.Equal(t, "blah", comment.Text)
@@ -58,3 +58,27 @@ func TestComment_Prepare(t *testing.T) {
assert.Equal(t, User{ID: "username"}, comment.User)
}
func TestComment_HashUserFields(t *testing.T) {
tbl := []struct {
inp Comment
out Comment
}{
{inp: Comment{}, out: Comment{}},
{
inp: Comment{
Text: "blah",
User: User{ID: "my id", IP: "127.0.0.1"},
},
out: Comment{
Text: "blah",
User: User{ID: "de58071dda71e1783b6deb931ddb48bb66966f79", IP: "4b84b15bff6ee5796152495a230e45e3d7e947d9"},
},
},
}
for n, tt := range tbl {
tt.inp.HashUserFields()
assert.Equal(t, tt.out, tt.inp, "check #%d", n)
}
}