Skip to content
This repository has been archived by the owner on Jul 23, 2020. It is now read-only.

Commit

Permalink
v0.1.2 - add rel="nofollow" to external links from users with less th…
Browse files Browse the repository at this point in the history
…an 10 reputation
  • Loading branch information
BenLubar committed Jul 12, 2016
1 parent efea3d1 commit a93b58b
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 97 deletions.
4 changes: 4 additions & 0 deletions cleaner/config.go
Expand Up @@ -13,6 +13,7 @@ var Config = &htmlcleaner.Config{
Elem: map[atom.Atom]map[atom.Atom]bool{
atom.A: {
atom.Href: true,
atom.Rel: true,
},
atom.Img: {
atom.Src: true,
Expand Down Expand Up @@ -125,6 +126,9 @@ var Config = &htmlcleaner.Config{
WrapText: true,

AttrMatch: map[atom.Atom]map[atom.Atom]*regexp.Regexp{
atom.A: {
atom.Rel: regexp.MustCompile(`\Anofollow\z`),
},
atom.Img: {
atom.Class: regexp.MustCompile(`\A((emoji|img-markdown|img-responsive)(\s+|\s*\z))*\z`),
},
Expand Down
51 changes: 51 additions & 0 deletions cleaner/nofollow.go
@@ -0,0 +1,51 @@
package cleaner

import (
"net/url"

"github.com/BenLubar/htmlcleaner"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
)

func NoFollow(content string, base *url.URL) string {
nodes := htmlcleaner.ParseDepth(content, 0)
for _, n := range nodes {
noFollow(n, base)
}
return htmlcleaner.Render(nodes...)
}

func noFollow(n *html.Node, base *url.URL) {
if n.Type != html.ElementNode {
return
}

for c := n.FirstChild; c != nil; c = c.NextSibling {
noFollow(c, base)
}

if n.DataAtom == atom.A {
for _, a := range n.Attr {
if a.Key == "href" {
u, err := base.Parse(a.Val)
if err != nil || u.Host != base.Host || u.Scheme != base.Scheme {
break
}
return
}
}

for i, a := range n.Attr {
if a.Key == "rel" {
n.Attr[i].Val = "nofollow"
return
}
}

n.Attr = append(n.Attr, html.Attribute{
Key: "rel",
Val: "nofollow",
})
}
}
27 changes: 25 additions & 2 deletions fix.go
@@ -1,20 +1,43 @@
package main

import (
"net/url"
"strings"

"github.com/BenLubar/nodebb-plugin-htmlcleaner/cleaner"
"github.com/gopherjs/gopherjs/js"
)

// zero width non-breaking space is illegal anyway, so removing it won't cause
// any problems as long as another plugin isn't using the same hack.
var fixer = strings.NewReplacer("\n<", "\n\ufeff<")
var remover = strings.NewReplacer("\ufeff", "")

func fix(s string) string {
func fix(s, uid string) string {
return fixer.Replace(s)
}

func clean(s string) string {
var nconfURL, _ = url.Parse(js.Module.Get("parent").Call("require", "nconf").Call("get", "url").String())
var user = js.Module.Get("parent").Call("require", "./user.js")

func clean(s, uid string) (content string) {
defer func() {
rep := make(chan int, 1)
if id := js.Global.Call("parseInt", uid, 10).Int(); id > 0 {
user.Call("getUserField", id, "reputation", func(err *js.Error, reputation int) {
if err != nil {
reputation = 0
}
rep <- reputation
})
} else {
rep <- 0
}

if <-rep < 10 {
content = cleaner.NoFollow(content, nconfURL)
}
}()

return cleaner.Clean(remover.Replace(s))
}
32 changes: 19 additions & 13 deletions main.go
Expand Up @@ -8,38 +8,44 @@ func main() {
exports := js.Module.Get("exports")

exports.Set("fix", fix)
exports.Set("fixPost", post(fix))
exports.Set("fixSignature", signature(fix))
exports.Set("fixRaw", raw(fix))
exports.Set("fixPost", async(post(fix)))
exports.Set("fixSignature", async(signature(fix)))
exports.Set("fixRaw", async(raw(fix)))

exports.Set("clean", clean)
exports.Set("cleanPost", post(clean))
exports.Set("cleanSignature", signature(clean))
exports.Set("cleanRaw", raw(clean))
exports.Set("cleanPost", async(post(clean)))
exports.Set("cleanSignature", async(signature(clean)))
exports.Set("cleanRaw", async(raw(clean)))

exports.Set("renderHelp", renderHelp)
}

func post(fn func(string) string) func(data, callback *js.Object) {
func async(fn func(data, callback *js.Object)) func(data, callback *js.Object) {
return func(data, callback *js.Object) {
go fn(data, callback)
}
}

func post(fn func(content, uid string) string) func(data, callback *js.Object) {
return func(data, callback *js.Object) {
if data != nil && data.Get("postData") != nil && data.Get("postData").Get("content") != nil {
data.Get("postData").Set("content", fn(data.Get("postData").Get("content").String()))
data.Get("postData").Set("content", fn(data.Get("postData").Get("content").String(), data.Get("postData").Get("uid").String()))
}
callback.Invoke(nil, data)
}
}

func signature(fn func(string) string) func(data, callback *js.Object) {
func signature(fn func(content, uid string) string) func(data, callback *js.Object) {
return func(data, callback *js.Object) {
if data != nil && data.Get("userData") != nil && data.Get("userData").Get("signature") != nil {
data.Get("userData").Set("signature", fn(data.Get("userData").Get("signature").String()))
data.Get("userData").Set("signature", fn(data.Get("userData").Get("signature").String(), data.Get("uid").String()))
}
callback.Invoke(nil, data)
}
}

func raw(fn func(string) string) func(raw string, callback *js.Object) {
return func(raw string, callback *js.Object) {
callback.Invoke(nil, fn(raw))
func raw(fn func(content, uid string) string) func(raw, callback *js.Object) {
return func(raw, callback *js.Object) {
callback.Invoke(nil, fn(raw.String(), ""))
}
}

0 comments on commit a93b58b

Please sign in to comment.