58c1237326
- Add contact form dialog with HTMX integration (hx-post) - Implement browser-only access middleware (blocks curl/Postman/wget) - Add rate limiting (5 requests/hour per IP) for contact endpoint - Implement honeypot and timing-based bot detection - Add input validation (email format, message length 10-5000 chars) - Create contact button in desktop and mobile navigation (last position) Security features: - Browser-only middleware validates User-Agent, Referer/Origin, HX-Request headers - Honeypot field returns fake success to fool bots while logging spam - Timing validation rejects forms submitted < 2 seconds - All security events logged for monitoring Documentation: - docs/SECURITY.md - Comprehensive security documentation - docs/HACK-CHALLENGE.md - "Try to Hack Me!" challenge for security researchers - docs/SECURITY-AUDIT-REPORT.md - Full security audit report - docs/CONTACT-FORM-QUICKSTART.md - Integration guide Form fields: email (required), name, company, subject, message (required)
109 lines
2.5 KiB
Go
109 lines
2.5 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
// Config holds all application configuration
|
|
type Config struct {
|
|
Server ServerConfig
|
|
Template TemplateConfig
|
|
Data DataConfig
|
|
Email EmailConfig
|
|
}
|
|
|
|
// ServerConfig contains server-specific settings
|
|
type ServerConfig struct {
|
|
Port string
|
|
Host string
|
|
ReadTimeout int
|
|
WriteTimeout int
|
|
}
|
|
|
|
// TemplateConfig contains template-specific settings
|
|
type TemplateConfig struct {
|
|
Dir string
|
|
PartialsDir string
|
|
HotReload bool
|
|
}
|
|
|
|
// DataConfig contains data directory settings
|
|
type DataConfig struct {
|
|
Dir string
|
|
}
|
|
|
|
// EmailConfig contains email/SMTP settings
|
|
type EmailConfig struct {
|
|
SMTPHost string
|
|
SMTPPort string
|
|
SMTPUser string
|
|
SMTPPassword string
|
|
FromEmail string
|
|
ContactEmail string
|
|
}
|
|
|
|
// Load creates a new Config with values from environment or defaults
|
|
func Load() *Config {
|
|
return &Config{
|
|
Server: ServerConfig{
|
|
Port: getEnv("PORT", "1999"),
|
|
Host: getEnv("HOST", "localhost"),
|
|
ReadTimeout: getEnvAsInt("READ_TIMEOUT", 15),
|
|
WriteTimeout: getEnvAsInt("WRITE_TIMEOUT", 15),
|
|
},
|
|
Template: TemplateConfig{
|
|
Dir: getEnv("TEMPLATE_DIR", "templates"),
|
|
PartialsDir: getEnv("PARTIALS_DIR", "templates/partials"),
|
|
HotReload: getEnvAsBool("TEMPLATE_HOT_RELOAD", isDevelopment()),
|
|
},
|
|
Data: DataConfig{
|
|
Dir: getEnv("DATA_DIR", "data"),
|
|
},
|
|
Email: EmailConfig{
|
|
SMTPHost: getEnv("SMTP_HOST", "smtp.gmail.com"),
|
|
SMTPPort: getEnv("SMTP_PORT", "587"),
|
|
SMTPUser: getEnv("SMTP_USER", ""),
|
|
SMTPPassword: getEnv("SMTP_PASSWORD", ""),
|
|
FromEmail: getEnv("SMTP_FROM_EMAIL", ""),
|
|
ContactEmail: getEnv("CONTACT_EMAIL", "txeo.msx@gmail.com"),
|
|
},
|
|
}
|
|
}
|
|
|
|
// Address returns the server address in host:port format
|
|
func (c *Config) Address() string {
|
|
return fmt.Sprintf("%s:%s", c.Server.Host, c.Server.Port)
|
|
}
|
|
|
|
// Helper functions
|
|
|
|
func getEnv(key, defaultValue string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func getEnvAsInt(key string, defaultValue int) int {
|
|
valueStr := os.Getenv(key)
|
|
if value, err := strconv.Atoi(valueStr); err == nil {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func getEnvAsBool(key string, defaultValue bool) bool {
|
|
valueStr := os.Getenv(key)
|
|
if value, err := strconv.ParseBool(valueStr); err == nil {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func isDevelopment() bool {
|
|
env := getEnv("GO_ENV", "development")
|
|
return env == "development" || env == "dev"
|
|
}
|