Add contact antispam and fix gallery video playback.
English-only messages, rate limiting, min fill time, and normalized email validation; improve modal video serving with posters, correct MIME types, and no gzip on gallery media. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
package contact
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"technical.kiwi/website/internal/contactcheck"
|
||||
)
|
||||
|
||||
const (
|
||||
maxNameLen = 120
|
||||
maxEmailLen = 254
|
||||
maxMessageLen = 8000
|
||||
minMessageLen = 10
|
||||
minMessageLen = 20
|
||||
)
|
||||
|
||||
// Submission is validated contact form input.
|
||||
@@ -45,18 +48,40 @@ func Parse(name, email, message string) (Submission, Errors) {
|
||||
errs["email"] = "Email is required."
|
||||
} else if utf8.RuneCountInString(email) > maxEmailLen {
|
||||
errs["email"] = "Email is too long."
|
||||
} else if _, err := mail.ParseAddress(email); err != nil {
|
||||
errs["email"] = "Enter a valid email address."
|
||||
} else {
|
||||
addr, err := mail.ParseAddress(email)
|
||||
if err != nil {
|
||||
errs["email"] = "Enter a valid email address."
|
||||
} else {
|
||||
email = addr.Address
|
||||
}
|
||||
}
|
||||
|
||||
if message == "" {
|
||||
errs["message"] = "Message is required."
|
||||
} else if utf8.RuneCountInString(message) < minMessageLen {
|
||||
errs["message"] = "Message must be at least 10 characters."
|
||||
errs["message"] = "Message must be at least 20 characters."
|
||||
} else if utf8.RuneCountInString(message) > maxMessageLen {
|
||||
errs["message"] = "Message is too long."
|
||||
}
|
||||
|
||||
if !errs.Any() {
|
||||
if err := contactcheck.ValidateEnglish(name, message); err != nil {
|
||||
switch {
|
||||
case errors.Is(err, contactcheck.ErrTooShort):
|
||||
errs["message"] = "Message must be at least 20 characters."
|
||||
case errors.Is(err, contactcheck.ErrTooLong):
|
||||
errs["message"] = "Message is too long."
|
||||
case errors.Is(err, contactcheck.ErrName):
|
||||
errs["name"] = "Name is too long."
|
||||
case errors.Is(err, contactcheck.ErrNotEnglish):
|
||||
errs["message"] = "This site only accepts messages written in English. If your message is in English, try adding a few more clear sentences so we can detect the language reliably."
|
||||
default:
|
||||
errs["message"] = "Could not accept this message."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errs.Any() {
|
||||
return Submission{}, errs
|
||||
}
|
||||
|
||||
@@ -12,16 +12,33 @@ func TestParse_valid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_normalizesEmail(t *testing.T) {
|
||||
sub, errs := Parse("Jimmy", "Jane Doe <jane@example.com>", "Hello there, this is a test message.")
|
||||
if errs.Any() {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if sub.Email != "jane@example.com" {
|
||||
t.Fatalf("email = %q", sub.Email)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_shortMessage(t *testing.T) {
|
||||
_, errs := Parse("Jimmy", "jim@example.com", "short")
|
||||
if !errs.Any() {
|
||||
t.Fatal("expected validation error")
|
||||
if errs["message"] == "" {
|
||||
t.Fatal("expected message error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_invalidEmail(t *testing.T) {
|
||||
_, errs := Parse("Jimmy", "not-an-email", "This message is long enough to pass.")
|
||||
_, errs := Parse("Jimmy", "not-an-email", "This message is long enough to pass validation here.")
|
||||
if errs["email"] == "" {
|
||||
t.Fatal("expected email error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_notEnglish(t *testing.T) {
|
||||
_, errs := Parse("Jimmy", "jim@example.com", "これは日本語のテストメッセージです。十分な長さがあります。")
|
||||
if errs["message"] == "" {
|
||||
t.Fatal("expected English-only message error")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user