Merge pull request #718 from NyaaPantsu/no-more-div-in-db
Fixing insert of unneeded html tags in db
Cette révision appartient à :
révision
891e385939
|
@ -20,7 +20,6 @@ import (
|
||||||
"github.com/NyaaPantsu/nyaa/util"
|
"github.com/NyaaPantsu/nyaa/util"
|
||||||
"github.com/NyaaPantsu/nyaa/util/categories"
|
"github.com/NyaaPantsu/nyaa/util/categories"
|
||||||
"github.com/NyaaPantsu/nyaa/util/metainfo"
|
"github.com/NyaaPantsu/nyaa/util/metainfo"
|
||||||
"github.com/microcosm-cc/bluemonday"
|
|
||||||
"github.com/zeebo/bencode"
|
"github.com/zeebo/bencode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,7 +82,7 @@ var ErrInvalidWebsiteLink = errors.New("Website url or IRC link is invalid")
|
||||||
// error indicating a torrent's category is invalid
|
// error indicating a torrent's category is invalid
|
||||||
var ErrInvalidTorrentCategory = errors.New("Torrent category is invalid")
|
var ErrInvalidTorrentCategory = errors.New("Torrent category is invalid")
|
||||||
|
|
||||||
var p = bluemonday.UGCPolicy()
|
// var p = bluemonday.UGCPolicy()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
UploadForm.ExtractInfo takes an http request and computes all fields for this form
|
UploadForm.ExtractInfo takes an http request and computes all fields for this form
|
||||||
|
@ -100,7 +99,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
||||||
|
|
||||||
// trim whitespace
|
// trim whitespace
|
||||||
f.Name = util.TrimWhitespaces(f.Name)
|
f.Name = util.TrimWhitespaces(f.Name)
|
||||||
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
|
f.Description = util.Sanitize(util.TrimWhitespaces(f.Description), "default")
|
||||||
f.WebsiteLink = util.TrimWhitespaces(f.WebsiteLink)
|
f.WebsiteLink = util.TrimWhitespaces(f.WebsiteLink)
|
||||||
f.Magnet = util.TrimWhitespaces(f.Magnet)
|
f.Magnet = util.TrimWhitespaces(f.Magnet)
|
||||||
cache.Impl.ClearAll()
|
cache.Impl.ClearAll()
|
||||||
|
@ -241,7 +240,7 @@ func (f *UploadForm) ExtractEditInfo(r *http.Request) error {
|
||||||
|
|
||||||
// trim whitespace
|
// trim whitespace
|
||||||
f.Name = util.TrimWhitespaces(f.Name)
|
f.Name = util.TrimWhitespaces(f.Name)
|
||||||
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
|
f.Description = util.Sanitize(util.TrimWhitespaces(f.Description), "default")
|
||||||
|
|
||||||
catsSplit := strings.Split(f.Category, "_")
|
catsSplit := strings.Split(f.Category, "_")
|
||||||
// need this to prevent out of index panics
|
// need this to prevent out of index panics
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/NyaaPantsu/nyaa/service/report"
|
"github.com/NyaaPantsu/nyaa/service/report"
|
||||||
"github.com/NyaaPantsu/nyaa/service/torrent"
|
"github.com/NyaaPantsu/nyaa/service/torrent"
|
||||||
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
||||||
|
"github.com/NyaaPantsu/nyaa/util"
|
||||||
"github.com/NyaaPantsu/nyaa/util/languages"
|
"github.com/NyaaPantsu/nyaa/util/languages"
|
||||||
"github.com/NyaaPantsu/nyaa/util/log"
|
"github.com/NyaaPantsu/nyaa/util/log"
|
||||||
msg "github.com/NyaaPantsu/nyaa/util/messages"
|
msg "github.com/NyaaPantsu/nyaa/util/messages"
|
||||||
|
@ -90,7 +91,7 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
messages.AddErrorT("errors", "bad_captcha")
|
messages.AddErrorT("errors", "bad_captcha")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
content := p.Sanitize(r.FormValue("comment"))
|
content := util.Sanitize(r.FormValue("comment"), "comment")
|
||||||
|
|
||||||
if strings.TrimSpace(content) == "" {
|
if strings.TrimSpace(content) == "" {
|
||||||
messages.AddErrorT("errors", "comment_empty")
|
messages.AddErrorT("errors", "comment_empty")
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/gorilla/context"
|
"github.com/gorilla/context"
|
||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
@ -123,7 +124,9 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
func CurrentUser(r *http.Request) (model.User, error) {
|
func CurrentUser(r *http.Request) (model.User, error) {
|
||||||
var user model.User
|
var user model.User
|
||||||
var encoded string
|
var encoded string
|
||||||
|
if r == nil {
|
||||||
|
fmt.Println("ERROR r is terminated")
|
||||||
|
}
|
||||||
encoded = r.Header.Get("X-Auth-Token")
|
encoded = r.Header.Get("X-Auth-Token")
|
||||||
if len(encoded) == 0 {
|
if len(encoded) == 0 {
|
||||||
// check cookie instead
|
// check cookie instead
|
||||||
|
|
242
util/markdown.go
242
util/markdown.go
|
@ -1,12 +1,17 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
md "github.com/russross/blackfriday"
|
md "github.com/russross/blackfriday"
|
||||||
|
"golang.org/x/net/html"
|
||||||
"html/template"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//Some default rules, plus and minus some.
|
//Some default rules, plus and minus some.
|
||||||
var mdOptions = 0 |
|
var mdOptions = 0 |
|
||||||
md.EXTENSION_AUTOLINK |
|
md.EXTENSION_AUTOLINK |
|
||||||
|
@ -38,3 +43,234 @@ func MarkdownToHTML(markdown string) template.HTML {
|
||||||
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
||||||
return template.HTML(html)
|
return template.HTML(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanitize a message passed as a string according to a setted model or allowing a set of html tags and output a string
|
||||||
|
*/
|
||||||
|
func Sanitize(msg string, elements ...string) string {
|
||||||
|
msg = repairHTMLTags(msg) // We repair possible broken html tags
|
||||||
|
p := bluemonday.NewPolicy()
|
||||||
|
if len(elements) > 0 {
|
||||||
|
if elements[0] == "default" { // default model same as UGC without div
|
||||||
|
///////////////////////
|
||||||
|
// Global attributes //
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
// "class" is not permitted as we are not allowing users to style their own
|
||||||
|
// content
|
||||||
|
|
||||||
|
p.AllowStandardAttributes()
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// Global URL format policy //
|
||||||
|
//////////////////////////////
|
||||||
|
|
||||||
|
p.AllowStandardURLs()
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Declarations and structure //
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
// "xml" "xslt" "DOCTYPE" "html" "head" are not permitted as we are
|
||||||
|
// expecting user generated content to be a fragment of HTML and not a full
|
||||||
|
// document.
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Sectioning root tags //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// "article" and "aside" are permitted and takes no attributes
|
||||||
|
p.AllowElements("article", "aside")
|
||||||
|
|
||||||
|
// "body" is not permitted as we are expecting user generated content to be a fragment
|
||||||
|
// of HTML and not a full document.
|
||||||
|
|
||||||
|
// "details" is permitted, including the "open" attribute which can either
|
||||||
|
// be blank or the value "open".
|
||||||
|
p.AllowAttrs(
|
||||||
|
"open",
|
||||||
|
).Matching(regexp.MustCompile(`(?i)^(|open)$`)).OnElements("details")
|
||||||
|
|
||||||
|
// "fieldset" is not permitted as we are not allowing forms to be created.
|
||||||
|
|
||||||
|
// "figure" is permitted and takes no attributes
|
||||||
|
p.AllowElements("figure")
|
||||||
|
|
||||||
|
// "nav" is not permitted as it is assumed that the site (and not the user)
|
||||||
|
// has defined navigation elements
|
||||||
|
|
||||||
|
// "section" is permitted and takes no attributes
|
||||||
|
p.AllowElements("section")
|
||||||
|
|
||||||
|
// "summary" is permitted and takes no attributes
|
||||||
|
p.AllowElements("summary")
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Headings and footers //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// "footer" is not permitted as we expect user content to be a fragment and
|
||||||
|
// not structural to this extent
|
||||||
|
|
||||||
|
// "h1" through "h6" are permitted and take no attributes
|
||||||
|
p.AllowElements("h1", "h2", "h3", "h4", "h5", "h6")
|
||||||
|
|
||||||
|
// "header" is not permitted as we expect user content to be a fragment and
|
||||||
|
// not structural to this extent
|
||||||
|
|
||||||
|
// "hgroup" is permitted and takes no attributes
|
||||||
|
p.AllowElements("hgroup")
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// Content grouping and separating //
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
// "blockquote" is permitted, including the "cite" attribute which must be
|
||||||
|
// a standard URL.
|
||||||
|
p.AllowAttrs("cite").OnElements("blockquote")
|
||||||
|
|
||||||
|
// "br" "div" "hr" "p" "span" "wbr" are permitted and take no attributes
|
||||||
|
p.AllowElements("br", "hr", "p", "span", "wbr")
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Links //
|
||||||
|
///////////
|
||||||
|
|
||||||
|
// "a" is permitted
|
||||||
|
p.AllowAttrs("href").OnElements("a")
|
||||||
|
|
||||||
|
// "area" is permitted along with the attributes that map image maps work
|
||||||
|
p.AllowAttrs("name").Matching(
|
||||||
|
regexp.MustCompile(`^([\p{L}\p{N}_-]+)$`),
|
||||||
|
).OnElements("map")
|
||||||
|
p.AllowAttrs("alt").Matching(bluemonday.Paragraph).OnElements("area")
|
||||||
|
p.AllowAttrs("coords").Matching(
|
||||||
|
regexp.MustCompile(`^([0-9]+,)+[0-9]+$`),
|
||||||
|
).OnElements("area")
|
||||||
|
p.AllowAttrs("href").OnElements("area")
|
||||||
|
p.AllowAttrs("rel").Matching(bluemonday.SpaceSeparatedTokens).OnElements("area")
|
||||||
|
p.AllowAttrs("shape").Matching(
|
||||||
|
regexp.MustCompile(`(?i)^(default|circle|rect|poly)$`),
|
||||||
|
).OnElements("area")
|
||||||
|
p.AllowAttrs("usemap").Matching(
|
||||||
|
regexp.MustCompile(`(?i)^#[\p{L}\p{N}_-]+$`),
|
||||||
|
).OnElements("img")
|
||||||
|
|
||||||
|
// "link" is not permitted
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// Phrase elements //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
// The following are all inline phrasing elements
|
||||||
|
p.AllowElements("abbr", "acronym", "cite", "code", "dfn", "em",
|
||||||
|
"figcaption", "mark", "s", "samp", "strong", "sub", "sup", "var")
|
||||||
|
|
||||||
|
// "q" is permitted and "cite" is a URL and handled by URL policies
|
||||||
|
p.AllowAttrs("cite").OnElements("q")
|
||||||
|
|
||||||
|
// "time" is permitted
|
||||||
|
p.AllowAttrs("datetime").Matching(bluemonday.ISO8601).OnElements("time")
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Style elements //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
// block and inline elements that impart no semantic meaning but style the
|
||||||
|
// document
|
||||||
|
p.AllowElements("b", "i", "pre", "small", "strike", "tt", "u")
|
||||||
|
|
||||||
|
// "style" is not permitted as we are not yet sanitising CSS and it is an
|
||||||
|
// XSS attack vector
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// HTML5 Formatting //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
// "bdi" "bdo" are permitted
|
||||||
|
p.AllowAttrs("dir").Matching(bluemonday.Direction).OnElements("bdi", "bdo")
|
||||||
|
|
||||||
|
// "rp" "rt" "ruby" are permitted
|
||||||
|
p.AllowElements("rp", "rt", "ruby")
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// HTML5 Change tracking //
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
// "del" "ins" are permitted
|
||||||
|
p.AllowAttrs("cite").Matching(bluemonday.Paragraph).OnElements("del", "ins")
|
||||||
|
p.AllowAttrs("datetime").Matching(bluemonday.ISO8601).OnElements("del", "ins")
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Lists //
|
||||||
|
///////////
|
||||||
|
|
||||||
|
p.AllowLists()
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// Tables //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
p.AllowTables()
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Forms //
|
||||||
|
///////////
|
||||||
|
|
||||||
|
// By and large, forms are not permitted. However there are some form
|
||||||
|
// elements that can be used to present data, and we do permit those
|
||||||
|
//
|
||||||
|
// "button" "fieldset" "input" "keygen" "label" "output" "select" "datalist"
|
||||||
|
// "textarea" "optgroup" "option" are all not permitted
|
||||||
|
|
||||||
|
// "meter" is permitted
|
||||||
|
p.AllowAttrs(
|
||||||
|
"value",
|
||||||
|
"min",
|
||||||
|
"max",
|
||||||
|
"low",
|
||||||
|
"high",
|
||||||
|
"optimum",
|
||||||
|
).Matching(bluemonday.Number).OnElements("meter")
|
||||||
|
|
||||||
|
// "progress" is permitted
|
||||||
|
p.AllowAttrs("value", "max").Matching(bluemonday.Number).OnElements("progress")
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// Embedded content //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
// Vast majority not permitted
|
||||||
|
// "audio" "canvas" "embed" "iframe" "object" "param" "source" "svg" "track"
|
||||||
|
// "video" are all not permitted
|
||||||
|
|
||||||
|
p.AllowImages()
|
||||||
|
} else if elements[0] == "comment" {
|
||||||
|
p.AllowElements("b", "strong", "em", "i", "u", "blockquote", "q")
|
||||||
|
p.AllowImages()
|
||||||
|
p.AllowStandardURLs()
|
||||||
|
p.AllowAttrs("cite").OnElements("blockquote", "q")
|
||||||
|
p.AllowAttrs("href").OnElements("a")
|
||||||
|
p.AddTargetBlankToFullyQualifiedLinks(true)
|
||||||
|
} else { // allowing set of html tags
|
||||||
|
p.AllowElements(elements...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.Sanitize(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should close any opened tags and strip any empty end tags
|
||||||
|
*/
|
||||||
|
func repairHTMLTags(brokenHtml string) string {
|
||||||
|
reader := strings.NewReader(brokenHtml)
|
||||||
|
root, err := html.Parse(reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
var b bytes.Buffer
|
||||||
|
html.Render(&b, root)
|
||||||
|
fixedHTML := b.String()
|
||||||
|
return fixedHTML
|
||||||
|
}
|
|
@ -18,7 +18,11 @@ type Messages struct {
|
||||||
|
|
||||||
func GetMessages(r *http.Request) *Messages {
|
func GetMessages(r *http.Request) *Messages {
|
||||||
if rv := context.Get(r, MessagesKey); rv != nil {
|
if rv := context.Get(r, MessagesKey); rv != nil {
|
||||||
return rv.(*Messages)
|
mes := rv.(*Messages)
|
||||||
|
T, _ := languages.GetTfuncAndLanguageFromRequest(r)
|
||||||
|
mes.T = T
|
||||||
|
mes.r = r
|
||||||
|
return mes
|
||||||
} else {
|
} else {
|
||||||
context.Set(r, MessagesKey, &Messages{})
|
context.Set(r, MessagesKey, &Messages{})
|
||||||
T, _ := languages.GetTfuncAndLanguageFromRequest(r)
|
T, _ := languages.GetTfuncAndLanguageFromRequest(r)
|
||||||
|
|
Référencer dans un nouveau ticket