Add SslSchema config setting.

Reject URL usernames on registration.

Reduce length of char variable name.
This commit is contained in:
Azareal 2019-11-04 21:55:52 +10:00
parent 0f75e96a2d
commit 142359ce11
13 changed files with 59 additions and 50 deletions

View File

@ -12,7 +12,7 @@ import (
func SendActivationEmail(username string, email string, token string) error { func SendActivationEmail(username string, email string, token string) error {
schema := "http" schema := "http"
if Site.EnableSsl { if Config.SslSchema {
schema += "s" schema += "s"
} }
// TODO: Move these to the phrase system // TODO: Move these to the phrase system
@ -23,7 +23,7 @@ func SendActivationEmail(username string, email string, token string) error {
func SendValidationEmail(username string, email string, token string) error { func SendValidationEmail(username string, email string, token string) error {
schema := "http" schema := "http"
if Site.EnableSsl { if Config.SslSchema {
schema += "s" schema += "s"
} }
r := func(body *string) func(name, val string) { r := func(body *string) func(name, val string) {

View File

@ -872,7 +872,7 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
host = strings.Split(Site.URL, ":")[0] host = strings.Split(Site.URL, ":")[0]
// ?- Test this as I'm not sure it'll do what it should. If someone's running SSL on port 80 or non-SSL on port 443 then... Well... They're in far worse trouble than this... // ?- Test this as I'm not sure it'll do what it should. If someone's running SSL on port 80 or non-SSL on port 443 then... Well... They're in far worse trouble than this...
port = Site.Port port = Site.Port
if Site.EnableSsl { if Config.SslSchema {
scheme = "https" scheme = "https"
} }
} }

View File

@ -293,7 +293,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
// TODO: Add a config setting to disable this header // TODO: Add a config setting to disable this header
// TODO: Have this header cover more things // TODO: Have this header cover more things
if Site.EnableSsl { if Config.SslSchema {
w.Header().Set("Content-Security-Policy", "upgrade-insecure-requests") w.Header().Set("Content-Security-Policy", "upgrade-insecure-requests")
} }

View File

@ -62,7 +62,7 @@ type config struct {
SslPrivkey string SslPrivkey string
SslFullchain string SslFullchain string
HashAlgo string // Defaults to bcrypt, and in the future, possibly something stronger HashAlgo string // Defaults to bcrypt, and in the future, possibly something stronger
ConvoKey string ConvoKey string
MaxRequestSizeStr string MaxRequestSizeStr string
MaxRequestSize int MaxRequestSize int
@ -89,9 +89,9 @@ type config struct {
MinifyTemplates bool MinifyTemplates bool
BuildSlugs bool // TODO: Make this a setting? BuildSlugs bool // TODO: Make this a setting?
PrimaryServer bool PrimaryServer bool
ServerCount int ServerCount int
PostIPCutoff int PostIPCutoff int
LogPruneCutoff int LogPruneCutoff int
DisableLiveTopicList bool DisableLiveTopicList bool
@ -99,13 +99,14 @@ type config struct {
//LooseCSP bool //LooseCSP bool
LooseHost bool LooseHost bool
LoosePort bool LoosePort bool
SslSchema bool // Pretend we're using SSL, might be useful if a reverse-proxy terminates SSL in-front of Gosora
DisableServerPush bool DisableServerPush bool
EnableCDNPush bool EnableCDNPush bool
DisableNoavatarRange bool DisableNoavatarRange bool
DisableDefaultNoavatar bool DisableDefaultNoavatar bool
RefNoTrack bool RefNoTrack bool
RefNoRef bool RefNoRef bool
Noavatar string // ? - Move this into the settings table? Noavatar string // ? - Move this into the settings table?
ItemsPerPage int // ? - Move this into the settings table? ItemsPerPage int // ? - Move this into the settings table?
@ -174,6 +175,9 @@ func ProcessConfig() (err error) {
Site.URL = strings.TrimSuffix(Site.URL, ":") Site.URL = strings.TrimSuffix(Site.URL, ":")
Site.URL = Site.URL + ":" + Site.Port Site.URL = Site.URL + ":" + Site.Port
} }
if Site.EnableSsl {
Config.SslSchema = Site.EnableSsl
}
if Config.DefaultPath == "" { if Config.DefaultPath == "" {
Config.DefaultPath = "/topics/" Config.DefaultPath = "/topics/"
} }

View File

@ -808,7 +808,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Abstract the redirect logic? // TODO: Abstract the redirect logic?
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
var s string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
s = "s" s = "s"
} }
var p string var p string
@ -833,8 +833,8 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
// TODO: Cover more suspicious strings and at a lower layer than this // TODO: Cover more suspicious strings and at a lower layer than this
for _, char := range req.URL.Path { for _, ch := range req.URL.Path { //char
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { if ch != '&' && !(ch > 44 && ch < 58) && ch != '=' && ch != '?' && !(ch > 64 && ch < 91) && ch != '\\' && ch != '_' && !(ch > 96 && ch < 123) {
r.SuspiciousRequest(req,"Bad char in path") r.SuspiciousRequest(req,"Bad char in path")
break break
} }
@ -869,7 +869,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h.Set("X-Frame-Options", "deny") h.Set("X-Frame-Options", "deny")
h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
h.Set("X-Content-Type-Options", "nosniff") h.Set("X-Content-Type-Options", "nosniff")
if c.Config.RefNoRef || !c.Site.EnableSsl { if c.Config.RefNoRef || !c.Config.SslSchema {
h.Set("Referrer-Policy","no-referrer") h.Set("Referrer-Policy","no-referrer")
} else { } else {
h.Set("Referrer-Policy","strict-origin") h.Set("Referrer-Policy","strict-origin")

View File

@ -97,6 +97,7 @@
"register_need_username":"You didn't put in a username.", "register_need_username":"You didn't put in a username.",
"register_need_email":"You didn't put in an email.", "register_need_email":"You didn't put in an email.",
"register_first_word_numeric":"The first word of your name must not be purely numeric", "register_first_word_numeric":"The first word of your name must not be purely numeric",
"register_url_username":"You cannot have a URL within your username",
"register_suspicious_email":"Your email address is suspicious.", "register_suspicious_email":"Your email address is suspicious.",
"register_password_mismatch":"The two passwords don't match.", "register_password_mismatch":"The two passwords don't match.",
"register_username_unavailable":"This username isn't available. Try another.", "register_username_unavailable":"This username isn't available. Try another.",

View File

@ -202,12 +202,12 @@ func TestParser(t *testing.T) {
l.Add("//"+url+"\n//"+url, eurl+"<br>"+eurl) l.Add("//"+url+"\n//"+url, eurl+"<br>"+eurl)
l.Add("//"+url+"\n\n//"+url, eurl+"<br><br>"+eurl) l.Add("//"+url+"\n\n//"+url, eurl+"<br><br>"+eurl)
pre2 := c.Site.EnableSsl pre2 := c.Config.SslSchema
c.Site.EnableSsl = true c.Config.SslSchema = true
local := func(u string) { local := func(u string) {
s := "//" + c.Site.URL s := "//" + c.Site.URL
fs := "http://" + c.Site.URL fs := "http://" + c.Site.URL
if c.Site.EnableSsl { if c.Config.SslSchema {
s = "https:" + s s = "https:" + s
fs = "https://" + c.Site.URL fs = "https://" + c.Site.URL
} }
@ -301,13 +301,13 @@ func TestParser(t *testing.T) {
break break
} }
} }
c.Site.EnableSsl = pre2 c.Config.SslSchema = pre2
l = &METriList{nil} l = &METriList{nil}
pre := c.Site.URL // Just in case this is localhost... pre := c.Site.URL // Just in case this is localhost...
pre2 = c.Site.EnableSsl pre2 = c.Config.SslSchema
c.Site.URL = "example.com" c.Site.URL = "example.com"
c.Site.EnableSsl = true c.Config.SslSchema = true
l.Add("//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>") l.Add("//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>")
l.Add("//"+c.Site.URL+"\n", "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br>") l.Add("//"+c.Site.URL+"\n", "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br>")
l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br><a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>") l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br><a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>")
@ -323,7 +323,7 @@ func TestParser(t *testing.T) {
} }
} }
c.Site.URL = pre c.Site.URL = pre
c.Site.EnableSsl = pre2 c.Config.SslSchema = pre2
c.AddHashLinkType("nnid-", func(sb *strings.Builder, msg string, i *int) { c.AddHashLinkType("nnid-", func(sb *strings.Builder, msg string, i *int) {
tid, intLen := c.CoerceIntString(msg[*i:]) tid, intLen := c.CoerceIntString(msg[*i:])

View File

@ -531,7 +531,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Abstract the redirect logic? // TODO: Abstract the redirect logic?
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
var s string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
s = "s" s = "s"
} }
var p string var p string
@ -556,8 +556,8 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
// TODO: Cover more suspicious strings and at a lower layer than this // TODO: Cover more suspicious strings and at a lower layer than this
for _, char := range req.URL.Path { for _, ch := range req.URL.Path { //char
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { if ch != '&' && !(ch > 44 && ch < 58) && ch != '=' && ch != '?' && !(ch > 64 && ch < 91) && ch != '\\' && ch != '_' && !(ch > 96 && ch < 123) {
r.SuspiciousRequest(req,"Bad char in path") r.SuspiciousRequest(req,"Bad char in path")
break break
} }
@ -592,7 +592,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h.Set("X-Frame-Options", "deny") h.Set("X-Frame-Options", "deny")
h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
h.Set("X-Content-Type-Options", "nosniff") h.Set("X-Content-Type-Options", "nosniff")
if c.Config.RefNoRef || !c.Site.EnableSsl { if c.Config.RefNoRef || !c.Config.SslSchema {
h.Set("Referrer-Policy","no-referrer") h.Set("Referrer-Policy","no-referrer")
} else { } else {
h.Set("Referrer-Policy","strict-origin") h.Set("Referrer-Policy","strict-origin")

View File

@ -235,6 +235,9 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
if isNumeric(nameBits[0]) { if isNumeric(nameBits[0]) {
regError(p.GetErrorPhrase("register_first_word_numeric"), "numeric-name") regError(p.GetErrorPhrase("register_first_word_numeric"), "numeric-name")
} }
if strings.Contains(name,"http://") || strings.Contains(name,"https://") || strings.Contains(name,"ftp://") || strings.Contains(name,"ssh://") {
regError(p.GetErrorPhrase("register_url_username"), "url-name")
}
// TODO: Add a dedicated function for validating emails // TODO: Add a dedicated function for validating emails
email := c.SanitiseSingleLine(r.PostFormValue("email")) email := c.SanitiseSingleLine(r.PostFormValue("email"))
@ -807,12 +810,12 @@ func AccountPasswordResetSubmit(w http.ResponseWriter, r *http.Request, user c.U
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var schema string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
schema = "s" s = "s"
} }
err = c.SendEmail(tuser.Email, p.GetTmplPhrase("password_reset_subject"), p.GetTmplPhrasef("password_reset_body", tuser.Name, "http"+schema+"://"+c.Site.URL+"/accounts/password-reset/token/?uid="+strconv.Itoa(tuser.ID)+"&token="+token)) err = c.SendEmail(tuser.Email, p.GetTmplPhrase("password_reset_subject"), p.GetTmplPhrasef("password_reset_body", tuser.Name, "http"+s+"://"+c.Site.URL+"/accounts/password-reset/token/?uid="+strconv.Itoa(tuser.ID)+"&token="+token))
if err != nil { if err != nil {
return c.LocalError(p.GetErrorPhrase("password_reset_email_fail"), w, r, user) return c.LocalError(p.GetErrorPhrase("password_reset_email_fail"), w, r, user)
} }

View File

@ -33,13 +33,13 @@ func writeXMLHeader(w http.ResponseWriter, r *http.Request) {
// TODO: Keep track of when a sitemap was last modifed and add a lastmod element for it // TODO: Keep track of when a sitemap was last modifed and add a lastmod element for it
func SitemapXml(w http.ResponseWriter, r *http.Request) c.RouteError { func SitemapXml(w http.ResponseWriter, r *http.Request) c.RouteError {
var sslBit string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
sslBit = "s" s = "s"
} }
sitemapItem := func(path string) { sitemapItem := func(path string) {
w.Write([]byte(`<sitemap> w.Write([]byte(`<sitemap>
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc> <loc>http` + s + `://` + c.Site.URL + "/" + path + `</loc>
</sitemap> </sitemap>
`)) `))
} }
@ -95,13 +95,13 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) c.RouteError {
} }
func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError { func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError {
var sslBit string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
sslBit = "s" s = "s"
} }
sitemapItem := func(path string) { sitemapItem := func(path string) {
w.Write([]byte(`<url> w.Write([]byte(`<url>
<loc>http` + sslBit + `://` + c.Site.URL + path + `</loc> <loc>http` + s + `://` + c.Site.URL + path + `</loc>
</url> </url>
`)) `))
} }
@ -129,13 +129,13 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError {
// TODO: Add a global ratelimit. 10 50MB files (smaller if compressed better) per minute? // TODO: Add a global ratelimit. 10 50MB files (smaller if compressed better) per minute?
// ? We might have problems with banned users, if they have fewer ViewTopic permissions than guests as they'll be able to see this list. Then again, a banned user could just logout to see it // ? We might have problems with banned users, if they have fewer ViewTopic permissions than guests as they'll be able to see this list. Then again, a banned user could just logout to see it
func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError { func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError {
var sslBit string var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
sslBit = "s" s = "s"
} }
sitemapItem := func(path string) { sitemapItem := func(path string) {
w.Write([]byte(`<sitemap> w.Write([]byte(`<sitemap>
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc> <loc>http` + s + `://` + c.Site.URL + "/" + path + `</loc>
</sitemap> </sitemap>
`)) `))
} }
@ -171,13 +171,13 @@ func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError {
} }
func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) c.RouteError { func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) c.RouteError {
/*var sslBit string /*var s string
if c.Site.EnableSsl { if c.Config.SslSchema {
sslBit = "s" s = "s"
} }
var sitemapItem = func(path string) { var sitemapItem = func(path string) {
w.Write([]byte(`<url> w.Write([]byte(`<url>
<loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc> <loc>http` + s + `://` + c.Site.URL + "/" + path + `</loc>
</url> </url>
`)) `))
}*/ }*/
@ -254,7 +254,7 @@ func APIMe(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
func OpenSearchXml(w http.ResponseWriter, r *http.Request) c.RouteError { func OpenSearchXml(w http.ResponseWriter, r *http.Request) c.RouteError {
furl := "http" furl := "http"
if c.Site.EnableSsl { if c.Config.SslSchema {
furl += "s" furl += "s"
} }
furl += "://" + c.Site.URL furl += "://" + c.Site.URL

View File

@ -61,7 +61,7 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filenam
} else { } else {
return c.LocalError("Unknown section", w, r, user) return c.LocalError("Unknown section", w, r, user)
} }
if originTable != "topics" && originTable != "replies" { if originTable != "topics" && originTable != "replies" {
return c.LocalError("Unknown origin", w, r, user) return c.LocalError("Unknown origin", w, r, user)
} }
@ -74,10 +74,11 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filenam
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
h := w.Header()
if guest.Perms.ViewTopic { if guest.Perms.ViewTopic {
w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year))) h.Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year)))
} else { } else {
w.Header().Set("Cache-Control", "private") h.Set("Cache-Control", "private")
} }
} }

View File

@ -99,7 +99,7 @@ func renderTemplate2(tmplName string, hookName string, w http.ResponseWriter, r
func FootHeaders(w http.ResponseWriter, header *c.Header) { func FootHeaders(w http.ResponseWriter, header *c.Header) {
if !header.LooseCSP { if !header.LooseCSP {
if c.Site.EnableSsl { if c.Config.SslSchema {
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests") w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests")
} else { } else {
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com") w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com")

View File

@ -24,7 +24,7 @@ func successRedirect(dest string, w http.ResponseWriter, r *http.Request, js boo
// TODO: Prerender needs to handle dyntmpl templates better... // TODO: Prerender needs to handle dyntmpl templates better...
func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError { func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError {
if !header.LooseCSP { if !header.LooseCSP {
if c.Site.EnableSsl { if c.Config.SslSchema {
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self';upgrade-insecure-requests") w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self';upgrade-insecure-requests")
} else { } else {
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self'") w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self'")