diff --git a/.gopmfile b/.gopmfile index 3ba514afc8..7b1bf3091e 100644 --- a/.gopmfile +++ b/.gopmfile @@ -24,6 +24,7 @@ github.com/macaron-contrib/session = github.com/macaron-contrib/toolbox = commit:57127bcc89 github.com/mattn/go-sqlite3 = commit:a80c27ba33 github.com/nfnt/resize = commit:581d15cb53 +github.com/russross/blackfriday = github.com/saintfish/chardet = commit:3af4cd4741 [res] diff --git a/gogs.go b/gogs.go index 289ad19123..12f142aba0 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.5.4.1003 Beta" +const APP_VER = "0.5.4.1004 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/repo.go b/models/repo.go index a79c2491ce..8e29b3357d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -23,6 +23,7 @@ import ( "github.com/Unknwon/cae/zip" "github.com/Unknwon/com" + "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/process" @@ -48,7 +49,7 @@ var ( ) var ( - DescriptionPattern = regexp.MustCompile(`https?://\S+`) + DescPattern = regexp.MustCompile(`https?://\S+`) ) func LoadRepoConfig() { @@ -181,7 +182,7 @@ func (repo *Repository) DescriptionHtml() template.HTML { ss := html.EscapeString(s) return fmt.Sprintf(`%s`, ss, ss) } - return template.HTML(DescriptionPattern.ReplaceAllStringFunc(repo.Description, sanitize)) + return template.HTML(DescPattern.ReplaceAllStringFunc(base.XSSString(repo.Description), sanitize)) } // IsRepositoryExist returns true if the repository with given name under user has already existed. diff --git a/modules/base/markdown.go b/modules/base/markdown.go index a3db15df1a..cb08320099 100644 --- a/modules/base/markdown.go +++ b/modules/base/markdown.go @@ -13,7 +13,8 @@ import ( "regexp" "strings" - "github.com/gogits/gfm" + "github.com/russross/blackfriday" + "github.com/gogits/gogs/modules/setting" ) @@ -74,7 +75,7 @@ func IsReadmeFile(name string) bool { } type CustomRender struct { - gfm.Renderer + blackfriday.Renderer urlPrefix string } @@ -154,39 +155,40 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte { func RenderRawMarkdown(body []byte, urlPrefix string) []byte { htmlFlags := 0 - // htmlFlags |= gfm.HTML_USE_XHTML - // htmlFlags |= gfm.HTML_USE_SMARTYPANTS - // htmlFlags |= gfm.HTML_SMARTYPANTS_FRACTIONS - // htmlFlags |= gfm.HTML_SMARTYPANTS_LATEX_DASHES - // htmlFlags |= gfm.HTML_SKIP_HTML - htmlFlags |= gfm.HTML_SKIP_STYLE - htmlFlags |= gfm.HTML_SKIP_SCRIPT - htmlFlags |= gfm.HTML_GITHUB_BLOCKCODE - htmlFlags |= gfm.HTML_OMIT_CONTENTS - // htmlFlags |= gfm.HTML_COMPLETE_PAGE + // htmlFlags |= blackfriday.HTML_USE_XHTML + // htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES + // htmlFlags |= blackfriday.HTML_SKIP_HTML + htmlFlags |= blackfriday.HTML_SKIP_STYLE + // htmlFlags |= blackfriday.HTML_SKIP_SCRIPT + // htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE + htmlFlags |= blackfriday.HTML_OMIT_CONTENTS + // htmlFlags |= blackfriday.HTML_COMPLETE_PAGE renderer := &CustomRender{ - Renderer: gfm.HtmlRenderer(htmlFlags, "", ""), + Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""), urlPrefix: urlPrefix, } // set up the parser extensions := 0 - extensions |= gfm.EXTENSION_NO_INTRA_EMPHASIS - extensions |= gfm.EXTENSION_TABLES - extensions |= gfm.EXTENSION_FENCED_CODE - extensions |= gfm.EXTENSION_AUTOLINK - extensions |= gfm.EXTENSION_STRIKETHROUGH - extensions |= gfm.EXTENSION_HARD_LINE_BREAK - extensions |= gfm.EXTENSION_SPACE_HEADERS - extensions |= gfm.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK + extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS + extensions |= blackfriday.EXTENSION_TABLES + extensions |= blackfriday.EXTENSION_FENCED_CODE + extensions |= blackfriday.EXTENSION_AUTOLINK + extensions |= blackfriday.EXTENSION_STRIKETHROUGH + extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK + extensions |= blackfriday.EXTENSION_SPACE_HEADERS + extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK - body = gfm.Markdown(body, renderer, extensions) + body = blackfriday.Markdown(body, renderer, extensions) return body } func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte { body := RenderSpecialLink(rawBytes, urlPrefix) body = RenderRawMarkdown(body, urlPrefix) + body = XSS(body) return body } diff --git a/modules/base/tool.go b/modules/base/tool.go index b4083d090f..38fd1e21e7 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -14,6 +14,7 @@ import ( "hash" "html/template" "math" + "regexp" "strings" "time" @@ -446,3 +447,29 @@ func DateFormat(t time.Time, format string) string { format = replacer.Replace(format) return t.Format(format) } + +type xssFilter struct { + reg *regexp.Regexp + repl []byte +} + +var ( + whiteSpace = []byte(" ") + xssFilters = []xssFilter{ + {regexp.MustCompile(`\ [ONon]\w*=["]*`), whiteSpace}, + {regexp.MustCompile(`<[SCRIPTscript]{6}`), whiteSpace}, + {regexp.MustCompile(`=[` + "`" + `'"]*[JAVASCRIPTjavascript \t\0 ]*:`), whiteSpace}, + } +) + +// XSS goes through all the XSS filters to make user input content as safe as possible. +func XSS(in []byte) []byte { + for _, filter := range xssFilters { + in = filter.reg.ReplaceAll(in, filter.repl) + } + return in +} + +func XSSString(in string) string { + return string(XSS([]byte(in))) +} diff --git a/templates/.VERSION b/templates/.VERSION index 24a40ce358..776ae02a15 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.5.4.1003 Beta \ No newline at end of file +0.5.4.1004 Beta \ No newline at end of file