add mask info to hide exposed ip, add separate cache for admins
This commit is contained in:
@@ -126,14 +126,28 @@ func (a *admin) checkBlocked(siteID string, user store.User) bool {
|
||||
}
|
||||
|
||||
// processes comments and hides text of all comments for blocked users.
|
||||
// resets score and votes too
|
||||
func (a *admin) maskBlockedUsers(comments []store.Comment) (res []store.Comment) {
|
||||
// resets score and votes too. Also hides sensitive info for non-admin users
|
||||
func (a *admin) maskInfo(comments []store.Comment, r *http.Request) (res []store.Comment) {
|
||||
res = make([]store.Comment, len(comments))
|
||||
|
||||
isAdmin := false
|
||||
if user, err := rest.GetUserInfo(r); err == nil && user.Admin { // make seprate cache key for admins
|
||||
isAdmin = true
|
||||
}
|
||||
|
||||
for i, c := range comments {
|
||||
|
||||
// process blocked users
|
||||
if a.dataService.IsBlocked(c.Locator.SiteID, c.User.ID) {
|
||||
c.Mask()
|
||||
c.User.Blocked = true
|
||||
}
|
||||
|
||||
// hide info from non-admins
|
||||
if !isAdmin {
|
||||
c.User.IP = ""
|
||||
}
|
||||
|
||||
res[i] = c
|
||||
}
|
||||
return res
|
||||
|
||||
+18
-8
@@ -228,12 +228,12 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")}
|
||||
log.Printf("[DEBUG] get comments for %+v", locator)
|
||||
|
||||
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
|
||||
data, err := s.Cache.Get(s.urlKey(r), time.Hour, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Find(locator, r.URL.Query().Get("sort"))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
maskedComments := s.mod.maskBlockedUsers(comments)
|
||||
maskedComments := s.mod.maskInfo(comments, r)
|
||||
var b []byte
|
||||
switch r.URL.Query().Get("format") {
|
||||
case "tree":
|
||||
@@ -261,12 +261,12 @@ func (s *Rest) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
max = 0
|
||||
}
|
||||
|
||||
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
|
||||
data, err := s.Cache.Get(s.urlKey(r), time.Hour, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Last(r.URL.Query().Get("site"), max)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.mod.maskBlockedUsers(comments)
|
||||
comments = s.mod.maskInfo(comments, r)
|
||||
return encodeJSONWithHTML(comments)
|
||||
})
|
||||
|
||||
@@ -291,7 +291,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.maskBlockedUsers([]store.Comment{comment})[0]
|
||||
comment = s.mod.maskInfo([]store.Comment{comment}, r)[0]
|
||||
render.Status(r, http.StatusOK)
|
||||
renderJSONWithHTML(w, r, comment)
|
||||
}
|
||||
@@ -309,12 +309,12 @@ func (s *Rest) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Printf("[DEBUG] get comments for userID %s, %s", userID, siteID)
|
||||
|
||||
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
|
||||
data, err := s.Cache.Get(s.urlKey(r), time.Hour, func() ([]byte, error) {
|
||||
comments, count, e := s.DataService.User(siteID, userID)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.mod.maskBlockedUsers(comments)
|
||||
comments = s.mod.maskInfo(comments, r)
|
||||
resp.Comments, resp.Count = comments, count
|
||||
return encodeJSONWithHTML(resp)
|
||||
})
|
||||
@@ -374,7 +374,7 @@ func (s *Rest) countCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Rest) listCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
siteID := r.URL.Query().Get("site")
|
||||
data, err := s.Cache.Get(r.URL.String(), 8*time.Hour, func() ([]byte, error) {
|
||||
data, err := s.Cache.Get(s.urlKey(r), 8*time.Hour, func() ([]byte, error) {
|
||||
posts, e := s.DataService.List(siteID)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
@@ -471,6 +471,16 @@ func (s *Rest) addFileServer(r chi.Router, path string, root http.FileSystem) {
|
||||
}))
|
||||
}
|
||||
|
||||
// urlKey gets url from request to use is as cache key
|
||||
// admins will have separate keys in order tp prevent leak of admin-only data to regular users
|
||||
func (s *Rest) urlKey(r *http.Request) string {
|
||||
key := r.URL.String()
|
||||
if user, err := rest.GetUserInfo(r); err == nil && user.Admin { // make seprate cache key for admins
|
||||
key = "admin!!" + key
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// renderJSONWithHTML allows html tags and forces charset=utf-8
|
||||
func renderJSONWithHTML(w http.ResponseWriter, r *http.Request, v interface{}) {
|
||||
data, err := encodeJSONWithHTML(v)
|
||||
|
||||
@@ -82,7 +82,7 @@ func TestServer_CreateAndGet(t *testing.T) {
|
||||
assert.Equal(t, "<p><strong>test</strong> <em>123</em> http://radio-t.com</p>", comment.Text)
|
||||
assert.Equal(t, store.User{Name: "developer one", ID: "dev",
|
||||
Picture: "https://friends.radio-t.com/resources/images/rt_logo_64.png",
|
||||
Profile: "https://radio-t.com/info/", Admin: true, Blocked: false, IP: ""},
|
||||
Profile: "https://radio-t.com/info/", Admin: true, Blocked: false, IP: "127.0.0.1"},
|
||||
comment.User)
|
||||
t.Logf("%+v", comment)
|
||||
}
|
||||
|
||||
+12
-2
@@ -34,10 +34,10 @@ type User struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Picture string `json:"picture"`
|
||||
Profile string `json:"profile"`
|
||||
Profile string `json:"profile,omitempty"`
|
||||
Admin bool `json:"admin"`
|
||||
Blocked bool `json:"block,omitempty"`
|
||||
IP string `json:"-"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
}
|
||||
|
||||
// Edit indication
|
||||
@@ -64,6 +64,16 @@ type NotifUser struct {
|
||||
Destination string `json:"destination"`
|
||||
}
|
||||
|
||||
// NotifScope defines "enum" of notification scopes
|
||||
type NotifScope int
|
||||
|
||||
// All NotifScope values
|
||||
const (
|
||||
ScopeSite NotifScope = 1
|
||||
ScopePost NotifScope = 2
|
||||
ScopeReply NotifScope = 3
|
||||
)
|
||||
|
||||
// Sanitize clean dangerous html/js from the comment
|
||||
func (c *Comment) Sanitize() {
|
||||
p := bluemonday.UGCPolicy()
|
||||
|
||||
+1
-11
@@ -33,23 +33,13 @@ type Admin interface {
|
||||
Blocked(siteID string) ([]BlockedUser, error) // get list of blocked users
|
||||
}
|
||||
|
||||
// Notifier defines all store ops for update modifications
|
||||
// Notifier defines all store ops to store/retrive notification info for users
|
||||
type Notifier interface {
|
||||
Set(locator Locator, user NotifUser, scope NotifScope, status bool) error // subscribe / unsubscribe user to locator updates
|
||||
Status(locator Locator, userID string) bool // get subscription status for user & locator
|
||||
List(locator Locator) ([]NotifUser, error) // list all subscribed users
|
||||
}
|
||||
|
||||
// NotifScope defines "enum" of notification scopes
|
||||
type NotifScope int
|
||||
|
||||
// All NotifScope values
|
||||
const (
|
||||
ScopeSite NotifScope = 1
|
||||
ScopePost NotifScope = 2
|
||||
ScopeReply NotifScope = 3
|
||||
)
|
||||
|
||||
func sortComments(comments []Comment, sortFld string) []Comment {
|
||||
sort.Slice(comments, func(i, j int) bool {
|
||||
switch sortFld {
|
||||
|
||||
Reference in New Issue
Block a user