From 7e6f143108cea1aa43f30c963c44f78bf56e6837 Mon Sep 17 00:00:00 2001 From: cathugger Date: Tue, 11 Dec 2018 22:56:29 +0000 Subject: [PATCH] generate compliant From headers, more tolerance to non-compliant From headers, other fixups --- .../backends/srndv2/src/srnd/frontend_http.go | 6 +++- contrib/backends/srndv2/src/srnd/message.go | 23 +++++++++--- contrib/backends/srndv2/src/srnd/nntp.go | 35 ++++++++----------- contrib/backends/srndv2/src/srnd/util.go | 13 +++++++ 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/contrib/backends/srndv2/src/srnd/frontend_http.go b/contrib/backends/srndv2/src/srnd/frontend_http.go index dd37673..c87798d 100644 --- a/contrib/backends/srndv2/src/srnd/frontend_http.go +++ b/contrib/backends/srndv2/src/srnd/frontend_http.go @@ -19,6 +19,7 @@ import ( "log" "mime" "net/http" + "net/mail" "strings" "time" ) @@ -829,7 +830,10 @@ func (self *httpFrontend) handle_postRequest(pr *postRequest, b bannedFunc, e er msgid = genMessageID(pr.Frontend) } - nntp.headers.Set("From", nntpSanitize(fmt.Sprintf("%s ", name, pr.Frontend))) + nntp.headers.Set("From", (&mail.Address{ + Name: name, + Address: "poster@" + pr.Frontend, + }).String()) nntp.headers.Set("Message-ID", msgid) // set message diff --git a/contrib/backends/srndv2/src/srnd/message.go b/contrib/backends/srndv2/src/srnd/message.go index e12cebe..a0a8922 100644 --- a/contrib/backends/srndv2/src/srnd/message.go +++ b/contrib/backends/srndv2/src/srnd/message.go @@ -135,7 +135,7 @@ func (self *nntpArticle) Reset() { self.boundary = "" self.message = "" if self.attachments != nil { - for idx, _ := range self.attachments { + for idx := range self.attachments { self.attachments[idx].Reset() self.attachments[idx] = nil } @@ -156,7 +156,10 @@ func newPlaintextArticle(message, email, subject, name, instance, message_id, ne nntp := &nntpArticle{ headers: make(ArticleHeaders), } - nntp.headers.Set("From", fmt.Sprintf("%s <%s>", name, email)) + nntp.headers.Set("From", (&mail.Address{ + Name: name, + Address: email, + }).String()) nntp.headers.Set("Subject", subject) if isSage(subject) { nntp.headers.Set("X-Sage", "1") @@ -296,18 +299,30 @@ func (self *nntpArticle) Newsgroup() string { func (self *nntpArticle) Name() string { const defname = "Anonymous" + from := strings.TrimSpace(self.headers.Get("From", "")) if from == "" { return defname } + a, e := mail.ParseAddress(from) + var name string if e != nil { - return fmt.Sprintf("[Invalid From header: %v]", e) + // try older method - some nodes generate non-compliant stuff + if i := strings.IndexByte(from, '<'); i > 1 { + name = from[:i] + } else { + return "[Invalid From header]" + } + } else { + name = a.Name } - name := strings.TrimSpace(a.Name) + + name = safeHeader(name) if name == "" { return defname } + return name } diff --git a/contrib/backends/srndv2/src/srnd/nntp.go b/contrib/backends/srndv2/src/srnd/nntp.go index 19a0e7f..2de8ca1 100644 --- a/contrib/backends/srndv2/src/srnd/nntp.go +++ b/contrib/backends/srndv2/src/srnd/nntp.go @@ -550,13 +550,6 @@ func (self *nntpConnection) checkMIMEHeaderNoAuth(daemon *NNTPDaemon, hdr textpr return } -var overReplacer = strings.NewReplacer("\t", " ", "\n", " ", "\r", "", "\000", "") - -// safeOver cleans string for OVER/XOVER output -func safeOver(s string) string { - return strings.TrimSpace(overReplacer.Replace(s)) -} - func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string, conn *textproto.Conn) (err error) { parts := strings.Split(line, " ") var msgid string @@ -922,24 +915,24 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string if model != nil { if err == nil { /* - The first 8 fields MUST be the following, in order: - "0" or article number (see below) - Subject header content - From header content - Date header content - Message-ID header content - References header content - :bytes metadata item - :lines metadata item + The first 8 fields MUST be the following, in order: + "0" or article number (see below) + Subject header content + From header content + Date header content + Message-ID header content + References header content + :bytes metadata item + :lines metadata item */ fmt.Fprintf(dw, "%.6d\t%s\t\"%s\" <%s@%s>\t%s\t%s\t%s\r\n", model.NNTPID(), - safeOver(model.Subject()), - safeOver(model.Name()), safeOver(model.Name()), safeOver(model.Frontend()), - safeOver(model.Date()), - safeOver(model.MessageID()), - safeOver(model.Reference())) + safeHeader(model.Subject()), + safeHeader(model.Name()), safeHeader(model.Name()), safeHeader(model.Frontend()), + safeHeader(model.Date()), + safeHeader(model.MessageID()), + safeHeader(model.Reference())) } } } diff --git a/contrib/backends/srndv2/src/srnd/util.go b/contrib/backends/srndv2/src/srnd/util.go index 70db80d..e3c6706 100644 --- a/contrib/backends/srndv2/src/srnd/util.go +++ b/contrib/backends/srndv2/src/srnd/util.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "time" + "unicode" ) func DelFile(fname string) { @@ -161,6 +162,18 @@ func nntpSanitize(data string) (ret string) { return ret } +var safeHeaderReplacer = strings.NewReplacer( + "\t", " ", + "\n", string(unicode.ReplacementChar), + "\r", string(unicode.ReplacementChar), + "\000", string(unicode.ReplacementChar)) + +// safeHeader replaces dangerous stuff from header, +// also replaces space with tab for XOVER/OVER output +func safeHeader(s string) string { + return strings.TrimSpace(safeHeaderReplacer.Replace(s)) +} + type int64Sorter []int64 func (self int64Sorter) Len() int {