From fe331128274cd82d739cb34a1865352a0046df77 Mon Sep 17 00:00:00 2001 From: Azareal Date: Sun, 24 Feb 2019 18:02:00 +1000 Subject: [PATCH] Added an experimental content security policy. Added support for Open Graph Descriptions. Nox now officially supports notices. Tweaked the language detection algorithm to cover more cases. Tweaked the user agent parser to accomodate DotBot better. Added a non-JS fallback for the theme selector. Tweaked the padding on widget simple. Scripts should now execute properly for individual language charts in the analytics panel. --- common/pages.go | 3 ++- common/site.go | 1 + gen_router.go | 7 ++++--- router_gen/main.go | 7 ++++--- routes/account.go | 1 + routes/common.go | 7 +++++++ routes/forum.go | 1 + routes/profile.go | 1 + routes/topic.go | 16 ++++++++++++++++ templates/footer.html | 1 + templates/header.html | 2 ++ templates/panel_analytics_lang_views.html | 1 - themes/nox/public/main.css | 9 +++++++++ themes/nox/public/misc.js | 14 ++++++++++++++ 14 files changed, 63 insertions(+), 8 deletions(-) diff --git a/common/pages.go b/common/pages.go index f5a373e8..92223b43 100644 --- a/common/pages.go +++ b/common/pages.go @@ -33,7 +33,8 @@ type Header struct { Path string MetaDesc string //OGImage string - //OGDesc string + OGDesc string + LooseCSP bool StartedAt time.Time Elapsed1 string Writer http.ResponseWriter diff --git a/common/site.go b/common/site.go index c239b3ae..c086860e 100644 --- a/common/site.go +++ b/common/site.go @@ -85,6 +85,7 @@ type config struct { DisableLiveTopicList bool DisableJSAntispam bool + //LooseCSP bool Noavatar string // ? - Move this into the settings table? ItemsPerPage int // ? - Move this into the settings table? diff --git a/gen_router.go b/gen_router.go index 38571705..05229d0d 100644 --- a/gen_router.go +++ b/gen_router.go @@ -768,7 +768,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { for _, item := range StringToBytes(ua) { if (item > 64 && item < 91) || (item > 96 && item < 123) { buffer = append(buffer, item) - } else if item == ' ' || item == '(' || item == ')' || item == '-' || (item > 47 && item < 58) || item == '_' || item == ';' || item == ':' || item == '.' || item == '+' || item == '~' || (item == ':' && bytes.Equal(buffer,[]byte("http"))) || item == ',' || item == '/' { + } else if item == ' ' || item == '(' || item == ')' || item == '-' || (item > 47 && item < 58) || item == '_' || item == ';' || item == ':' || item == '.' || item == '+' || item == '~' || item == '@' || (item == ':' && bytes.Equal(buffer,[]byte("http"))) || item == ',' || item == '/' { if len(buffer) != 0 { if len(buffer) > 2 { // Use an unsafe zero copy conversion here just to use the switch, it's not safe for this string to escape from here, as it will get mutated, so do a regular string conversion in append @@ -862,8 +862,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if lang != "" { lang = strings.TrimSpace(lang) lLang := strings.Split(lang,"-") - common.DebugDetail("lLang:", lLang) - validCode := counters.LangViewCounter.Bump(lLang[0]) + llLang := strings.Split(strings.Split(lLang[0],";")[0],",") + common.DebugDetail("llLang:", llLang) + validCode := counters.LangViewCounter.Bump(llLang[0]) if !validCode { r.DumpRequest(req,"Invalid ISO Code") } diff --git a/router_gen/main.go b/router_gen/main.go index 571e8ec2..e0c33e3c 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -560,7 +560,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { for _, item := range StringToBytes(ua) { if (item > 64 && item < 91) || (item > 96 && item < 123) { buffer = append(buffer, item) - } else if item == ' ' || item == '(' || item == ')' || item == '-' || (item > 47 && item < 58) || item == '_' || item == ';' || item == ':' || item == '.' || item == '+' || item == '~' || (item == ':' && bytes.Equal(buffer,[]byte("http"))) || item == ',' || item == '/' { + } else if item == ' ' || item == '(' || item == ')' || item == '-' || (item > 47 && item < 58) || item == '_' || item == ';' || item == ':' || item == '.' || item == '+' || item == '~' || item == '@' || (item == ':' && bytes.Equal(buffer,[]byte("http"))) || item == ',' || item == '/' { if len(buffer) != 0 { if len(buffer) > 2 { // Use an unsafe zero copy conversion here just to use the switch, it's not safe for this string to escape from here, as it will get mutated, so do a regular string conversion in append @@ -654,8 +654,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if lang != "" { lang = strings.TrimSpace(lang) lLang := strings.Split(lang,"-") - common.DebugDetail("lLang:", lLang) - validCode := counters.LangViewCounter.Bump(lLang[0]) + llLang := strings.Split(strings.Split(lLang[0],";")[0],",") + common.DebugDetail("llLang:", llLang) + validCode := counters.LangViewCounter.Bump(llLang[0]) if !validCode { r.DumpRequest(req,"Invalid ISO Code") } diff --git a/routes/account.go b/routes/account.go index acf1ca10..603b972d 100644 --- a/routes/account.go +++ b/routes/account.go @@ -200,6 +200,7 @@ func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User, h return common.LocalError("You're already logged in.", w, r, user) } header.Title = phrases.GetTitlePhrase("register") + header.LooseCSP = true pi := common.Page{header, tList, nil} return renderTemplate("register", w, r, header, pi) } diff --git a/routes/common.go b/routes/common.go index bf1c63c7..980604d2 100644 --- a/routes/common.go +++ b/routes/common.go @@ -21,6 +21,13 @@ func ParseSEOURL(urlBit string) (slug string, id int, err error) { } func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *common.Header, pi interface{}) common.RouteError { + if header.MetaDesc != "" && header.OGDesc == "" { + header.OGDesc = header.MetaDesc + } + // TODO: Expand this to non-HTTPS requests too + if !header.LooseCSP && common.Site.EnableSsl { + w.Header().Set("Content-Security-Policy", "default-src https: 'unsafe-eval'; style-src https: 'unsafe-eval' 'unsafe-inline'; img-src https: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; upgrade-insecure-requests") + } if header.CurrentUser.IsAdmin { header.Elapsed1 = time.Since(header.StartedAt).String() } diff --git a/routes/forum.go b/routes/forum.go index 218244d3..52b1ef1e 100644 --- a/routes/forum.go +++ b/routes/forum.go @@ -52,6 +52,7 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user common.User, header return common.InternalError(err, w, r) } header.Title = forum.Name + header.OGDesc = forum.Desc // TODO: Does forum.TopicCount take the deleted items into consideration for guests? We don't have soft-delete yet, only hard-delete offset, page, lastPage := common.PageOffset(forum.TopicCount, page, common.Config.ItemsPerPage) diff --git a/routes/profile.go b/routes/profile.go index b63eb0fd..89cdb21c 100644 --- a/routes/profile.go +++ b/routes/profile.go @@ -31,6 +31,7 @@ func init() { func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { // TODO: Preload this? header.AddSheet(header.Theme.Name + "/profile.css") + header.LooseCSP = true var err error var replyCreatedAt time.Time diff --git a/routes/topic.go b/routes/topic.go index 22a5f9ee..5c8f89c8 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -70,6 +70,11 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header topic.ContentHTML = common.ParseMessage(topic.Content, topic.ParentID, "forums") topic.ContentLines = strings.Count(topic.Content, "\n") + header.OGDesc = topic.Content + if len(header.OGDesc) > 200 { + header.OGDesc = header.OGDesc[:197] + "..." + } + postGroup, err := common.Groups.Get(topic.Group) if err != nil { return common.InternalError(err, w, r) @@ -123,6 +128,10 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header // Get the replies if we have any... if topic.PostCount > 0 { + var pFrag int + if strings.HasPrefix(r.URL.Fragment, "post-") { + pFrag, _ = strconv.Atoi(strings.TrimPrefix(r.URL.Fragment, "post-")) + } var likedMap map[int]int if user.Liked > 0 { likedMap = make(map[int]int) @@ -156,6 +165,13 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header replyItem.ContentHtml = common.ParseMessage(replyItem.Content, topic.ParentID, "forums") replyItem.ContentLines = strings.Count(replyItem.Content, "\n") + if replyItem.ID == pFrag { + header.OGDesc = replyItem.Content + if len(header.OGDesc) > 200 { + header.OGDesc = header.OGDesc[:197] + "..." + } + } + postGroup, err = common.Groups.Get(replyItem.Group) if err != nil { return common.InternalError(err, w, r) diff --git a/templates/footer.html b/templates/footer.html index 146c111b..ace0807a 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -17,6 +17,7 @@ {{if not .HideFromThemes}}{{end}} {{end}} + diff --git a/templates/header.html b/templates/header.html index af4a6914..df13a205 100644 --- a/templates/header.html +++ b/templates/header.html @@ -18,6 +18,8 @@ + {{if .OGDesc}} + {{end}} {{if not .CurrentUser.IsSuperMod}}{{end}} diff --git a/templates/panel_analytics_lang_views.html b/templates/panel_analytics_lang_views.html index 06086ee1..b2e26542 100644 --- a/templates/panel_analytics_lang_views.html +++ b/templates/panel_analytics_lang_views.html @@ -15,6 +15,5 @@ -