This commit is contained in:
@@ -15,14 +15,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
maxBodyBytes = 32 << 10
|
||||
maxBodyBytes = 32 << 10
|
||||
perIPLimit = 5
|
||||
perIPWindow = 10 * time.Minute
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
type Server struct {
|
||||
mail mail.Config
|
||||
limiter *limiter
|
||||
@@ -49,7 +46,7 @@ func (s *Server) Routes() http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("POST /api/contact", s.handleContact)
|
||||
mux.HandleFunc("POST /api/signup", s.handleSignup)
|
||||
|
||||
|
||||
mux.HandleFunc("GET /api/verify", s.handleVerify)
|
||||
mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||||
@@ -57,8 +54,6 @@ func (s *Server) Routes() http.Handler {
|
||||
return s.withCORS(mux)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func parseOrigins(raw string) map[string]bool {
|
||||
out := map[string]bool{}
|
||||
for _, o := range strings.Split(raw, ",") {
|
||||
@@ -69,10 +64,6 @@ func parseOrigins(raw string) map[string]bool {
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *Server) withCORS(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
origin := r.Header.Get("Origin")
|
||||
@@ -91,9 +82,6 @@ func (s *Server) withCORS(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *Server) clientIP(r *http.Request) string {
|
||||
if s.trustProxy {
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
@@ -110,15 +98,13 @@ func (s *Server) clientIP(r *http.Request) string {
|
||||
return host
|
||||
}
|
||||
|
||||
|
||||
|
||||
type contactBody struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Servers string `json:"servers"`
|
||||
Topic string `json:"topic"`
|
||||
Message string `json:"message"`
|
||||
Website string `json:"website"`
|
||||
Website string `json:"website"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -137,8 +123,6 @@ func (s *Server) handleContact(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
if strings.TrimSpace(body.Website) != "" {
|
||||
writeJSON(w, http.StatusAccepted, map[string]string{"status": "received"})
|
||||
return
|
||||
@@ -201,9 +185,6 @@ func (s *Server) handleContact(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if err := s.mail.Send(subject(addr, fields), plainBody(addr, fields), addr); err != nil {
|
||||
log.Printf("contact send: %v", err)
|
||||
writeJSON(w, http.StatusBadGateway, map[string]string{
|
||||
@@ -216,7 +197,7 @@ func (s *Server) handleContact(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func subject(addr string, fields map[string]string) string {
|
||||
return fmt.Sprintf("[Vantage] %s — %s", fields["topic"], addr)
|
||||
return fmt.Sprintf("[Vantage] %s %s", fields["topic"], addr)
|
||||
}
|
||||
|
||||
func plainBody(addr string, fields map[string]string) string {
|
||||
@@ -233,8 +214,6 @@ func plainBody(addr string, fields map[string]string) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
|
||||
|
||||
func decode(w http.ResponseWriter, r *http.Request, dst any) bool {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxBodyBytes)
|
||||
dec := json.NewDecoder(r.Body)
|
||||
|
||||
@@ -25,20 +25,15 @@ type signupBody struct {
|
||||
OrgName string `json:"org_name"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Website string `json:"website"`
|
||||
Website string `json:"website"`
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *Server) handleSignup(w http.ResponseWriter, r *http.Request) {
|
||||
var body signupBody
|
||||
if !decode(w, r, &body) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
if strings.TrimSpace(body.Website) != "" {
|
||||
writeJSON(w, http.StatusAccepted, map[string]string{"status": "check_email"})
|
||||
return
|
||||
@@ -114,9 +109,7 @@ func (s *Server) handleSignup(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
link := s.verifyURL(token)
|
||||
if err := s.mail.SendVerification(addr, orgName, link, store.PendingTTL); err != nil {
|
||||
|
||||
|
||||
|
||||
|
||||
log.Printf("signup: send verification to %s: %v", addr, err)
|
||||
writeJSON(w, http.StatusBadGateway, map[string]string{
|
||||
"error": "We could not send the confirmation email. Check the address, or email support@hostxtra.co.uk.",
|
||||
@@ -132,9 +125,6 @@ func (s *Server) verifyURL(token string) string {
|
||||
return fmt.Sprintf("%s/api/verify?token=%s", base, url.QueryEscape(token))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *Server) handleVerify(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.URL.Query().Get("token")
|
||||
if token == "" {
|
||||
@@ -178,9 +168,6 @@ func (s *Server) handleVerify(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Sprintf("%s is set up and you are its owner. You can sign in now.", org.Name))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *Server) verifyPage(w http.ResponseWriter, status int, heading, detail string) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
@@ -193,7 +180,7 @@ func (s *Server) verifyPage(w http.ResponseWriter, status int, heading, detail s
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>%s — Vantage</title>
|
||||
<title>%s Vantage</title>
|
||||
<style>
|
||||
:root { color-scheme: light dark; }
|
||||
body {
|
||||
|
||||
Reference in New Issue
Block a user