api,frontend: add Akismet spam flagging integration

This commit is contained in:
Adhityaa Chandrasekar 2018-12-19 22:57:02 -05:00
parent d1318daaca
commit 9fcf67d667
8 changed files with 102 additions and 19 deletions

9
api/Gopkg.lock generated
View File

@ -9,6 +9,14 @@
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239" revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
version = "v0.26.0" version = "v0.26.0"
[[projects]]
branch = "master"
digest = "1:9769b231d8f5ff406a012aa7f293e45ed69d11617832a1c3c7b8c6ce1558a2a1"
name = "github.com/adtac/go-akismet"
packages = ["akismet"]
pruneopts = "UT"
revision = "0ca9e1023047c869ecd4bd3c20780511597a4a77"
[[projects]] [[projects]]
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861" digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
@ -143,6 +151,7 @@
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
input-imports = [ input-imports = [
"github.com/adtac/go-akismet/akismet",
"github.com/gorilla/handlers", "github.com/gorilla/handlers",
"github.com/gorilla/mux", "github.com/gorilla/mux",
"github.com/lib/pq", "github.com/lib/pq",

31
api/akismet.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"github.com/adtac/go-akismet/akismet"
"os"
)
func isSpam(domain string, userIp string, userAgent string, name string, email string, url string, markdown string) bool {
akismetKey := os.Getenv("AKISMET_KEY")
if akismetKey == "" {
return false
}
res, err := akismet.Check(&akismet.Comment{
Blog: domain,
UserIP: userIp,
UserAgent: userAgent,
CommentType: "comment",
CommentAuthor: name,
CommentAuthorEmail: email,
CommentAuthorURL: url,
CommentContent: markdown,
}, akismetKey)
if err != nil {
logger.Errorf("error: cannot validate commenet using Akismet: %v", err)
return true
}
return res
}

View File

@ -89,8 +89,12 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
var state string var state string
if *x.CommenterToken == "anonymous" { if *x.CommenterToken == "anonymous" {
state = "unapproved"
commenterHex = "anonymous" commenterHex = "anonymous"
if isSpam(*x.Domain, getIp(r), getUserAgent(r), "Anonymous", "", "", *x.Markdown) {
state = "flagged"
} else {
state = "unapproved"
}
} else { } else {
c, err := commenterGetByCommenterToken(*x.CommenterToken) c, err := commenterGetByCommenterToken(*x.CommenterToken)
if err != nil { if err != nil {
@ -111,6 +115,9 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
if isModerator { if isModerator {
state = "approved" state = "approved"
} else {
if isSpam(*x.Domain, getIp(r), getUserAgent(r), c.Name, c.Email, c.Link, *x.Markdown) {
state = "flagged"
} else { } else {
if d.RequireModeration { if d.RequireModeration {
state = "unapproved" state = "unapproved"
@ -119,6 +126,7 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
} }
}
commentHex, err := commentNew(commenterHex, domain, path, *x.ParentHex, *x.Markdown, state, time.Now().UTC()) commentHex, err := commentNew(commenterHex, domain, path, *x.ParentHex, *x.Markdown, state, time.Now().UTC())
if err != nil { if err != nil {
@ -126,5 +134,5 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
bodyMarshal(w, response{"success": true, "commentHex": commentHex, "approved": state == "approved"}) bodyMarshal(w, response{"success": true, "commentHex": commentHex, "state": state})
} }

View File

@ -43,6 +43,8 @@ func configParse() error {
"SMTP_PORT": "", "SMTP_PORT": "",
"SMTP_FROM_ADDRESS": "", "SMTP_FROM_ADDRESS": "",
"AKISMET_KEY": "",
"GOOGLE_KEY": "", "GOOGLE_KEY": "",
"GOOGLE_SECRET": "", "GOOGLE_SECRET": "",
} }

View File

@ -43,3 +43,16 @@ func bodyMarshal(w http.ResponseWriter, x map[string]interface{}) error {
w.Write(resp) w.Write(resp)
return nil return nil
} }
func getIp(r *http.Request) string {
ip := r.RemoteAddr
if r.Header.Get("X-Forwarded-For") != "" {
ip = r.Header.Get("X-Forwarded-For")
}
return ip
}
func getUserAgent(r *http.Request) string {
return r.Header.Get("User-Agent")
}

View File

@ -51,6 +51,7 @@
var ID_REMOVE = "commento-comment-remove-"; var ID_REMOVE = "commento-comment-remove-";
var ID_STICKY = "commento-comment-sticky-"; var ID_STICKY = "commento-comment-sticky-";
var ID_CONTENTS = "commento-comment-contents-"; var ID_CONTENTS = "commento-comment-contents-";
var ID_NAME = "commento-comment-name-";
var ID_SUBMIT_BUTTON = "commento-submit-button-"; var ID_SUBMIT_BUTTON = "commento-submit-button-";
var ID_FOOTER = "commento-footer"; var ID_FOOTER = "commento-footer";
@ -519,14 +520,17 @@
$(ID_COMMENTS_AREA).innerHTML = ""; $(ID_COMMENTS_AREA).innerHTML = "";
commentsRender(); commentsRender();
if (!resp.approved) { var message = "";
if (id == "root") { if (resp.state == "unapproved")
var body = $(ID_SUPER_CONTAINER + id); message = "Your comment is under moderation.";
prepend(body, messageCreate("Your comment is under moderation.")); else if (resp.state == "flagged")
} else { message = "Your comment was flagged as spam and is under moderation.";
var body = $(ID_BODY + id);
append(body, messageCreate("Your comment is under moderation.")); if (message != "") {
} if (id == "root")
prepend($(ID_SUPER_CONTAINER + id), messageCreate(message));
else
append($(ID_BODY + id), messageCreate(message));
} }
}); });
}); });
@ -652,6 +656,7 @@
remove.id = ID_REMOVE + comment.commentHex; remove.id = ID_REMOVE + comment.commentHex;
sticky.id = ID_STICKY + comment.commentHex; sticky.id = ID_STICKY + comment.commentHex;
contents.id = ID_CONTENTS + comment.commentHex; contents.id = ID_CONTENTS + comment.commentHex;
name.id = ID_NAME + comment.commentHex;
collapse.title = "Collapse"; collapse.title = "Collapse";
upvote.title = "Upvote"; upvote.title = "Upvote";
@ -692,8 +697,10 @@
} }
classAdd(card, "card"); classAdd(card, "card");
if (isModerator && comment.state == "unapproved") if (isModerator && comment.state != "approved")
classAdd(card, "dark-card"); classAdd(card, "dark-card");
if (comment.state == "flagged")
classAdd(name, "flagged");
classAdd(header, "header"); classAdd(header, "header");
classAdd(name, "name"); classAdd(name, "name");
classAdd(subtitle, "subtitle"); classAdd(subtitle, "subtitle");
@ -773,7 +780,7 @@
if (parentHex == "root") if (parentHex == "root")
append(options, sticky); append(options, sticky);
append(options, remove); append(options, remove);
if (comment.state == "unapproved") if (comment.state != "approved")
append(options, approve); append(options, approve);
} }
else { else {
@ -823,10 +830,12 @@
} }
var card = $(ID_CARD + commentHex); var card = $(ID_CARD + commentHex);
var name = $(ID_NAME + commentHex);
var options = $(ID_OPTIONS + commentHex); var options = $(ID_OPTIONS + commentHex);
var tick = $(ID_APPROVE + commentHex); var tick = $(ID_APPROVE + commentHex);
classRemove(card, "dark-card"); classRemove(card, "dark-card");
classRemove(name, "flagged");
remove(tick); remove(tick);
}); });
} }

View File

@ -124,6 +124,17 @@
width: fit-content; width: fit-content;
} }
.commento-flagged::after {
content: "Flagged";
text-transform: uppercase;
font-size: 10px;
background: $red-7;
color: white;
margin-left: 8px;
padding: 2px 6px 2px 6px;
border-radius: 100px;
}
.commento-subtitle { .commento-subtitle {
display: block; display: block;
color: #999; color: #999;