generate compliant From headers, more tolerance to non-compliant From headers, other fixups
This commit is contained in:
		| @@ -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 <poster@%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 | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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())) | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user