diff options
| author | 2022-01-31 10:46:20 +0000 | |
|---|---|---|
| committer | 2022-01-31 11:46:20 +0100 | |
| commit | 5be8a7a7ea96d962d0f0b9f09b967e403a227698 (patch) | |
| tree | 448ae55de146463dc86005e55ae5f2e1eb8f8bc8 | |
| parent | [bug] Fix sqlite empty address issue (#370) (diff) | |
| download | gotosocial-5be8a7a7ea96d962d0f0b9f09b967e403a227698.tar.xz | |
[bug] Send plaintext emails to fix "message refused: Message is not RFC 2822 compliant" (#366)
* trying to fix "message refused: Message is not RFC 2822 compliant"
* fix "message refused: Message is not RFC 2822 compliant"
550 5.7.1 Delivery not authorized, message refused: Message is not RFC
2822 compliant
* remove silly regex
* lint
* fix tests
* we should use text/template instead of html/template now
| -rw-r--r-- | internal/email/confirm.go | 14 | ||||
| -rw-r--r-- | internal/email/noopsender.go | 12 | ||||
| -rw-r--r-- | internal/email/reset.go | 9 | ||||
| -rw-r--r-- | internal/email/sender.go | 2 | ||||
| -rw-r--r-- | internal/email/util.go | 45 | ||||
| -rw-r--r-- | internal/email/util_test.go | 4 | ||||
| -rw-r--r-- | internal/processing/user/emailconfirm_test.go | 2 | ||||
| -rw-r--r-- | web/template/email_confirm_html.tmpl (renamed from web/template/email_confirm.tmpl) | 0 | ||||
| -rw-r--r-- | web/template/email_confirm_text.tmpl | 9 | ||||
| -rw-r--r-- | web/template/email_reset_html.tmpl (renamed from web/template/email_reset.tmpl) | 0 | ||||
| -rw-r--r-- | web/template/email_reset_text.tmpl | 9 | 
11 files changed, 78 insertions, 28 deletions
diff --git a/internal/email/confirm.go b/internal/email/confirm.go index 4503137b3..34e2fb660 100644 --- a/internal/email/confirm.go +++ b/internal/email/confirm.go @@ -21,11 +21,15 @@ package email  import (  	"bytes"  	"net/smtp" + +	"github.com/sirupsen/logrus" +	"github.com/spf13/viper" +	"github.com/superseriousbusiness/gotosocial/internal/config"  )  const ( -	confirmTemplate = "email_confirm.tmpl" -	confirmSubject  = "Subject: GoToSocial Email Confirmation" +	confirmTemplate = "email_confirm_text.tmpl" +	confirmSubject  = "GoToSocial Email Confirmation"  )  func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error { @@ -35,7 +39,11 @@ func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {  	}  	confirmBody := buf.String() -	msg := assembleMessage(confirmSubject, confirmBody, toAddress, s.from) +	msg, err := assembleMessage(confirmSubject, confirmBody, toAddress, s.from) +	if err != nil { +		return err +	} +	logrus.WithField("func", "SendConfirmEmail").Trace(s.hostAddress + "\n" + viper.GetString(config.Keys.SMTPUsername) + ":password" + "\n" + s.from + "\n" + toAddress + "\n\n" + string(msg) + "\n")  	return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)  } diff --git a/internal/email/noopsender.go b/internal/email/noopsender.go index efec303f0..9f587f319 100644 --- a/internal/email/noopsender.go +++ b/internal/email/noopsender.go @@ -20,7 +20,7 @@ package email  import (  	"bytes" -	"html/template" +	"text/template"  	"github.com/sirupsen/logrus"  	"github.com/spf13/viper" @@ -57,7 +57,10 @@ func (s *noopSender) SendConfirmEmail(toAddress string, data ConfirmData) error  	}  	confirmBody := buf.String() -	msg := assembleMessage(confirmSubject, confirmBody, toAddress, "test@example.org") +	msg, err := assembleMessage(confirmSubject, confirmBody, toAddress, "test@example.org") +	if err != nil { +		return err +	}  	logrus.Tracef("NOT SENDING confirmation email to %s with contents: %s", toAddress, msg) @@ -74,7 +77,10 @@ func (s *noopSender) SendResetEmail(toAddress string, data ResetData) error {  	}  	resetBody := buf.String() -	msg := assembleMessage(resetSubject, resetBody, toAddress, "test@example.org") +	msg, err := assembleMessage(resetSubject, resetBody, toAddress, "test@example.org") +	if err != nil { +		return err +	}  	logrus.Tracef("NOT SENDING reset email to %s with contents: %s", toAddress, msg) diff --git a/internal/email/reset.go b/internal/email/reset.go index 7a08ebda9..b646ef99b 100644 --- a/internal/email/reset.go +++ b/internal/email/reset.go @@ -24,8 +24,8 @@ import (  )  const ( -	resetTemplate = "email_reset.tmpl" -	resetSubject  = "Subject: GoToSocial Password Reset" +	resetTemplate = "email_reset_text.tmpl" +	resetSubject  = "GoToSocial Password Reset"  )  func (s *sender) SendResetEmail(toAddress string, data ResetData) error { @@ -35,7 +35,10 @@ func (s *sender) SendResetEmail(toAddress string, data ResetData) error {  	}  	resetBody := buf.String() -	msg := assembleMessage(resetSubject, resetBody, toAddress, s.from) +	msg, err := assembleMessage(resetSubject, resetBody, toAddress, s.from) +	if err != nil { +		return err +	}  	return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)  } diff --git a/internal/email/sender.go b/internal/email/sender.go index 97bbcd23b..f44627496 100644 --- a/internal/email/sender.go +++ b/internal/email/sender.go @@ -20,8 +20,8 @@ package email  import (  	"fmt" -	"html/template"  	"net/smtp" +	"text/template"  	"github.com/spf13/viper"  	"github.com/superseriousbusiness/gotosocial/internal/config" diff --git a/internal/email/util.go b/internal/email/util.go index db95128fa..52290dbe4 100644 --- a/internal/email/util.go +++ b/internal/email/util.go @@ -19,15 +19,12 @@  package email  import ( +	"errors"  	"fmt" -	"html/template"  	"os"  	"path/filepath" -) - -const ( -	mime = `MIME-version: 1.0; -Content-Type: text/html;` +	"strings" +	"text/template"  )  func loadTemplates(templateBaseDir string) (*template.Template, error) { @@ -41,16 +38,34 @@ func loadTemplates(templateBaseDir string) (*template.Template, error) {  	return template.ParseGlob(tmPath)  } -func assembleMessage(mailSubject string, mailBody string, mailTo string, mailFrom string) []byte { -	from := fmt.Sprintf("From: GoToSocial <%s>", mailFrom) -	to := fmt.Sprintf("To: %s", mailTo) +// https://datatracker.ietf.org/doc/html/rfc2822 +// I did not read the RFC, I just copy and pasted from +// https://pkg.go.dev/net/smtp#SendMail +// and it did seem to work. +func assembleMessage(mailSubject string, mailBody string, mailTo string, mailFrom string) ([]byte, error) { + +	if strings.Contains(mailSubject, "\r") || strings.Contains(mailSubject, "\n") { +		return nil, errors.New("email subject must not contain newline characters") +	} + +	if strings.Contains(mailFrom, "\r") || strings.Contains(mailFrom, "\n") { +		return nil, errors.New("email from address must not contain newline characters") +	} + +	if strings.Contains(mailTo, "\r") || strings.Contains(mailTo, "\n") { +		return nil, errors.New("email to address must not contain newline characters") +	} + +	// normalize the message body to use CRLF line endings +	mailBody = strings.ReplaceAll(mailBody, "\r\n", "\n") +	mailBody = strings.ReplaceAll(mailBody, "\n", "\r\n")  	msg := []byte( -		mailSubject + "\r\n" + -			from + "\r\n" + -			to + "\r\n" + -			mime + "\r\n" + -			mailBody + "\r\n") +		"To: " + mailTo + "\r\n" + +			"Subject: " + mailSubject + "\r\n" + +			"\r\n" + +			mailBody + "\r\n", +	) -	return msg +	return msg, nil  } diff --git a/internal/email/util_test.go b/internal/email/util_test.go index b5c7a9852..8895785f7 100644 --- a/internal/email/util_test.go +++ b/internal/email/util_test.go @@ -39,7 +39,7 @@ func (suite *UtilTestSuite) TestTemplateConfirm() {  	suite.sender.SendConfirmEmail("user@example.org", confirmData)  	suite.Len(suite.sentEmails, 1) -	suite.Equal("Subject: GoToSocial Email Confirmation\r\nFrom: GoToSocial <test@example.org>\r\nTo: user@example.org\r\nMIME-version: 1.0;\nContent-Type: text/html;\r\n<!DOCTYPE html>\n<html>\n    </head>\n    <body>\n        <div>\n            <h1>\n                Hello test!\n            </h1>\n        </div>\n        <div>\n            <p>\n                You are receiving this mail because you've requested an account on <a href=\"https://example.org\">Test Instance</a>.\n            </p>\n            <p>\n                We just need to confirm that this is your email address. To confirm your email, <a href=\"https://example.org/confirm_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\">click here</a> or paste the following in your browser's address bar:\n            </p>\n            <p>\n                <code>\n                    https://example.org/confirm_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\n                </code>\n            </p>\n        </div>\n        <div>\n            <p>\n                If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of <a href=\"https://example.org\">Test Instance</a>.\n            </p>\n        </div>\n    </body>\n</html>\r\n", suite.sentEmails["user@example.org"]) +	suite.Equal("To: user@example.org\r\nSubject: GoToSocial Email Confirmation\r\n\r\nHello test!\r\n\r\nYou are receiving this mail because you've requested an account on https://example.org.\r\n\r\nWe just need to confirm that this is your email address. To confirm your email, paste the following in your browser's address bar:\r\n\r\nhttps://example.org/confirm_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\r\n\r\nIf you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of https://example.org\r\n\r\n", suite.sentEmails["user@example.org"])  }  func (suite *UtilTestSuite) TestTemplateReset() { @@ -52,7 +52,7 @@ func (suite *UtilTestSuite) TestTemplateReset() {  	suite.sender.SendResetEmail("user@example.org", resetData)  	suite.Len(suite.sentEmails, 1) -	suite.Equal("Subject: GoToSocial Password Reset\r\nFrom: GoToSocial <test@example.org>\r\nTo: user@example.org\r\nMIME-version: 1.0;\nContent-Type: text/html;\r\n<!DOCTYPE html>\n<html>\n    </head>\n    <body>\n        <div>\n            <h1>\n                Hello test!\n            </h1>\n        </div>\n        <div>\n            <p>\n                You are receiving this mail because a password reset has been requested for your account on <a href=\"https://example.org\">Test Instance</a>.\n            </p>\n            <p>\n                To reset your password, <a href=\"https://example.org/reset_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\">click here</a> or paste the following in your browser's address bar:\n            </p>\n            <p>\n                <code>\n                    https://example.org/reset_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\n                </code>\n            </p>\n        </div>\n        <div>\n            <p>\n                If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of <a href=\"https://example.org\">Test Instance</a>.\n            </p>\n        </div>\n    </body>\n</html>\r\n", suite.sentEmails["user@example.org"]) +	suite.Equal("To: user@example.org\r\nSubject: GoToSocial Password Reset\r\n\r\nHello test!\r\n\r\nYou are receiving this mail because a password reset has been requested for your account on https://example.org.\r\n\r\nTo reset your password, paste the following in your browser's address bar:\r\n\r\nhttps://example.org/reset_email?token=ee24f71d-e615-43f9-afae-385c0799b7fa\r\n\r\nIf you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of https://example.org.\r\n\r\n", suite.sentEmails["user@example.org"])  }  func TestUtilTestSuite(t *testing.T) { diff --git a/internal/processing/user/emailconfirm_test.go b/internal/processing/user/emailconfirm_test.go index 58836d40d..6f22306a1 100644 --- a/internal/processing/user/emailconfirm_test.go +++ b/internal/processing/user/emailconfirm_test.go @@ -54,7 +54,7 @@ func (suite *EmailConfirmTestSuite) TestSendConfirmEmail() {  	suite.NotEmpty(token)  	// email should contain the token -	emailShould := fmt.Sprintf("Subject: GoToSocial Email Confirmation\r\nFrom: GoToSocial <test@example.org>\r\nTo: some.email@example.org\r\nMIME-version: 1.0;\nContent-Type: text/html;\r\n<!DOCTYPE html>\n<html>\n    </head>\n    <body>\n        <div>\n            <h1>\n                Hello the_mighty_zork!\n            </h1>\n        </div>\n        <div>\n            <p>\n                You are receiving this mail because you've requested an account on <a href=\"http://localhost:8080\">localhost:8080</a>.\n            </p>\n            <p>\n                We just need to confirm that this is your email address. To confirm your email, <a href=\"http://localhost:8080/confirm_email?token=%s\">click here</a> or paste the following in your browser's address bar:\n            </p>\n            <p>\n                <code>\n                    http://localhost:8080/confirm_email?token=%s\n                </code>\n            </p>\n        </div>\n        <div>\n            <p>\n                If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of <a href=\"http://localhost:8080\">localhost:8080</a>.\n            </p>\n        </div>\n    </body>\n</html>\r\n", token, token) +	emailShould := fmt.Sprintf("To: some.email@example.org\r\nSubject: GoToSocial Email Confirmation\r\n\r\nHello the_mighty_zork!\r\n\r\nYou are receiving this mail because you've requested an account on http://localhost:8080.\r\n\r\nWe just need to confirm that this is your email address. To confirm your email, paste the following in your browser's address bar:\r\n\r\nhttp://localhost:8080/confirm_email?token=%s\r\n\r\nIf you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of http://localhost:8080\r\n\r\n", token)  	suite.Equal(emailShould, email)  	// confirmationSentAt should be recent diff --git a/web/template/email_confirm.tmpl b/web/template/email_confirm_html.tmpl index 0a9907921..0a9907921 100644 --- a/web/template/email_confirm.tmpl +++ b/web/template/email_confirm_html.tmpl diff --git a/web/template/email_confirm_text.tmpl b/web/template/email_confirm_text.tmpl new file mode 100644 index 000000000..8682cc49c --- /dev/null +++ b/web/template/email_confirm_text.tmpl @@ -0,0 +1,9 @@ +Hello {{.Username}}! + +You are receiving this mail because you've requested an account on {{.InstanceURL}}. + +We just need to confirm that this is your email address. To confirm your email, paste the following in your browser's address bar: + +{{.ConfirmLink}} + +If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{.InstanceURL}} diff --git a/web/template/email_reset.tmpl b/web/template/email_reset_html.tmpl index 7318c6a45..7318c6a45 100644 --- a/web/template/email_reset.tmpl +++ b/web/template/email_reset_html.tmpl diff --git a/web/template/email_reset_text.tmpl b/web/template/email_reset_text.tmpl new file mode 100644 index 000000000..ccac3bf75 --- /dev/null +++ b/web/template/email_reset_text.tmpl @@ -0,0 +1,9 @@ +Hello {{.Username}}! + +You are receiving this mail because a password reset has been requested for your account on {{.InstanceURL}}. + +To reset your password, paste the following in your browser's address bar: + +{{.ResetLink}} + +If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{.InstanceURL}}.  | 
