nutrition docker file fix
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Sending email.
|
||||
@@ -97,10 +98,56 @@ func MailFromEnv() MailConfig {
|
||||
Host: env("MAIL_HOST", ""),
|
||||
Port: port,
|
||||
Username: env("MAIL_USERNAME", ""),
|
||||
Password: env("MAIL_PASSWORD", ""),
|
||||
Password: smtpPassword(env("MAIL_HOST", ""), env("MAIL_PASSWORD", "")),
|
||||
// A name is optional; an address is not.
|
||||
FromAddress: env("MAIL_FROM", ""),
|
||||
FromName: env("MAIL_FROM_NAME", "Nearle"),
|
||||
ConsoleURL: env("MAIL_CONSOLE_URL", "https://app.nearledaily.com"),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
smtpPassword takes the spaces out of a Google App Password.
|
||||
|
||||
Google shows a 16-character App Password formatted for reading — "abcd efgh
|
||||
ijkl mnop" — and the spaces are presentation, not part of the secret. Pasted
|
||||
verbatim they survive into the credential and Gmail refuses the login, which
|
||||
Fiesta reports as "the mail server refused our credentials". That sends somebody
|
||||
to revoke a perfectly good password and generate another one with the same four
|
||||
spaces in it.
|
||||
|
||||
ONLY for Google's own SMTP hosts, and only when what is left is the 16
|
||||
alphanumeric characters an App Password actually is. A password is a secret and
|
||||
quietly editing one is normally the wrong thing: another relay's password may
|
||||
legitimately contain a space, and stripping it there would turn a working
|
||||
credential into a silent authentication failure — the exact bug this avoids,
|
||||
pointed the other way.
|
||||
*/
|
||||
func smtpPassword(host, password string) string {
|
||||
if !isGoogleSMTP(host) {
|
||||
return password
|
||||
}
|
||||
|
||||
stripped := strings.Join(strings.Fields(password), "")
|
||||
if stripped == password || len(stripped) != googleAppPasswordLength {
|
||||
return password
|
||||
}
|
||||
for _, r := range stripped {
|
||||
if !unicode.IsLetter(r) && !unicode.IsDigit(r) {
|
||||
return password
|
||||
}
|
||||
}
|
||||
return stripped
|
||||
}
|
||||
|
||||
// googleAppPasswordLength is what Google issues: sixteen characters, shown in
|
||||
// four groups of four.
|
||||
const googleAppPasswordLength = 16
|
||||
|
||||
func isGoogleSMTP(host string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(host)) {
|
||||
case "smtp.gmail.com", "smtp-relay.gmail.com", "aspmx.l.google.com":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -34,3 +34,62 @@ func TestCommittedEnvLeavesMailOffWithAReason(t *testing.T) {
|
||||
t.Fatalf("wrong SMTP address: %q", on.Address())
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Google App Passwords ────────────────────────────────────────────────── */
|
||||
|
||||
func TestAGoogleAppPasswordSurvivesBeingPastedWithItsSpaces(t *testing.T) {
|
||||
// Google shows it as "abcd efgh ijkl mnop". The spaces are presentation.
|
||||
// Pasted verbatim they reach Gmail, which refuses the login — reported as
|
||||
// "the mail server refused our credentials", sending somebody to revoke a
|
||||
// password that was fine.
|
||||
t.Setenv("MAIL_HOST", "smtp.gmail.com")
|
||||
t.Setenv("MAIL_PORT", "587")
|
||||
t.Setenv("MAIL_USERNAME", "care@nearledaily.com")
|
||||
t.Setenv("MAIL_PASSWORD", "abcd efgh ijkl mnop")
|
||||
t.Setenv("MAIL_FROM", "care@nearledaily.com")
|
||||
t.Setenv("MAIL_CONSOLE_URL", "https://app.nearledaily.com")
|
||||
|
||||
if got := MailFromEnv().Password; got != "abcdefghijklmnop" {
|
||||
t.Fatalf("password reached the relay as %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnAlreadyCleanAppPasswordIsUntouched(t *testing.T) {
|
||||
t.Setenv("MAIL_HOST", "smtp.gmail.com")
|
||||
t.Setenv("MAIL_PASSWORD", "abcdefghijklmnop")
|
||||
|
||||
if got := MailFromEnv().Password; got != "abcdefghijklmnop" {
|
||||
t.Fatalf("got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnotherRelaysPasswordIsNeverEdited(t *testing.T) {
|
||||
// A secret is a secret. Another relay's password may legitimately contain a
|
||||
// space, and stripping it there turns a working credential into a silent
|
||||
// authentication failure — this bug pointed the other way.
|
||||
for _, host := range []string{"smtp.sendgrid.net", "email-smtp.ap-south-1.amazonaws.com", "postal.nearledaily.com"} {
|
||||
t.Setenv("MAIL_HOST", host)
|
||||
t.Setenv("MAIL_PASSWORD", "two words here x")
|
||||
|
||||
if got := MailFromEnv().Password; got != "two words here x" {
|
||||
t.Errorf("%s: password was edited to %q", host, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSomethingThatIsNotAnAppPasswordIsLeftAlone(t *testing.T) {
|
||||
// Only the exact shape Google issues — sixteen alphanumerics — is treated
|
||||
// as display formatting. Anything else is somebody's real password.
|
||||
t.Setenv("MAIL_HOST", "smtp.gmail.com")
|
||||
|
||||
for _, password := range []string{
|
||||
"short one", // not 16 after stripping
|
||||
"a much longer pass phrase here", // not 16
|
||||
"abcd efgh ijkl mno!", // punctuation: not an App Password
|
||||
} {
|
||||
t.Setenv("MAIL_PASSWORD", password)
|
||||
if got := MailFromEnv().Password; got != password {
|
||||
t.Errorf("%q was rewritten to %q", password, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user