package main
import (
"html/template"
"net/http"
"regexp"
"strings"
)
// Safe: Structured data with validation
type ElementData struct {
Class string
ID string
Title string
Valid bool
}
// Safe: Pre-compiled template with auto-escaping
var safeTemplate = template.Must(template.New("page").Parse(`
<html>
<body>
<div class="{{.Class}}" id="{{.ID}}" title="{{.Title}}">Safe Element</div>
{{if .Valid}}<div class="validated">Attributes validated</div>{{end}}
</body>
</html>
`))
// Validation functions
func validateClass(class string) string {
allowedClasses := map[string]bool{
"primary": true,
"secondary": true,
"success": true,
"danger": true,
"warning": true,
"info": true,
}
// Clean and check against whitelist
clean := strings.TrimSpace(strings.ToLower(class))
if allowedClasses[clean] {
return clean
}
return "default" // Safe fallback
}
func validateID(id string) string {
// Only allow alphanumeric, hyphen, underscore
re := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
if re.MatchString(id) && len(id) <= 50 {
return id
}
return "" // Invalid ID
}
func validateTitle(title string) string {
// Limit length and remove dangerous characters
title = strings.TrimSpace(title)
if len(title) > 100 {
title = title[:100]
}
// Remove quotes and script-like content
dangerous := regexp.MustCompile(`[<>'"&]`)
return dangerous.ReplaceAllString(title, "")
}
func safeAttrHandler(w http.ResponseWriter, r *http.Request) {
userClass := r.URL.Query().Get("class")
userID := r.URL.Query().Get("id")
userTitle := r.URL.Query().Get("title")
// Safe: Validate all inputs
data := ElementData{
Class: validateClass(userClass),
ID: validateID(userID),
Title: validateTitle(userTitle),
}
// Mark as valid if all validations passed
data.Valid = data.Class != "" && data.ID != "" && data.Title != ""
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// Safe: Template auto-escapes all values
safeTemplate.Execute(w, data)
}
// Alternative: If HTMLAttr is absolutely necessary
func conditionalAttrHandler(w http.ResponseWriter, r *http.Request) {
userClass := r.URL.Query().Get("class")
// Safe: Only use HTMLAttr with validated, constant strings
var classAttr template.HTMLAttr
switch validateClass(userClass) {
case "primary":
classAttr = template.HTMLAttr(`class="btn btn-primary"`)
case "secondary":
classAttr = template.HTMLAttr(`class="btn btn-secondary"`)
case "danger":
classAttr = template.HTMLAttr(`class="btn btn-danger"`)
default:
classAttr = template.HTMLAttr(`class="btn btn-default"`)
}
tmpl := template.Must(template.New("page").Parse(`
<button {{.ClassAttr}}>Click Me</button>
`))
tmpl.Execute(w, map[string]interface{}{
"ClassAttr": classAttr,
})
}