sanitize html with bluemonday

This commit is contained in:
Guilherme Rugai Freire 2024-07-10 17:31:09 -03:00
parent 36f8ff684a
commit 8ef8cf75ef
No known key found for this signature in database
GPG Key ID: AC1D9B6E48E16AC1
5 changed files with 26 additions and 17 deletions

View File

@ -5,6 +5,5 @@ A temporary email service
## TODO
- Do not store the raw mail data in the DB, maybe use block storage (the provider can be a disk provider at first)
- Use `bluemonday` to sanitize the mail html before rendering
- Cache subject parsed from email. Then when listing the email it is not necessary to parse all mails and retrieve them.
- Cache in general?

4
go.mod
View File

@ -10,7 +10,7 @@ require (
github.com/go-chi/chi v1.5.5 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/net v0.26.0 // indirect
)

4
go.sum
View File

@ -16,7 +16,11 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=

View File

@ -2,10 +2,11 @@ package web_server
import (
"github.com/russross/blackfriday/v2"
"github.com/microcosm-cc/bluemonday"
"github.com/GRFreire/nthmail/pkg/mail_utils"
)
templ mail_body_comp(rcpt_addr string, m mail_utils.Mail_obj) {
templ mail_body_comp(rcpt_addr string, m mail_utils.Mail_obj, policy *bluemonday.Policy) {
<!DOCTYPE html>
<html lang="en">
<head>
@ -32,16 +33,16 @@ templ mail_body_comp(rcpt_addr string, m mail_utils.Mail_obj) {
</div>
</div>
<main>
@mime_type(m.Body[m.PreferedBodyIndex])
@mime_type(m.Body[m.PreferedBodyIndex], policy)
</main>
</body>
</html>
}
templ mime_type(b mail_utils.Mail_body) {
templ mime_type(b mail_utils.Mail_body, policy *bluemonday.Policy) {
switch b.MimeType {
case mail_utils.Html:
@body_html(b.Data)
@body_html(b.Data, policy)
case mail_utils.Markdown:
@body_markdown(b.Data)
case mail_utils.PlainText:
@ -59,9 +60,9 @@ templ body_plain(s string) {
</div>
}
templ body_html(s string) {
templ body_html(s string, policy *bluemonday.Policy) {
<div class="content-html">
@templ.Raw(s)
@templ.Raw(policy.Sanitize(s))
</div>
}

View File

@ -14,11 +14,15 @@ import (
"github.com/GRFreire/nthmail/pkg/rig"
"github.com/go-chi/chi"
_ "github.com/mattn/go-sqlite3"
"github.com/microcosm-cc/bluemonday"
)
func Start(db *sql.DB) error {
server := &ServerResouces{}
server.db = db
server.db = db
server.policy = bluemonday.UGCPolicy()
server.policy.AllowAttrs("style").Globally()
domain, exists := os.LookupEnv("MAIL_SERVER_DOMAIN")
if !exists {
@ -27,7 +31,7 @@ func Start(db *sql.DB) error {
server.domain = domain
var port int
var err error
var err error
port_str, exists := os.LookupEnv("WEB_SERVER_PORT")
if exists {
port, err = strconv.Atoi(port_str)
@ -46,11 +50,12 @@ func Start(db *sql.DB) error {
return err
}
return nil
return nil
}
type ServerResouces struct {
db *sql.DB
policy *bluemonday.Policy
domain string
}
@ -98,7 +103,7 @@ func (sr ServerResouces) handleInbox(res http.ResponseWriter, req *http.Request)
log.Println("could not begin db transaction")
return
}
defer tx.Commit()
defer tx.Commit()
stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ?")
if err != nil {
@ -133,7 +138,7 @@ func (sr ServerResouces) handleInbox(res http.ResponseWriter, req *http.Request)
}
mail_obj, err := mail_utils.Parse_mail(m.Data, true)
mail_obj.Date = time.Unix(m.Arrived_at, 0)
mail_obj.Date = time.Unix(m.Arrived_at, 0)
mail_obj.Id = m.Id
if err != nil {
res.WriteHeader(500)
@ -174,7 +179,7 @@ func (sr ServerResouces) handleMail(res http.ResponseWriter, req *http.Request)
log.Println("could not begin db transaction")
return
}
defer tx.Commit()
defer tx.Commit()
stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ? AND mails.id = ?")
if err != nil {
@ -200,7 +205,7 @@ func (sr ServerResouces) handleMail(res http.ResponseWriter, req *http.Request)
}
mail_obj, err := mail_utils.Parse_mail(m.Data, false)
mail_obj.Date = time.Unix(m.Arrived_at, 0)
mail_obj.Date = time.Unix(m.Arrived_at, 0)
mail_obj.Id = m.Id
if err != nil {
res.WriteHeader(500)
@ -213,6 +218,6 @@ func (sr ServerResouces) handleMail(res http.ResponseWriter, req *http.Request)
mail_obj = mail_utils.Set_format_index(mail_obj, format, f_pref)
body := mail_body_comp(rcpt_addr, mail_obj)
body := mail_body_comp(rcpt_addr, mail_obj, sr.policy)
body.Render(req.Context(), res)
}